15.2 Packet Filter(PF)

PF(Packet Filter,包过滤器)是一款由 OpenBSD 移植而来的防火墙,提供了大量功能,包括 ALTQ (Alternate Queuing,交错队列) 等。

启用 PF

# kldload pf # ① 加载内核模块
# 复制示例文件作为默认配置规则集文件,否则 pf 无法启动 ②
# cp /usr/share/examples/pf/pf.conf /etc/
# service pf enable # 设置 pf 开机启动
# service pf start  # 启动 pf
  • ① 如不做,则提示 pfctl: /dev/pf: No such file or directory。或者你重启再 service pf start

  • ② 否则提示:

/etc/rc.d/pf: WARNING: /etc/pf.conf is not readable.

pfctl

pf 的管理命令为 pfctl,常用操作示例如下:

# 启动 pf,相当于 service pf start
# pfctl -e

# 即禁止规则。几乎相当于 service pf stop(停止防火墙)
# pfctl -d

# 加载规则集文件中的规则
# pfctl -f /etc/pf.conf

# 解析规则,但不加载。-f 参数还可以与其他参数配合,如 -N 表示只载入 NAT 规则,-R 表示只载入过滤规则,-A 只载入队列规则,-O 只载入选项规则
# pfctl -nf /etc/pf.conf

# 查看 pf 所有对象信息。如果想查看特定对象信息,可以用 nat、queue、rules、Anchors、states、Sources、info、Running、labels、timeouts、memory、Tables、osfp、Interfaces 替换 all
# pfctl -s all

# 清理 pf 所有规则
# pfctl -F all

如果想查看特定规则,可以用 nat、queue、rules、states、Sources、info、Tables、osfp 替换 all。

不过以上操作并没有对规则的管理,因此还需要修改规则集文件,常用示例如下:

# 整理所有输入的数据
scrub in all

# 拒绝所有访问
block all  # 默认明示禁止所有访问。block 是动作,all 是从任何源到任何目标的简写,表示从源地址到目标地址。 

# 放开回环接口的访问权限,回环接口不对外部
pass quick on lo0 all  # quick 关键字表示若规则匹配,就停止执行,不会再执行后续规则

# 增加 TCP 协议访问 80 端口的规则,允许任何设备以 TCP 协议访问本机 80 端口
pass in quick proto tcp from any to 192.168.1.184 port 80  # proto tcp 是访问协议,port 80 是目标端口

# 允许回显信息给任何访问的设备
pass out quick proto tcp from 192.168.1.184 port 80 to any  # 允许本机向外发送 80 端口的响应

# 增加 80 端口到 8080 端口流量转发的规则
rdr pass on em0 inet proto tcp from any to 192.168.1.184 port 80 -> 192.168.1.166 port 8080  # 转发流量到内网地址 192.168.1.166 端口 8080

# 允许本机与外部设备互 ping
pass quick inet proto icmp all icmp-type 8 code 0  # icmp-type 8 是查询请求,code 0 表示返回码为 0

# 允许 traceroute 命令以 ICMP 协议执行
pass out quick inet proto icmp from 192.168.1.184 to any icmp-type 11 code 0  # icmp-type 11 用于时间超时

# 允许 traceroute 使用 UDP 协议执行,端口号从 33434 开始
pass out quick proto udp from 192.168.1.184 to any port 33434 >< 34500  # 默认 UDP 协议,端口号从 33434 开始,每转发一次端口号加 1

可能用到的规则集文件 /etc/pf.conf 如下:

# 数据包标准化
scrub in all

# 转发规则
rdr pass on em0 inet proto tcp from any to 192.168.1.184 port 8080 -> 192.168.1.184 port 80  # 注意规则次序,根据 pf.conf 规则,转发规则应位于过滤规则之前,相关内容请参考帮助

# 过滤规则
block all pass quick on lo0 all  # 阻止所有流量,但允许回环接口(lo0)上的流量

# 设置任何设备可以访问服务器的 22、80、443、4200、10000 端口
pass in quick proto tcp from any to 192.168.1.184 port { 22, 80, 443, 4200, 10000 }

# 设置服务器可以访问外部设备的 22、80、443、4200、10000 端口
pass out quick proto tcp from 192.168.1.184 port { 22, 80, 443, 4200, 10000 } to any

# 设置服务器访问任何网络设备的 80、443 端口,并保持状态
pass out quick proto tcp from 192.168.1.184 to any port { 80, 443 } keep state

# 设置服务器访问 DNS 服务器(UDP 端口 53)
pass out quick proto udp from any to any port 53 keep state

# 设置服务器访问 DHCP 服务器(UDP 端口 67)
pass out quick proto udp from any to any port 67 keep state

# 允许服务器发送 ICMP 请求
pass quick inet proto icmp all icmp-type 8 code 0

# 允许服务器发送 ICMP 超时消息(TTL 超过)
pass out quick inet proto icmp from 192.168.1.184 to any icmp-type 11 code 0

# 允许服务器访问 UDP 范围端口 33434 到 34500
pass out quick proto udp from 192.168.1.184 to any port 33434 >< 34500

保存文件,接下来在终端执行命令:

# 加载规则集文件中的规则 就可以看到效果了。
# pfctl -Fa -f /etc/pf.conf 

最后更新于