FreeBSD PF 安装与使用详解如下。PF 是 OpenBSD 开发的一款功能强大的防火墙和流量整形工具,FreeBSD 从 5.3 版本开始将其引入,并已成为系统首选的内置防火墙。
一、PF 的安装与启用
在 FreeBSD 13.0 及以后版本中,PF 已作为内核模块直接包含在基础系统中,无需额外安装。
1. 加载 PF 内核模块
在 /boot/loader.conf 中添加一行,让系统启动时自动加载 PF 模块:
echo 'pf_load="YES"' >> /boot/loader.conf
或者手动立即加载(无需重启):
kldload pf
2. 启用 PF
编辑 /etc/rc.conf,启用 PF 并指定规则配置文件路径:
sysrc pf_enable="YES"
sysrc pf_rules="/etc/pf.conf" # 默认规则文件路径
sysrc pflog_enable="YES" # 启用 PF 日志
sysrc pflog_logfile="/var/log/pflog" # 日志文件位置
3. 启动 PF 服务
service pf start
常用管理命令:
service pf status # 查看状态
service pf stop # 停止
service pf restart # 重启(重新加载规则)
pfctl -s rules # 查看当前加载的规则
二、PF 配置文件详解 (/etc/pf.conf)
PF 规则文件语法清晰,主要由以下几部分组成:
1.
宏定义:定义变量,便于维护
ext_if="em0" # 外网接口
int_if="em1" # 内网接口
localnet=$int_if:network # 内网网段
webserver="192.168.1.10"
ssh_port="22"
2.
表:用于存储一组 IP 地址,高效处理大量地址
table <spam> persist file "/etc/spammers.txt" # 从文件加载黑名单
table <goodguys> { 10.0.0.0/24, !10.0.0.5 } # 定义内网网段,排除某个 IP
3.
选项:调整 PF 行为
set skip on lo0 # 忽略本地回环接口
set block-policy return # 阻塞时返回 RST/ICMP,默认是 drop
set state-policy if-bound # 状态绑定到接口
4.
规则:核心部分,包括过滤规则、NAT、重定向等
规则顺序至关重要,从上到下逐条匹配。
三、核心规则编写
1.
基本过滤规则
block all # 默认拒绝所有流量
pass out quick on $ext_if # 允许所有外网出口流量
pass in on $int_if from $localnet to any # 允许所有内网到外网的流量
2.
按协议/端口控制
# 允许来自外网的入站 SSH (限制在特定 IP 段)
pass in on $ext_if proto tcp from { 192.168.2.0/24 } to $ext_if port $ssh_port
# 允许来自任何地方的 HTTPS
pass in on $ext_if proto tcp to any port 443
# 允许内网 DNS 查询
pass in on $int_if proto udp from $localnet to any port 53
3.
状态化过滤
PF 是状态防火墙,keep state 或 flags S/SA 可跟踪连接状态。
pass in on $ext_if proto tcp to $webserver port { 80, 443 } flags S/SA keep state
4.
网络地址转换
# 出站 NAT (经典 IP 伪装,内网共享公网 IP)
nat on $ext_if from $localnet to any -> ($ext_if)
# 入站端口转发 (将公网 IP 的 443 端口转发到内网服务器)
rdr on $ext_if proto tcp from any to $ext_if port 443 -> $webserver port 443
# 双向转发/1:1 NAT
nat on $ext_if from 192.168.1.100 to any -> 203.0.113.10
5.
流量整形与队列
PF 通过 ALTQ 系统进行 QoS。
# 在接口上启用 CBQ 队列
altq on $ext_if cbq bandwidth 100Mb queue { std, bulk, web }
queue std bandwidth 30% cbq(default) # 默认队列
queue bulk bandwidth 20% cbq # 大流量队列
queue web bandwidth 50% cbq # Web 流量队列
# 将流量分类到队列
pass in on $ext_if proto tcp to any port 80 queue web
pass in on $ext_if proto tcp to any port 22 queue std
四、高级特性与实用技巧
1.
锚点:用于动态规则(如 FTP 被动模式)或与第三方程序集成
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
rdr pass on $int_if proto tcp to any port 21 -> 127.0.0.1 port 8021
2.
日志记录
# 记录被阻止的流量到 pflog
block in log (all) on $ext_if
# 使用 pflogd 服务捕获日志,用 tcpdump 查看:
tcpdump -n -e -ttt -r /var/log/pflog
3.
防止 IP 欺骗
antispoof for $ext_if
4.
规则集优化与调试
# 测试规则文件语法
pfctl -nf /etc/pf.conf
# 详细显示当前所有状态和规则
pfctl -s all
# 查看状态表
pfctl -s states
pfctl -s info # 查看统计信息
# 动态添加/删除规则(临时生效)
echo "block in on $ext_if from 1.2.3.4 to any" | pfctl -f -
五、一个完整的基础配置文件示例
适用于家庭或小型办公室网关:
# /etc/pf.conf
# 宏定义
ext_if="igb0" # 外网接口
int_if="igb1" # 内网接口
localnet="192.168.1.0/24"
webserver="192.168.1.10"
ssh_port="22"
# 选项
set skip on lo0
set block-policy return
# 默认规则:拒绝所有入站,允许所有出站
block all
pass out quick on $ext_if
pass in quick on $int_if from $localnet to any
# NAT:内网共享公网 IP
nat on $ext_if from $localnet to any -> ($ext_if)
# 入站规则
# 1. 允许来自外网的 SSH (限制 IP 范围)
pass in on $ext_if proto tcp from { 192.168.2.0/24 } to $ext_if port $ssh_port
# 2. 允许来自外网的 Web 访问(转发到内网服务器)
rdr pass on $ext_if proto tcp from any to $ext_if port { 80, 443 } -> $webserver
pass in on $ext_if proto tcp to $webserver port { 80, 443 } flags S/SA keep state
# 3. 允许 ICMP (Ping)
pass in on $ext_if inet proto icmp all icmp-type echoreq
六、与 IPFW 的比较(FreeBSD 另一款防火墙)
| 特性 |
PF |
IPFW |
|---|
| 来源 |
OpenBSD |
FreeBSD |
| 语法 |
较简洁,类似配置文件 |
规则编号,类似 Cisco IOS |
| NAT/重定向 |
集成度高,语法直观 (nat, rdr) |
需要 libalias 或内核模块 |
| 流量整形 |
内置 ALTQ |
使用 dummynet |
| 状态检测 |
内置 |
需要 stateful 规则 |
| 学习曲线 |
中等 |
较简单 |
建议:如果你来自 OpenBSD 背景或需要复杂策略路由/流量整形,选 PF;如果你习惯 IPFW 语法或需要极简方案,选 IPFW。
七、故障排除
规则不生效:
- 运行
pfctl -nf /etc/pf.conf 检查语法。
- 确保
pf_enable="YES" 在 /etc/rc.conf 中。
- 使用
pfctl -s all 查看加载的规则。
网络中断:
- 在物理控制台或通过
ssh 连接执行 pfctl -d 临时禁用 PF 进行排查。
- 在规则顶部添加
pass in quick on $int_if 确保内网管理不中断。
查看日志:
tcpdump -n -e -ttt -r /var/log/pflog 分析日志。
八、下一步
- 阅读官方手册:
man pf.conf、man pfctl
- 深入 PF 书籍:The Book of PF (No Starch Press)
- 访问 OpenBSD PF 文档:https://www.openbsd.org/faq/pf/
PF 功能极为丰富,建议从简单规则开始测试,逐步增加复杂性。在测试新规则时,始终在本地控制台操作,避免被锁在远程主机外。