15.2 Packet Filter(PF)

PF(Packet Filter,包过滤器)是一款源自 OpenBSD 的防火墙,提供了丰富功能,包括 ALTQ(Alternate Queuing,交替队列)等。ALTQ 是 PF 的流量队列管理机制,用于实现服务质量(QoS)控制。作为一种状态防火墙(stateful firewall),PF 通过跟踪网络连接状态实现精细化的访问控制。

启用 PF

在启用 PF 之前,需要先加载内核模块、准备配置文件并启动相关服务,按以下步骤依次操作。

# kldload pf                  # 加载 pf 内核模块,使系统能够识别和使用 PF 防火墙
# cp /usr/share/examples/pf/pf.conf /etc/  # 复制示例文件作为默认配置规则集,否则 pf 无法启动
# 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.

PF 的管理命令为 pfctl

相关文件结构

/
├── etc
   └── pf.conf
└── usr
    └── share
        └── examples
            └── pf
                └── pf.conf

一次性操作命令

PF 提供了丰富的一次性操作命令,可用于管理防火墙的运行状态。

  1. 启动 PF 防火墙

作用:启用 PF,相当于执行 service pf start

  1. 禁用 PF 防火墙规则

作用:停用 PF 防火墙,相当于执行 service pf stop

  1. 加载规则集文件中的规则

作用:将 /etc/pf.conf 文件中的规则加载到 PF 中。

  1. 解析规则但不加载

作用:检查规则语法是否正确,但不实际应用。

可选参数:

  • -N:只解析 NAT 规则

  • -R:只加载过滤规则

  • -A:只加载队列规则

  • -O:只加载选项规则

  1. 查看 PF 的对象信息

作用:显示 PF 的所有对象信息。

可用替换 all 的选项及其含义:

  • nat:查看 NAT 规则

  • queue:查看队列规则

  • rules:查看过滤规则

  • anchors:查看 anchor

  • states:查看状态表

  • sources:查看源跟踪信息

  • info:查看 PF 运行信息

  • running:查看运行状态

  • labels:查看规则标签

  • timeouts:查看超时设置

  • memory:查看内存使用

  • tables:查看表

  • osfp:查看操作系统指纹

  • interfaces:查看接口信息

  1. 删除 PF 的所有规则

作用:删除 PF 中所有已加载的规则和状态信息。

如果想查看特定规则,可以用 natqueuerulesstatessourcesinfotablesosfp 替换 all

永久性的规则集

上述操作仅针对 PF 的运行状态和规则加载,并未对规则进行管理,因此仍需修改规则集文件,常用示例如下。

规则集文件

以下是一些常用的 PF 规则示例,可根据实际需求进行选择和组合。注意:示例中使用的 IP 地址 192.168.1.184 为演示用途,请根据实际情况修改。

  1. 整理所有输入的数据

作用:对所有进入的数据包进行规范化处理(如重组分片、清理异常标志等),提高规则匹配的可靠性。scrub 可以防御某些利用分片或异常标志的攻击。

  1. 阻止所有访问

作用:默认阻止所有访问。

说明:block 表示动作,all 表示从任何源到任何目标的所有流量。

  1. 允许回环接口访问

作用:允许本地回环接口 lo0 的所有访问,但不影响外部访问。 说明:quick 表示匹配该规则后立即停止,不再继续匹配后续规则。

  1. 允许 TCP 协议访问 80 端口

作用:允许任意设备通过 TCP 协议访问本机的 80 端口(通常用于 HTTP 服务)。

  1. 允许本机对外发送 80 端口的响应

作用:允许本机向任意设备发送 TCP 80 端口的响应数据。

  1. 端口转发 80 → 8080

作用:将访问本机 80 端口的 TCP 流量转发到内网地址 192.168.1.166 的 8080 端口。 说明:rdr 表示重定向(端口转发),on em0 指定接口,inet 指定 IPv4 协议。

  1. 允许本机与外部设备进行 ping

作用:允许 ICMP 回显请求(ping)通过,icmp-type 8 表示请求,code 0 表示标准返回码。

  1. 允许 traceroute 的 ICMP 流量

作用:允许本机发送 ICMP“时间超时”报文,用于执行 traceroute

  1. 允许 traceroute 的 UDP 流量

作用:允许本机通过 UDP 协议发送端口范围 33434-34500 的数据,用于 traceroute

说明:>< 表示端口范围。

完整规则集示例

以下是一个完整的规则集文件示例,可直接复制到 /etc/pf.conf 中使用。转发规则应置于过滤规则之前以确保生效。

  1. 对数据包进行标准化

  1. 端口转发规则

作用:将访问本机 8080 端口的 TCP 流量转发到 80 端口。

  1. 阻止所有流量并允许回环接口

作用:默认阻止所有流量,但允许本机回环接口 lo0 的所有访问。

说明:quick 表示匹配该规则后立即停止,不再继续匹配后续规则。

  1. 允许外部访问服务器特定端口

作用:允许任意设备访问服务器的 SSH(22)、HTTP(80)、HTTPS(443)、4200、10000 端口。

  1. 允许服务器访问外部设备的特定端口

作用:允许服务器向外部发送数据到指定端口。

  1. 服务器访问任意设备的 HTTP/HTTPS 并保持状态

作用:允许服务器访问外部 HTTP/HTTPS 服务,同时跟踪连接状态。

  1. 服务器访问 DNS 服务器

作用:允许服务器通过 UDP 端口 53 查询 DNS,并保持状态。

  1. 服务器访问 DHCP 服务器

作用:允许服务器通过 UDP 端口 67 与 DHCP 服务器通信,并保持状态。

  1. 允许服务器发送 ICMP 请求

作用:允许发送 ICMP 回显请求(ping)。

  1. 允许 ICMP 超时消息(traceroute)

作用:允许发送 ICMP“时间超时”报文,用于 traceroute。

  1. 允许服务器访问 UDP 端口范围 33434 至 34500

作用:允许服务器通过 UDP 协议发送端口范围 33434-34500 的数据,用于 traceroute。

  1. 加载规则文件使其生效

规则编辑完成后,需要执行以下命令使其生效。

作用:

  • -F a:清除所有已加载的规则和状态

  • -f /etc/pf.conf:加载指定规则文件

课后习题

  1. 查找 FreeBSD 源码中的 PF 实现,选取其中一个核心数据结构(如状态表或规则匹配逻辑),重构最小化实现。

  2. 选取 PF 的 anchor 机制,为其设计并实现一个分层的规则管理方案,验证其功能。

  3. 修改 PF 的默认行为(如禁用 scrub 或改变默认块策略),验证其行为变化。

最后更新于