IPFILTER,也称为 IPF,是一个跨平台的开源防火墙,已经移植到多个操作系统,包括 FreeBSD、NetBSD、OpenBSD 和 Solaris™。
IPFILTER 是一个可以由用户态程序控制和监控的内核级防火墙和 NAT 机制。防火墙规则可以使用 ipf 进行设置或删除,NAT 规则可以使用 ipnat 进行设置或删除,可以使用 ipfstat 打印 IPFILTER 内核部分的运行时统计信息,并可以使用 ipmon 将 IPFILTER 操作记录到系统日志文件中。
IPF 最初是使用“最后匹配规则获胜”的规则处理逻辑编写的,并且只使用无状态规则。自那时起,IPF 已得到增强,以包括 quick 和 keep state 选项。
IPF 常见问题解答在 http://www.phildev.net/ipf/index.html。IPFilter 邮件列表的可搜索存档可在 http://marc.info/?l=ipfilter 找到。
本手册的这一部分侧重于与 FreeBSD 相关的 IPF。它提供了包含 quick 和 keep state 选项的规则示例。
IPF 包含在基本的 FreeBSD 安装中作为一个内核可加载模块,这意味着为了启用 IPF 不需要自定义内核。
对于偏好将 IPF 支持静态编译到定制内核中的用户,请参考《配置 FreeBSD 内核》中的说明。以下内核选项可用:
其中 options IPFILTER 启用 IPFILTER 支持,options IPFILTER_LOG 使用 ipl 数据包记录伪设备启用 IPF 日志以处理每个带有 log 关键字的规则,IPFILTER_LOOKUP 启用 IP 池以加快 IP 查找速度,options IPFILTER_DEFAULT_BLOCK 更改默认行为以使不符合防火墙 pass 规则的任何数据包被阻止。
要配置系统以在启动时启用 IPF,请将以下条目添加到/etc/rc.conf 中。这些条目还将启用日志记录和 default pass all。要在不编译定制内核的情况下将默认策略更改为 block all,请记住在规则集末尾添加一个 block all 规则。
如果需要 NAT 功能,还需添加以下行:
现在,启动 IPF:
要加载防火墙规则,请使用 ipf 指定规则集文件的名称。可以使用以下命令替换当前运行的防火墙规则:
其中 -Fa 刷新所有内部规则表,-f 指定包含要加载规则的文件。
这提供了修改定制规则集并用新规则副本更新正在运行的防火墙的能力,而无需重启系统。此方法方便测试新规则,因为可以根据需要多次执行该过程。
有关此命令的其他可用标志,请参阅 ipf(8)。
本节说明了用于创建有状态规则的 IPF 规则语法。在创建规则时,请记住,除非 quick 关键字出现在规则中,否则每条规则都按顺序阅读,最后匹配的规则将被应用。这意味着即使匹配数据包的第一条规则是 pass,如果有一条稍后匹配的规则是 block,数据包将被丢弃。示例规则集可以在/usr/share/examples/ipfilter 中找到。
创建规则时,# 字符用于标记注释的开始,并可能出现在规则的末尾,解释该规则的功能,或独立一行。任何空行都将被忽略。
用于规则的关键字必须按特定顺序从左到右编写。某些关键字是必需的,而其他一些是可选的。某些关键字具有子选项,子选项本身可以是关键字,并且还可以包含更多的子选项。关键字的顺序如下,其中大写字母表示变量,小写字母表示必须在其后面跟随的变量:
ACTION DIRECTION OPTIONS proto PROTO_TYPE from SRC_ADDR SRC_PORT to DST_ADDR DST_PORT TCP_FLAG|ICMP_TYPE keep state STATE
本节说明了每个关键字及其选项。这不是创建 IPF 规则时可用的每个可能选项的详尽列表。有关使用每个关键字的规则语法和示例,请参阅 ipf(5)。
行为
动作关键字指示如果数据包与该规则匹配时要执行的操作。每个规则必须有一个动作。识别以下操作:
block :丢弃数据包。
pass :允许数据包。
log :生成日志记录。
count :计算数据包和字节数的数量,可以提供规则使用频率的指示。
auth :将数据包排队,以便另一个程序进一步处理。
call :提供对内置于 IPF 中的更复杂操作的功能的访问。
decapsulate :移除任何头部以处理数据包的内容。
DIRECTION 接下来,每个规则必须明确指定流量的方向,使用以下关键字之一:
in :该规则适用于入站数据包。
out :该规则适用于出站数据包。
all :该规则适用于任一方向。
如果系统具有多个接口,则可以在方向指定接口。一个例子是 in on fxp0 .
选项
选项是可选的。然而,如果指定多个选项,则必须按照这里显示的顺序使用。
log :执行指定的操作时,将数据包头部的内容写入到 ipl(4)数据包日志伪设备中。
quick :如果数据包与此规则匹配,则执行规则指定的操作,并且不会对此数据包进行任何后续规则的处理。
on :必须跟随由 ifconfig(8)显示的接口名称。只有当数据包通过指定接口和指定方向时,规则才会匹配。
当使用 log 关键字时,以下限定词可以按顺序使用:
body :表示在头部之后将记录数据包内容的前 128 字节。
first :如果 log 关键字与 keep state 选项一起使用,则建议使用此选项,以便仅记录触发数据包,而不是匹配有状态连接的每个数据包。
其他选项可用于指定错误返回消息。有关更多详细信息,请参阅 ipf(5)。
协议类型
协议类型是可选的。但是,如果规则需要指定 SRC_PORT 或 DST_PORT,则是必需的,因为它定义了协议的类型。在指定协议类型时,请使用 proto 关键字,后面可以跟 /etc/protocols 中的协议号或名称。例如,协议名称包括 tcp 、 udp 或 icmp。如果指定了 PROTO_TYPE,但没有指定 SRC_PORT 或 DST_PORT,则该协议的所有 port 号都将与该规则匹配。
源地址
from 关键字是必需的,并且后跟表示数据包源的关键字。源可以是主机名、IP 地址后跟 CIDR 掩码、地址池,或者关键字 all。请参考 ipf(5) 获取示例。
没有办法匹配不易以点分数字形式 / 掩码长度表示的 IP 地址范围。可以使用 net-mgmt/ipcalc 软件包或者 port 来简化 CIDR 掩码的计算。有关该实用工具的更多信息,请访问其网页:http://jodies.de/ipcalc。
SRC_PORT
源的port号是可选的。但是,如果使用它,则需要先在规则中定义 PROTO_TYPE。port号前面还必须有 proto 关键字。
支持多种不同的比较操作符: = (等于),!= (不等于),< (小于),> (大于),⇐ (小于或等于)和 >= (大于或等于)。
为了指定 port 范围,将两个 port 数字放在 <> (小于和大于)、 >< (大于和小于)或 : (大于或等于和小于或等于)之间。
DST_ADDR
to 关键字是必需的,后面跟着表示数据包目的地的关键字。与 SRC_ADDR 类似,它可以是主机名、后跟 CIDR 掩码的 IP 地址、地址池或关键字 all。
目的端口
类似于源端口,目的的port号是可选的。但是,如果使用了目的端口,则需要在规则中首先定义协议类型。port号之前还必须加上 proto 关键字。
TCP 标志|ICMP 类型
如果 tcp 被指定为 PROTO_TYPE,可以将标志指定为字母,每个字母代表用于确定连接状态的可能的 TCP 标志。可能的值是: S (SYN)、 A (ACK)、 P (PSH)、 F (FIN)、 U (URG)、 R (RST)、 C (CWN) 和 E (ECN)。
如果 icmp 被指定为 PROTO_TYPE,可以指定要匹配的 ICMP 类型。有关允许的类型,请参阅 ipf(5)。
状态
如果 pass 规则包含 keep state,IPF 将在其动态状态表中添加一个条目,并允许匹配连接的后续数据包。IPF 可以跟踪 TCP、UDP 和 ICMP 会话的状态。任何被 IPF 确认为活跃会话一部分的数据包,即使是不同的协议,也将被允许。
在 IPF 中,目的地要通过连接到公共互联网的接口传出的数据包首先会被检查动态状态表。如果数据包与包含活跃会话对话的下一个预期数据包匹配,它将通过防火墙并且会话对话流的状态在动态状态表中更新。不属于已活跃会话的数据包将根据出站规则集进行检查。从连接到公共互联网的接口进入的数据包首先会被检查动态状态表。如果数据包与包含活跃会话的下一个预期数据包匹配,它将通过防火墙并且会话对话流的状态在动态状态表中更新。不属于已活跃会话的数据包将根据入站规则集进行检查。
可以在 keep state 之后添加几个关键字。如果使用,这些关键字设置各种控制状态过滤的选项,例如设置连接限制或连接时长。请参阅 ipf(5) 了解可用选项及其说明。
本节介绍如何创建一个仅允许匹配 pass 规则并阻止所有其他服务的示例规则集。
FreeBSD 使用回环接口(lo0)和 IP 地址 127.0.0.1 进行内部通信。防火墙规则集必须包含允许这些内部使用的数据包自由移动的规则:
与互联网连接的公共接口用于授权和控制所有出站和入站连接的访问。如果一个或多个接口连接到私人网络,则这些内部接口可能需要规则,以允许源自局域网的数据包在内部网络之间或流向连接到互联网的接口之间传输。规则集应该分为三个主要部分:任何受信任的内部接口,通过公共接口的出站连接,以及通过公共接口的入站连接。
这两个规则允许所有流量通过名为 xl0 的受信任的局域网接口。
公共接口的出站和入站部分的规则应该将最常匹配的规则放在不太常匹配的规则之前,每个部分中的最后一条规则应该阻止并记录该接口和方向的所有数据包。
这组规则定义了名为 dc0 的公共接口的出站部分。这些规则保持状态并识别内部系统被授权用于公共互联网访问的特定服务。所有规则都使用 quick 并指定适当的 port 数字以及如适用的目标地址。
公共接口入站部分规则的示例首先阻止所有不必要的数据包。这减少了最后一个规则记录的数据包数量。
每当某条带有 log first 选项的规则上有记录的消息时,运行 ipfstat -hio 来评估该规则匹配的次数。大量匹配可能表明系统正遭受攻击。
入站部分中的其余规则定义了允许从互联网发起的连接。最后一条规则拒绝所有未在本节先前规则明确允许的连接。
要启用 NAT,请将这些语句添加到/etc/rc.conf,并指定包含 NAT 规则的文件的名称:
NAT 规则灵活,可以完成许多不同的任务,以满足商业和家庭用户的需求。这里介绍的规则语法已经简化,以演示常见用法。有关完整的规则语法说明,请参阅 ipnat(5)。
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 地址的过程成为一个资源问题。有两种方法可用于解决这个问题。
第一种方法是分配一个范围为ports的范围用作源ports。通过添加 portmap 关键字,NAT 可以指示仅在指定范围内使用源ports。
或者,使用 auto 关键字,告诉 NAT 确定可用于使用的ports:
第二种方法是使用一组公共地址。当有太多 LAN 地址无法适应单个公共地址时,以及一组公共 IP 地址可用时,这将非常有用。这些公共地址可以用作 NAT 从中选择 IP 地址的池,作为数据包地址在传输时映射的方式。
可以使用网络掩码或 CIDR 表示法指定公共 IP 地址范围。这两个规则是等效的:
一种常见做法是将公共可访问的 Web 服务器或邮件服务器隔离到内部网络段。这些服务器的流量仍然必须经过 NAT,但需要进行port重定向以将入站流量引导到正确的服务器。例如,要将使用内部地址 10.0.10.25 的 Web 服务器映射到其公共 IP 地址 20.20.20.5,请使用此规则:
如果这是唯一的 Web 服务器,这条规则也有效,因为它将所有外部 HTTP 请求重定向到 10.0.10.25 :
IPF 具有内置的 FTP 代理,可与 NAT 一起使用。它监视所有出站流量,以查找主动或被动 FTP 连接请求,并动态创建包含 FTP 数据通道使用的port号的临时过滤规则。这消除了为 FTP 连接打开大量高序ports的需要。
在此示例中,第一条规则调用代理以传出内部 LAN 的 FTP 流量。第二条规则将防火墙的 FTP 流量传递到互联网,第三条规则处理内部 LAN 的所有非 FTP 流量:
FTP map 规则应放在 NAT 规则之前,这样当数据包匹配 FTP 规则时,FTP 代理会创建临时过滤规则,以允许 FTP 会话数据包通过并经过 NAT。所有不是 FTP 的 LAN 数据包不会匹配 FTP 规则,但如果它们匹配第三条规则,则会经过 NAT。
没有 FTP 代理,将需要以下防火墙规则。请注意,如果没有代理,则所有 1024 以上的ports都需要被允许。
每当编辑包含 NAT 规则的文件时,运行 ipnat 与 -CF 以删除当前 NAT 规则并清除动态转换表的内容。包括 -f 并指定要加载的 NAT 规则集的名称:
要显示 NAT 统计信息:
要列出 NAT 表的当前映射:
打开详细模式并显示与规则处理、活动规则和表项相关的信息:
IPF 包括 ipfstat(8),可用于检索和显示在防火墙上通过规则的数据包匹配时收集的统计信息。自防火墙最后启动或自上次使用 ipf -Z 将其重置为零以来,将累积统计信息。
默认 ipfstat 输出如下所示:
有几个选项可用。当使用 -i 作为入站或者 -o 作为出站时,该命令将检索并显示内核当前安装并使用的适当过滤规则列表。要查看规则编号,包括 -n。例如,ipfstat -on 显示带有规则编号的出站规则表:
包括 -h 以在每个规则前加上规则被匹配的次数。例如,ipfstat -oh 显示出站内部规则表,为每个规则加上其使用计数:
要以类似 top(1) 的格式显示状态表,请使用 ipfstat -t。当防火墙受到攻击时,此选项提供了识别和查看攻击数据包的能力。可选的子标志使你能够选择目标或源 IP、port,或实时监控的协议。有关详细信息,请参阅 ipfstat(8)。
IPF 提供 ipmon,可用于以人类可读的格式写入防火墙的日志信息。它要求首先使用“配置 FreeBSD 内核”中的说明将 options IPFILTER_LOG 添加到定制内核中。
此命令通常以守护进程模式运行,以提供连续的系统日志文件,以便可以审查过去事件的日志记录。由于 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 表示日志规则。
地址写成三个字段:源地址和port 用逗号分隔,然后是 → 符号,目标地址和port。例如: 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 表示 port 不可达消息。