摘要:本文介绍linux2.4.x内核中的防火墙工具–iptables的原理与配置,同时还给出了实际运用的例子,在文章的最后归纳了iptables与ipchains的区别。
一、 概述
从1.1内核开始,linux就已经具有包过虑功能了,在2.0的内核中我们采用ipfwadm来操作内核包过虑规则。之后在2.2内核中,采用了大家并不陌生的ipchains来控制内核包过虑规则。现在最新linux内核版本是2.4.1,在2.4内核中我们不再使用ipchains,而是采用一个全新的内核包过虑管理工具–iptables。 这个全新的内核包过虑工具将使用户更易于理解其工作原理,更容易被使用,当然也将具有更为强大的功能。
我们说过iptables只是一个管理内核包过虑的工具,iptables 可以加入、插入或删除核心包过滤表格(链)中的规则。实际上真正来执行这些过虑规则的是netfilter(linux 核心中一个通用架构)及其相关模块(如iptables模块和nat模块),下面我们一起来看看netfilter的工作原理。
二、 原理
netfilter是linux 核心中一个通用架构,它提供了一系列的”表”(tables),每个表由若干”链”(chains)组成,而每条链中可以有一条或数条规则(rule)组成。我们可以这样来理解,netfilter是表的容器,表是链的容器,而链又是规则的容器(如图一所示)。
系统缺省的表为”filter”,该表中包含了input、forward和output 3个链。每一条链中可以有一条或数条规则,每一条规则都是这样定义的“如果数据包头符合这样的条件,就这样处理这个数据包”。当一个数据包到达一个链时,系统就会从第一条规则开始检查,看是否符合该规则所定义的条件: 如果满足,系统将根据该条规则所定义的方法处理该数据包;如果不满足则继续检查下一条规则。最后,如果该数据包不符合该链中任一条规则的话,系统就会根据该链预先定义的策略(policy)来处理该数据包。
数据包在filter表中的流程如图二所示。有数据包进入系统时,系统首先根据路由表决定将数据包发给哪一条链,则可能有三种情况:
1. 如果数据包的目的地址是本机,则系统将数据包送往input链,如果通过规则检查,则该包被发给相应的本地进程处理;如果没通过规则检查,系统就会将这个包丢掉;
2. 如果数据包的目的地址不是本机,也就是说,这个包将被转发,则系统将数据包送往forward链,如果通过规则检查,则该包被发给相应的本地进程处理;如果没通过规则检查,系统就会将这个包丢掉;
3. 如果数据包是由本地系统进程产生的,则系统将其送往output链,如果通过规则检查,则该包被发给相应的本地进程处理;如果没通过规则检查,系统就会将这个包丢掉。
从以上我们可以看出,netfilter比起以前的ipfwadm和ipchains思路上清晰了好多,也好理解了好多,这对于原先对ipfwadm和ipchains总是感到一头雾水的用户来说无疑是一个福音。
三、 准备工作
1. 系统需求
netfilter要求内核版本不低于2.3.5,在编译新内核时,要求选择和netfilter相关的项目。这些项目通常都是位于“networking options”子项下。以2.4.0内核为例,我们应该选中的项目有:
[*] kernel/user netlink socket
[ ] routing messages
<*> netlink device emulation
[*] network packet filtering (replaces ipchains)
…….
然后,在“ip: netfilter configuration —->”选中:
connection tracking (required for masq/nat)
ftp protocol support
ip tables support (required for filtering/masq/nat)
limit match support
mac address match support
netfilter mark match support
multiple port match support
tos match support
connection state match support
packet filtering
reject target support
full nat
masquerade target support
redirect target support
packet mangling
tos target support
mark target support
log target support
ipchains (2.2-style) support
ipfwadm (2.0-style) support
其中最后两个项目可以不选,但是如果你比较怀念ipchains或者ipfwadm,你也可以将其选中,以便在2.4内核中使用ipchians或ipfwadm。但是需要注意的是,iptables是和ipchians/ipfwadm相对立的,在使用iptables的同时就不能同时使用ipchains/ipfwadm。编译成功后,这些模块文件都位于以下目录中
/lib/modules/2.4.0/kernel/net/ipv4/netfilter
编译2.4.0的新内核时还应该注意要在“processor type and features”中选择和你的cpu相对应的正确的cpu选项,否则新内核可能无法正常工作。
2. 载入模块
要使用iptables,还必须载入相关模块。可以使用以下命令载入相关模块:
#modprobe iptable_tables
modprobe命令会自动载入指定模块及其相关模块。iptables_filter模块会在运行时自动载入。
三、 语法
1. 对链的操作
建立一个新链 (-n)。
删除一个空链 (-x)。
改变一个内建链的原则 (-p)。
列出一个链中的规则 (-l)。
清除一个链中的所有规则 (-f)。
归零(zero) 一个链中所有规则的封包字节(byte) 记数器 (-z)。
2. 对规则的操作
加入(append) 一个新规则到一个链 (-a)的最后。
在链内某个位置插入(insert) 一个新规则(-i),通常是插在最前面。
在链内某个位置替换(replace) 一条规则 (-r)。
在链内某个位置删除(delete) 一条规则 (-d)。
删除(delete) 链内第一条规则 (-d)。
3. 指定源地址和目的地址
通过–source/–src/-s来指定源地址(这里的/表示或者的意思,下同),通过–destination/–dst/-s来指定目的地址。可以使用以下四中方法来指定ip地址:
a. 使用完整的域名,如“www.linuxaid.com.cn”;
b. 使用ip地址,如“192.168.1.1”;
c. 用x.x.x.x/x.x.x.x指定一个网络地址,如“192.168.1.0/255.255.255.0”;
d. 用x.x.x.x/x指定一个网络地址,如“192.168.1.0/24”这里的24表明了子网掩码的有效位数,这是 unix环境中通常使用的表示方法。
缺省的子网掩码数是32,也就是说指定192.168.1.1等效于192.168.1.1/32。
4. 指定协议
可以通过–protocol/-p选项来指定协议,比如-p tcp。
5. 指定网络接口将
可以使用–in-interface/-i或–out-interface/-o来指定网络接口。需要注意的是,对于input链来说,只可能有-i,也即只会有进入的包;通理,对于output链来说,只可能有-o,也即只会有出去的包。只有forward链既可以有-i的网络接口,也可以有-o的网络接口。我们也可以指定一个当前并不存在的网络接口,比如ppp0,这时只有拨号成功后该规则才有效。
6. 指定ip碎片
在tcp/ip通讯过程中,每一个网络接口都有一个最大传输单元(mtu),这个参数定义了可以通过的数据包的最大尺寸。如果一个数据包大于这个参数值时,系统会将其划分成更小的数个数据包(称之为ip碎片)来传输,而接收方则对这些ip碎片再进行重组以还原整个包。
但是再进行包过滤的时候,ip碎片会导致这样一个问题:当系统将大数据包划分成ip碎片传送时,第一个碎片含有完整的包头信息,但是后续的碎片只有包头的部分信息,比如源地址,目的地址。因此假如我们有这样一条规则:
iptables -a forward -p tcp -s 192.168.1.0/24 -d 192.168.2.100 –dport 80 -j accept
并且这时的forward的策略(policy)为drop时,系统只会让第一个ip碎片通过,而丢掉其余的ip碎片,因为第一个碎片含有完整的包头信息,可以满足该规则的条件,而余下的碎片因为包头信息不完整而无法满足规则定义的条件,因而无法通过。
我们可以通过–fragment/-f选项来指定第二个及其以后的ip碎片,比如以上面的例子为例,我们可以再加上这样一条规则来解决这个问题:
iptables -a forward -f -s 192.168.1.0/24 -d 192.168.2.100 -j accept
但是需要注意的是,现在已经有好多进行ip碎片攻击的实例(比如向win98 nt4/sp5,6 win2k发送大量的ip碎片进行dos攻击),因此允许ip碎片通过是有安全隐患的,对于这一点我们可以采用iptables的匹配扩展来进行限制,但是这又会影响服务质量,我们将在下面讨论这个问题。
7. 指定非
可以在某些选项前加上!来表示非指定值,比如“-s -! 192.168.1.1/32”表示除了192.168.1.1以外的ip地址,“-p -! tcp”表示除了tcp以外的协议。
8. tcp匹配扩展
通过使用–tcp-flags选项可以根据tcp包的标志位进行过滤,该选项后接两个参数:第一个参数为要检查的标志位,可以是syn,ack,fin,rst,urg,psh的组合,可以用all指定所有标志位;第二个参数是标志位值为1的标志。比如你要过滤掉所有syn标志位为1的tcp包,可以使用以下规则:
iptables -a forward -p tcp –tcp-flags all syn -j drop
选项–syn是以上的一种特殊情况,相当于“–tcp-flags syn,rst,ack syn”的简写。
9. mac匹配扩展
可以使用-m选项来扩展匹配内容。使用–match mac/-m mac匹配扩展可以用来检查ip数据包的源mac地址。只要在–mac-source后面跟上mac地址就可以了。比如:
iptables -a forward -m mac –mac-source 00:00:ba:a5:7d:12 -j drop
需要注意的是一个ip包在经过路由器转发后,其源mac地址已经变成了路由器的mac地址。
10. limit匹配扩展
limit扩展是一个非常有用的匹配扩展。使用-m nat 来指定,其后可以有两个选项:
–limit avg: 指定单位时间内允许通过的数据包的个数。单位时间可以是/second、/minute、/hour、/day或使用第一个字母,比如5/second和5/s是一样的,都是表示每秒可以通过5个数据包,缺省值是3/hour。
–limit-burst number:指定触发事件的阀值,缺省值是5。
看起来好像有点复杂,就让我们来看一个例子:
假设又如下的规则:
iptables -a input -p icmp -m limit –limit 6/m –limit-burst 5 -j accept
iptables -p input drop
然后从另一部主机上ping这部主机,就会发生如下的现象:
首先我们可以看到前四个包的回应都很正常,然后从第五个包开始,我们每10秒可以收到一个正常的回应。这是因为我们设定了单位时间(在这里是每分钟)内允许通过的数据包的个数是每分钟6个,也即每10秒钟一个;其次我们又设定了事件触发阀值为5,所以我们的前四个包都是正常的,只是从第五个包开始,限制规则开始生效,故只能每10秒收到一个正常回应。
假设我们停止ping,30秒后又开始ping,这时的现象是:
前两个包是正常的,从第三个包开始丢包,这是因为在这里我的允许一个包通过的周期是10秒,如果在一个周期内系统没有收到符合条件的包,系统的触发值就会恢复1,所以假如我们30秒内没有符合条件的包通过,系统的触发值就会恢复到3,假如5个周期内都没有符合条件的包通过,系统都触发值就会完全恢复。不知道你明白了没有,欢迎你来信讨论。
11. log目标扩展
netfilter缺省的目标(也就是一旦满足规则所定义以后系统对数据包的处理方法)有:
aceept:接收并转发数据包
dorp:丢掉数据包
目标扩展模块提供了扩展的目标。log目标提供了记录数据包的功能。该目标扩展有以下几个参数:
–log-level:指定记录信息的级别,级别有debug、info、notice、warning、err、crit、alert、emerg分别对应7到0的数字。其含义请参看syslog.conf的man手册。
–log-prefix:后接一个最长为30个字符的字符串,该字符串将出现在每一条日志的前面。
12. reject目标扩展
该目标扩展完全和dorp标准目标一样,除了向发送方返回一个“port unreachable”的icmp信息外。
还有其他一些扩展是常用的,如果你想了解可以参考packet-filtering-howto。当然,最直接获得帮助的办法是查看iptables的在线帮助,比如想得到关于mac匹配扩展的帮助可以执行“iptables -m mac -help”命令,想得到log目标扩展的帮助可以执行“iptables -j log -help”命令。
(作者:bye2000)