30.4. IPFW

IPFW是一套专为FreeBSD所写的具状态防火墙(Stateful firewall),它同时支持IPv4IPv6,它由数个元件组成:核心防火墙过滤规则处理器与其整合的封包计帐设施、记录设施、NATdummynet(4)流量限制程序、转送设施、桥接设施以及ipstealth设施。

FreeBSD提供一个模板规则集於/etc/rc.firewall,其定义了几个常见情境会使用的防火墙类型来协助初学的使用者撰写合适的规则集。IPFW提供了强大的语法让进阶的使用者可以用来自定义符合环境安全性要求的规则集。

本节介绍如何启用IPFW,概述了其规则语法,并演示了常见配置方案的几个规则集。

30.4.1. 开启IPFW

IPFW 是基本的 FreeBSD 安装的一部分, 以单独的可加载内核模块的形式提供。 这意味着不需要自定义内核即可启用IPFW

若希望将IPFW支持静态编译到内核中,请参阅第 30.4.6 节 “IPFW 内核选项”

若希望IPFW在系统启动时启动,将firewall_enable="YES"添加到/etc/rc.conf文件中:

# sysrc firewall_enable="YES"

要选择由 FreeBSD 提供的几种防火墙类型中的一种来作为默认配置, 您需要阅读 /etc/rc.firewall 文件并选出合适的类型, 然后在 /etc/rc.conf 中加入类似下面的配置:

# sysrc firewall_type="open"

可用的类型有:

  • open:允许所有流量通过。

  • client:只保护本机。

  • simple: protects the whole network.

  • closed:完全禁止除回环设备之外的全部 IP 流量。

  • workstation:仅使用有状态规则保护此计算机。

  • UNKNOWN:禁止加载防火墙规则。

  • filename:到防火墙规则文件的绝对路径。

如果firewall_type被设置为clientopen,修改/etc/rc.firewall中的默认规则来适应系统配置。

请注意,filename类型被用于加载自定义规则集。

除此之外, 也可以将 firewall_script 变量设为包含 ipfw 命令的可执行脚本,本例将firewall_script设为/etc/ipfw.rules

# sysrc firewall_script="/etc/ipfw.rules"

若要启用防火墙日志(记录到syslogd(8)),请输入下列命令:

# sysrc firewall_logging="YES"

警告:

只有带有 log选项的防火墙规则才会被记录。默认规则不包括此选项,必须手动添加。因此,建议编辑默认规则集以进行日志记录。此外,如果日志存储在单独的文件中,则可能需要日志日志轮转。

/etc/rc.conf中没变量用于设置日志记录限制。要限制每次连接尝试记录规则的次数,请在/etc/sysctl.conf中使用此行指定编号:

# echo "net.inet.ip.fw.verbose_limit=5" >> /etc/sysctl.conf

为启用日志通过名为ipfw0的特定端口,添加下面这行到/etc/rc.conf

# sysrc firewall_logif="YES"

然后使用tcpdump来查看日志信息:

# tcpdump -t -n -i ipfw0

提示:

除非附加tcpdump,否则不会产生日志记录的开销。

可加载内核模块在编译时加入了记录日志的能力。 要启用日志功能, 并配置详细日志记录的限制, 需要在 /etc/sysctl.conf 中加入一些配置。 这些设置将在重新启动之后生效:

# service ipfw start
# sysctl net.inet.ip.fw.verbose_limit=5

30.4.2. IPFW规则语法

当一个数据包进入IPFW防火墙时,它将与规则集中的第一个规则进行比较,并按顺序从上到下依次递进一个规则。当数据包与某条规则的选择参数相匹配时,该规则的动作就会被执行,并终止对该数据包在规则集中的搜索。这被称为先匹配后胜利(first match wins)。如果数据包不匹配任何一条规则,它将被IPFW默认规则号65535捕获,该规则将拒绝所有数据包,并静静地丢弃它们。但是,如果数据包匹配了包含countskiptotee关键字的规则,搜索将继续进行。有关这些关键字如何影响规则处理的详细信息,请参阅 ipfw(8)

创建IPFW规则时,关键字必须按以下顺序编写。某些关键字是强制性的,而其他关键字是可选的。大写的单词表示变量,以小写显示的单词必须位于它后面的变量之前。*符号用于标记注释的开始,并可能出现在规则末尾或其自己的行上。忽略空白行。

CMD RULE_NUMBER set SET_NUMBER ACTION log LOG_AMOUNT PROTO from SRC SRC_PORT to DST DST_PORT OPTIONS

本节仅介绍部分关键字及其选项。完整的 IPFW 规则语法请参阅。

CMD

每一个新的规则都应以 add 作为前缀, 它表示将规则加入内部表。

RULE_NUMBER

每一条规则都与一个范围在 1 到 65535 之间的规则编号相关联。该数字用于指示规则处理的顺序。多个规则可以具有相同的编号,在这种情况下,它们根据添加的顺序应用。

SET_NUMBER

每个规则都与一个031之间的数字相关联。可以单独禁用或启用集,从而可以快速添加或删除一组规则。如果未指定 SET_NUMBER,则规则将添加到设置为0 。

ACTION

每一个规则可以与下列的动作之一相关联, 所指定的动作将在进入的数据包与规则所指定的选择标准相匹配时执行。

allow | accept | pass | permit:这些关键字都表示允许匹配规则的包通过防火墙, 并停止继续搜索规则。

根据动态规则表检查数据包。 如果匹配, 则执行规则所指定的动作, 亦即生成动态规则; 否则, 转移到下一个规则。 check-state 规则没有选择标准。 如果规则集中没有 check-state 规则, 则会在第一个 keep-state 或 limit 规则处, 对动态规则表实施检查。

count:更新与规则匹配的所有数据包的计数器。搜索将继续进行下一条规则。

deny | drop:这两个关键字都表示丢弃匹配规则的包。 同时, 停止继续搜索规则。

更多可用的 ACTION 请参考ipfw(8)

LOG_AMOUNT

当数据包与带 log 关键字的规则匹配时, 将通过名为 SECURITY 的 facility 来把消息记录到 syslogd(8)。 只有在记录的次数没有超过 logamount 参数所指定的次数时, 才会记录日志。 如果没有指定 logamount, 则会以 sysctl 变量 net.inet.ip.fw.verbose_limit 所指定的限制为准。 如果将这两种限制值之一指定为零, 则表示不作限制。 如果达到了限制数, 可以通过将规则的日志计数或包计数清零来重新启用日志, 请参见 ipfw resetlog 命令来了解细节。

注意:

日志是在所有其他匹配条件都验证成功之后, 在针对包实施最终动作 (accept, deny) 之前进行的。 您可以自行决定哪些规则应启用日志。

PROTO

也可以指定在 /etc/protocols 中所定义的协议。 这个值定义的是匹配的协议, 在规则中必须指定它。

SRC

from关键字后面必须有源地址或代表源地址的关键字。地址可以用anyme(在此系统的接口上配置的任何地址)、me6、(在此系统的接口上配置的任何IPv6地址)或table后面的包含地址列表的查找表的编号。当指定一个IP地址时,可以选择在它的CIDR掩码或子网掩码后面加上它的CIDR掩码或子网掩码。例如,1.2.3.3.4/251.2.3.4:255.255.255.255.255.128

SRC_PORT

这个参数主要用于那些支持端口号的协议 (例如 TCPUDP)。 如果要通过端口号匹配某个协议, 就必须指定这个参数。 此外, 也可以通过服务的名字 (根据 /etc/services) 来指定服务, 这样会比使用数字指定端口号直观一些。

DST

to关键字必须后跟目标地址或表示目标地址的关键字。SRC中描述的相同关键字和地址可用于描述目的地。

DST_PORT

可以使用/etc/services中的端口号或名称指定可选的目标端口。

OPTIONS

源和目标后面可以有几个关键字。顾名思义,OPTIONS 是可选的。常用的选项包括inout,它们指定数据包流的方向、icmptypes后跟ICMP消息的类型和keep-state

当匹配 keep-state 规则时,防火墙将创建一个动态规则,该规则匹配使用相同协议的源地址和目标地址以及端口之间的双向流量。

动态规则工具很容易遭受SYN洪水攻击,消耗大量资源,这将打开大量动态规则。 要使用 IPFW应对此类攻击,请使用 limit。 此选项通过检查打开的动态规则,计算此规则和 IP地址组合发生的次数来限制同时进行的会话数。 如果此计数大于 limit,则丢弃该数据包。

有许多可用的 OPTIONS,详情请见ipfw(8)

30.4.3. 规则集示例

本节演示创建名为/etc/ipfw.rules的有状态防火墙规则集脚本。在此示例中,所有连接规则都使用inout来阐明方向。它们还通过interface-name来指定数据包经过的接口。

注意:

若您第一次创建防火墙规则,请把下面这个 sysctl 变量暂时设为 1:

net.inet.ip.fw.default_to_accept="1"

ipfw(8)的默认规则是deny ip from any to any。将变量设为此值可以让规则宽松一点,以防系统重启后用户被挡在外头。

防火墙脚本的开头指明了这是一个 Bourne shell 脚本,并在规则载入之前刷新现有规则。它创建了cmd变量,这样就不用在每条规则开头输入ipfw add。同时还定义了pif变量,该变量表示连接到 Internet 接口的名称。

#!/bin/sh
# Flush out the list before we begin.
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"
pif="dc0"     # interface name of NIC attached to Internet

前两个规则允许受信任内部接口和环回接口上的所有流量:

# Change xl0 to LAN NIC interface name
$cmd 00005 allow all from any to any via xl0

# No restrictions on Loopback Interface
$cmd 00010 allow all from any to any via lo0

这条规则表示允许所有符合规则的流量通过:

$cmd 00101 check-state

下一条规则说明系统中的哪些服务能与 Internet 创建有状态连接:

# Allow access to public DNS
# Replace x.x.x.x with the IP address of a public DNS server
# and repeat for each DNS server in /etc/resolv.conf
$cmd 00110 allow tcp from any to x.x.x.x 53 out via $pif setup keep-state
$cmd 00111 allow udp from any to x.x.x.x 53 out via $pif keep-state

# Allow access to ISP's DHCP server for cable/DSL configurations.
# Use the first rule and check log for IP address.
# Then, uncomment the second rule, input the IP address, and delete the first rule
$cmd 00120 allow log udp from any to any 67 out via $pif keep-state
#$cmd 00120 allow udp from any to x.x.x.x 67 out via $pif keep-state

# Allow outbound HTTP and HTTPS connections
$cmd 00200 allow tcp from any to any 80 out via $pif setup keep-state
$cmd 00220 allow tcp from any to any 443 out via $pif setup keep-state

# Allow outbound email connections
$cmd 00230 allow tcp from any to any 25 out via $pif setup keep-state
$cmd 00231 allow tcp from any to any 110 out via $pif setup keep-state

# Allow outbound ping
$cmd 00250 allow icmp from any to any out via $pif keep-state

# Allow outbound NTP
$cmd 00260 allow udp from any to any 123 out via $pif keep-state

# Allow outbound SSH
$cmd 00280 allow tcp from any to any 22 out via $pif setup keep-state

# deny and log all other outbound connections
$cmd 00299 deny log all from any to any out via $pif

下一组规则控制 Internet 到内部网络的连接。它首先拒绝可能发起攻击的数据包,然后显式允许特定类型的连接。源自 Internet 的所有授权服务都使用limit来防止洪水攻击。

# Deny all inbound traffic from non-routable reserved address spaces
$cmd 00300 deny all from 192.168.0.0/16 to any in via $pif     #RFC 1918 private IP
$cmd 00301 deny all from 172.16.0.0/12 to any in via $pif      #RFC 1918 private IP
$cmd 00302 deny all from 10.0.0.0/8 to any in via $pif         #RFC 1918 private IP
$cmd 00303 deny all from 127.0.0.0/8 to any in via $pif        #loopback
$cmd 00304 deny all from 0.0.0.0/8 to any in via $pif          #loopback
$cmd 00305 deny all from 169.254.0.0/16 to any in via $pif     #DHCP auto-config
$cmd 00306 deny all from 192.0.2.0/24 to any in via $pif       #reserved for docs
$cmd 00307 deny all from 204.152.64.0/23 to any in via $pif    #Sun cluster interconnect
$cmd 00308 deny all from 224.0.0.0/3 to any in via $pif        #Class D & E multicast

# Deny public pings
$cmd 00310 deny icmp from any to any in via $pif

# Deny ident
$cmd 00315 deny tcp from any to any 113 in via $pif

# Deny all Netbios services.
$cmd 00320 deny tcp from any to any 137 in via $pif
$cmd 00321 deny tcp from any to any 138 in via $pif
$cmd 00322 deny tcp from any to any 139 in via $pif
$cmd 00323 deny tcp from any to any 81 in via $pif

# Deny fragments
$cmd 00330 deny all from any to any frag in via $pif

# Deny ACK packets that did not match the dynamic rule table
$cmd 00332 deny tcp from any to any established in via $pif

# Allow traffic from ISP's DHCP server.
# Replace x.x.x.x with the same IP address used in rule 00120.
#$cmd 00360 allow udp from any to x.x.x.x 67 in via $pif keep-state

# Allow HTTP connections to internal web server
$cmd 00400 allow tcp from any to me 80 in via $pif setup limit src-addr 2

# Allow inbound SSH connections
$cmd 00410 allow tcp from any to me 22 in via $pif setup limit src-addr 2

# Reject and log all other incoming connections
$cmd 00499 deny log all from any to any in via $pif

最后一条规则拒绝所有不符合规则的流量:

# Everything else is denied and logged
$cmd 00999 deny log all from any to any

30.4.4. In-kernel NAT

Contributed by Chern Lee.
Rewritten and updated by Dries Michiels.

FreeBSD 的IPFW防火墙有两个NAT实现:一个是用户态natd(8)实现,另一个是最新的内核内NAT实现。两者都可与IPFW配合使用,提供网络地址转换。这可用于提供 Internet 连接共享解决方案,以便多个内部计算机可以使用单个公网IP地址连接到 Internet。

为此,连接到 Internet 的 FreeBSD 计算机必须充当网关。此系统必须具有两个NIC(网口),其中一个连接到互联网,另一个连接到内部LAN(本地网络)。在LAN后面的每一台机子和接口应该被分配私有地址空间(由RFC 1918定义)里的 IP 地址。

为了启用IPFW的 in-kernelNAT功能,需要进行一些额外的配置。要在启动时启用内核内NAT支持,必须在/etc/rc.conf中设置以下内容:

gateway_enable="YES"
firewall_enable="YES"
firewall_nat_enable="YES"

注意:

firewall_nat_enable已设置,但firewall_enable未设置时,它将没有效果,不执行任何操作,因为 in-kernelNAT实现仅与IPFW兼容。

当规则集包含有状态的规则时,NAT规则的定位非常关键,并使用skipto动作。skipto动作需要一个规则编号,以便知道要跳转到哪个规则。下面的示例基于上一节中所示的防火墙规则集。它添加了一些条目并修改了一些现有规则,以便为 in-kernel NAT配置防火墙。它首先添加一些表示要跳到的规则编号、keep-state 选项和用于减少规则数的TCP端口列表。

#!/bin/sh
ipfw -q -f flush
cmd="ipfw -q add"
skip="skipto 1000"
pif=dc0
ks="keep-state"
good_tcpo="22,25,37,53,80,443,110"

With in-kernel NAT it is necessary to disable TCP segmentation offloading (TSO) due to the architecture of libalias(3), a library implemented as a kernel module to provide the in-kernel NAT facility of IPFW. TSO can be disabled on a per network interface basis using ifconfig(8) or on a system wide basis using sysctl(8). To disable TSO system wide, the following must be set it /etc/sysctl.conf:

net.inet.tcp.tso="0"

A NAT instance will also be configured. It is possible to have multiple NAT instances each with their own configuration. For this example only one NAT instance is needed, NAT instance number 1. The configuration can take a few options such as: if which indicates the public interface, same_ports which takes care that alliased ports and local port numbers are mapped the same, unreg_only will result in only unregistered (private) address spaces to be processed by the NAT instance, and reset which will help to keep a functioning NAT instance even when the public IP address of the IPFW machine changes. For all possible options that can be passed to a single NAT instance configuration consult ipfw(8). When configuring a stateful NATing firewall, it is neseccary to allow translated packets to be reinjected in the firewall for further processing. This can be achieved by disabling one_pass behavior at the start of the firewall script.

ipfw disable one_pass
ipfw -q nat 1 config if $pif same_ports unreg_only reset

NAT入站规则插入在两个规则之后,这两个规则允许受信任和环回接口上的所有流量,在重新命名规则之后,但在检查状态规则之前。在本示例中为此NAT规则选择的规则编号(在此示例中为100)高于前三个规则,并且低于检查状态规则,这一点很重要。此外,由于内核内NAT的行为,建议在第一个NAT规则之前和允许在受信任接口上进行流量的规则之后放置一个可重新传输规则。通常,IP碎片不应发生,但在处理IPSEC/ESP/GRE隧道流量时,在将完整数据包移交给内核内NAT组件之前,可能需要重新组织片段。

注意:

用户态 natd(8) 不需要重组规则,因为IPFW divert已经自动处理了这一点,如ipfw(8)中所述。

本例中使用的 NAT 实例和规则号与 rc.firewall 创建的默认 NAT 实例和规则号不匹配。rc.firewall 是 FreeBSD 的默认防火墙规则集。

$cmd 005 allow all from any to any via xl0  # exclude LAN traffic
$cmd 010 allow all from any to any via lo0  # exclude loopback traffic
$cmd 099 reass all from any to any in       # reassemble inbound packets
$cmd 100 nat 1 ip from any to any in via $pif # NAT any inbound packets
# Allow the packet through if it has an existing entry in the dynamic rules table
$cmd 101 check-state

修改出站规则,将allow替换为$skip,指示规则处理将在1000规则中继续进行。七个tcp规则已被125规则替换,因为$good_tcpo变量包含七个允许的出站端口。

注意:

请记住,IPFW的性能很大程度上取决于规则集中的规则数。

# Authorized outbound packets
$cmd 120 $skip udp from any to x.x.x.x 53 out via $pif $ks
$cmd 121 $skip udp from any to x.x.x.x 67 out via $pif $ks
$cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks
$cmd 130 $skip icmp from any to any out via $pif $ks

入站规则保持不变,除了最后一条规则,它去掉了via $pif,以便同时抓住入站和出站规则。NAT规则必须跟在这最后一条出站规则之后,必须有一个比最后一条规则更高的编号,而且规则编号必须由skipto操作引用。在这个规则集中,规则号1000将所有数据包传给我们配置的NAT实例进行处理。下一条规则允许任何经过NAT处理的数据包通过。

$cmd 999 deny log all from any to any
$cmd 1000 nat 1 ip from any to any out via $pif # skipto location for outbound stateful rules
$cmd 1001 allow ip from any to any

本例中,规则1001011251000、和1001控制出站包和入站包的地址转换,这样动态状态表中的条目总是注册私有的LAN IP地址。

考虑一个内部web浏览器,它通过端口80初始化一个新的出站HTTP会话。当第一个出站数据包进入防火墙时,它与规则100不匹配,因为它是向外而不是向内的。它通过了规则101,因为这是第一个数据包,它还没有被发送到动态状态表。数据包最终与规则125匹配,因为它是在允许的端口上出站的,并且具有来自内部LAN的源IP地址。匹配此规则时,将执行两个操作。首先,keep-state操作向动态状态表添加一个条目,然后执行指定的操作skipto rule 1000。接下来,包经过NAT并发送到 Internet。此数据包将被发送到目标 web 服务器,在那里生成并发送响应数据包。这个新包进入规则集的顶部。它匹配规则100,并将其目标IP地址映射回原始内部地址。然后由检查状态规则处理,在表中被发现为现有会话,并被释放到LAN

在入站端,规则集必须拒绝错误数据包,并且仅允许已授权的服务通过。与入站规则匹配的数据包将发布到动态状态表,数据包被释放到LAN。作为响应生成的数据包被check-state规则识别为属于现有会话。然后,它发送到规则1000以进行NAT,然后再释放到出站接口。

注意:

Transitioning from userland natd(8) to in-kernel NAT might seem seamless at first but there is small catch. When using the GENERIC kernel, IPFW will load the libalias.ko kernel module, when firewall_nat_enable is enabled in rc.conf. The libalias.ko kernel module only provides basic NAT functionality, whereas the userland implementation natd(8) has all NAT functionality available in its userland library without any extra configuration. All functionality refers to the following kernel modules that can additionally be loaded when needed besides the standard libalias.ko kernel module: alias_cuseeme.ko, alias_ftp.ko, alias_bbt.ko, skinny.ko, irc.ko, alias_pptp.ko and alias_smedia.ko using the kld_list directive in rc.conf. If a custom kernel is used, the full functionality of the userland library can be compiled in, in the kernel, using the options LIBALIAS.

30.4.4.1. 端口重定向

NAT有个缺点:无法从 Internet 访问LAN客户端。LAN可以向 Internet 发出连接,但不能接收传入连接。如果尝试在其中一台LAN客户端计算机上运行 Internet 服务,则这会带来问题。解决方法是将 NAT 上的端口重定向到 LAN 中的计算机上。

例如例如:在客户端 A 上运行 IRC 服务,而在客户端 B 上运行 web 服务。 想要正确的工作,在端口 6667 (IRC) 和 80 (web) 上接收到的连接就必须重定向到相应的机子上。

使用 in-kernel NAT,所有配置都在NAT实例配置中完成。有关内核内NAT实例可以使用的选项的完整列表,请参阅ipfw(8)IPFW语法遵循natd的语法。redirect_port的语法如下所示:

redirect_port proto targetIP:targetPORT[-targetPORT]
  [aliasIP:]aliasPORT[-aliasPORT]
  [remoteIP[:remotePORT[-remotePORT]]]

要配置上述示例设置,参数应为:

redirect_port tcp 192.168.0.2:6667 6667
redirect_port tcp 192.168.0.3:80 80

在上述规则集中将这些参数添加到NAT实例 1 的配置后,TCP端口将端口转发到运行IRCHTTP服务的LAN客户端计算机。

ipfw -q nat 1 config if $pif same_ports unreg_only reset \
  redirect_port tcp 192.168.0.2:6667 6667 \
  redirect_port tcp 192.168.0.3:80 80

-redirect_port 参数可以用来指出端口范围来代替单个端口。例如, tcp 192.168.0.2:2000-3000 2000-3000 就会把所有在端口 2000 到 3000 上接收到的连接重定向到主机 A 上的端口 2000 到 3000。

30.4.4.2. 地址重定向

如果有多个可用IP地址,则地址重定向非常有用。每个LAN客户端可以通过ipfw(8)为其自己分配外部IP地址,然后它将用适当的外部IP地址重写来自LAN客户端的传出数据包,并将该特定IP地址上传入的所有流量重定向回特定的LAN客户端。这也称为静态NAT。例如,如果IP地址128.1.1.1128.1.1.2128.1.1.3可用,则128.1.1.1可用作ipfw(8)计算机的外部IP地址,而128.1.1.2128.1.1.3可分配给AB

redirect_address语法如下所示。localIPLAN客户端的内部IP地址。publicIPLAN客户端对应的外部IP地址。

redirect_address localIP publicIP

在此示例中,参数效果等同于:

redirect_address 192.168.0.2 128.1.1.2
redirect_address 192.168.0.3 128.1.1.3

-redirect_port 一样,这些参数也是放在 NAT实例的配置文件里。使用地址重定向, 就没有必要用端口重定向了,因为所有在某个 IP 地址上收到的数据都被重定向了。

ipfw(8)机器上的外部IP地址必须处于活动状态,并且与外部接口进行别名化(aliased )。详情请参阅rc.conf(5)

30.4.4.3. Userspace NAT

让我们从一个语句开始:用户态NAT实现:natd(8),比内核态NAT产生更多开销。对于natd(8)要转换数据包,数据包必须从内核复制到用户空间,并返回,这带来了额外的开销,而内核态NAT不存在。

为了在启动时启用NAT守护进程natd(8),以下是/etc/rc.conf中的最小配置。natd_interface设置为连接到 Internet 的NIC的名称。natd(8)rc(8)脚本将自动检查是否使用了动态IP地址,并配自动处理该地址。

gateway_enable="YES"
natd_enable="YES"
natd_interface="rl0"

一般情况下,上述适用于内核态NAT的规则集也可以和natd(8)一起使用。例外的是内核态NAT实例的配置(ipfw -q nat 1 config ...),因为它的功能包含在divert动作中,所以不需要和重装规则99一起使用。如下图所示,规则100和1000需要修改。

$cmd 100 divert natd ip from any to any in via $pif
$cmd 1000 divert natd ip from any to any out via $pif

要配置端口或地址重定向,使用与 in-kernelNAT类似的语法。虽然现在,不是像 in-kernelNAT那样在我们的规则集脚本中指定配置,而是最好在配置文件中完成natd(8) 的配置。为此,必须在/etc/rc.conf中通过“natd_flags“指定配置文件路径。

natd_flags="-f /etc/natd.conf"

注意:

指定的文件必须包含配置选项的列表,每行一个。有关配置文件和可能的变量的详细信息,请参阅natd(8)。下面是两个示例条目,每行一个:

redirect_port tcp 192.168.0.2:6667 6667
redirect_address 192.168.0.3 128.1.1.3

30.4.5. IPFW指令

ipfw 命令是在防火墙运行时, 用于在其内部规则表中手工逐条添加或删除防火墙规则的标准工具。 这一方法的问题在于, 一旦您的关闭计算机或停机, 则所有增加或删除或修改的规则也就丢掉了。 把所有的规则都写到一个文件中, 并在启动时使用这个文件来加载规则, 或一次大批量地替换防火墙规则, 那么推荐使用这里介绍的方法。

ipfw 的另一个非常实用的功能是将所有正在运行的防火墙规则显示出来。 IPFW的记账机制会为每一个规则动态地创建计数器, 用以记录与它们匹配的包的数量。 在测试规则的过程中, 列出规则及其计数器是了解它们是否工作正常的重要手段。

按顺序列出所有正在运行的规则:

# ipfw list

列出所有正在运行的规则,并带有上次匹配规则的时间戳:

# ipfw -t list

下一个示例列出所有的记账信息、 匹配规则的包的数量, 以及规则本身。 第一列是规则的编号, 随后是发出包匹配的数量, 进入包的匹配数量, 最后是规则本身。

# ipfw -a list

除了静态规则之外,还列出动态规则:

# ipfw -d list

显示已过期的动态规则:

# ipfw -d -e list

将计数器归零:

# ipfw zero

将仅具有NUM值的规则的计数器归零 :

# ipfw zero NUM

30.4.5.1. 记录防火墙信息

即使启用了日志机制, IPFW也不会自行生成任何规则的日志。 防火墙管理员需要指定规则集中的哪些规则应该记录日志, 并在这些规则上增加 log 动作。 一般来说, 只有 deny 规则应记录日志。另外,复制 默认的 ipfw 终极 deny 规则, 并加入 log 动作来作为您的规则集的最后一条规则也是很常见的用法。 这样, 您就能看到没有匹配任何一条规则的那些数据包。

日志是一把双刃剑, 如果不谨慎地加以利用, 则可能会陷入过多的日志数据中, 并导致磁盘被日志塞满。 将磁盘填满是 DoS 攻击最为老套的手法之一。 由于 syslogd 除了会将日志写入磁盘之外, 还会输出到 root 的控制台屏幕上, 因此有过多的日志信息是很让人恼火的事情。

IPFIREWALL_VERBOSE_LIMIT=5 内核选项将限制同一个规则发到系统日志程序 syslogd(8) 的连续消息的数量。 当内核启用了这个选项时, 某一特定规则所产生的连续消息的数量将封顶为这个数字。 一般来说, 没有办法从连续 200 条一模一样的日志信息中获取更多有用的信息。 举例来说, 如果同一个规则产生了 5 次消息并被记录到 syslogd, 余下的相同的消息将被计数, 并像下面这样发给 syslogd

last message repeated 45 times

所有日志默认保存在/var/log/security,可在/etc/syslog.conf中设置日志保存位置。

30.4.5.2. 构建规则脚本

大部分有经验的 IPFW 用户会创建一个包含规则的文件,并按照与作为脚本运行规则兼容的方式对这些规则进行编码。这样做的主要好处是防火墙规则可以大规模刷新,而无需重新启动系统来激活它们。此方法在测试新规则时很方便,因为该过程可以根据需要多次执行。作为脚本,符号替换可用于将常用值替换到多个规则中。

此脚本与sh(1), csh(1), and tcsh(1) shell 语法兼容。符号替换字段前缀有一个美元符号 ($)。符号字段没有 $。填充符号字段的值必须用双引号("")括起来。

像这样启动规则文件:

############### start of example ipfw rules script #############
#
ipfw -q -f flush       # Delete all rules
# Set defaults
oif="tun0"             # out interface
odns="192.0.2.11"      # ISP's DNS server IP address
cmd="ipfw -q add "     # build rule prefix
ks="keep-state"        # just too lazy to key this each time
$cmd 00500 check-state
$cmd 00502 deny all from any to any frag
$cmd 00501 deny tcp from any to any established
$cmd 00600 allow tcp from any to any 80 out via $oif setup $ks
$cmd 00610 allow tcp from any to $odns 53 out via $oif setup $ks
$cmd 00611 allow udp from any to $odns 53 out via $oif $ks
################### End of example ipfw rules script ############

规则并不重要,重点是演示符号替换字段的填充方式。

如果上面的示例位于/etc/ipfw.rules,则可以通过以下命令重新加载规则:

# sh /etc/ipfw.rules

/etc/ipfw.rules可以位于任何位置,并且文件可以有任何名称。

通过手动运行这些命令也可以完成同样的事情:

# ipfw -q -f flush
# ipfw -q add check-state
# ipfw -q add deny all from any to any frag
# ipfw -q add deny tcp from any to any established
# ipfw -q add allow tcp from any to any 80 out via tun0 setup keep-state
# ipfw -q add allow tcp from any to 192.0.2.11 53 out via tun0 setup keep-state
# ipfw -q add 00611 allow udp from any to 192.0.2.11 53 out via tun0 keep-state

30.4.6. IPFW 内核选项

若要将 IPFW 静态编译到自定义内核中,详细方法请参阅第 8 章 配置 FreeBSD 内核。以下选项可用于自定义内核配置文件:

options    IPFIREWALL			# enables IPFW
options    IPFIREWALL_VERBOSE		# enables logging for rules with log keyword to syslogd(8)
options    IPFIREWALL_VERBOSE_LIMIT=5	# limits number of logged packets per-entry
options    IPFIREWALL_DEFAULT_TO_ACCEPT # sets default policy to pass what is not explicitly denied
options    IPFIREWALL_NAT		# enables basic in-kernel NAT support
options    LIBALIAS			# enables full in-kernel NAT support
options    IPFIREWALL_NAT64		# enables in-kernel NAT64 support
options    IPFIREWALL_NPTV6		# enables in-kernel IPv6 NPT support
options    IPFIREWALL_PMOD		# enables protocols modification module support
options    IPDIVERT			# enables NAT through natd(8)

注意:

IPFW可以加载为内核模块:默认情况下,上述选项作为模块构建,或者可以使用可调功能在运行时进行设置。

本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读 文档,如不能解决再联系 <questions@FreeBSD.org>.

关于本文档的问题请发信联系 <doc@FreeBSD.org>.