PF 防火墙

当我们使用 Linux 时,iptables 能够很容易的实现对入站和出站的访问控制,也能够很容易的完成端口转发与 NAT 转化等需求。那么在 Mac 上该怎么做到呢?

实际上,macOS 预置了从 OpenBSD 引入的 PF 防火墙。

基本结构

PF Firewall 主要由以下三个文件完成配置和加载

/etc/pf.conf

PF Firewall 的配置文件,规则的存放位置,锚点 \(anchors\) 文件也可以在这里被指定进行加载

/etc/pf.conf/anchors/

pf.conf 中需要加载的锚点文件的存放目录。

/System/Library/LaunchDaemons/com.apple.pfctl.plist

在启动时执行 "pfctl -f /etc/pf.conf" 完成 PF Firewall 的加载。

修改配置文件

你可以直接修改 /etc/pf.conf, 但是该文件会在系统每次升级后被重置。因此,最好的办法是另外写一份配置文件 /opt/pf.conf,然后设置为开机自动加载。

  • 配置文件

en3 是当前正在使用的物理网卡,请根据情况配置

# PF Set
set block-policy drop
set fingerprints '/etc/pf.os'
set skip on lo0
scrub-anchor "com.apple/*"

# NAT NET
nat on en3 from 198.51.100.0/24 to any -> (en3)

# TABLES
table <Everyone> {0.0.0.0/0 ::/0 } persist
table <192.168-net> {192.168.0.0/16 } persist
table <10-net> {10.0.0.0/8 } persist
table <172.16-net> {172.16.0.0/12 } persist
table <IPv6-net> {fe80::/10 } persist
table <169.254-net> {169.254.0.0/16 } persist
table <bruteforce> { } persist
table <Blacklist> { 104.24.28.50 104.24.29.50 } persist
table <sshguard> { } persist
table <spam> { } persist
table <NatLanInterfaces> {en3 }

# Block
block in quick from <sshguard> to any label "SSHGuard_BruteForce"
block in quick proto tcp  from <spam> to any port {25 465 }
block in log quick from <Blacklist> to any label "BlackList_IN"
block out log quick from any to <Blacklist> label "BlackList_OUT"
block in quick from no-route to any label "NO_BACK_ROUTE"
block in quick from urpf-failed label "uRPF"
#block log inet all label "Generic_blocks_(IPv4)"
block log inet6 all label "Generic_blocks_(IPv6)"

# MDNS
pass proto igmp allow-opts
pass quick from any to {224.0.0.0/4 ff00::/8} allow-opts
pass in quick proto udp from any port {5353} to any port {5353} allow-opts
pass out quick proto udp from any port {5353} to any port {5353} allow-opts

# APPLE ANCHOR
anchor 'com.apple/*'
load anchor 'com.apple' from '/etc/pf.anchors/com.apple'

# INBOUND ALLOW
block in quick from <bruteforce> to any label "Inbound"
block in proto {tcp, udp} from any to any port {49152:65535} label "Inbound"
block in proto {tcp, udp} from any to any port {53 67 68 123 389 546 547 636 5353 5354} label "Inbound"
pass in proto {tcp, udp} from <192.168-net> to any port {53 67 68 123 389 546 547 636 5353 5354} flags S/SA keep state label "Inbound"
pass in proto {tcp, udp} from <10-net> to any port {53 67 68 123 389 546 547 636 5353 5354} flags S/SA keep state label "Inbound"
pass in proto {tcp, udp} from <172.16-net> to any port {53 67 68 123 389 546 547 636 5353 5354} flags S/SA keep state label "Inbound"
pass in proto {tcp, udp} from <IPv6-net> to any port {53 67 68 123 389 546 547 636 5353 5354} flags S/SA keep state label "Inbound"
pass in proto {tcp, udp} from <192.168-net> to any port {49152:65535} flags S/SA keep state label "Inbound"
pass in proto {tcp, udp} from <10-net> to any port {49152:65535} flags S/SA keep state label "Inbound"
pass in proto {tcp, udp} from <172.16-net> to any port {49152:65535} flags S/SA keep state label "Inbound"
pass in proto {tcp, udp} from <IPv6-net> to any port {49152:65535} flags S/SA keep state label "Inbound"

# OUTBOUND
pass out proto {tcp, udp} from any to any port {1:65535} label "Outbound"

# OUTBOUND NAT
pass inet proto {tcp, udp} from { 198.51.100.0/24 } to !<NatLanInterfaces> port {1:65535} label "NAT_Clients"

创建执行脚本

为了完成 pf.conf 的加载,我们需要创建一份开机脚本来加载 pf.conf 并打开系统的路由转发功能,这是 NAT 规则所需要的。

创建 /etc/mypfctl.sh,并修改权限

chown root:wheel /etc/mypfctl.sh
chmod a+x /etc/mypfctl.sh
  • 脚本文件
#!/bin/sh
# Trap On TERM Signals
trap 'exit 1' 15

# Wait For All The Interfaces
ipconfig waitall
sleep 5

# System Sysctl
sysctl -w net.inet6.ip6.fw.verbose=0
sysctl -w net.inet.ip.fw.verbose=0
sysctl -w net.inet.ip.fw.verbose_limit=0

# Enable Interface Forwarding
sysctl -w net.inet.ip.forwarding=1

# Enable PF And Load Rules
/sbin/pfctl -e
/sbin/pfctl -Ef /opt/pf.conf

# Enable PF Logs
ifconfig pflog0 create

# /usr/local/bin/pfloggerd
/usr/sbin/tcpdump -lnettti pflog0 | /usr/bin/logger -t pf -p local2.info

# Exit With a Clean Status
exit 0

设置开机启动

/etc/mypfctl.sh 虽然已经创建完成,但是并不会在开机时自动执行。可以使用 Launch Daemon 来完成 /etc/mypfctl.sh 的开机自动加载。

  • 创建 /Library/LaunchDaemons/pf.mypfctl.plist 并修改权限。
chmod 644 /Library/LaunchDaemons/pf.mypfctl.plist
chown root:wheel /Library/LaunchDaemons/pf.mypfctl.plist
  • 编辑 /Library/LaunchDaemons/pf.mypfctl.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>pf.firewall</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/sh</string>
        <string>-c</string>
        <string>/etc/mypfctl.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ExitTimeOut</key>
    <integer>1</integer>
</dict>
</plist>

查看实时日志

sudo /usr/sbin/tcpdump -lnettti pflog0

results matching ""

    No results matching ""