Skip to content

29.3 IPFilter(IPF)

警告

本节内容未经实际测试,仅理论验证通过。请勿直接用于生产环境!建议在测试环境中验证后再用于生产部署。

IPFilter(IPF)是早期跨平台开源防火墙,作者为 Darren Reed。IPF 提供包过滤和网络地址转换(NAT)功能,最初被移植到多种 Unix-like 操作系统。

注意

IPFilter 的上游开发已长期停滞:最后一个正式版本 5.1.2 发布于 2012 年 7 月,此后上游再无新版本发布。OpenBSD(2001 年)、DragonFly BSD(2011 年)和 Oracle Solaris(11.4 起)已先后移除 IPFilter。FreeBSD 当前仍将 IPFilter 纳入基本系统,但其维护仅限于兼容性适配与安全修复,不再引入新功能。对于新部署的防火墙,建议优先考虑本章中的 PF 或 IPFW。

IPFILTER 是一款内核级防火墙,还提供了 NAT 机制,可通过用户空间程序控制和监控。防火墙规则可通过 ipf 设置或删除,NAT 规则可通过 ipnat 设置或删除,IPFILTER 内核部分的运行时统计信息可通过 ipfstat 打印,而 ipmon 可将 IPFILTER 操作记录至系统日志文件。

sh
用户空间工具

   ├── ipf 设置/删除防火墙规则
   ├── ipnat 设置/删除 NAT 规则
   ├── ipfstat 打印运行时统计信息
   └── ipmon 记录日志至 syslog

  控制/监控

IPFILTER 内核(包过滤 + NAT)

IPF 最初采用“最后匹配规则优先”的规则处理逻辑,且仅使用无状态规则。此后,IPF 已扩展至支持 quick 和 keep state 选项。

本节重点介绍与 FreeBSD 相关的 IPF,并提供包含 quick 和 keep state 选项的规则示例。

29.3.1 启用 IPF 防火墙

启用 IPF 防火墙需要准备配置文件并启动相关服务,具体步骤如下。

如需启用 IPF,可执行以下命令:

sh
# 复制示例文件作为默认配置规则集文件,否则 ipfilter 启动后将无规则生效。示例文件自带的规则不影响使用
cp /usr/share/examples/ipfilter/ipf.conf.sample /etc/ipf.rules

若要配置系统在引导时启用 IPF,需要在 /etc/rc.conf 中添加以下条目。这些条目还将启用日志记录并设置 default pass all。若要将默认策略更改为 block all,而无需编译定制内核,需要在规则集末尾添加 block all 规则。

ini
ipfilter_enable="YES"             # 在引导时启用 ipfilter
ipfilter_rules="/etc/ipf.rules"   # 加载规则定义文件
ipmon_enable="YES"                # 在引导时启用 ipmon
ipmon_flags="-Ds"                 # 详见下表
ipmon_flags 标志描述
D以守护进程模式启动
s记录到 syslog
v记录 tcp 窗口、ack、seq
n将 IP 和端口映射为名称
  • 启动
sh
# service ipmon enable # 启动 IP 监控日志
# service ipfilter enable # 设置 ipfilter 在系统启动时自动启动
# service ipfilter start # 启动 ipfilter 服务

加载防火墙规则时,以 ipf 指定规则集文件名。可使用以下命令替换当前运行中的防火墙规则:

sh
# ipf -Fa -f /etc/ipf.rules

其中,-Fa 会刷新所有内部规则表,-f 指定要加载的规则文件。

这样就可以修改自定义规则集,并通过更新规则副本来更新运行中的防火墙,而无需重启系统。此方法便于测试新规则,且可反复执行。

若需要 NAT 功能,还需要在 /etc/rc.conf 中添加以下行:

ini
gateway_enable="YES"              # 启用作为 LAN 网关
  • 启动 ipnat:

ipnat 是 IPF 的组成部分,专门用于维护网络地址转换(NAT)规则。NAT 可以实现内网 IP 与公网 IP 的转换,以及端口转发等功能。

sh
# cp /usr/share/examples/ipfilter/ipnat.conf.sample /etc/ipnat.rules   # 复制示例文件作为默认配置规则集,否则 ipnat 无法启动
# service ipnat enable   # 设置 ipnat 在系统启动时自动启动
# service ipnat start    # 启动 ipnat 服务

注意

ipfilter 服务重启后,ipnat 也需要重启。

IPF 的管理命令主要有 ipfipfstatipnat

29.3.1.1 相关文件结构

IPFilter 的配置文件结构如下。

sh
/
├── etc
   ├── ipf.rules                     # IPFilter 防火墙规则文件
   └── ipnat.rules                    # IPNAT 转发规则文件
└── usr
    └── share
        └── examples
            └── ipfilter
                ├── ipf.conf.sample   # IPFilter 示例配置
                └── ipnat.conf.sample # IPNAT 示例配置

29.3.2 IPF 规则语法

本节说明了用于创建有状态规则的 IPF 规则语法。创建规则时需要注意,除非规则中包含 quick 关键字,否则每条规则均按顺序读取,最后匹配的规则 将生效。这意味着,即使第一个匹配数据包的规则是 pass,若之后有匹配的规则为 block,该数据包也将被丢弃。可在 /usr/share/examples/ipfilter 中找到示例规则集。

创建规则时,# 字符用于标记注释的开始,也可以出现在规则末尾以解释该规则的功能,或单独占一行。空白行均被忽略。

规则中使用的关键字需要按特定顺序书写,从左到右。有些关键字为必需,其余为可选。某些关键字有子选项,子选项本身也可以是关键字,且可包含更多子选项。关键字的顺序如下,其中大写字母表示变量,小写字母为关键字,需要位于其后的变量之前:

ini
ACTION DIRECTION OPTIONS proto PROTO_TYPE from SRC_ADDR SRC_PORT to DST_ADDR DST_PORT TCP_FLAG|ICMP_TYPE keep state STATE

本节将说明这些关键字及其选项,但并非所有选项的详尽列表。

29.3.2.1 ACTION

关键字 ACTION 指定数据包匹配该规则时应执行的操作。每条规则 必须 有一个操作。以下为支持的操作:

动作说明
block丢弃数据包
pass允许数据包
log生成一条日志记录
count统计数据包和字节数,可用于反映规则匹配频率
auth将数据包排队,交由另一个程序进一步处理
call访问 IPF 内置的功能,以执行更复杂的操作
decapsulate去除任何头部,以处理数据包的内容

29.3.2.2 DIRECTION

接下来,每条规则必须明确指定流量的方向,使用以下关键字之一:

  • in:规则应用于传入的数据包。
  • out:规则应用于传出的数据包。

如果系统有多个接口,可以在方向后指定接口名。例如 in on em0

注意

all 关键字不是方向关键字,而是地址匹配的简写,表示匹配所有地址(等同于 from any to any)。例如 block in all 中的 all 是地址部分,而非方向。

29.3.2.3 OPTIONS

OPTIONS 是可选的。但若指定多个选项,需要按此处显示的顺序排列。

  • log:执行指定的操作时,数据包头部的内容将写入 ipl(4) 包日志伪设备。
  • quick:若数据包匹配此规则,则执行规则指定的操作,且不再处理后续规则。
  • on:后需要跟接口名,即 ifconfig(8) 所显示的接口名。仅当数据包通过指定接口且符合指定方向时,规则才匹配。

使用 log 关键字时,可以按顺序使用以下修饰符:

  • body:表示数据包内容的前 128 字节将在头部之后记录。
  • first:若 log 关键字与 keep state 选项配合使用,建议使用此选项,以便仅记录触发数据包,而非每个匹配的有状态连接数据包。

还可用附加选项指定错误返回消息。

29.3.2.4 PROTO_TYPE

PROTO_TYPE 是可选的。但若规则需要指定 SRC_PORTDST_PORT,则为必需,因为它定义了协议类型。在指定协议类型时,使用 proto 关键字后跟协议号或 /etc/protocols 中的协议名称。示例协议名称包括 tcpudpicmp。若指定了 PROTO_TYPE,但未指定 SRC_PORTDST_PORT,则该规则将匹配该协议的所有端口号。

29.3.2.5 SRC_ADDR

关键字 from 是必需的,后跟表示数据包来源的关键字。源地址可以是主机名、带有 CIDR 掩码的 IP 地址、地址池或 all 关键字。

无法匹配不以点分十进制/掩码长度形式表示的 IP 地址范围。可使用 net-mgmt/ipcalc 软件包和 Ports 来简化 CIDR 掩码的计算。可在该工具的网页上找到更多信息:http://jodies.de/ipcalc

29.3.2.6 SRC_PORT

关键字 SRC_PORT 是可选的。但若使用该选项,则需要先定义 PROTO_TYPE。端口号必须以 port 关键字为前缀。

支持多种比较运算符:=(等于)、!=(不等于)、<(小于)、>(大于)、<=(小于或等于)和 >=(大于或等于)。

指定端口范围时,需要将两个端口号置于 <>(小于 x 或大于 y)、><(大于 x 且小于 y)或 :(大于或等于,且小于或等于)之间。

29.3.2.7 DST_ADDR

关键字 to 是必需的,后跟表示数据包目的地的关键字。与 SRC_ADDR 类似,它可以是主机名、带有 CIDR 掩码的 IP 地址、地址池或 all 关键字。

29.3.2.8 DST_PORT

SRC_PORT 类似,DST_PORT 是可选的。但若使用该选项,则需要先定义 PROTO_TYPE。端口号也必须以 port 关键字为前缀。

29.3.2.9 TCP_FLAG|ICMP_TYPE

tcp 指定为 PROTO_TYPE,则可指定标志,以字母表示 TCP 连接状态:

字母TCP 标志
SSYN
AACK
PPSH
FFIN
UURG
RRST
CCWR
EECE

icmp 指定为 PROTO_TYPE,则可指定要匹配的 ICMP 类型。

29.3.2.10 STATE

pass 规则包含 keep state,IPF 将在其动态状态表中添加一条记录,并允许后续匹配该连接的数据包。IPF 可跟踪 TCP、UDP 和 ICMP 会话的状态。任何 IPF 确定属于已激活会话的数据包,即使它属于不同的协议,也将被允许。

在 IPF 中,数据包通过连接到公共互联网的接口时,首先对照动态状态表进行检查。若数据包匹配组成活动会话的下一个预期数据包,它将通过防火墙并更新该会话的状态。不属于已有活动会话的数据包将与出站规则集匹配。从连接到公共互联网的接口传入的数据包同样首先对照动态状态表进行检查。若数据包匹配组成活动会话的下一个预期数据包,它将通过防火墙并更新该会话的状态。不属于已有活动会话的数据包将与入站规则集匹配。

keep state 后可添加若干关键字。若使用这些关键字,它们将设置控制有状态过滤的各种选项,例如设置连接限制或连接时长。

29.3.3 示例规则集

本节演示创建示例规则集,该规则集仅允许与 pass 规则匹配的服务,并阻止所有其他服务。

FreeBSD 使用回环接口(lo0)和 IP 地址 127.0.0.1 用于内部通信。防火墙规则集必须包含允许这些内部使用的包自由通过的规则:

sh
# 允许回环接口上的所有流量
pass in quick on lo0 all
pass out quick on lo0 all

连接到互联网的公共接口用于授权和控制所有出站和入站连接的访问。若一个或多个接口连接到私有网络,则这些内部接口可能需要规则以允许从局域网起始的包在内部网络之间传输或流向连接到互联网的接口。规则集应分为三个主要部分:任何受信任的内部接口、通过公共接口的出站连接和通过公共接口的入站连接。

这两条规则允许所有流量通过受信任局域网接口 em1

ini
# 允许通过内部局域网接口的所有流量(用于私有网络)
pass out quick on em1 all
pass in quick on em1 all

公共接口的出站和入站部分的规则应将最常匹配的规则放在前面,将不常匹配的规则放在后面,最后一条规则用于阻止和记录该接口和方向的所有包。

以下规则集定义了公共接口 em0 的出站部分。这些规则保持状态并标识内部系统被授权访问公共互联网的特定服务。所有规则都使用 quick 并指定适当的端口号,并在适用时指定目标地址。

ini
# 面向互联网的接口(出站)
# 匹配由内网发往互联网的会话请求

# 允许访问公共 DNS 服务器
# 将 x.x.x.x 替换为 /etc/resolv.conf 中列出的地址
# 对每个 DNS 服务器重复此规则
pass out quick on em0 proto tcp from any to x.x.x.x port = 53 flags S keep state
pass out quick on em0 proto udp from any to x.x.x.x port = 53 keep state

# 允许访问 ISP 的 DHCP 服务器,适用于电缆调制解调器或 ADSL 等宽带连接
# 默认使用记录日志的通用规则;确认 DHCP 服务器地址后,
# 可将 z.z.z.z 填入下一条规则并启用它,同时注释掉当前通用规则
pass out log quick on em0 proto udp from any to any port = 67 keep state
#pass out quick on em0 proto udp from any to z.z.z.z port = 67 keep state

# 允许出站 HTTP 和 HTTPS
pass out quick on em0 proto tcp from any to any port = 80 flags S keep state
pass out quick on em0 proto tcp from any to any port = 443 flags S keep state

# 允许出站 SMTP 邮件提交
pass out quick on em0 proto tcp from any to any port = 587 flags S keep state

# 允许出站 NTP 时间同步
pass out quick on em0 proto udp from any to any port = 123 keep state

# 允许出站 SSH
pass out quick on em0 proto tcp from any to any port = 22 flags S keep state

# 允许出站 ICMP 回显请求(ping)
pass out quick on em0 proto icmp from any to any icmp-type 8 keep state

# 阻止并记录其他所有出站流量(仅记录首次出现)
block out log first quick on em0 all

此示例展示了公共接口入站部分的规则集,它首先阻止所有不需要的包。如此可减少最后一条规则记录的包的数量。

ini
# 面向互联网的接口(入站)
# 阻止所有来自非可路由或保留地址空间的入站流量
block in quick on em0 from 192.168.0.0/16 to any    # RFC 1918 私有地址
block in quick on em0 from 172.16.0.0/12 to any     # RFC 1918 私有地址
block in quick on em0 from 10.0.0.0/8 to any        # RFC 1918 私有地址
block in quick on em0 from 127.0.0.0/8 to any       # 回环地址
block in quick on em0 from 0.0.0.0/8 to any         # 本网络地址
block in quick on em0 from 169.254.0.0/16 to any    # 链路本地地址(APIPA)
block in quick on em0 from 192.0.2.0/24 to any      # 文档示例保留地址
block in quick on em0 from 224.0.0.0/3 to any       # D 类组播与 E 类保留

# 阻止分片和过短的 TCP 包
block in quick on em0 all with frag
block in quick on em0 proto tcp all with short

# 阻止源路由包
block in quick on em0 all with opt lsrr
block in quick on em0 all with opt ssrr

# 阻止操作系统指纹探测,仅记录首次出现
block in log first quick on em0 proto tcp from any to any flags FUP

# 阻止包含特殊 IP 选项的包
block in quick on em0 all with ipopts

# 阻止来自外部的 ICMP 回显请求(禁止外部 ping 本机)
block in quick on em0 proto icmp all icmp-type 8

# 阻止 NetBIOS/SMB 相关端口的入站访问,仅记录首次出现
block in log first quick on em0 proto tcp/udp from any to any port = 137
block in log first quick on em0 proto tcp/udp from any to any port = 138
block in log first quick on em0 proto tcp/udp from any to any port = 139
block in log first quick on em0 proto tcp from any to any port = 445

每当使用 log first 选项的规则生成日志消息时,运行 ipfstat -hio 以评估该规则被匹配的次数。大量的匹配可能表明系统正遭受攻击。

入站部分的其余规则定义了哪些连接可以从互联网发起。最后一条规则拒绝所有未被前述规则明确允许的连接。

ini
# 允许来自 ISP DHCP 服务器的入站流量;将 z.z.z.z 替换为出站规则中使用的同一地址
pass in quick on em0 proto udp from z.z.z.z to any port = 68 keep state

# 允许到指定内部 Web 服务器的公共 HTTP 连接
pass in quick on em0 proto tcp from any to x.x.x.x port = 80 flags S keep state

# 阻止并记录所有其他入站流量(仅记录首次出现)
block in log first quick on em0 all

29.3.4 配置 NAT

启用 NAT 需要在 /etc/rc.conf 中添加以下语句,并指定包含 NAT 规则的文件名:

ini
gateway_enable="YES"
ipnat_enable="YES"
ipnat_rules="/etc/ipnat.rules"

NAT 规则较为灵活,可根据商业和家庭用户的需要实现多种功能。此处展示的规则语法已简化,以演示常见的使用方式。

NAT 规则的基本语法如下,其中 map 开始规则,IF 应替换为外部接口的名称:

sh
# 语法:map 外部接口 内部 IP 范围 -> 公共地址
map IF LAN_IP_RANGE -> PUBLIC_ADDRESS

LAN_IP_RANGE 是内部客户端使用的 IP 地址范围,通常是类似 192.168.1.0/24 的私有地址范围。PUBLIC_ADDRESS 可为静态外部 IP 地址,也可以是关键字 0/32,表示分配给 IF 的 IP 地址。

在 IPF 中,当一个包从局域网到达防火墙且目标为公共地址时,包首先会经过防火墙规则集的出站规则。然后,包会传递到 NAT 规则集,该规则集从上到下读取,匹配的第一个规则会生效。IPF 会根据包的接口名称和源 IP 地址测试每个 NAT 规则。当包的接口名称与 NAT 规则匹配时,包的源 IP 地址(位于私有局域网中)会与 LAN_IP_RANGE 中指定的 IP 地址范围匹配。匹配后,包的源 IP 地址会被重写为 PUBLIC_ADDRESS 中指定的公共 IP 地址。IPF 会在其内部 NAT 表中记录一条条目,以便当包从互联网返回时,可将其映射回原始的私有 IP 地址,然后将包传递到防火墙规则作进一步处理。

sh
内网数据包

  到达防火墙

防火墙规则集(出站规则)

  匹配通过

NAT 规则集

 IP 重写为公网 IP
  记录 NAT 映射条目

互联网

  返回流量

NAT 表查找

  映射回原始私有 IP

防火墙规则集(进一步处理)

  传递到内网

内网主机

对于拥有大量内部系统或多个子网的网络,将每个私有 IP 地址转换为单个公共 IP 地址将成为资源瓶颈。解决此问题可采用两种方法。

第一种方法是为源端口分配一个端口范围。通过添加 portmap 关键字,NAT 将仅使用指定范围内的源端口:

sh
# 将 192.168.1.0/24 地址映射到外部接口,并限定 TCP/UDP 源端口范围
map em0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:60000

此外,可使用 auto 关键字,由 NAT 自行决定可用端口:

sh
# 使用 auto 让系统自动分配源端口
map em0 192.168.1.0/24 -> 0/32 portmap tcp/udp auto

第二种方法是使用一个公共地址池。当局域网地址太多而无法适配单个公共地址时,此方法尤为适用。若有一块公共 IP 地址池可用,可将这些公共 IP 地址用作 NAT 选择的 IP 地址池,在数据包外发时实现地址映射。

公共 IP 地址范围可使用子网掩码或 CIDR 表示法指定。以下两条规则等效:

sh
# 使用子网掩码形式表示公共地址池
map em0 192.168.1.0/24 -> 204.134.75.0/255.255.255.0
# 使用 CIDR 表示公共地址池(与上一条等效)
map em0 192.168.1.0/24 -> 204.134.75.0/24

一种常见的做法是将一个公开可访问的 Web 服务器或邮件服务器隔离到内部网络段。这些服务器的流量仍需要经过 NAT,但需要通过端口重定向将入站流量引导至正确的服务器。例如,将内部地址为 10.0.10.25 的 Web 服务器映射到其公共 IP 地址 20.20.20.5,可使用以下规则:

sh
# 将发往 20.20.20.5 的 80 端口重定向到内部 Web 服务器 10.0.10.25
rdr em0 20.20.20.5/32 port 80 -> 10.0.10.25 port 80

若这是唯一的 Web 服务器,此规则也适用,因为它将所有外部 HTTP 请求重定向至 10.0.10.25

sh
# 将所有发往外部接口 80 端口的流量全部重定向到内部服务器
rdr em0 0.0.0.0/0 port 80 -> 10.0.10.25 port 80

IPF 内置了一个 FTP 代理,可与 NAT 配合使用。它监控所有出站流量的主动或被动 FTP 连接请求,并动态创建临时过滤规则,包含 FTP 数据通道使用的端口号。这消除了为 FTP 连接打开大量高端端口的需要。

注意

FTP 协议已逐渐被 SFTP 和 SCP 等安全替代方案取代。现代网络中 FTP 的使用场景已大幅减少,以下 FTP 代理配置仅适用于仍需支持 FTP 的遗留环境。

在此示例中,第一条规则为来自内部局域网的出站 FTP 流量调用代理。第二条规则将 FTP 流量从防火墙传递到互联网,第三条规则处理所有非 FTP 流量:

sh
# 对内部 10.0.10.0/29 的出站 FTP 流量启用 FTP 代理
map em0 10.0.10.0/29 -> 0/32 proxy port 21 ftp/tcp
# 对所有其他源地址的出站 FTP 流量也启用 FTP 代理
map em0 0.0.0.0/0 -> 0/32 proxy port 21 ftp/tcp
# 对该网段的其余非 FTP 流量执行普通 NAT
map em0 10.0.10.0/29 -> 0/32

FTP map 规则应位于 NAT 规则之前,这样当包与 FTP 规则匹配时,FTP 代理会创建临时的过滤规则,让 FTP 会话数据包通过并经过 NAT。所有非 FTP 的局域网包不会匹配 FTP 规则,但若它们匹配第三条规则,将会经过 NAT。

若无 FTP 代理,则需要使用以下防火墙规则。需要注意,若无代理,则需要允许所有高于 1024 的端口:

ini
# 允许局域网客户端的出站 FTP 控制连接(主动与被动模式均需要)
pass out quick on em0 proto tcp from any to any port = 21 flags S keep state

# 允许被动模式 FTP 的出站高端数据端口
pass out quick on em0 proto tcp from any to any port > 1024 flags S keep state

# 允许主动模式 FTP 服务器回连到本地的数据通道(端口 20)
pass in quick on em0 proto tcp from any to any port = 20 flags S keep state

每次编辑包含 NAT 规则的文件时,运行 ipnat 需要使用 -CF 选项以删除当前的 NAT 规则并刷新动态转换表的内容,同时使用 -f 指定要加载的 NAT 规则文件名:

sh
# ipnat -CF -f /etc/ipnat.rules

要显示 NAT 统计信息:

sh
# ipnat -s

要列出 NAT 表的当前映射:

sh
# ipnat -l

要开启详细模式并显示与规则处理、活动规则和表条目相关的信息:

sh
# ipnat -v

29.3.5 查看 IPF 统计信息

IPF 包含 ipfstat(8) 命令,可用于检索和显示统计信息,这些统计信息是在数据包经过防火墙时与规则匹配时收集的。统计信息自上次启动防火墙或自上次通过 ipf -Z 将其重置为零以来累积。

默认的 ipfstat 输出如下所示:

sh
input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0
 output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0
 input packets logged: blocked 99286 passed 0
 output packets logged: blocked 0 passed 0
 packets logged: input 0 output 0
 log failures: input 3898 output 0
 fragment state(in): kept 0 lost 0
 fragment state(out): kept 0 lost 0
 packet state(in): kept 169364 lost 0
 packet state(out): kept 431395 lost 0
 ICMP replies: 0 TCP RSTs sent: 0
 Result cache hits(in): 1215208 (out): 1098963
 IN Pullups succeeded: 2 failed: 0
 OUT Pullups succeeded: 0 failed: 0
 Fastroute successes: 0 failures: 0
 TCP cksum fails(in): 0 (out): 0
 Packet log flags set: (0)

该命令提供多个选项。使用 -i 表示入站,-o 表示出站时,命令将检索并显示当前由内核安装并使用的相应过滤规则列表。若还需要查看规则编号,可添加 -n。例如,ipfstat -on 会显示带有规则编号的出站规则表:

sh
@1 pass out on em1 from any to any
@2 block out on em0 from any to any
@3 pass out quick on em0 proto tcp/udp from any to any keep state

添加 -h 可以在每条规则前添加规则匹配的次数。例如,ipfstat -oh 会显示出站内部规则表,并在每条规则前加上其使用次数:

sh
2451423 pass out on em1 from any to any
354727 block out on em0 from any to any
430918 pass out quick on em0 proto tcp/udp from any to any keep state

若要以类似 top(1) 的格式显示状态表,可使用 ipfstat -t。当防火墙遭受攻击时,此选项可用于识别和查看攻击数据包。可选的子标志可用于实时监控目标或源 IP、端口或协议。

29.3.6 IPF 日志记录

IPF 提供了 ipmon,可用于以可读格式记录防火墙的日志信息。它要求在定制内核中首先添加 options IPFILTER_LOG,按配置 FreeBSD 内核中的说明操作。

此命令通常以守护进程模式运行,以提供持续的系统日志文件,便于查看历史事件。由于 FreeBSD 内置了 syslogd(8) 系统,自动轮替系统日志,因此默认的 rc.conf ipmon_flags 语句使用 -Ds

sh
ipmon_flags="-Ds" # D = 以守护进程模式启动
                  # s = 记录到 syslog
                  # v = 记录 TCP 窗口、ack、seq
                  # n = 将 IP 和端口映射为名称

日志记录可用于事后查看信息,例如哪些数据包被丢弃,它们来自哪里,以及它们的目的地。此信息对追踪攻击者非常有用。

rc.conf 中启用日志记录功能并经 service ipmon start 启动后,IPF 仅记录包含 log 关键字的规则。防火墙管理员决定应记录规则集中哪些规则,通常仅拒绝规则会被记录。惯例上,将 log 关键字包含在规则集中的最后一条规则中,以便查看所有未匹配任何规则的数据包。

默认情况下,ipmon -Ds 模式使用 local0 作为日志记录设施。以下日志级别可用于进一步区分记录的数据:

sh
LOG_INFO - 使用 "log" 关键字记录的包,作为动作而不是 pass block。
LOG_NOTICE - 记录的同时也被通过的数据包
LOG_WARNING - 记录的同时也被阻止的数据包
LOG_ERR - 已记录且因首部不完整而被认为是短包的数据包

若要将 IPF 的所有日志记录到 /var/log/ipfilter.log,需要先创建一个空文件:

sh
# touch /var/log/ipfilter.log

然后,要将所有记录的消息写入指定文件,需要在 /etc/syslog.conf 中添加以下语句:

sh
local0.* /var/log/ipfilter.log

使更改生效并让 syslogd(8) 读取修改后的 /etc/syslog.conf,可运行 service syslogd reload

还需要编辑 /etc/newsyslog.conf 以轮替新日志文件。

ipmon 生成的消息由空格分隔的数据字段组成。所有消息的公共字段如下:

字段说明
日期数据包接收的日期。
时间格式为 HH:MM:SS.F,表示小时、分钟、秒和秒的小数部分。
接口处理数据包的接口名称。
规则规则组和规则号,格式为 @0:17
动作p 代表通过,b 代表阻止,S 代表短包,n 代表未匹配任何规则,L 代表日志规则。
地址源地址和端口由逗号分隔,后跟 → 符号,再加上目标地址和端口。例如:209.53.17.22,80 → 198.73.220.17,1722
协议PR 后跟协议名称或编号。例如:PR tcp
长度len 后跟数据包的头部长度和总长度。例如:len 20 40

若数据包为 TCP 包,还有一个附加字段,以连字符为前缀,后跟与所设标志对应的字母。有关字母和标志的列表,请参阅 ipf(5)。

若数据包为 ICMP 包,消息末尾有两个字段,第一个始终是“icmp”,第二个为 ICMP 消息和子消息类型,用斜杠分隔。例如:icmp 3/3 表示端口不可达消息。