用IPIW实现BSD防火墙(下)

/ns/wz/net/data/20010909032659.htm

上面我们已经创建了一个规则集,使ipfw能够允许对发出的互联网请求进行响应,并能进行DNS名字解析。下面我们将仔细调节已经创建的规则集的性能,并通过内置的登录工具对它进行测试。

创建的规则集已经可以起作用了,因此可以在DHCP规定的时间用完之前使用互联网连接了。时间用完后,互联网连接就不能再使用了。要搞清楚是哪条规则实现互联网连接的,对DHCP的基本工作原理有一定的了解是很有必要的。

DHCP使用UDP数据包,意味着动态规则和状态表在这里是不起作用的。因此必须允许在我的计算机和ISP的DHCP服务器之间传输UDP数据包。DHCP需要二个端口:DHCP客户端使用端口68,ISP的DHCP服务器使用端口67。

为了搞明白DHCP的工作原理,我们来看一下我的计算机的DHCP“租用”文件:

more /var/db/dhclient.leases

lease {
interface "ed0";
fixed-address 24.141.119.162;
option subnet-mask 255.255.252.0;
option time-offset -18000;
option routers 24.141.116.1;
option domain-name-servers 24.226.1.90,24.226.1.20,24.2.9.34;
option host-name "my_hostname";
option domain-name "my_domainname";
option broadcast-address 255.255.255.255;
option dhcp-lease-time 604800;
option dhcp-message-type 5;
option dhcp-server-identifier 24.226.1.41;
renew 2 2001/5/15 13:12:11;
rebind 5 2001/5/18 04:12:11;
expire 6 2001/5/19 01:12:11;
}

DHCP服务器提供了一个IP地址、子网掩码、缺省的网关地址、三个DNS服务器的IP地址、我的主机名和提供服务的DHCP服务器的IP地址。由于DHCP“租用”契约是一种真正的“契约”,这意味着我必须保存好这些信息,最后三行内容与我的DHCP客户端如何重新修改“租用”契约有关。

以renew开头的这一行向我的DHCP客户端表明它何时应该结束,并更新其“租用”契约,这一时间要早于expire行中列出的时间。在2001年5月15日13时12分11秒,我的计算机将会向IP地址为24.226.1.41的DHCP服务器上的端口67发送UDP数据包,因此需要添加一条规则允许向外发送UDP数据包。如果DHCP服务器收到了我的计算机发送的UDP数据包,它应该对要求更新“租用”契约的要求作出响应,并且以UDP数据包形式将此信息发回到我的计算机上的68端口。因此,我另外还需要在规则集中添加一规则,允许ipfw对此信息作出反应。

如果不在规则集中添加这些规则,或者由于其他原因DCHP服务器没有对我的计算机发出的更新“租用”契约的要求作出响应,rebind行将在2001年5月18日4时12分11秒启动,这时,我的DCHP客户端就会开始担心“租用”期满,将会向DHCP服务器发出更多的UDP数据包,只是这次将不再向特定的DHCP服务器发送数据包,而是会向255.255.255.255发送数据包,任何服务器都可以响应发出的请求。

如果没有DHCP服务器进行响应,我的计算机的契约会在2001年5月19日1时12分11秒结束,这意味着我的DCHP客户端不能保证还可以继续使用这些租用信息。这时,会有几种情况出现。客户端将继续试图与DHCP服务器联系,向端口67发送UDP数据包。它将继续试图用ping与缺省的网关联系,检查其IP地址是否仍然有效。在最坏的情况下,我的客户端的IP地址已经无效,DHCP服务器的应答将作为广播被IP地址为255.255.255.255的机器的68端口接收。

既然已经明白了其工作原理,我们就清楚应该在规则集中添加什么样的规则了。在添加规则前,应该对规则进行仔细的检查,因为规则的顺序已经越来越重要了。规则集中的规则越多,前面的规则覆盖后面新添加的规则的可能性也就越大。设计一个好的规则集的诀窍是让你希望的数据包使用尽可能少的规则,如果添加的规则过多,尽管防火墙仍然会起作用,但这样会加重ipfw不必要的负担,因为在找出一个数据包适应的规则前它需要读取更多的规则。此外,在你希望搞清楚到底是哪一条规则使系统不能按你的意愿运行时,规则太多了会相当的麻烦。

我将以超级用户的身份运行ipfw show命令检查当前的规则:

su
Password:
ipfw show

00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 0 0 allow tcp from any to any keep-state setup
00400 0 0 allow udp from 24.226.1.90 53 to any in recv ed0
00401 0 0 allow udp from 24.226.1.20 53 to any in recv ed0
00402 0 0 allow udp from 24.2.9.34 53 to any in recv ed0
00403 0 0 allow udp from any to any out
65535 0 0 deny ip from any to any

由于我需要向外发送UDP数据包,因此需要指明DHCP端口号和DHCP服务器的IP地址,作为超级用户,我将考虑在/etc/ipfw.rules文件中添加下面的内容:

#allow DHCP
add 00500 allow udp from any 68 to 24.226.1.41 67 out via ed0
add 00501 allow udp from 24.226.1.41 67 to any 68 in via ed0

这些规则可以说是使DHCP客户端更新其“租用”契约所需要的最少的规则了,是否需要添加更多的规则会因DHCP服务器可靠性的不同而有所不同。如果DHCP服务器总是能够响应我的更新请求,我也就无需采用发送UDP广播、ping缺省的网关或者接收UDP广播这些方式了。如果DHCP服务器的可靠性不高,那就还需要添加下面的规则:

add 00502 allow udp from any 68 to 255.255.255.255 67 out via ed0
add 00503 allow udp from any 67 to 255.255.255.255 68 in via ed0

由于我使用的DHCP服务器是相当可靠的,因此不需要立即添加00502和00503这二条规则。我只是反复提醒自己,在ISP的DHCP服务器出了问题或其IP地址有变化的时候就需要考虑这二条规则了。

在保存修改之前,我将把00500和00501二条规则与其余的规则进行比较,以确保它们之间没有任何冲突和重复之处,结果00403和00500之间确实存在着部分重复:

add 00403 allow udp from any to any out
add 00500 allow udp from any 68 to 24.226.1.41 67 out via ed0

因为规则00403允许我的计算机发出任何的UDP数据包,ipfw就不会读取其他的只从端口68发送UDP数据包的规则,在这里,就需要在使用数量最少的规则还是使用把各种可能都考虑在内的数量最多的规则之间进行选择了。

规则00403是在创建允许DNS解析时添加的,如果删除了它,就需要添加三条规则才能实现向三个DNS服务器发送UDP数据包的功能。另外,如果还需要向其他的服务器发送UDP数据包,我就必须再添加规则。因此,如果不使用这样一条“通用”的规则,ipfw规则集中就会包含一些多余的规则,使系统负担不必要的负荷。

这样作也不符合使用最少数量规则的原则,但我们必须仔细审查一下“通用”规则带来的潜在后果。如果我限制系统接受UDP数据包,向外发送UDP数据包是不会有什么危险的。例如,规则00403允许我的计算机向外发送任何数据包,但规则00400、00401、0402和00501保证我的计算机只能接受我的ISP的3台DNS和一台DHCP服务器发送的UDP数据包。因此,对于我的单独运行的FreeBSD计算机而言,这个规则集还是比较合理的。

如果我在FreeBSD防火墙后面添加新的客户端机器,就需要重新考虑这个规则集。例如,微软的客户端会发送数量不等的UDP数据包通报其共享资源,让这些数据包通过防火墙发送出去,对我而言是不负责任并具有一定安全风险的。在本例中,我将使用只能发出我需要发出的UDP数据包的规则,而删除可以发出任意UDP数据包的规则。

由于我现在保护的只是一台单独的FreeBSD计算机,因此我将保留规则00403,删除规则00500,因为系统永远都不会读取到它。我将对规则进行如下的改变:

#允许DHCP 操作
add 00501 allow udp from 24.226.1.41 67 to any 68 in via ed0

保存所作的改变,并通过使用killall init命令进行测试,以超级用户身份重新登录,看看所作改变的效果。

su
Password:
ipfw show

00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 0 0 allow tcp from any to any keep-state setup
00400 8 1322 allow udp from 24.226.1.90 53 to any in recv ed0
00401 0 0 allow udp from 24.226.1.20 53 to any in recv ed0
00402 0 0 allow udp from 24.2.9.34 53 to any in recv ed0
00403 8 469 allow udp from any to any out
00501 4 1592 allow udp from 24.226.1.41 67 to any 68 in recv ed0
65535 29 8591 deny ip from any to any

我好象从IP地址为24.226.1.90的DNS服务器收到了8个UDP数据包,从IP地址为24.226.1.41的DHCP服务器收到了4个UDP数据包。现在,我们再来看看DHCP的“租用”时间问题。

more /var/db/dhclient.leases


renew 3 2001/5/16 07:46:25;
rebind 5 2001/5/18 08:50:46;
expire 6 2001/5/19 01:12:14;

在执行killall init命令时,我成功地找到了DHCP服务器并更新了其“租用”时间,因此,我的DHCP规则是比较成功的。

由于我的规则集还拒绝收发所有的ICMP数据包,下面我们再来研究一下允许ICMP数据包收发的问题。阻止收发ICMP数据包并不是一件好事,因为它会破坏Path-MTU发现并阻止Source Quench信息。另外,ICMP使用types和codes来指定真正的ICMP信息。

在创建与ICMP有关的规则时,只能指定ICMP数据包的type而不能指定它的code。我将以超级用户的身份登录,在/etc/ipfw.rules文件中添加下面的内容:

#允许接受一些ICMP types (不支持codes)
###########允许双向的path-mtu
add 00600 allow icmp from any to any icmptypes 3
add 00601 allow icmp from any to any icmptypes 4

我需要考虑是否需要ping我的网络之外的主机或运行traceroute命令,由于二者都需要,并希望收到相应的应答,但我并不希望互联网上的所有用户都可以对我运行ping 或traceroute命令,因此,我需要添加下面的规则:

###########允许我对外部的主机运行ping命令,并得到相应的应答
add 00602 allow icmp from any to any icmptypes 8 out
add 00603 allow icmp from any to any icmptypes 0 in

###########允许我运行traceroute命令
add 00604 allow icmp from any to any icmptypes 11 in

ICMP type 8是一个重复的请求,ICMP type 0是反复的应答。由于我只允许反复地发出请求并接受应答,从而我可以ping别人而别人不能ping我。

在运行traceroute命令时,就会向外发出UDP数据包,这一点在规则00403中已经得到了保证。如果希望能够获得所有应答信息,我还必须允许系统接受所有的CMP type 11数据包。

好了,我们现在保存所作的修改,并使用ipfw zero命令对ipfw计数器重新复位。然后运行killall init命令,并试运行ping和traceroute命令:

ping www.freebsd.org
PING freefall.freebsd.org (216.136.204.21): 56 data bytes
64 bytes from 216.136.204.21: icmp_seq=0 ttl=239 time=85.250 ms
64 bytes from 216.136.204.21: icmp_seq=1 ttl=239 time=88.338 ms
64 bytes from 216.136.204.21: icmp_seq=2 ttl=239 time=83.757 ms
^C
--- freefall.freebsd.org ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 83.757/85.782/88.338/1.908 ms

traceroute www.freebsd.org
traceroute to freefall.freebsd.org (216.136.204.21), 30 hops max, 40 byte packets
1 10.69.4.1 (10.69.4.1) 8.678 ms 8.739 ms 10.055 ms
2 d226-12-1.home.cgocable.net (24.226.12.1) 9.800 ms 10.642 ms 7.876 ms
3 cgowave-0-158.cgocable.net (24.226.0.158) 25.910 ms 15.288 ms 13.693 ms
4 cgowave-busy-core.cgocable.net (24.226.1.1) 26.982 ms 16.521 ms 12.376 ms
5 cgowave-0-202.cgocable.net (24.226.0.202) 14.372 ms 14.224 ms 13.728 ms
6 216.197.153.65 (216.197.153.65) 14.112 ms 13.544 ms 42.612 ms
7 c1-pos8-0.bflony1.home.net (24.7.74.29) 15.093 ms 22.387 ms 18.530 ms
8 c1-pos1-0.hrfrct1.home.net (24.7.65.253) 25.953 ms 26.703 ms 26.514 ms
9 c1-pos3-0.nycmny1.home.net (24.7.69.2) 26.279 ms 29.810 ms 38.940 ms
10 * ibr02-p1-0.jrcy01.exodus.net (24.7.70.122) 32.121 ms 38.211 ms
11 bbr02-g5-0.jrcy01.exodus.net (216.32.223.130) 34.239 ms 34.815 ms 37.106 ms
12 bbr01-p2-0.okbr01.exodus.net (216.32.132.109) 37.643 ms 36.883 ms 36.201 ms
13 216.34.183.66 (216.34.183.66) 37.624 ms 39.455 ms 40.243 ms
14 bbr01-p0-0.snva03.exodus.net (206.79.9.85) 81.494 ms 82.421 ms 83.230 ms
15 64.15.192.34 (64.15.192.34) 79.431 ms 80.981 ms 115.289 ms
16 bbr02-p4-0.sntc05.exodus.net (209.185.9.70) 81.993 ms 99.964 ms 82.169 ms
17 dcr01-g6-0.sntc05.exodus.net (64.56.192.19) 81.324 ms 81.603 ms 80.146 ms
18 g2-1.bas1-m.sc5.yahoo.com (64.56.207.146) 81.867 ms 100.628 ms 94.995 ms
19 freefall.freebsd.org (216.136.204.21) 104.100 ms 95.821 ms 85.909 ms

一切正常。现在我将以超级用户的身份来看看系统使用了哪些规则。

su
Password:
ipfw show

00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 0 0 allow tcp from any to any keep-state setup
00400 29 5847 allow udp from 24.226.1.90 53 to any in recv ed0
00401 2 163 allow udp from 24.226.1.20 53 to any in recv ed0
00402 3 397 allow udp from 24.2.9.34 53 to any in recv ed0
00403 93 4712 allow udp from any to any out
00501 0 0 allow udp from 24.226.1.41 67 to any 68 in recv ed0
00600 3 168 allow icmp from any to any icmptype 3
00601 0 0 allow icmp from any to any icmptype 4
00602 3 252 allow icmp from any to any out icmptype 8
00603 3 252 allow icmp from any to any in icmptype 0
00604 53 2968 allow icmp from any to any in icmptype 11
65535 29 8591 deny ip from any to any

我们可以发现,运行ping命令时使用了三个反复的请求数据包(规则00602)和三个反复的应答数据包(规则00603)。此外,有53个ICMP type 11数据包响应traceroute命令(规则00604),然而,由于我不能够在规则中指定具体的code,因此我不能说出为什么会接收到三个“找不到目标”的信息。

通过上述的三篇文章,我简要地介绍了如何使用FreeBSD操作系统自带的IPIW实现防火墙,希望能够起到抛砖引玉的作用,使大家充分认识FreeBSD中的网络安全机制。


来源:赛迪网