3.4 有状态的icmp IPFilter像处理tcp,udp一样处理icmp状态,就像你理解的那样。ICMP主要有两种信息类型:请求和回复。 假设我们写了这样一条规则: 3.5 FIN扫描检测;关键字flags,keep frags 先回顾一下上面的4条规则 现在被我们阻止的包都被丢弃,或者记录,我们没有发送任何回应包给源主机。有时侯这不是最好的办法,因为如果这样做就等于告诉一个攻击者我们有一个包过滤器。最好是我们能够误导使攻击者相信我们没有包过滤器,并且没有提供服务可供攻击。
IP Filter Based Firewalls HOWTO
3.3 有状态的udp
udp是无状态协议,因此对它建立可靠的状态连接有很大的难度,尽管如此,ipf在这方面做得相当好。当机器A给B发送一个udp包,源端口是X,目的端口是Y,ipf将允许从机器Y到机器X源端口是Y,目的端口是X的回复包通过。这是一条短期的状态记录,仅仅是60秒。
这是一个例子,用nslookup查询www.3com.com的ip地址:
$nslookup www.3com.com
一个DNS包产生:
17:54:25.499852 20.20.20.1.2111 > 198.41.0.5.53: 51979+
这个包从20.20.20.1端口2111到192.41.0.5端口53。一条60秒的状态记录被创建。在60秒的时间内从192.41.0.5端口53到20.20.20.1端口2111的包将通过,就像你所看到的:
17:54:25.501209 198.41.0.5.53 > 20.20.20.1.2111: 51979 q: www.3com.com
回复包符合状态记录,允许通过,回复包通过之后这条状态记录被关闭,不在允许新的数据包进入,即使这个包来自同一个地方。
pass out on tun0 proto icmp from any to any icmp-type 8 keep state
允许向外发送回复请求(典型的ping),结果是类型为icmp-type 0的包回复并通过。这条状态记录是一种不完全的0/0(相比4/4)状态,它将在60秒的空闲时间后删除。这样当你为每个外出的icmp包保存状态,你将会得到每个icmp的回复。
然而,大部分icmp消息是由错误的udp(有时是tcp)包产生的,而且在3.4.X的ipfilter中错误的icmp消息(超时或端口不可达)会根据udp(有时是tcp)状态记录而通过防火墙。在旧的ipfilter中,如果你想让traceroute正常工作,你需要这样:
pass out on tun0 proto udp from any to any port 33434><33690 keep state
pass in on tun0 proto icmp from any to any icmp-type timex
而现在你只需要为udp保存状态就可以了:
pass out on tun0 proto udp from any to any port 33434><33690 keep state
block in quick on tun0 all
pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state
为了防止第三方icmp消息通过一个活动的连接进入你的防火墙,防火墙不仅对进入的icmp消息进行源地址和目的地址的检查(有时包括端口,如果可用的话),还对icmp消息中的荷载(产生icmp消息的包的一部分)进行检查。
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state
pass out quick on tun0 proto tcp from any to any keep state
block in quick all
block out quick all
这几条规则还不能令人满意,问题在于不仅允许SYN包到达23端口而且允许老的数据包通过。我们可以用关键字flags改变上面的规则:
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state
pass out quick on tun0 proto tcp from any to any flags S keep state
block in quick all
block out quick all
现在只有目的地址是20.20.20.1,目的端口23带有SYN标志的tcp包可以通过。SYN标志只存在于tcp会话的第一个数据包(称为tcp第一次握手),这也是我们所希望,这样做至少有两个好处:首先不是所有的包都可以进入防火墙并把你的状态表搞的乱七八糟。其次,FIN和XMAS扫描将会行不通,因为它们的标志位不是SYN。现在进入的数据包要么是SYN包要么是已经建立连接的数据包。如果其它的数据包进入,很可能是端口扫描或者伪造的数据包,但是也有可能是一个分片。IPF用关键字keep frags就可以处理分片。加上这个关键字,IPF将跟踪那些分片,允许我们需要的分片通过。我们重写一下规则,允许分片并记录伪装包:
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state keep frags
pass out quick on tun0 proto tcp from any to any keep state flags S keep frags
block in log quick all
block out log quick all
这几条规则将起作用,因为所有的包在block之前就已经通过了。但是无法发现SYN扫描,如果你感到不爽你可以记录所有的SYN包。
3.6 回应被阻止的数据包
当一个服务运行在unix系统上,它通常通过回复包让远程主机知道。在tcp中使通过RST包来回复。当阻止一个tcp通过时,实际上IPF返回一个RST给源主机(用关键字return-rst)。现在我们可以这样做
block return-rst in log proto tcp from any to 20.20.20.0/24 port = 23
block in log quick on tun0
pass in all
return-rst只适用于tcp,我们还想用于udp,icmp及其它协议(下面将介绍),现在远程主机将得到connection refused而不是connection timed out。
当有人给你的系统的一个udp端口发送数据包,防火墙也可能发送一条错误信息。只要你的规则是这样的:
block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111
你可以用加入return-icmp关键字的规则来代替上面的规则来发送回复
block return-icmp(port-unr) in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111
根据tcp/ip的规范,当给服务器某个端口发送一个数据包,而服务器没有服务进程在监听这个端口时将发出port-unreachable。当然你可以用其它的icmp类型,但是port-unreachable可能是最好的。这也是默认的用来回复的icmp类型
然而当你用return-icmp的时候,你将会发现也不是很安全的,因为icmp包包含了防火墙的ip地址,而不是原始数据包的目的地址。这个问题已经在ipfilter3.3以后的版本中得到解决,一个新的关键字return-icmp-as-dest已经加入。这是新的规则:
block return-icmp-as-dest(port-unr) in log on tun0 proto udp from any to 20.20.20.0/24 port = 111
另外,你要慎用回复包,只有在你很清楚你要对什么数据进行回复的时候才能使用。例如:如果你给局域网的广播地址发送return-icmp,局域网将会在短时间内被淹没。