在重新启动机器运行新的内核之前,有一点需要注意。如果LINT文件显示出“YOU WILL LOCK YOURSELF OUT”(你将封锁自己),说明新的规则已经起作用了。在重新创建允许所需的IP数据包进入系统之前,所有的IP数据包都不能进入或传出计算机。如果想从互联网上收发电子邮件和下载资料,就需要在重新启动系统之前完成这些工作。
好了,下面我要重新启动机器加载新的内核。在启动时盯着屏幕,在NIC加载后会看到下面的信息:
Flushed all rules.
00100 allow ip from any to any via lo0
00200 deny ip from any to any to 127.0.0.0/8
Firewall rules loaded, starting divert daemons:.
Additional routing options: tcp extensions=NO ignore ICMP redirect=YES TCP keepalive=YES restrict TCP reset=YES drop SYN+FIN packets=YES.
在启动时系统会读取/etc/rc.firewall文件,该文件包含下面的内容:
############
# Flush out the list before we begin.
#
${fwcmd} -f flush
############
# 只有在极少数的情况下才需要改变这些规则
#
${fwcmd} add 100 pass all from any to any via lo0
${fwcmd} add 200 deny all from any to 127.0.0.0/8
由于规则100和规则200在启动时会用到,因此在创建规则时应该从规则300开始。在创建规则之前,我会用下面的方法分二次检查ipfw是否缺省地禁止所有的信息包出入我的计算机系统。可以通过运行ipfw show命令来进行检查:
ipfw show
ipfw: socket: Operation not permitted
似乎只有超级用户才有查看防火墙规则的权限,因此我将再次以超级用户再身份次进行检查:
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
65535 115 14092 deny ip from any to any
我可能已经发现问题出在哪了。如果DNS使用的是UDP而不是TCP,而我的规则只允许TCP协议的数据包响应我的TCP连接,域名解析就会失败。
man dnsquery
<只显示我们感兴趣的部分>
-s 使用流格式而非信息包。它使用一个带名字服务器的TCP流式连接而不是UDP,这一选项会设置解析软件选项字段的RES_USEVC位。(缺省状态下使用UDP)
现在,我们来试试这个选项:
dnsquery -s www.freebsd.org
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39772
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 5, ADDITIONAL: 5
;; www.freebsd.org, type = ANY, class = IN www.freebsd.org. 49m21s IN CNAME freefall.freebsd.org.
freebsd.org. 22m43s IN NS ns1.iafrica.com.
freebsd.org. 22m43s IN NS ns2.iafrica.com.
freebsd.org. 22m43s IN NS ns.gnome.co.uk.
freebsd.org. 22m43s IN NS ns0.freebsd.org.
freebsd.org. 22m43s IN NS ns1.root.com.
ns1.iafrica.com. 1h1m3s IN A 196.7.0.139
ns2.iafrica.com. 1h1m3s IN A 196.7.142.133
ns.gnome.co.uk. 12m37s IN A 193.243.228.142
ns0.freebsd.org. 11h9m9s IN A 216.136.204.126
ns1.root.com. 1h8m12s IN A 209.102.106.178
在向规则集中添加任何新的规则前,必须以超级用户身份重新登录。我们来看看ipfw的输出:
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 21 15144 allow tcp from any to any out keep-state setup
65535 142 10531 deny ip from any to any
## 动态规则:
00302 19 15040 (T 0, # 147) ty 0 tcp, 24.141.119.162 2932 <-> 216.136.204.21 80
下面,我将添加一些允许进行DNS名字解析的规则。由于DNS使用UDP,UDP不进行连接,我不能指定只允许对我的连接的有效的响应数据包进入系统。但是,我可以限制DNS使用的端口(端口 53)进出的数据包,选择只接受来自我的ISP的DNS服务器的IP地址发出的数据包。运行more /etc.resolv.conf命令就能发现这些IP地址。我将在/etc/ipfw.rules文件中添加下面的内容:
#允许 DNS
add 00400 allow udp from 24.226.1.90 53 to any in recv ed0
add 00401 allow udp from 24.226.1.20 53 to any in recv ed0
add 00402 allow udp from 24.2.9.34 53 to any in recv ed0
然后,通过运行killall init命令重新加载规则集,看名字解析是否已经可以成功地运行了:
lynx www.freebsd.org
Alert!. Unable to access document.
怎么回事?我已经在规则集中添加了允许使用UDP数据包的规则,怎么名字解析服务仍然不行呢?我们运行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
65535 30 2196 deny ip from any to any
## Dynamic rules:
后面跟有统计数字的唯一的规则是最后一条拒绝服务的规则,说明添加的允许UDP数据包的规则没有作用。现在我才明白,我还没有允许向外发送UDP数据包,没有UDP数据包返回来也就没有什么好奇怪的了。下面我们再往规则集中添加一行内容:
00403 allow udp from any to any out
FreeBSD的主页终于出现了。如果我以超级用户的身份运行ipfw show命令,就会得到更令人满意的输出:
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 20 15061 allow tcp from any to any keep-state setup
00400 10 1882 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 10 591 allow udp from any to any out
65535 31 2577 deny ip from any to any
## Dynamic rules:
00302 19 15017 (T 0, # 236) ty 0 tcp, 24.141.119.162 4363 <-> 216.136.204.21 80
我将以超级用户的身份运行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
在保存修改之前,我将把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
由于我现在保护的只是一台单独的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
在创建与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,因此我不能说出为什么会接收到三个“找不到目标”的信息。