安庆市文章资讯

Freebsd PF 安装使用详解

2026-04-02 18:54:01 浏览次数:2
详细信息

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 stateflags 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。

七、故障排除

规则不生效

网络中断

查看日志

八、下一步

PF 功能极为丰富,建议从简单规则开始测试,逐步增加复杂性。在测试新规则时,始终在本地控制台操作,避免被锁在远程主机外。

相关推荐