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 操作记录至系统日志文件。
用户空间工具
│
├── ipf → 设置/删除防火墙规则
├── ipnat → 设置/删除 NAT 规则
├── ipfstat → 打印运行时统计信息
└── ipmon → 记录日志至 syslog
│
│ 控制/监控
▼
IPFILTER 内核(包过滤 + NAT)IPF 最初采用“最后匹配规则优先”的规则处理逻辑,且仅使用无状态规则。此后,IPF 已扩展至支持 quick 和 keep state 选项。
本节重点介绍与 FreeBSD 相关的 IPF,并提供包含 quick 和 keep state 选项的规则示例。
启用 IPF 防火墙
启用 IPF 防火墙需要准备配置文件并启动相关服务,具体步骤如下。
如需启用 IPF,可执行以下命令:
若要配置系统在引导时启用 IPF,需要在 /etc/rc.conf 中添加以下条目。这些条目还将启用日志记录并设置 default pass all。若要将默认策略更改为 block all,而无需编译定制内核,需要在规则集末尾添加 block all 规则。
ipmon_flags 标志
描述
D
以守护进程模式启动
s
记录到 syslog
v
记录 tcp 窗口、ack、seq
n
将 IP 和端口映射为名称
启动
加载防火墙规则时,以 ipf 指定规则集文件名。可使用以下命令替换当前运行中的防火墙规则:
其中,-Fa 会刷新所有内部规则表,-f 指定要加载的规则文件。
这样就可以修改自定义规则集,并通过更新规则副本来更新运行中的防火墙,而无需重启系统。此方法便于测试新规则,且可反复执行。
若需要 NAT 功能,还需要在 /etc/rc.conf 中添加以下行:
启动 ipnat:
ipnat 是 IPF 的组成部分,专门用于维护网络地址转换(NAT)规则。NAT 可以实现内网 IP 与公网 IP 的转换,以及端口转发等功能。
注意
ipfilter 服务重启后,ipnat 也需要重启。
IPF 的管理命令主要有 ipf、ipfstat 和 ipnat。
相关文件结构
IPFilter 的配置文件结构如下。
IPF 规则语法
本节说明了用于创建有状态规则的 IPF 规则语法。创建规则时需要注意,除非规则中包含 quick 关键字,否则每条规则均按顺序读取,最后匹配的规则 将生效。这意味着,即使第一个匹配数据包的规则是 pass,若之后有匹配的规则为 block,该数据包也将被丢弃。可在 /usr/share/examples/ipfilter 中找到示例规则集。
创建规则时,# 字符用于标记注释的开始,也可以出现在规则末尾以解释该规则的功能,或单独占一行。空白行均被忽略。
规则中使用的关键字需要按特定顺序书写,从左到右。有些关键字为必需,其余为可选。某些关键字有子选项,子选项本身也可以是关键字,且可包含更多子选项。关键字的顺序如下,其中大写字母表示变量,小写字母为关键字,需要位于其后的变量之前:
本节将说明这些关键字及其选项,但并非所有选项的详尽列表。
ACTION
关键字 ACTION 指定数据包匹配该规则时应执行的操作。每条规则 必须 有一个操作。以下为支持的操作:
block
丢弃数据包
pass
允许数据包
log
生成一条日志记录
count
统计数据包和字节数,可用于反映规则匹配频率
auth
将数据包排队,交由另一个程序进一步处理
call
访问 IPF 内置的功能,以执行更复杂的操作
decapsulate
去除任何头部,以处理数据包的内容
DIRECTION
接下来,每条规则必须明确指定流量的方向,使用以下关键字之一:
in:规则应用于传入的数据包。out:规则应用于传出的数据包。
如果系统有多个接口,可以在方向后指定接口名。例如 in on em0。
注意
all关键字不是方向关键字,而是地址匹配的简写,表示匹配所有地址(等同于from any to any)。例如block in all中的all是地址部分,而非方向。
OPTIONS
OPTIONS 是可选的。但若指定多个选项,需要按此处显示的顺序排列。
log:执行指定的操作时,数据包头部的内容将写入 ipl(4) 包日志伪设备。quick:若数据包匹配此规则,则执行规则指定的操作,且不再处理后续规则。on:后需要跟接口名,即 ifconfig(8) 所显示的接口名。仅当数据包通过指定接口且符合指定方向时,规则才匹配。
使用 log 关键字时,可以按顺序使用以下修饰符:
body:表示数据包内容的前 128 字节将在头部之后记录。first:若log关键字与keep state选项配合使用,建议使用此选项,以便仅记录触发数据包,而非每个匹配的有状态连接数据包。
还可用附加选项指定错误返回消息。
PROTO_TYPE
PROTO_TYPE 是可选的。但若规则需要指定 SRC_PORT 或 DST_PORT,则为必需,因为它定义了协议类型。在指定协议类型时,使用 proto 关键字后跟协议号或 /etc/protocols 中的协议名称。示例协议名称包括 tcp、udp 或 icmp。若指定了 PROTO_TYPE,但未指定 SRC_PORT 或 DST_PORT,则该规则将匹配该协议的所有端口号。
SRC_ADDR
关键字 from 是必需的,后跟表示数据包来源的关键字。源地址可以是主机名、带有 CIDR 掩码的 IP 地址、地址池或 all 关键字。
无法匹配不以点分十进制/掩码长度形式表示的 IP 地址范围。可使用 net-mgmt/ipcalc 软件包和 Ports 来简化 CIDR 掩码的计算。可在该工具的网页上找到更多信息:http://jodies.de/ipcalc。
SRC_PORT
关键字 SRC_PORT 是可选的。但若使用该选项,则需要先定义 PROTO_TYPE。端口号必须以 port 关键字为前缀。
支持多种比较运算符:=(等于)、!=(不等于)、<(小于)、>(大于)、<=(小于或等于)和 >=(大于或等于)。
指定端口范围时,需要将两个端口号置于 <>(小于 x 或大于 y)、><(大于 x 且小于 y)或 :(大于或等于,且小于或等于)之间。
DST_ADDR
关键字 to 是必需的,后跟表示数据包目的地的关键字。与 SRC_ADDR 类似,它可以是主机名、带有 CIDR 掩码的 IP 地址、地址池或 all 关键字。
DST_PORT
与 SRC_PORT 类似,DST_PORT 是可选的。但若使用该选项,则需要先定义 PROTO_TYPE。端口号也必须以 port 关键字为前缀。
TCP_FLAG|ICMP_TYPE
若 tcp 指定为 PROTO_TYPE,则可指定标志,以字母表示 TCP 连接状态:
S
SYN
A
ACK
P
PSH
F
FIN
U
URG
R
RST
C
CWR
E
ECE
若 icmp 指定为 PROTO_TYPE,则可指定要匹配的 ICMP 类型。
STATE
若 pass 规则包含 keep state,IPF 将在其动态状态表中添加一条记录,并允许后续匹配该连接的数据包。IPF 可跟踪 TCP、UDP 和 ICMP 会话的状态。任何 IPF 确定属于已激活会话的数据包,即使它属于不同的协议,也将被允许。
在 IPF 中,数据包通过连接到公共互联网的接口时,首先对照动态状态表进行检查。若数据包匹配组成活动会话的下一个预期数据包,它将通过防火墙并更新该会话的状态。不属于已有活动会话的数据包将与出站规则集匹配。从连接到公共互联网的接口传入的数据包同样首先对照动态状态表进行检查。若数据包匹配组成活动会话的下一个预期数据包,它将通过防火墙并更新该会话的状态。不属于已有活动会话的数据包将与入站规则集匹配。
在 keep state 后可添加若干关键字。若使用这些关键字,它们将设置控制有状态过滤的各种选项,例如设置连接限制或连接时长。
示例规则集
本节演示创建示例规则集,该规则集仅允许与 pass 规则匹配的服务,并阻止所有其他服务。
FreeBSD 使用回环接口(lo0)和 IP 地址 127.0.0.1 用于内部通信。防火墙规则集必须包含允许这些内部使用的包自由通过的规则:
连接到互联网的公共接口用于授权和控制所有出站和入站连接的访问。若一个或多个接口连接到私有网络,则这些内部接口可能需要规则以允许从局域网起始的包在内部网络之间传输或流向连接到互联网的接口。规则集应分为三个主要部分:任何受信任的内部接口、通过公共接口的出站连接和通过公共接口的入站连接。
这两条规则允许所有流量通过受信任局域网接口 em1:
公共接口的出站和入站部分的规则应将最常匹配的规则放在前面,将不常匹配的规则放在后面,最后一条规则用于阻止和记录该接口和方向的所有包。
以下规则集定义了公共接口 em0 的出站部分。这些规则保持状态并标识内部系统被授权访问公共互联网的特定服务。所有规则都使用 quick 并指定适当的端口号,并在适用时指定目标地址。
此示例展示了公共接口入站部分的规则集,它首先阻止所有不需要的包。如此可减少最后一条规则记录的包的数量。
每当使用 log first 选项的规则生成日志消息时,运行 ipfstat -hio 以评估该规则被匹配的次数。大量的匹配可能表明系统正遭受攻击。
入站部分的其余规则定义了哪些连接可以从互联网发起。最后一条规则拒绝所有未被前述规则明确允许的连接。
配置 NAT
启用 NAT 需要在 /etc/rc.conf 中添加以下语句,并指定包含 NAT 规则的文件名:
NAT 规则较为灵活,可根据商业和家庭用户的需要实现多种功能。此处展示的规则语法已简化,以演示常见的使用方式。
NAT 规则的基本语法如下,其中 map 开始规则,IF 应替换为外部接口的名称:
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 地址,然后将包传递到防火墙规则作进一步处理。
对于拥有大量内部系统或多个子网的网络,将每个私有 IP 地址转换为单个公共 IP 地址将成为资源瓶颈。解决此问题可采用两种方法。
第一种方法是为源端口分配一个端口范围。通过添加 portmap 关键字,NAT 将仅使用指定范围内的源端口:
此外,可使用 auto 关键字,由 NAT 自行决定可用端口:
第二种方法是使用一个公共地址池。当局域网地址太多而无法适配单个公共地址时,此方法尤为适用。若有一块公共 IP 地址池可用,可将这些公共 IP 地址用作 NAT 选择的 IP 地址池,在数据包外发时实现地址映射。
公共 IP 地址范围可使用子网掩码或 CIDR 表示法指定。以下两条规则等效:
一种常见的做法是将一个公开可访问的 Web 服务器或邮件服务器隔离到内部网络段。这些服务器的流量仍需要经过 NAT,但需要通过端口重定向将入站流量引导至正确的服务器。例如,将内部地址为 10.0.10.25 的 Web 服务器映射到其公共 IP 地址 20.20.20.5,可使用以下规则:
若这是唯一的 Web 服务器,此规则也适用,因为它将所有外部 HTTP 请求重定向至 10.0.10.25:
IPF 内置了一个 FTP 代理,可与 NAT 配合使用。它监控所有出站流量的主动或被动 FTP 连接请求,并动态创建临时过滤规则,包含 FTP 数据通道使用的端口号。这消除了为 FTP 连接打开大量高端端口的需要。
注意
FTP 协议已逐渐被 SFTP 和 SCP 等安全替代方案取代。现代网络中 FTP 的使用场景已大幅减少,以下 FTP 代理配置仅适用于仍需支持 FTP 的遗留环境。
在此示例中,第一条规则为来自内部局域网的出站 FTP 流量调用代理。第二条规则将 FTP 流量从防火墙传递到互联网,第三条规则处理所有非 FTP 流量:
FTP map 规则应位于 NAT 规则之前,这样当包与 FTP 规则匹配时,FTP 代理会创建临时的过滤规则,让 FTP 会话数据包通过并经过 NAT。所有非 FTP 的局域网包不会匹配 FTP 规则,但若它们匹配第三条规则,将会经过 NAT。
若无 FTP 代理,则需要使用以下防火墙规则。需要注意,若无代理,则需要允许所有高于 1024 的端口:
每次编辑包含 NAT 规则的文件时,运行 ipnat 需要使用 -CF 选项以删除当前的 NAT 规则并刷新动态转换表的内容,同时使用 -f 指定要加载的 NAT 规则文件名:
要显示 NAT 统计信息:
要列出 NAT 表的当前映射:
要开启详细模式并显示与规则处理、活动规则和表条目相关的信息:
查看 IPF 统计信息
IPF 包含 ipfstat(8) 命令,可用于检索和显示统计信息,这些统计信息是在数据包经过防火墙时与规则匹配时收集的。统计信息自上次启动防火墙或自上次通过 ipf -Z 将其重置为零以来累积。
默认的 ipfstat 输出如下所示:
该命令提供多个选项。使用 -i 表示入站,-o 表示出站时,命令将检索并显示当前由内核安装并使用的相应过滤规则列表。若还需要查看规则编号,可添加 -n。例如,ipfstat -on 会显示带有规则编号的出站规则表:
添加 -h 可以在每条规则前添加规则匹配的次数。例如,ipfstat -oh 会显示出站内部规则表,并在每条规则前加上其使用次数:
若要以类似 top(1) 的格式显示状态表,可使用 ipfstat -t。当防火墙遭受攻击时,此选项可用于识别和查看攻击数据包。可选的子标志可用于实时监控目标或源 IP、端口或协议。
IPF 日志记录
IPF 提供了 ipmon,可用于以可读格式记录防火墙的日志信息。它要求在定制内核中首先添加 options IPFILTER_LOG,按配置 FreeBSD 内核中的说明操作。
此命令通常以守护进程模式运行,以提供持续的系统日志文件,便于查看历史事件。由于 FreeBSD 内置了 syslogd(8) 系统,自动轮替系统日志,因此默认的 rc.conf ipmon_flags 语句使用 -Ds:
日志记录可用于事后查看信息,例如哪些数据包被丢弃,它们来自哪里,以及它们的目的地。此信息对追踪攻击者非常有用。
在 rc.conf 中启用日志记录功能并经 service ipmon start 启动后,IPF 仅记录包含 log 关键字的规则。防火墙管理员决定应记录规则集中哪些规则,通常仅拒绝规则会被记录。惯例上,将 log 关键字包含在规则集中的最后一条规则中,以便查看所有未匹配任何规则的数据包。
默认情况下,ipmon -Ds 模式使用 local0 作为日志记录设施。以下日志级别可用于进一步区分记录的数据:
若要将 IPF 的所有日志记录到 /var/log/ipfilter.log,需要先创建一个空文件:
然后,要将所有记录的消息写入指定文件,需要在 /etc/syslog.conf 中添加以下语句:
使更改生效并让 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 表示端口不可达消息。
最后更新于