Username: Password:

Linux 2.4 Packet Filtering HOWTO 简体中文版
来源:作者:Rusty Russell 发布时间:2007-11-21 13:26:00

 $Revision: 1.3 $ $Date: 2002/06/05 13:21:56 $
简体中文:洋鬼鬼?NetSnake
感谢 网中人netmanforever@yahoo.com 提供的繁体参照

此文档描述在Linux2.4 内核中,怎样使用iptables过滤不正确的包
(译者:Packet在很多专业书籍中译为分组,此处根据大部分人的习惯,仍译为包)

1. 简介
2. 官方站点及邮件列表
3. 那么,什么是Packet Filter?
3.1 我为什么需要Packet Filter?
3.2 怎样在Linux下进行包过滤?
3.2.1 iptables
3.2.2 创建永久性规则
4. 您算老几,凭什么玩弄我的内核?
5. Rusty的真正的包过滤快速指南
6. 包是怎样穿过过滤器的
7. 使用iptables
7.1 当电脑启动后您会看到的
7.2 对单个规则的操作
7.3 过滤规格
7.3.1 指定源和目的IP地址
7.3.2 反向指定
7.3.3 协议指定
7.3.4 接口指定
7.3.5 分片指定
7.3.6 iptables扩展:新的匹配
7.3.6.1 TCP 扩展
7.3.6.1.1 TCP标志的解释
7.3.6.2 UDP 扩展
7.3.6.3 ICMP扩展
7.3.6.4 其他匹配的扩展
7.3.6.5 状态匹配
7.4 目标规格
7.4.1 用户定义链
7.4.2 iptables扩展:新目标
7.4.3 特别的内建目标
7.5 对整个链进行操作
7.5.1 创建新链
7.5.2 删除链
7.5.3 清空一个链
7.5.4 对链进行列表
7.5.5 重置(清零)计数器
7.5.6 配置原则(默认规则)
8. 使用ipchains和ipfwadm
9. NAT和包过滤的混合使用
10. iptables和ipchains之间的差别
11. 对定制包过滤器的建议
1. 简介
欢迎,亲爱的读者。
这篇文章假设您知道有关IP地址、网络地址、网络掩码、选路和DNS。假如不知道,我建议您先阅读网络概念的HowTo(Network Concepts HOWTO)。
这篇HOWTO并非一个简要的介绍(会让您发热、发毛,没有安全感),也非一个完全的原始的披露(最吃苦耐劳的人也会被搅晕,但是必定会有所斩获)。
您的网络并不安全。问题在于,必须获取快速、简洁的通讯,但又必须限于良好的、无恶意的行为,就如同在嘈杂的大戏院里,您能够高谈阔论,但是绝不能大喊:着火了!。这篇HOWTO不能解决这种问题。
(译者:任何安全都只是相对的,否则根本不会产生这种东西了)
因此,您只能决定在哪方面妥协。我想帮助您使用一些可用的工具和一些通常需要注意的漏洞,希望您将他们用在好的一面,而不是出于恶意的目的 -- 另一个同样重要的问题。
(C) 2000 Paul `Rusty’ Russell. Licenced under the GNU GPL.

2、 官方站点及邮件列表位置
这里有三个官方站点:
o Thanks to Filewatcher http://netfilter.filewatcher.org.
o Thanks to The Samba Team and SGI http://netfilter.samba.org.
o Thanks to Harald Welte http://netfilter.gnumonks.org.
您能够通过以下站点访问全部相关站点。
http://www.netfilter.org and http://www.iptables.org
以下是netfilter官方邮件列表
http://www.netfilter.org/contact.html#list.

3.那么,什么是包过滤器?
包过滤器是这样一种软件:他检查通过的每个包的头部,然后决定怎样处置他们。能够这样对待他们:丢弃(也就是说,假如这个包从未被接受,那么丢弃他),通过(也就是说,让包通过),或更复杂的(操作)。
Linux下,包过滤内建在内核中(内核模块,或内建),而且我们更有处理包的一些技巧,但是检查头部和处理包的一般性原则仍在这里。

3.1 我为何要包过滤?
控制、安全、警戒。
 
控制:
当您用您的Linux服务器把您的内部网和另一个网络(就是Internet吧)连起来,您能够决定哪些通信是允许的,哪些不允许。例如,包头部包含了包的目标地址,您能够阻碍包发送到(您)确定的几个外部网络,另一个例子,我用NetScape连接到Dilbert archives。页面上有来自doubleclick.net的广告,然后NetScape浪费了我的时间愉快的下载他们。告诉包过滤器禁止任何来自或发往doubleclick.net地址的包,问题就解决了。(当然有更好的办法,见Junkbuster)。
 
安全:
当Linux服务器是混乱的Internet和您良好的、有序的网络之间唯一的东西时, 您最好能知道哪些东西能够进入您的大门。例如,您能够允许任何(包)从您的网络 发出,但是您可能会为来自外部的著名的“Ping of Death”而焦急。另一个例子,您不希望 外人telnet到您的Linux服务器,尽管任何账户都有密码。或许您只想(像绝大多数人)成为 Internet的旁观者,而非他的服务器(也可能愿意是吧)。简单的不允许任何人接入,配置 包过滤器拒绝任何进入的包(是不错的办法)。
 
警戒:
有时,本地网络上错误配置的机器可能会向外部喷射出大量的包。最好是当(网络中)出现任何不正常现象时,让包过滤器告诉您。这样您可能能够做点什么,或您天生就很好奇。

3.2 怎样在Linux下进行包过滤?
Linux内核在其1.1系列中就有了包过滤功能。第一代,由Alan Cox 1994年移植于BSD的ipfw。这在Linux 2.0中由Jos Vos和其他人进行了加强;用户空间工具’ipfwadm’可用来控制内核过滤规则。1998年中,我在Michael Neuling的帮助下,为Linux 2.2进行了重写,推出了用户空间工具’ipchains’。最后,1999年中,基于Linux 2.4的第四代工具,’iptables’,和其他内核的改写正式推出。这就是这个iptables的HOWTO文档的所在。
译者:userspace根据台湾同胞的说法,是用来区分系统内存中的适用范围的,分为核心空间和使用者空间,不必深究)
您需要包含netfilter架构的内核。netfilter是Linux中的一个通用框架,也能够插入(plug in)其他内容(如iptables模块)。也就是说您需要2.3.15及以后版本,而且在配置内核时对CONFIG_NETFILTER回答’Y’。
iptables这个工具用来和内核交互并告诉他哪些包应该过滤。除非您是程式员或 特别好奇,否则这就是您用来控制包过滤的了。

3.2.1. iptables
iptables工具向内核的包过滤表中插入和删除规则。这就意味着无论怎样配置,启动后信息都会丢失;请参看“定制永久性规则”(Making Rules Permanent)来确定怎样确保下次启动这些规则能被恢复。
iptables是ipfwadm和ipchains的替代品。假如您是他们的使用者,请参看 “使用ipchains和ipfwadm”,怎样轻松使用iptables。

3.2.2 创建永久性规则
您当前的防火墙配置保存在内核中,所以重启后就会丢失。您能够试着用iptables-save和iptables-restore脚本来保存他们,并由一个文档恢复。

4. 您算老几,凭什么玩弄我的内核?
我是Rusty Russell。Linux IP防火墙的维护者,也是个适当的时候出现在适当的地方的coder。我写了ipchains(参见“怎样在Linux下进行包过滤?”看看实际的工作其实由哪些人完成),并希望能学到足够的东西修正这次的包过滤。
WatchGuard,一个很出色的防火墙公司,总之一堆广告,此处省略一千字……
在此,我想澄清一个误解:我不是内核专家,我了解他,是因为我的核心工作让我接触了他们:David S. Miller, Alexey Kuznetsov, Andi Kleen, Alan Cox。无论怎样,他们做了最深层的工作,轮到我时,已很安全和容易了。

5. Rusty的真正的包过滤快速指南
绝大部分人只有一个PPP连接到Internet,而且不希望有人由此进入他们的网络或防火墙:
# 插入connection-tracking模块(如国内建在内核中就无需)
# insmod ip_conntrack
# insmod ip_conntrack_ftp
 
# 对创建大量新的连接创建一个链,除非这些连接来自内部。
# iptables -N block
# iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A block -j DROP
 
# 由INPUT和FORWARD链跳往(刚刚创建的)那条链。
# iptables -A INPUT -j block
# iptables -A FORWARD -j block

6. 包是怎样穿过过滤器的
内核由’filter’表中的以下三个规则开始。这些被称为防火墙链或就叫链。这三个链分别是 INPUT、OUTPUT和FORWARD。
对于ASCII艺术迷来说,链好象这样:(注意:这和2.0和2.2内核很不同)
译者:ASCII艺术,这里指的是利用纯ASCII文本作图
                         _____
  Incoming                 /     \         Outgoing
         -->[Routing ]--->|FORWARD|------->
            [Decision]     \_____/        ^
                 |                        |
                 v                       ____
                ___                     /    \
               /   \                 |OUTPUT|
              |INPUT|                  \____/
               \___/                      ^
                 |                        |
                  ----> Local Process ----
三个圈代表上面说的三个链。当包到达图中的一个圈,那个链就检查并确定包的命运。 假如链决定DROP包,包在那里就被杀死。但是假如链决定让包ACCEPT,包就继续在图中前进。
一个链是规则的列表。每个规则都会说:’假如包头看上去像这个的话,那么就这样处理’。 假如规则和包不匹配,由链中的下一个规则处理。最后,假如再也没有要进行处理的规则了, 内核就根据链的原则(policy,有时称为默认规则)来决定应当怎样做。在一个注重安全的 系统中,原则通常是让内核丢弃这个包。
1. 当一个包进入时(就是由以太网卡),内核首先检查包的目的地。这被称作“选路”。
2. 假如他就是进入本机的,包会向图中的下方移动,到达INPUT链。假如到了这里,任何等待这个包的进程都会收到他。
3. 否则,假如内核未被允许转发,或不知道该怎样转发这个包,他会被丢弃。假如允许转发,而且包的目的地是另一个网络接口(假如您有另一个的话),那么包向我们图中的右边行进,到达FORWARD链。假如允许通过(ACCEPT),他就被送了出去。
4. 最后,服务器上运行的程式能够发送网络包。这些包马上通过OUTPUT链。假如被允(ACCEPT),那么包继续向能够到达他的目的地的网络接口发送。

7. 使用iptables
iptables有着很详尽的使用手册(man iptables),而且假如您需要某个选项更周详的介绍。看看“iptables和ipchains的差别”可能对您很有用。
使用iptables您能够做很多不同的事。开始的内建的三个链INPUT、OUTPUT和FORWARD是不能被删除的。让我们看看整个链的管理。
1. 创建一个新的链 (-N)。
2. 删除一个空链(-X)。
3.修改内建链的原则(-P)。
4. 显示链中的规则(表)(-L)。
5. 清空一个链(-F)。
6. 将链中任何规则的包和字节计数器清零(-Z)。
有几种办法操作链中的规则:
1. 向链中添加一条新规则(-A)。
2. 在链中某个位置插入一条新规则(-I)。
3. 替换某个位置的规则(-R)。
4. 删除链中某个位置的规则,或是第一个被匹配的。(-D)。

7.1. 当电脑启动后您会看到的
ptables能够作为模块,称为’iptables_filter.o,能够在第一次运行iptables时自动被装载。也能够永久性的编到内核中。
在任何iptables命令执行之前(当心:某些发布版会在初始化脚本中运行iptables),任何内建链中都没有任何规则(’INPUT’、’FORWARD’和’OUTPUT’),任何链的原则都是ACCEPT。您能够在装载iptable_filter模块时,提供 ’forward=0’选项来修改FORWARD的默认原则。

7.2. 对单个规则的操作
这是基本的包过滤:管理规则,添加(-A)和删除(-D)命令可能是最常用的。其他的(-I插入和-R替换)只是简单的扩展而已。
每个规则都有一组条件来匹配包,和假如匹配了该怎样做(target)。例如,您可能希望丢弃任何来自127.0.0.1的ICMP包。这样我们的条件就是协议必须是ICMP,而且源地址必须是127.0.0.1,我们的目标是丢弃(DROP)。127.0.0.1是个回送接口,即使您没有真正的网络连接他也会存在。您能够用ping程式生成这样的包(他简单的发送ICMP 类型8(echo request),任何愿意响应的主机都会用ICMP 类型0(echo reply)来响应)。这对于测试很有用。
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.2 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.2/0.2/0.2 ms
# iptables -A INPUT -s 127.0.0.1 -p icmp -j DROP
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
这里,第一个ping是成功的(’-c 1’告诉ping只发送一个包)
然后我们能够向’INPUT’链中添加(-A)一个规则,定制来自127.0.0.1(’-s 127.0.0.1’)的ICMP协议(’-p icmp’)包都将被丢弃(’-j DROP’)。
然后我们测试我们的规则,用第二个ping。在程式放弃等待永远不可能的响应之前,会暂停一下。
我们能够用两种办法中的任一种删除规则。首先,因为知道这是INPUT链中唯一的规则,我们用编号删除:
# iptables -D INPUT 1
删除INPUT链中的编号为1的规则
第二种办法是 -A 命令的映射,但是用-D替换-A。当您的链中规则很复杂,而您不想计算他们的编号的时候这就十分有用了。这样的话,我们能够使用:
# iptables -D INPUT -s 127.0.0.1 -p icmp -j DROP
-D的语法必须和-A(或-I或-R)相同精确。假如链中有多个相同的规则,只会删除第一个。

7.3 过滤规格
我们已看了,用’-p’指定协议,用’-s’指定源地址,但是更有其他选项我们能够用来指定包的特征。下面是个周详的手册。

7.3.1 指定源和目的IP地址
源(’-s’,’--source’或’--src’)和目的(’-d’,’--destination’或’-- dst’)IP地址能够用四种办法指定。最常用的方法是使用全名,就像’localhost’或’www.linuxhq.com’。第二种办法是指定 IP地址,如’127.0.0.1’。
第三和第四种办法允许指定一组IP地址,就像’199.95.207.0/24’或 ’199.95.207.0/255.255.255.0’。这指定了从199.95.207.0到199.95.207.255范围内的任何IP地址。 ’/’后面的数字说明哪部分IP地址是有效的。’32’或’255.255.255.255‘为默认的(匹配整个IP地址)。用’/0’来指定任何IP 地址,像这样:
# ’-s 0/0’在这里是多余的
# iptables -A INPUT -s 0/0 -j DROP
这很少用到,这和上面出现过的不指定’-s’结果完全相同。

7.3.2 反向指定
很多标记,包括’-s’(或’--source’)和’-d’(’--destination’)标记能够在前面加上’!’标志(读作’not’),来匹配任何和给出的 NOT 的地址。例如, ’-s ! localhost’匹配任何不是来自本机的包。

7.3.3 协议指定
能够用’-p’(或’--protocol’)指定协议。协议能够是数字(假如您知道IP的协议数值)或像’TCP’、’UDP’或’ICMP’这类的名称。大小写无所谓,所以’tcp’和’TCP’相同。
协议名称前可加上’!’,以反向解释他,例如’-p ! TCP’将匹配任何不是TCP的包。

7.3.4 接口指定
’-i’(或’--in-interface’)和’-o’(或’--out-interface’)选项指定匹配的接口名。接口能够是包进入的(’-i’)或送出(’-o’)的物理设备。您能够用ifconfig命令列出当前’up’的接口。(也就是说正在工作的)。
通过INPUT链的包不会有送出接口,所以在这个链中’-o’永远不会匹配。同样,通过OUTPUT链的包也没有进入接口,这个链中的’-i’也不会被匹配。
只有通过FORWARD链的包才有进入和送出两个接口。
能够指定一个当前不存在的接口。在这个接口可用之前,规则不能匹配任何东西。这对于拨号PPP连接及类似的很有用(通常是ppp0接口)。
一个特别情况,接口名后面是个’+’,那就会匹配以这个字符串开头的任何接口(无论当前是否存在)。例如,指定一个匹配任何ppp接口的规则,要用到-i ppp+选项。
接口名也能够在前面插入 ’!’,来匹配任何和指定接口不同的包,如-i ! ppp+。

7.3.5 分片指定
译者:为帮助大家理解,此处附上IP数据报的格式,摘自《Internetworking with TCP/IP》
0 4 8 16 19 24 31
版本号 首部长度 服务类型 总长度
标志符 标志 分片偏移量
寿命 协议 首部效验和
源IP地址
目的IP地址
IP选项 填充
数据
……

有时一个包太大,不可能适合任何线路。这样的话,包会被分成片,然后当作多个包发送。最终重组这些分片来重建整个包。
分片的问题是,被检查的初始片含有整个头部字段(IP+TCP,UDP和ICMP),但随后的包只有一部分头(没有附加协议字段的IP),因此,检查后面的分片的头部(就像有TCP、UDP和ICMP相同)是不可能的。
假如您在做NAT或连接追踪,那么任何分片在包过滤代码处理以前都会合并,所以您无需为分片担心。
还请注意,到filter表中的INPUT链(或任何由NF_IP_LOCAL_IN钩子程式钩入的表)的包实际上由核心IP栈片重组后到达。
否则,理解分片是怎样被过滤规则处理的就很重要了。任何过滤规则需要我们没有的信息,将被认为不匹配。这意味着(分片的)第一片像普通的包相同被处理。第二及后面的片则不会。因此,规则 -p TCP --sport www(指定源端口为’www’)永远不会匹配一个分片(的包)(除了第一片),相反的规则 -p TCP --sport ! www也不会。
无论怎样,您能够用’-f’(或’--fragment’)标记指定专门处理第二及以后的分片的规则。当然也能够指定一个规则,让他不去匹配第二及以后的分片,在’-f’前加上’!’。
通常,让第二及以后的分片通过被认为是安全的,因为假如过滤处理了第一片,那么就无法在目标主机上进行重组。但是,已知的Bug是发送分片可能会轻易的让主机崩溃。您自己看着办吧。
网络高手注意:当这类检查进行时,畸形的包(防火墙读取的ICMP代码和类型过短的TCP、UDP和ICMP包)都将被丢弃。所以TCP分片从位置8开始。(译者:什么意思?大概是指IP包中的首部字段位置)
例如,下面的规则会丢弃任何发往192.168.1.1的分片。
# iptables -A OUTPUT -f -d 192.168.1.1 -j DROP

7.3.6 iptables扩展:新的匹配
iptables是可扩展的,也就是包括内核和iptables工具都能够扩充新的特性。
下列部分扩展是标准的,其他的则是派生的。其他人能够做出扩展并发布给合适的人。
内核扩展一般位于内核模块子目录,诸如/lib/modules/2.4.0-test10/kernel/net/ipv4/netfilter。假如您使用了CONFIG_KMOD配置来编译内核,那么他们需要被装载,所以您无需手工插入。
iptables程式扩展通常是位于/usr/local/lib/iptables/下的共享库,当然也可能在/lib/iptables或/usr/lib/iptables,具体的要根据不同的发行版本来确定。
扩展有两种:新的目标,新的匹配(我们马上会谈到新的目标)。有些协议自动给出新的测试:如下所示,现有的包括TCP、UDP和ICMP。
这样,您能够在命令行中在 ’-p’选项后指定新的测试,就能够载入扩展(模块)了。当允许扩展时,能够用’-m’选项装入扩展。
在选项后面(’-p’,’-j’或’-m’)加上 ’-h’或’--help’来获取扩展的帮助。
# iptables -p tcp --help

7.3.6.1. TCP 扩展
假如指定了’-p tcp’,那么TCP扩展将自动加载,并提供下列选项(不匹配分片)。
--tcp-flags
可附加一个’!’。有两个标志字串能够通过TCP标记来过滤。第一个标志字符串是mask:您想要测验的标志列表。第二个指出哪些将要被配置。例如:
# iptables -A INPUT --protocol tcp --tcp-flags ALL SYN,ACK -j DROP
意思是任何标志都将被测试(’ALL’和’SYN, ACK,FIN,RST,URG,PSH’同义),但是只配置SYN和ACK。当然也能够用’NONE’表示无标志。
--syn
前面的’!’是可选的,是’--tcp-flags SYN, RST, ACK, SYN’的缩写
--source-port
后面能够跟一个’!’,能够是单个TCP端口,或一段端口。能够是/etc/services中的端口名或数字。端口范围格式是低端口名 : 高端口名,或(指定大于或等于给出的端口)是端口名 + :,或(指定小于或等于给出的端口)是: + 端口名。
--sport
就是 ’--source-port’。
--destination-port
--dport
和上面类似,但是是指定匹配的目的端口(范围)。
--tcp-option
能够跟一个’!’和一个数字,匹配的是TCP选项和数字相等的包。假如试图用 这个TCP选项匹配一个没有完整的TCP包头的包,那么这个包会被自动丢弃。

7.3.6.1.1. TCP标志的解释
有时只允许单向的TCP连接会很有用。例如,您可能会允许连接到外部WWW服务器,但不会允许来自那个服务器的连接。
最简单的举动可能是阻止来自那个服务器的包,可惜,TCP连接需要包双向传送(才能正常工作)。
解决办法是,只阻挡那些用来请求连接的包。这些包称为SYN包(OK,从技术上说,他们的SYN标志被配置,而没有配置RST和ACK标志,但是我们简单的称为SYN包)。通过只阻止这种包,我们就能够阻止来自那些地方的连接企图。
’--syn’标志是这样用的:只对指定了TCP协议的规则有效。例如,指定来自192.168.1.1的连接请求。
-p TCP -s 192.168.1.1 --syn
当然也能够在前面加上’!’,意即任何不是初始连接的包。

7.3.6.2 UDP 扩展
这些扩展在指定’-p udp’时自动加载。能够提供 ’--source-port’、’--sport’、’--destination-port’和’--dport’等和TCP类似的选项。

7.3.6.3 ICMP扩展
这些扩展在指定’-p icmp’时自动加载。只提供一个新的选项:
--icmp-type
能够跟’!’,icmp类型名称(如’host-unreachable’)或数值(如’3’),或数值类型/代码(如’3/3’)。用’-p icmp --help’能够列出可用的icmp类型名。

7.3.6.4 其他匹配的扩展
这些netfilter包中的其他扩展尚属于演示阶段,(假如安装了的话)能够用’-m’来启用。
mac
--mac-source
能够跟一个’!’,后面是以太网地址,用冒号分隔的16近制表示,如`--mac-source 00:60:08:91:CC:B7’。
limit
此模块必须明确指定’-m limit’或’--match limit’。用来限制匹配的速率。就像抑制记录信息。只会匹配给定的数字/每秒(默认是每小时3个匹配,和5个触发)。能够有两个参数:
--limit
后面跟数字:指定每秒钟允许的匹配最大平均数。这个数字能够指定 明确的单位,使用’/second’、`/minute’、`/hour’ 或 `/day’,或 只写一部分(如’5/second’和’5/s’相同)。
--limit-burst
后面跟一个数字,指明在上面的limit起作用前最大的触发值。
这个匹配(项)通常和LOG目标结合起来使用,以对速率限制进行记录。 为了理解他是怎样工作的,我们来看看下面这条规则,他使用默认限制参数 记录包。
# iptables -A FORWARD -m limit -j LOG
当这条规则第一次启用时,包开始被记录。实际上,由于默认触发是5,前五个包会被记录。然后,每隔20分钟再记录一次包,无论这期间有多少包到达。而且,每个不匹配包的20分钟间隔里,会恢复一个触发(值)。假如100分钟都没有包到达这个规则,那么任何触发都会恢复,回到起点。
提示:您现在不能以大于59小时的时间来创建这种规则,所以假如您配置一个平均率为一天,那么您的触发率必须小于3。
您也能够将此模块用于避免使用快速响应速率的各类拒绝服务攻击(DoS,Denial of Server)。
(译者:以下是较著名的攻击)
Syn-flood protection:
# iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT
 
Furtive port scanner:
# iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT
 
Ping of death:
# iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
这个模块工作原理类似于“节流阀”,以下是图示。

                 rate (pkt/s)
                       ^        .---.
                       |       / DoS \
                       |      /       \
          Edge of DoS -|.....:.........\....................... DoS的边界 = 
           = (limit *  |    /:          \
          limit-burst) |   / :           \         .-.
                       |  /  :            \       /   \
                       | /   :             \     /     \
          End of DoS  -|/....:..............:.../.......\..../.  DoS结束
           = limit     |     :              :`-’         `--’
          -------------+-----+--------------+------------------> time (s)
             LOGIC =>  Match | Didn’t Match |    Match

我们匹配由五个包触发的每秒一个包,但是每秒钟第四个包才开始进入(这个规则),进行三秒钟,然后重新开始。
                  <--Flood 1-->           <---Flood 2--->

          Total  ^                   Line  __--      YNNN
          Packets|               Rate  __--      YNNN
                 |            mum  __--      YNNN
              10 |        Maxi __--         Y
                 |         __--            Y
                 |     __--               Y
                 | __--    YNNN
                 |-    YNNN
               5 |    Y
                 |   Y                                Key:  Y -> Matched Rule
                 |  Y                                       N -> Didn’t Match Rule
                 | Y
                 |Y
               0 +-------------------------------------------------->  Time (seconds)
                  0   1   2   3   4   5   6   7   8   9  10  11  12

您能够看见,前五个包是允许超过一个包/每秒(这个速率)的,然后就开始限制。 假如有一个暂停,那么另一个触发也是允许的,但不能超过规则配置的最大速率。
owner
--uid-owner userid
根据给出的有效的(数值)user id来匹配包的创建进程。
--gid-owner groupid
根据给出的有效的(数值)group id 来匹配包的创建进程。
--pid-owner processid
根据给出的process id 来匹配包的创建进程。
--sid-owner sessionid
根据给出的 session group 来匹配包的创建进程。
unclean
这是试验性模块,必须明确指定’-m unclean’或’--match unclean’。 他对包进行各种随机判断。此模块还未通过审核,所以不要用在安全设施上。 (可能造成更糟糕的结果,他自己可能更有Bug)。没有提供选项。

7.3.6.5 状态匹配
最有用的匹配标准是’state’扩展。他负责解释’ip_conntrack’模块的connection-tracking分析。 这是推荐使用的(好东东)。
通过指定’-m state’来允许附加的’--state’选项,匹配用逗号分割的状态列表(’!’标志表明不符合那些状态(的状态))。
NEW
由新连接创建的包
ESTABLISHED
属于已存在连接的包(也就是说,响应的包)
RELATED
和一个已存在连接有关,但不是他的一部分的包。如ICMP错误,或(已加载FTP模块)一个建立FTP数据连接的包。
INVALID
由于以下原因而不能被识别的包:包括内存不足和不是相应当前任何连接的ICMP错误。通常这些包会被丢弃。
这个强大的匹配扩展的一个例子:
# iptables -A FORWARD -i ppp0 -m state ! --state NEW -j DROP

7.4 目标规格
现在,我们知道了怎样对包进行测试,但是我们还需要告诉那些匹配的包应该怎样做。这被称作规则的目标。
有两个很简单的内建目标:DROP和ACCEPT。我们已看过了。假如包匹配的规则,其目标是这二者中的一个,那么不再考虑更多的规则了:包的命运已决定。
除此之外有两种目标:扩展的和用户定义的链。

7.4.1 用户定义链
iptables一个强大的特点是由ipchains继承来的能够让用户创建新的链,附加在三个内建的链上(INPUT、 FORWARD和OUTPUT)。按照惯例,用户定义链使用小写以区分他们。(我们会在“Operations on an Entire Chains”中描述怎样创建新的用户定义链)。
当包匹配的链的目标是个用户定义链时,包就转移到用户定义链中的规则。假如 没有决定包的命运,那么包在(用户定义链)中的移动就结束了,并回到当前链的下一个规则。
搞搞ASCII艺术吧。考虑两个(笨蛋)链:INPUT(内建的)和test(用户定义的)。
                `INPUT’                         `test’
               ----------------------------    ----------------------------
               | Rule1: -p ICMP -j DROP   |    | Rule1: -s 192.168.1.1    |
               |--------------------------|    |--------------------------|
               | Rule2: -p TCP -j test    |    | Rule2: -d 192.168.1.1    |
               |--------------------------|    ----------------------------
               | Rule3: -p UDP -j DROP    |
               ----------------------------
考虑一个由192.168.1.1到1.2.3.4的TCP包。他进入INPUT链,由Rule1检查 - 不匹配。 Rule2匹配,那么他的目标就是test,所以下一个检查由test开始。test中的第一个规则 Rule1是匹配的,但是没有指定目标,所以由第二个规则Rule2检查。结果是不匹配,而我们 到达了链的尾部。于是回到INPUT链,因为刚刚被Rule2检查,所以现在由Rule3来检查,仍然 不匹配。
所以这个包的路线是:
                                       v    __________________________
                `INPUT’                |   /    `test’                v
               ------------------------|--/    -----------------------|----
               | Rule1                 | /|    | Rule1                |   |
               |-----------------------|/-|    |----------------------|---|
               | Rule2                 /  |    | Rule2                |   |
               |--------------------------|    -----------------------v----
               | Rule3                 /--+___________________________/
               ------------------------|---
                                       v
用户定义链能够跳转到另一个用户定义链(但是不能循环:假如发现循环,包就会被丢弃)。

7.4.2 iptables扩展:新目标
其他类型的扩展是目标。目标扩展由内核模块组成,而且iptables的一个可选扩展提供了新的命令行选项。有几个扩展是包含在默认netfilter发布中的。
LOG
--log-level
跟一个级别名称或数字。合适的名字是(忽略大小写)’debug’、’info’、’notice’、’warning’、 ’err’、’crit’、’alert’和’emerg’,相当于数字7到0。请参考syslog.conf的手册获取这些级别的说明。默认是 ’warning’。
--log-prefix
跟一个最多29个字符的字符串,他被写入到log信息的开始处,这样能够区分出来。
这个模块最有用的就是跟在limit match后面,这样您就不会被您的log淹没了。
REJECT
此模块和’DROP’效果相同,除了会发送一个’port unreachable’的ICMP错误报文。注意假如属于以下情况,ICMP错误报文不会发送:
o 包一开始就是ICMP错误报文,或是未知的ICMP类型。
o 包被作为无头的分片过滤了。
o 我们已向那里发送了太多的ICMP错误报文(参见/proc/sys/net/ipv4/icmp ratelimit)。

7.4.3 特别的内建目标
有两个特别的内建目标:RETURN和QUEUE。
RETURN如同到达这个链的尾部:假如是内建的链的规则,那么这个链的默认规则将被执行。假如是用户定义链,当跳至这个链中的这条规则(包含RETURN)时,回到前面的链继续匹配。
QUEUE是个特别的目标,会为用户空间进程队列这个包。要这样使用,需要两个部件:
o 一个"queue handler",处理用户空间和内核之间的机制。
o 和一个用户空间用来接收的应用程式,可能是操作,连同对包进行裁决。
IPv4 iptables的标准queue handler是 ip_queue 模块,跟随内核发布并标记为实验中。
下面是个怎样用iptables为用户空间进程队列包的快速例子:
# modprobe iptable_filter
# modprobe ip_queue
# iptables -A OUTPUT -p icmp -j QUEUE
在这个例子中,本地生成的送出ICMP包(如由ping产生)到达ip_queue模块,然后包被试图送往用户空间应用。假如没有用户空间应用在(那儿)等着,包就被丢弃了。
要写一个用户空间应用,需要libipq API。和iptables一起发布。在CVS的testsuite tools(如redirect.c)中能够找到相关例子。
能够通过这里检查ip_queue的状态:
/proc/net/ip_queue
队列的最大长度(也就是不包含返回包的送往用户空间包的数量)能够通过这里控制:
/proc/sys/net/ipv4/ip_queue_maxlen
默认队列长度是1024。一旦达到这个长度,新的包就会被丢弃,直到队列长度小于这个值。好的协议如TCP,会对丢弃的包作出拥挤的解释,而且在队列满了后会很理想的将他挡回。无论怎样,假如默认值太小的话,最好是多实验以决定队列的最大长度。

7.5 对整个链进行操作
iptables一个很有用的特性是能够将链中相关的规则成组。您能够随意给链取名,但是我建议使用小写字母以避免和内建的链和目标产生冲突。链的名称最长为31个字母。

7.5.1 创建新链
让我们创建一个新链。因为我是个充满想象的家伙,我叫他test。使用’-N’或’--new-chain’选项:
# iptables -N test
如此简单,现在您能够像上面说的那样放入规则了。

7.5.2 删除链
删除一个链同样简单,使用 ’-X’或’--delete-chain’选项。为什么是’-X’?嗯,因为任何合适的字母都已被使用了。
# iptables -X test
有几个删除链的限制:他们必须是空的(见下面的"Flushing a Chain")而且他们不能是任何规则的目标。您也不能删除任何一个内建的链。
假如您不指定链名的话,任何能够被删除的用户定义链都将被删除。

7.5.3 清空一个链
这是清除一个链中任何规则的简单方法,使用’-F’ 或 ’--flush’命令。
# iptables -F FORWARD
假如不指定链的话,任何链都将被清空。

7.5.4 对链进行列表
用’-L’或’--list’命令,您能够列出一个链中的任何规则。
用户定义链中的’refcnt’是有多少链的规则指向了他。这个值必须为0,然后才能够删除这个链。
假如链名被忽略,任何链都将被列出,即便是空的。
’-L’能够有三个选项。’-n’(数字)选项对于阻止iptables试图查找IP地址时很有用,因为(假如您像大多数人相同使用DNS)假如您的DNS配置不太合适的话,可能会造成长时间的停顿,或您滤掉了DNS请求。他还会让TCP或UDP端口以数字显示。
’-v’选项显示任何规则的细节,包括饱和字节计数器,TOS比较,连同接口。否则这些值是被忽略的。
注意,报和字节计数器能够分别使用’K’、’M’或’G’来代替1000、1,000,000 和1,000,000,000。使用’-x’(扩展数字)标志来打印整个值,不管他有多大。

7.5.5 重置(清零)计数器
能够重置计数器很有用。能够用’-Z’或’--zero’来完成。
考虑下面的:
# iptables -L FORWARD
# iptables -Z FORWARD
在上述例子中,有些包在’-L’和’-Z’命令之间通过。因此,您能够把’-L’和’-Z’一起使用,读取时就清空计数器。

7.5.6 配置原则(默认规则)
我们在前面讨论包是怎样通过链的时候,已解释了当包到达内建链的尾部时会发生什么。这时,链的原则就决定包的命运。只有内建的链(INPUT、OUTPUT和FORWARD)有原则,因为假如包到达用户定义链的尾部会返回到前面的链。
原则能够是ACCEPT或DROP,例如:
# iptables -P FORWARD DROP

8. 使用ipchains和ipfwadm
netflter发布中有ipchains.o和ipfwadm.o模块。把其中一个加载到您的内核(注意:他们和ip_tables.o不兼容)。然后您就能够像以前那样使用ipchains和ipfwadm了。
这在一段时间内仍然被支持。我认为合理的计算方式是 2*(替代发布 - 初始的稳定版本),超过了这个时间,就应当使用替代的稳定版本了。这意味着在Linux 2.6或2.8中对他们的支持很可能被放弃。

9. NAT和包过滤的混合使用
想要做网络地址转换(参见NAT HowTo)和包过滤的已很常见。好消息是他们能够混合起来使用的,而且工作得很好。
您能够完全忽略您的NAT,来定义您的包过滤。包过滤看见的包的源及目标是“真正”的源和目标。例如,假如您将任何发往 1.2.3.4 80端口的包DNAT到10.1.1.1的8080端口。包过滤器看见的是包发往10.1.1.1的8080端口(真正的目的地),而非1.2.3.4 的80端口。同样,您能够忽略伪装:看到的是包的真实外部IP地址(如10.1.1.1),而响应的则返回到那里。
您能够使用’state’匹配扩展,使包过滤器无需做任何额外的工作,因为无论怎样,NAT都会需要连接跟踪。扩展NAT HowTo中简单的伪装例子,以禁止任何来自ppp0接口的新的连接,您能够这样:
#对送至ppp0的包进行伪装
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# 禁止由ppp0进入的新的或不合适的包
iptables -A INPUT -i ppp0 -m state --state NEW,INVALID -j DROP
iptables -A FORWARD -i ppp0 -m state --state NEW,INVALID -j DROP
# 开启IP转发
echo 1 > /proc/sys/net/ipv4/ip_forward

10. iptables和ipchains之间的差别
o 首先,内建链的名称从小写改成了大写,因为现在的INPUT和OUTPUT链只获取指向本地和本地生成的包。他们用来检查任何进入和发送的包。
o ’-i’标志现在表示进入接口的意思,而且只适用于INPUT和FORWORD链。FORWORD或OUTPUT链中的规则应该将’-i’改为’-o’。
o TCP和UDP端口现在必须用--source-port或--sport(或--destination-port/--dport)拼写,而且必须放在’-p tcp’或’-p udp’选项之后,因为TCP或UDP扩展是分别加载的。
o TCP -y 标志现在是 --syn,而且必须在’-p tcp’之后。
o DENY目标现在是DROP.
o 对单个链,能够在列出其工作同时清零。
o 清空内建链同时清除了原则计数器。
o 列出链给出的是个计数器的微型的快照。
o REJECT和LOG现在是扩展目标,意思是他们是单独的内核模块。
o 链的名称最多能够是31个字符。
o MASQ现在是MASQUERADE而且使用不同的语法。REDRIRECT,在保留相同的名字时,也经历了语法的改变。参见NAT-HOWTO以获取配置他们的更多信息。
o -o选项不再用于将包传递给用户空间设备了(见上面的-i)。现在通过 QUEUE目标传递到用户空间。
o 很可能更有一些我也忘了。

11. 对定制包过滤器的建议
在电脑安全领域中,最明智的办法是阻挡任何东西,然后对需要的开启。这通常称为“凡是没有明确允许的都是禁止的”。我建议这样做假如安全是您最关心的。
不要运行任何您无需的服务,即使您认为您已阻碍了对他们的访问。
假如您创建专用防火墙,开始时不运行任何东西,并阻止任何包,然后添加服务并让需要的包通过。
我强调安全:结合tcp-wrappers(对于包过滤器本身的连接),代理(通过包过滤器的连接),路由验证和包过滤。路由验证是假如包来自未预期的接口那么将被删除:例如,假如您的内部网络地址是10.1.1.0/24,而一个包的源地址是您的外部接口,那么他将被丢弃。对一个接口如ppp0来说能够这样:
# echo 1 > /proc/sys/net/ipv4/conf/ppp0/rp_filter
或对任何已有的或将有的接口:
# for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
# echo 1 > $f
# done
Debian在可能的范围了将这些设为默认。假如您使用非对称路由(如您期望包来自一个其他的方向),您可能需要在这些接口上禁止这一过滤。
记录对于当工作不正常时配置防火墙很有用,但是在一个作为产品的防火墙上,总是应当将他和’limit’匹配结合,以防止有人充斥您的记录。
我极力推荐对安全系统使用连接追踪:他虽然会造成负担,因为任何连接都被追踪。但是对于控制对您的网络的访问很有用。假如您的内核没有自动加载而且没有内建,您需要加载’ip_conntrack.o’这个模块。假如想要精确追踪复杂的协议,您需要加载合适的相关模块(如 ’ip_conntrack_ftp.o’)。
# iptables -N no-conns-from-ppp0
# iptables -A no-conns-from-ppp0 -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A no-conns-from-ppp0 -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A no-conns-from-ppp0 -i ppp0 -m limit -j LOG --log-prefix "Bad packet from ppp0:"
# iptables -A no-conns-from-ppp0 -i ! ppp0 -m limit -j LOG --log-prefix "Bad packet not from ppp0:"
# iptables -A no-conns-from-ppp0 -j DROP
 
# iptables -A INPUT -j no-conns-from-ppp0
# iptables -A FORWARD -j no-conns-from-ppp0
建造一个好的防火墙超越了这个HOWTO的范围,但是我的建议是“一切从严”。请参见Security HOWTO获取更多信息,来测试和探索您的服务器。

喜欢本文,那就收藏到:

    Del.icio.us Google书签 Digg Live Bookmark Technorati Furl Yahoo书签 Facebook 百度搜藏 新浪ViVi 365Key网摘 天极网摘 和讯网摘 博拉网 POCO网摘 添加到饭否 QQ书签 Digbuzz我挖网
相关评论  我也要评论
还没有关于此文章的相关评论!
  • 昵称: (为空则显示guest)
  • 评论分数: ★ ★ ★★★ ★★★★ ★★★★★
  • 评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
  • 导航
    赞助商
    文章类别
    订阅