IPFW中文手册

2008-02-13 10:36:17| 分类:ipfw|字号订阅

ipfw是FreeBSD内建的防火墙指令,我们可以用它来管理进出的网络交通。如果防火墙服务器是扮演着路由器(gateway)的角色,则进出的封包会被ipfw处理二次;而如果防火墙扮演的是桥接器(bridge)的角色,则封包只会被处理一次。这个观念关系着我们以下所要介绍的语法,有的语法并不适用于桥接器。

另外,我们在设定防火墙时有二种模式,一种模式是预设拒绝所有联机,再一条一条加入允许的联机;另一种是预设接受所有联机,加入几条拒绝的规则。如果是非常强调安全性,应该是使用预设拒绝所有联机,再一条一条加入我们允许的规则。

我们会将firewall的设定写在/etc/rc.firewall中,每一条设定都是以先入为主(firstmatch wins)的方式来呈现,也就是先符合的规则(rules)为优先。所有进出的封包都会被这些规则过滤,因此我们会尽量减少规则的数量,以加速处理的速度。

在kernel中,关于防火墙的设定有下列几条:

# 防火墙

options IPFIREWALL

# 支援NAT

options IPDIVERT

# 下面这一行是预设允许所有封包通过,如果没有这一行,

# 就必须在/etc/rc.firewall中设定封包的规则。

# 这条规则内定编号是65535,也就是所有规则的最后一条。

# 如果没有加这一条规则,内定就是拒绝所有封包,

# 只允许规则中允许的封包通过。

options IPFIREWALL_DEFAULT_TO_ACCEPT

# 这一行是让你可以在ipfw中设定要记录哪些封包

# 如果没有这一行,就算设定了要留下记录也不会有作用。

options IPFIREWALL_VERBOSE

# 这一行是限制每一条规则所要记录的封包数量

# 因为同样的规则可能有许多记录,加上这一条可以使

# 同样的记录重复数减少,以避免记录文件爆增。

options IPFIREWALL_VERBOSE_LIMIT=10

# 下面这一行是用来支援封包转向,

# 当你要使用fwd动作时必须要有这一项设定。

options IPFIREWALL_FORWARD

# 如果要使用pipe来限制频宽,必须加入下列选项以支持dummynet。

options DUMMYNET


ipfw 也支持状态维持(keep-state)的功能,就是可以让符合设定的规则以动态的方式来分配增加规则(地址或连接端口) 来让封包通过。也就是说防火墙可以记住一个外流的封包所使用的地址及连接端口,并在接下来的几分钟内允许外界响应。这种动态分配的规则有时间的限制,一段时间内会检查联机状态,并清除记录。

所有的规则都有计数器记录封包的数量、位数、记录的数量及时间等。而这些记录可以用ipfw指令来显示或清除。

在说明ipfw规则的语法之前,我们先来看这个指令的用法。ipfw可以使用参数:

指令说明

ipfw add[rule] 新增一条规则。规则(rule)的语法请参考下一节的说明。

ipfw delete [number] 删除一条编号为number的规则。

ipfw -fflush 清除所有的规则。

ipfwzero 将计数统计归零。

ipfwlist 列出现在所有规则,可以配合下列参数使用。

-a 使用list时,可以列出封包统计的数目。(相当于ipfw show)

-f 不要提出确认的询问。

-q 当新增(add)、归零(zero)、或清除(flush) 时,不要列出任何回应。当使用远程登入,以script(如sh /etc/rc.firewall)来修改防火墙规则时,内定会列出你修改的规则。但是当执行了flush之后,会立即关掉所有联机,这时候响应的讯息无法传达到终端机,而规则也将不被继续执行。此时唯一的方法就是回到该计算机前重新执行了。在修改防火墙规则时,最好在计算机前修改,以免因为一个小错误而使网络联机中断。

-t 当使用list时,列出最后一个符合的时间。

-N 在输出时尝试解析IP地址及服务的名称。

-s [field] 当列出规则时,依哪一个计数器(封包的数量、位数、记录的数量及时间)来排序。


ipfw规则:

我们在过滤封包时,可以依据下列的几个封包所包含的信息来处理该封包:

接收或传送的接口,可以使用接口名称或地址。

方向,流入或流出。

来源或目的地的IP地址,也可以加上子网掩码。

通讯协议,TCP,UDP,ICMP 等。

TCP标志

IP段落标志

IP选项

ICMP的类型

和封包相关的socket User/group ID

使用IP地址或TCP/UDP的端口号来做为规则可能蛮危险的,因为这二种都有可能被以假的信息所蒙骗(spoof)。但是这二种却也是最常被使用的方法。


下列为ipfw rules的语法:

[number] action [log] proto from src to dist[interface_spec] [option]

使用 [ ] 包起来的表示可有可无,我们一一为大家说明它们的意义:

number

number是一个数字,用来定义规则的顺序,因为规则是以先入为主的方式处理,如果你将规则设定放在一个档案中(如/etc/rc.firewall),规则会依每一行排列的顺序自动分配编号。你也可以在规则中加上编号,这样就不需要按顺序排列了。如果是在命令列中使用ipfw指令来新增规则的话,也要指定编号,这样才能让规则依我们的喜好排列,否则就会以指令的先后顺序来排。这个编号不要重复,否则结果可能不是你想要的样子。

action

action表示我们这条规则所要做的事,可以用的action有下列几个:

命令意义

allow允许的规则,符合则通过。也可以使用pass,permit, accept等别名。

deny 拒绝通过的规则。

reject 拒绝通过的规则,符合规则的封包将被丢弃并传回一个host unreachable的ICMP。

count 更新所有符合规则的计数器。

check-state 检查封包是否符合动态规则,如果符合则停止比对。若没有check-state这条规则,动态规则将被第一个keep-state的规则所检查。

divert port 将符合divert sock的封包转向到指定的port。

fwd ipaddr[,port]将符合规则的封包转向到ipaddr,ipaddr可以是IP地址或是hostname。如果设定的ipaddr不是直接可以到达的地址,则会依本机即有的routing table来将封包送出。如果该地址是本地地址(localaddress),则保留本地地址并将封包送原本指定的IP地址。这项设定通常用来和transparent proxy(透明代理)搭配使用。例如:

ipfw add 50000 fwd 127.0.0.1,3128 tcp from\192.168.1.0/24 to any 80

如果没有设定port,则会依来源封包的port将封包送到指定的IP。使用这项规则时,必须在kernel中设定选项options IPFIREWALL_FORWARD

pipe pipe_nr传递封包给dummynet(4) “pipe”,用以限制频宽。使用本语法必须先在核心中加入optionsDUMMYNET。请man ipfw及mandummynet。

基本语法是先将要设定频宽的规则加入:

ipfw add pipe pipe_nr ....

再设定该规则的频宽:

ipfw pipe pipe_nr config bw B delay D queue Qplr P

这里的pipe_nr指的是pipe规则编号,从1~65535;B是指频宽,可以表示为bit/s、Kbit/s、Mbit/s、Bytes/s、KBytes/s或MBytes/s。D延迟多少milliseconds(1/1000)。Qqueue size的大小(单位为packages或Bytes)。P是要随机丢弃的封包数量

例如我们要限制内部网域的计算机对外上传的最大频宽是20KBytes:

ipfw add pipe 1 ip from 192.168.0.1/24 to anyin

ipfw pipe 1 config bw 20KBytes/s

log

如果该规则有加上log这个关键词,则会将符合规则的封包记录在/var/log/security中。前提是在核心中有设定optionsIPFIREWALL_VERBOSE的选项。有时因为同样的封包太多,会使记录文件保有大量相同的记录,因此我们会在核心中再设定options IPFIREWALL_VERBOSE_LIMIT这个选项,来限制要记录多少相同的封包。

proto

proto表示protocol,即网络协议的名称,如果使用ip或all表示所有协议。可以使用的选项有ip,all,tcp,udp,icmp等。

srcdist

src是封包来源;dist是封包目的地。在这二个项目可以用的关键词有any,me或是以<address/mask>[ports]的方式明确指定地址及端口号。

若使用关键词any表示使这条规则符合所有ip地址。若使用关键词me则代表所有在本系统接口的IP地址。而使用明确指定地址的方式有下列三种:

IP地址:指定一个 IP,如168.20.33.45。

IP/bits:如 1.2.3.4/24,表示所有从1.2.3.0到1.2.3.255的IP都符合规则。

IP:mask:由IP加上子网掩码,如1.2.3.4:255.255.240.0表示从1.2.0.0到1.2.15.255都符合。

而在me, any及指定的ip之后还可以再加上连接埠编号(ports),指定port的方法可以是直接写出port,如23;或给定一个范围,如23-80;或是指定数个ports,如23,21,80以逗点隔开。或者是写出在/etc/services中所定义的名称,如ftp,在services中定义是21,因此写ftp则代表port 21。

interface-spec

interface-spec表示我们所要指定的网络接口及流入或流出的网络封包。我们可以使用下列几个关键词的结合:

关键词意义

in 只符合流入的封包。

out 只符合流出的封包。

via ifX封包一定要经过接口ifX,if为接口的代号,X为编号,如vr0。

via if*表示封包一定要经过接口ifX,if为接口的代号,而*则是任何编号,如vr*代表vr0,vr1,...。

via any表示经过任何界面的封包。

via ipno表示经过IP为ipno界面的封包。

via使接口永远都会被检查。如果用另一个关键词recv,则表示只检查接收的封包;而xmit则是送出的封包。这二个选项有时也很有用,例如要限制进出的接口不同时:

ipfw add 100 deny ip from any to any out xmited1 recv vr0

recv接口可以检查流入或流出的封包,而xmit接口只能检查流出的封包。所以在上面这里一定要用out而不能用in,只要有使用xmit就一定要使用out。另外,如果via和recv或xmit一起使用是没有效的。

有的封包可能没有接收或传送的接口:例如原本就由本机所送出的封包没有接收接口,而目的是本机的封包也没有传送接口。

options

我们再列出一些常用的option选项 ,更多选项请man ipfw:

选项名称意义

keep-state 当符合规则时,ipfw会建立一个动态规则,内定是让符合规则的来源及目的地址使用相同的协议时就让封包通过。这个规则有一定的生存期限 (lift time,由sysctl中的变量所控制),每当有新的封包符合规则时,便用重设生存期限。

bridged 只符合bridged的封包。

established只适用于TCP封包,当封包中有RST或ACKbits时就符合。

uid xxx 当使用者uid为xxx则符合该规则。例如,我们如果要限制Anonymous FTP的下载速度最大为64KB/s,则可以使用:

ipfw pipe 1 config bw 512Kbit/s

ipfw add pipe 1 tcp from me to any uid 21

上列规则第一行是先建一个编号为1的pipe,限制频宽为512 Kbit/s(也就是64 KByte/s),接着第二条是当使用者uid为21时,从本机(me)下载的tcp封包都使用编号1的pipe。因为AnonymousFTP的使用者是ftp,它的预设uid为21,所以这条规则会被套用在Anonymous FTP user上。

setup只适用于TCP封包,当封包中有SYNbits时就符合。