当前位置: > Linux服务器 > iptables >

Iptables 指南 1.1.19(8)

时间:2014-12-10 23:35来源:www.it.net.cn 作者:IT
Chapter 7. 防火墙配置实例 rc.firewall
在本章里,我们将要建立一个防火墙,并且详细地说明了如何去阅读、理解它。在这个例子中,我们使 用的是最基本的配置,对其工作方式和我们在里面做了些什么都有深入的解释。这个例子应该能在某些方面 给你提供基本的思路,比如,如何解决不同的问题(当然是网络方面的),再如,在真正把脚本应用于工作 之前应该考虑些什么,等等。对本例中的变量值做些修改就可能在实际的网络中使用,但不建议你这样做, 因为你的网络配置和我在例子中使用的情况可能不一样哦。但只要你有了这个基本的防火墙规则集,很可能 只需要少量的调整就可以把它用于实际了。
 
 
 
Note
可能有效率更高的方法来建立规则集,但这个脚本就是为易读而写的,所以每个人都能理解它, 即使没有多少BASH脚本编程的知识。
 
7.1. 关于rc.firewall
好,既然你能从头看到这儿,就说明你已经做好一切准备来检查这个脚本了。例子rc.firewall.txt(代码在附录示例脚本 的代码里)很大,但没有多少注释。我建议你先大致看看它的内容,留个印象,再来仔细地阅读本 章(要有耐心哦)。
 
7.2. rc.firewall详解
7.2.1. 参数配置
本小节要对照着rc.firewall脚本代码来看。
 
rc.firewall.txt的第一小节是配置选项,包含的都是一些至关 重要的信息,它们是随着你的网络的不同而改变的。比如,每个网络的IP地址都不一样,所有要把它放在这 儿。$INET_IP的值应该是在Internet上能使用的才可以,如果你有$INET_IP的话。如果没有,你就要看看 rc.DHCP.firewall.txt这种配置方法了,里面有很多有趣的东西。变量 $INET_IFACE应该指向连接Internet的真实设备,比如eth0、eth1、ppp0、tr0等等。
 
这个脚本里没有包含任何DHCP或PPPoE的选项,所以这两节是空白的。其他空白的部分,也是这样的原 因。之所以保留这些空白,是为了更容易区分这些结构相同而内容不同的脚本。如果你需要这些部分,可以 从其他脚本拷贝过来,或者你自己写了:)
 
Local Area Network小节包含的是LAN必须的信息,如连接到LAN的网 卡的IP、LAN所用的地址段等。
 
Localhost configuration小节里的信息在99%的情况下都不要改变,因为我们总是使用127.0.0.1作为地 址,也总是把接口命名为lo。紧随其后的是IPTables Configuration,里面只有一个变量,即$IPTABLES。它指定的是iptables程序的准确位置,如果是自己编译安装的话,一般都 是/usr/local/sbin/iptables。但更多的发行版都把程序放在另外的地方,如 /usr/sbin/iptables,等等。
 
7.2.2. 外部模块的装载
首先,我们要使用命令/sbin/depmod -a使module dependencies files保持最 新,然后,再装载脚本需要的模块。我们应该始终避免装入不需要的模块,如果可能,还要尽力避免装入无 所事事的模块,除非你确实需要它们。这样做主要是为了安全,因为每增加一个模块都要花费额外的努力以 增加新的规则(这样就容易出漏洞哦)。比如,如果你想支持LOG、REJECT和MASQUERADE target,不要把相 应的功能静态地编译进内核,我们使用以下模块来完成:
 
 
 
/sbin/insmod ipt_LOG
/sbin/insmod ipt_REJECT
/sbin/insmod ipt_MASQUERADE
    
 
 
 
 
Caution
注意,本文使用的脚本都是用类似命令装入模块,这可能会引起装载失败(有错误信息显示)。 原因是多方面的,但如果较基本的模块也失败的话,那最大的可能是哪个模块或相应的功能已被静态地编译 进内核了。进一步的信息可以看看附录常见问题与解答中的模块装载问题。
 
接下来的一行是装载ipt_owner模块,它的作用是“只允许特定的用户 创建特定的连接”。在这个例子中,我没有使用到它,但你可能会用到。比如,你可能只允许root建立FTP 和HTTP连接访问redhat.com,而其他用户都不可以。你也可以只允许你自己使用的用户名和root才能访问 Internet,这样别人会很烦的,但你的安全性在某些方面会有所提高哦,比如,把你当作发起攻击的跳板的 情况。关于ipt_owner的更多信息,可以看看章节规则是如何练成的里的Owner match 。
 
在这儿我们也可以为状态匹配安装扩展模块。状态匹配和连接跟踪的所有扩展模块的名字都是这样的: ip_conntrack_*和ip_nat_* 。连接跟踪的helper是一些特殊的模块,正是它们告诉了内核怎样恰当地跟踪 特殊的连接。没有这些helper,内核在处理特殊连接的时候,就不知道该查看些什么东西。NAT helper就是 连接跟踪helper的扩展,它会告诉内核在包里找什么、如何转换它们,这样连接才能真正工作起来。比如, FTP是一个复杂的协议,它利用包的有效数据部分来发送连接信息。如果一台需要被NAT的机子(译者注:也 就是说,机子在一个内网里)连接Internet上的FTP服务器,它就会把自己的内网IP地址放在包的数据区内 发送出去,以使FTP服务器能连接到那个地址。但私有地址不能在LAN外使用,所以FTP服务器不知道用它做 什么,连接就会断掉了。FTP NAT helper能完成这些连接中所有的地址转换工作,因此FTP服务器就知道该 往哪儿连了。同样的事情也发生在DCC的文件传输(这里指的是发送)和聊天上,为了建立连接,IP地址和 端口都需要利用IRC协议的数据区发送,而且还要做一些转换工作。没有这些helper的话,FTP和IRC只有一 部分工作是正常的,但另一部分根本就无法工作。例如,你可以通过DCC接收文件,但就是不能发送。这个 问题的原因在于DCC是如何建立连接的。当DCC想发送文件时,会告诉接收者你要发送文件,并让它知道要连 接到什么地方。如果没有helper,这个DCC连接最终会断开,因为接收者收到的是内网的地址。这样,当它 按那个地址连接时,其实就连到和它在同一内网的机子了。那为什么可以接收呢?因为发送者给你的是可在 Internet上使用的IP地址(大部分情况下,IRC服务器都有真实的IP地址)。
 
 
 
Note
如果你在通过防火墙使用mIRC DCC时遇到了问题,但和其他IRC客户沟通很正常,看看附录常见问题与解答里的 关于mIRC DCC的问题 吧。
 
在这个例子中,我们在这儿装载支持FTP和IRC协议的模块。有关连接跟踪和nat的详细信息,请查看附录 常见问题与解答。在patch-o-matic中,还有H.323 conntrack helper等其他象NAT helper的模块。但为了使用它们,你需要使用patch-o-matic提供的补丁,还需要编译 内核。详细的操作信息可以查看章节准备阶段 。
 
 
 
Note
注意,为了能对FTP和IRC协议做网络地址转换,需要装载ip_nat_ftp和ip_nat_irc。在装载NAT模 块之前,你还要载入ip_conntrack_ftp和ip_conntrack_irc模块。NAT模块和conntrack模块以相同的方式被 使用,但NAT模块使我们能对这两个协议做NAT。
 
7.2.3. proc的设置
我们可以使用下面的语句打开IP转发功能(IP forwarding):
 
echo "1" > /proc/sys/net/ipv4/ip_forward
 
 
 
Warning
注意,何时何地打开这个功能才算合适是值得好好考虑的一个问题。在本文所用的脚本中,我都 是在创建IP过滤器(在本文里就是指iptables的过滤规则)之前打开它的。这可能引起这样一种情况,就是 在一小段时间内(时间的长短随脚本的复杂程度和机子的性能高低而变化,可能只有一毫秒,也可能会长达 一分钟),防火墙可以转发任何包(译者注:因为这时防火墙的过滤规则还没有被装入)。这种情况又会导 致安全方面的问题,不怀好意的人可能会趁此通过防火墙破坏我们的网络。也就是说,我们应该在创建所有 防火墙的规则之后再打开IP转发功能,我这样做只是为了保正所有脚本的兼容性。(译者注:我们在实际应 用中一定要注意这一点,尽量不要先开IP转发功能)
 
万一你使用的是SLIP、PPP或DHCP,也就是说你是动态获取IP的,那还要用下面的命令打开ip_dynaddr:
 
echo "1" > /proc/sys/net/ipv4/ip_dynaddr
 
如果你还要打开其他的proc选项,也是用类似的方法,但有关那些选项的具体介绍以不是本文的内容, 你可以看看其他相关的文章。在附录其他资源和链接里就有一些 介绍了内核proc系统的短小精干的文章。如果你在本文中找不到想要的资料,就可以到附录其他资源和链接去看看,你会有所收获的。
 
 
 
Note
在本文所用的脚本中还包含了一个名为Non-Required proc configuration(非必需的proc设置) 的小节。当有什么工作不象你所想象的那么正常时,可以来这儿看看,它能提供给你最基本的一些信息,但 在你真正弄明白它们的含义之前不要进行改动。
 
7.2.4. 规则位置的优化
本节简要地描述了针对脚本rc.firewall.txt,我将如何选择、使用内建的链 链和自定义的链。我选择过的一些路径从这个或那个角度看可能是错误的,我会指出这些情况和问题发生在 何时何地。这里还对章节 表和链 做了简要的回顾,希望能 给你一点儿提醒,以使你能想起在实际应用中包是如何表和链的。
 
为了尽可能地少占用CPU,我们已经替换了所有不同的自定义链,与此同时,我把主要的精力放在了安全 性和易读性上。我不让TCP包去经历ICMP、UDP和TCP规则的洗礼,而是简单地匹配所有的TCP包,然后让它去 一个自定义链中旅行。这种方法并不比让它经历所有的规则开销大。下图可以解释在Netfilter中,外来的 包是如何被处理的(相对于章节表和链的深入讨论,这个图 形太粗糙了)。我希望通过上面的解释和下面的图形能让大家明白写这个脚本的目的,详细的注释在后面几 节。
 
 
 
 
 
 
 
利用这个图形,我们可以弄清楚脚本的目的。整个脚本基于这样一种假设,我们有一个局域网,一个防 火墙及一个Internet连接,且有一个静态IP地址(相对的是动态地址,它们使用的连接是DHCP、PPP、 SLIP,等等),还想把防火墙作为Internet上的一台服务器来运行某些服务。我们完全信任局域网,因此不 能阻塞任何从局域网发出的数据传输。还有一个要优先考虑的事,我们只允许那些被明确说明为可以接受的 数据通过。为了做到这一点,我们就要把缺省策略设为DROP。这样,那些没有被明确标识为允许进入的数据 就都被阻塞了。
 
在上面的假设里,我们想让局域网能够访问Internet。因为局域网是被完全信任的,所以我们应该允许 所有来自局域网的数据通过。但Internet是不被信任的,所以我们想阻塞从Internet向我们的局域网发起的 连接。根据上面的所有假设,我们来考虑考虑需要做什么、不需要做什么以及我们想做什么。
 
 
 
 
 
 
 
首先,我们解决的是局域网要能连接到Internet的问题。那我们就要对所有数据包做NAT操作,因为局域 网内的机子都没有真实的IP地址。NAT是在PREROUTING链中完成的,这也是脚本最后创建的那个规则所在的 链。这意味着我们必须要在FORWARD链中做过滤工作,否则我们就是允许所有外部的机子都能完全访问局域 网了。因为我们完全信任局域网,所以允许所有由内向外的数据通过。由于我们假设Internet上的机子都不 可以 访问局域网内的机子,所以要阻塞所有由外向内的连接,但已经建立的或相关的连接除外,因为它们只是用 来回应内网对外网的访问,而不是建立对内网的新连接。
 
 
 
 
 
 
 
由于资金有限,我们的防火墙只提供了有限的几个服务:HTTP、 FTP、SSH和IDENTD。因此,我们要在INPUT链里允许这些协议通过,还要在 OUTPUT链里允许返回的数据通过。我们除了完全信任局域网,也信任loopback和 它的IP地址,因此我们要有相应的规则来允许所有来自局域网和loopback的数据通过。但是我们不会允许一 些特 殊的包或包头通过,也不会接受Internet上某一段IP的访问。比如,网段 10.0.0.0/8是为局域网而保留的,一般来说,我们不允许来自它们的包进入,因为这样的包90%都是 用来进行欺骗的。不过,在实现这条标准之前,还要注意一个问题,就是有一些ISP在他们的网络里使用的 恰恰就是这些地址。 在附录常见问题与解答里有这个问题的进一 步说明。
 
因为我们在防火墙上运行FTP服务,而且想让包经历最少的规则,所以要把处理established和related状 态的规则放到INPUT链的顶部。基于同样的原因,我们把这些规则分到子 链中。这样,包就可以尽量少地穿越规则,从而节省时间,也可以降低网络的冗余。
 
在这个脚本里,我们依据不同的协议(如TCP、 UDP或ICMP)把包分到子链中。用 来匹配 TCP包的链叫做tcp_packets,它可以匹配所有我们允许通过的TCP端口和子协 议(如FTP、HTTP等)。我们还要建立一个名为allowed的子链,以便在真正接受“那些使用有效端口 来访问防火墙的TCP包”之前,对它们进行附加的检查。至于ICMP包,自有称作 icmp_packets的链来处理。在决定如何建立这个链时,我考虑到如果我们同意接受ICMP包的类型 和代码,就没有必要对它们做附加的检查,所以直接接受它们就行了。最后,UDP包由谁处理呢?当然就是 udp_packets了。如果包是那种允许被接收的类型,就直接放行了。
 
因为我们的网络很小,所以防火墙也要作为工作站来用。这就要求我们要允许一些特殊的协议能和它通 信,比如speak freely和ICQ。
 
 
 
 
 
 
 
现在,我们来考虑考虑OUTPUT链。因为很信任防火墙,所以我们允许几乎所有离开它的包通过,而没有阻 塞任何用户和协议。但我们也不想让人利用这台机子进行IP欺骗,因此我们只放行那些从防火墙本身的IP发 出的包。为了实现这一点,我们很可能在ACCEPT链中加入这样一条规则:如果包是由防火墙的IP发出的,就 放行,否则,它们就会被OUTPUT链的缺省策略DROP掉。
 
7.2.5. 缺省策略的设置
在开始写其他规则之前,我们先要用下面的语句建立缺省的策略:
 
 
 
iptables [-P {chain} {policy}]
 
 
 
每一条链的策略都是用来处理那些在相应的链里没被规则匹配的包。也就是说,如果有一个包没有被规 则集中的任何规则匹配,那策略就有用武之地了。
 
 
 
Caution
要谨慎地设置其他表里的链的策略,因为它们不是用来过滤包的,这就可能引起很怪异的行为发 生。
 
7.2.6. 自定义链的设置
现在,你对我们的防火墙应该已经有了一个很清晰的印象,心动了吧。心动不如行动,让我们把它变为现 实吧。这一节我们就要小心仔细地创建所有自定义链和链内的规则。
 
如前所述,我们要建立这几条自定义链:icmp_packets、tcp_packets、udp_packets 和allowed,其中allowed链是由tcp_packets链调用的。所有进入$INET_IFACE的ICMP包都会被重定向到icmp_packets链,TCP包是到 tcp_packets链,那UDP包自然就是udp_packets链了,详细的解释都在 INPUT chain里。创建自定义链的命令还记得吗?很简单哦,只要使用选项-N ,再指定链的名字即可(不要忘了,新建的链都是空的),如下:
 
 
 
iptables [-N chain]
 
 
 
在下面的几节里,我们会详尽地介绍上面创建的每一条链,以使你了解它们包含哪些规则、有什么作用。
 
7.2.6.1. bad_tcp_packets链
这条链包含的规则检查进入包(incoming packet)的包头是否不正常或有没有其他问题,并进行相应地 处理。但事实上,我们使用它只是为了过滤掉一些特殊的包:没有设置SYN位但又是NEW状态的TCP包,还有那 些设置了SYN/ACK但也被认为是NEW状态的TCP包。这条链可以用来检查所有可能的不一致的东西,比如上面的 包或者XMAS port-scans等。我们还可以为INVALID状态的包 增加一条规则的。
 
如果你想完全了解无SYN位的NEW状态(NEW not SYN),可以去附录常见 问题与解答里看看未设置SYN的NEW状态包一节,它介绍了未设 置SYN的NEW状态包通过其他规则的情况。在某些情况下可以允许这种包通过,但99%的情况是我们不想让它们 通过。因此,我们会先记录这种包,然后再扔掉它们。
 
我们拒绝SYN/ACK包以NEW状态进入的原因也是非常简单的,深入的说明在附录常见问题与解答的NEW状态的SYN/ACK包 里。基本上,我们这样做是出于对其他主机的好意,因为我们为他们预防了序列号预测攻击 (sequence number prediction)。
 
7.2.6.2. allowed链
如果包是从$INET_IFACE进入的,而且是TCP包,那它就要经过tcp_packets 链的检验。如果这个连接就是冲着被允许通过的端口来的,我们还要对它进行一些检查,以确定是否真 的要接受它。这些“最后的审判”都是在allowed链里进行的。
 
首先,我们看看这个包是否是SYN包,如果是,它很可能是新连接的第一个包,我们当然接受了。如果不 是,那就看看包是否来自某个ESTABLISHED或RELATED状态的 连接,是的话,就接受。ESTABLISHED状态的连接是那种在两个方向上都有流量存在 的连接。依据状态机制的观点,这个连接一定处于是ESTABLISHED状态的,因为我们 现在能看到这个包,说明以前肯定收到了相应的SYN包。最后一条规则将DROP所有其 他的包。当包到达最后这条规则,就几乎意味着所有连接都不会有双向的交流,也就是说,我们不会回应 SYN包。当试图用非SYN包开始新的连接时,包也会走到这条规则。不用SYN包建立新连接 没有什么实际的用处,当然,端口扫描要排除在外。就我知道的而言,现在没有什么有用的TCP/ IP程序会使用SYN包以外的包来打开一个TCP连接。因此,我们要把这样的包DROP掉,我 有99%的把握说它们是端口扫描用的。
 
7.2.6.3. 处理TCP的链
tcp_packets链指定了哪些端口可从Internet访问。但我们还要对进入的包做更多的检查,因此, 每个包都会被发送到上面提到的allowed链。
 
-A tcp_packets告诉iptables要在哪条链里增加规则,规则被放在指定链的末 尾。-p TCP指定要匹配的是TCP包,-s 0/0说明要匹 配的源地址是从网络掩码为0.0.0.0的地址0.0.0.0开始的,换句话说,就是所有的地址。这实际上是默认 值,我写出来只是尽可能使你更明白。--dport 21指定目的端口,也就是说如果包是 发往端口21的,就会被匹配。如果所有的标准都匹配了,包就要被送往allowed链。
 
TCP的21号端口也是允许访问的,也就是FTP的控制端口,它可以控制FTP连接,前面提到 过,我还允许所有RELATED状态的连接通过。这样,我们也就可以使用PASSIVE(主 动)和ACTIVE(被动)的连接了,当然,要事先装载ip_conntrack_ftp模块。如果我们不想再提供 FTP服务,就卸载ip_conntrack_ftp模块,并把$IPTABLES -A tcp_packets -p TCP -s 0/0 --dport 21 -j allowed 这一行从文件 rc.firewall.txt里删掉。
 
22号端口是SSH使用的。如果你允许外网的如何人都能通过telnet(使用23号端口)访问你的机 子,那你还是使用SSH吧,它的安全性要好很多。注意,你操作的是防火墙,把任何访问权分配给除 你自己之外的人都不是什么好主意。防火墙总是应该尽量少地暴露自己。
 
80是HTTP端口,也就是说你在防火墙上运行了网页服务。如果你不提供网页服务,就删掉这条规 则吧。
 
最后我们还提供了IDENTD服务,端口是113。这个服务对某些协议是必须的,如IRC。注意,如果 你NAT一些在内网里的主机的话,软件oidentd也值得一用,它会把 IDENTD请求中继给内网里正确的机子。
 
如果没有匹配上面任何一条规则,包就会被送回tcp_packets链的父链,也就是把它发到 tcp_packets链的那条规则所在的链。如果你想打开更多的端口,只要对tcp_packets链里的任何 一行使用“复制、粘贴大法”,再修改一下端口号即可。
 
7.2.6.4. 处理UDP的链
如果我们在INPUT链中遇到了UDP包,就把它发送到udp_packets链。在那里,我们 只处理UDP包,所以要用-p UDP来指定相应的协议。我们接受来自任何地址的 包,故有-s 0/0,这其实就是源地址选项的默认值,但为了更明确,我们还是把它写 出来了。此外,我们只接受发往特定端口的包,这些端口是我们想对Internet开放的。注意,我们不需要依 据发送端的源端口来决定是否打开某个端口,这个工作是由状态机制完成的。如果我们想运行某个使用 UDP端口的服务(如DNS),只要开放相应的端口,其他的端口不需要打开。那些处于 ESTABLISHED状态、正在进入防火墙的包在到达包含--state ESTABLISHED,RELATED的规则(这是 INPUT链里那些“处理来自Internet的包的规则”中的第一条规则)之后就会被接受了。
 
我们不接受外来的以53号端口为目的的UDP包,也就是说,我们不想接受外来的DNS查询。 其实,规则已经写好了,我只是把它给注释掉了。如果你想把防火墙作为一台允许Internet访问的DNS 服务器,那就把注释符号去掉。
 
就我个人而言,我会打开123号端口,它对应的协议是network time protocol,简称NTP 。我们可以利用这个协议与某台具有精确时间的时间服务器联系,以设置本机的时间。你们中的大部分 可能用不到此协议,所以我也把它注释掉了,虽然我已经写出了规则。
 
我打开了2074号端口,它是某些实时的多媒体应用程序使用的。比如speak freely ,你可以用这个程序通过音箱、麦克风或耳麦与其他人进行实时交谈。如果你不需要,就把这条规则注 释掉吧。
 
端口4000相应的协议是ICQ协议,由ICQ使用,世界上使用最广泛的聊天程序之一,“地球人都知 道”。Linux上至少有2-3种不同的ICQ克隆。我想不必解释为什么要开放这个端口了吧。(译者注:国产的聊 天程序,常见的是QQ(端口8000),现在又有了UC(端口3001)等。)
 
如果你正在经历日志满天飞的苦恼,这里有两个额外的规则可以使用,当然,这要看是因为什么引起的 了。我们这里的第一条规则会阻塞目的端口是135到139的广播包。大部分Microsoft使用者会用到NetBIOS 或SMB,而它们就使用这些广播包。这条规则可以阻塞所有位于外网的那些Microsoft Network产 生的广播包,我们的日志也就可以简洁一些了。第二条规则也是解决日志问题,不过问题的产生者变了,这 回是外网的DHCP查询。如果你的外网是由非交换的以太网组成的,在那里客户机可以通过DHCP 得到IP地址,也就是说,如果外网里会有很多DHCP查询广播包,那就启用这条规则吧。
 
 
 
Note
注意,我把最后这两条规则也注释掉了,因为有些人可能想看看相关的记录。如果你正经历“合法 日志过多”的痛苦,就试试丢弃那些包吧。其实,在INPUT链中,就在这两条有关日志的规则之前, 还有更多这种类型的规则。
 
7.2.6.5. 处理ICMP的链
现在,我们该决定可以接受哪些ICMP类型了。在INPUT链中,如果ICMP包是从eth0 (即本例的Internet接口)进入的,我们就要把它重定向到icmp_packets 链(前面提到过),以检查是否是可以接受的类型。目前,我只接受三种ICMP包:ICMP Echo requests,TTL equals 0 during transit和TTL equals 0 during reassembly。默认不 接受其他任何ICMP类型的原因是,几乎所有其他类型的ICMP包都是RELATED状态的,也就是说它们都会被处理 RELATED状态的规则放行。
 
 
 
Note
如果一个ICMP包是用来回应“已经存在的包或流”的,那它就是与那些流相关的,也就是说,它的 状态是RELATED。更多的信息在章节状态机制里。
 
现在来解释一下我为什么只接受上面提到的三种ICMP包。Echo Request用来请求echo reply,这个操作主 要被用来ping其他的机子,以确定那些机子是否可用。如果没有这一条规则,其他机子将不能通过ping来确 定我们是否可用。注意,有些人倾向于删掉此规则,只是因为他们不想被Internet看到。删掉这个规则将会 使任何来自Internet的、对我们防火墙的ping都无效,因为防火墙对他们完全没有回应。
 
允许超时(Time Exceeded,如TTL equals 0 during transit传输期间生存时间为0和TTL equals 0 during reassembly在数据报组装期间生存时间为0)信息进入,我们就可以追踪从本地到某台 主机的路径,或者在包的TTL为0时,我们能得到回应信息。比如,在我们追踪到某台主机的路径时,会以 TTL = 1的包开始。当它得到第一个路由时,TTL减为0,我们也会得到第一个路由返回的超时信息。然后 是TTL = 2的包,我们就会得到第二个路由器返回的超时信息。如此,直到得到我们的目的主机返回 的信息。这样,我们就可以从路径上的每一台主机得到一个回应,从而我们可以看到路径上的每一台主机, 也就可以知道路径是断在哪台机子了。
 
完整的ICMP类型列表在附录ICMP类型里。关于ICMP类型的更 多信息与用法,我建议你看看下面的文章:
 
 
 
 
 
Ralph Walden的The Internet Control Message Protocol。
 
J. Postel的RFC 792 - Internet Control Message Protocol。
 
 
 
 
 
Note
注意,我阻塞了所有我不想接受的ICMP包,这对你的网络来说可能会有问题,但在我这 里,一切工作正常。
 
7.2.7. INPUT链
我写的INPUT链大部分是使用其他链来完成这个艰难的工作的。这样做,我们就不需要从iptables 装载太多的规则(译者注:这是针对装载INPUT链的规则说的,因为这时其他规则已经装载好了),而且它在 较慢的机子上也可以工作得很好,但另一方面,这样的机子在高负载时还是会丢弃很多包(译者注:机子 慢,就是不行)。之所以能做到这一点,是因为对于大量不同的包,我们通过检查特定的细节来确定它们的 类别,再把这些包发送到相应的自定义链去处理。这样,我们可以分割规则集使之包含很少的规则,每个包 要经历的规则也就少了。从而,在过滤包时,防火墙的开销也就小多了。
 
首先,我们要检查进入的tcp包的形态是否是不正常的或我们不想要的。这个工作是这样完成的,我们把 所有的tcp包送到bad_tcp_packets链,由其中的规则进行检查,具体的描述在小节bad_tcp_packets链里。
 
然后,我们开始处理被信任的网络的数据传输。这包括所有来自“连接内网的网卡”的流量,所有来自和 发往loopback的流量(要注意,和loopback相对应的IP地址包括了所有分配给防火墙的地 址,其中也包括连接Internet的地址)。我们把处理LAN的流量的规则放在防火墙的上部,因为我们 的局域网产生的流量要远远多于Internet连接。这样,规则会更有效率,防火墙就能以较小的开销去匹配 包,从而网络阻塞的可能性也就减小了,而且也便于我们查看经过防火墙的包主要是什么类型。
 
下面的一些规则会处理来自Internet的信息,在接触这些规则之前,有一个相关的规则,我们可用它来减 少一些开销。这是一个处理状态的规则,它允许所有处于状态ESTABLISHED或RELATED且发往 Internet接口的包进入。在allowed链中有一个与此类似的规则(译者注:实在是多余,建议大家把它拿掉 吧)。顺序上,当然是INPUT链里的规则先处理包了。然而,在allowed链里保留--state ESTABLISHED,RELATED规则还是有一些原因的,比如,方便某些人想剪切此功 能,粘贴到其他地方。
 
在INPUT链里,我们会把从$INET_IFACE进入的所有TCP包发往tcp_packets链,类似地,把UDP包发往udp_packets链,把 ICMP包发往icmp_packets链。一般说来,防火墙遇到的最多的包是TCP包,其次是 UDP包,最后是ICMP包。但要注意,这只是一般情况,对你可能不适用。一样的规则因为顺序不 同,或者说逻辑不同,效率会有很大的差别。如果规则集写得不好,即使只有100条规则,而且有100mbit的 网卡,就算是Pentium III的机子也会吃不消的。所以你自己写规则集时一定要注意这一点。
 
这里有一条被注释掉了规则,万一在我们的防火墙外部有一些Microsoft网络,我们可以启用它来解除日 志过多的烦恼。Microsoft的客户机有个坏习惯,就是向地址224.0.0.0/8发送大量的多播包。因此我们要有 这条规则来阻塞那些包,以免我们的日志被它们填满。还记得吗?udp_packets链里也有两条类似的 规则。忘了的话,就到处理UDP的链看看吧。
 
在其他的包被INPUT链的策略处理之前,我们会把它们记录下来,以便查找可能的问题或bug:它 可能就是我们不想允许它进入的那种包,也可能是对我们做了什么坏事的用户,还可能是防火墙的问题,如 我们阻塞了应该被放行的包。我们要了解所有的情况,这样问题才能得以解决。我们每分钟最多记录3个包, 因为我们可不想让日志里记载的都是废话。为了容易辨别包的来源,我们还对所有的记录设置了前缀。
 
所有没被上面的规则处理的包都会被策略DROP掉。策略的设置在本章的小节缺省策略的设置里,距离我们已经很远喽。
 
7.2.8. FORWARD链
在本例中,FORWARD链包含的规则很少。首先,我们会把所有的包发往bad_tcp_packets 链。此链我们前面提到过多次,它可以被多条链调用,其实它也就是为这个目的而设计的。
 
之后就是FORWARD链的主要规则了。第一个允许所有来自$LAN_IFACE的数 据通过,没有任何限制,也就是说,我们的LAN可自由地访问Internet。第二个允许ESTABLISHED和RELATED状态的包能通过防火墙。换句话说,就是 所有对我们的内网发出的连接的回应都可以返回局域网。为了使我们的内网能访问Internet,这些规则是必 须的,因为我们在前面已经把FORWARD链的策略设为DROP了。这样设置规则也 是很聪明的,因为它在保证局域网可以访问Internet的同时阻止了Internet对局域网的访问。
 
最后我们也有一个处理日志的规则,用来记录没被上面任何规则匹配的包。这样的包很可能是形态不正常 的或者是其他问题,比如可能是黑客攻击。这个规则与INPUT链中的那个类似,只是前缀不同,这里 用的是:"IPT FORWARD packet died: "。前缀主要用来分离日志的记录,便于我们 查找包的来源和包头的一些信息。
 
7.2.9. OUTPUT链
除了我几乎没有人把防火墙还当作工作站来使用,但正因为这样,我允许几乎所有从防火墙的IP(包括 LOCALHOST_IP,$LAN_IP或$STATIC_IP )出发的数据,而阻塞其他情况。因为其他任何情况都可能被人以某种方式欺骗。最后的规则还是用来 记录那些要被策略DROP掉的包。这样,我们就可以了解它们,继而可以对产生的问题(可能是具有威胁性的 错误,或者是用来进行欺骗的包)采取行动。
 
7.2.10. PREROUTING链
顾名思义,PREROUTING链(nat表的)是在路由之前做网络地址转换工作的。然后,包再经过路 由,就会被送到filter表的INPUT或FORWARD链。我们在这里讨论这个链的唯一原因是,我们 觉得有责任再次指出你不应该在此链中做任何过滤。PREROUTING链只会匹配流的第一个包,也就是 说,这个流的所有其他的包都不会被此链检查。事实上,在这个脚本中,我们根本没有用到PREROUTING 链。如果你想对一些包做DNAT操作,例如,你把web server放在了局域网内,这里就是 你放置规则的地方。有关PREROUTING链的详细信息在章节表和 链中。
 
 
 
Caution
千万注意,PREROUTING链只能做网络地址转换,不能被用来做任何过滤,因为每个流只有 第一个包才会经过此链。
 
7.2.11. POSTROUTING链
我们最后的任务应该是构造网络地址转换,对吧?至少对我来说是的。我们在nat表的 POSTROUTING里只加入了一条规则,它会对所有从Internet接口(对我来说,这是eth0)发出的 包进行NAT操作。在所有的例子脚本里,都有一些变量,它们要给以正确的配置。选项-t指定要在那个表里插入规则,这里是nat表。命令-A说明我们要把规则添加到 POSTROUTING链末尾。-o $INET_IFACE指定要匹配所有从接口INET_IFACE出去的包,这里我们使用的是eth0。最后,我们把target设置为SNAT。这样,所有匹配此规则的包都会由SNAT target处理,之后,它们的源地 址就是Internet接口的地址了。不要忘了SNAT可是一定要有IP地址的,用--to-source 来设置哦。
 
在这个脚本中,我们选择SNAT而不用MASQUERADE是有原因 的。主要的原因是我们的防火墙有静态IP地址,使用SNAT会更快更有效。还有一个原因是我们要在这 个例子中展示它的作用以及怎样使用它。如果你没有静态的IP地址,要想实现SNAT,还是使用MASQUERADE为好,因为它简单易用,而且它可以自动获得IP地址。当然,计算机的消耗 会多一点,但如果你使用DHCP,这样做是很值得的。如果你想了解MASQUERADE target的表现,应该看看脚本rc.DHCP.firewall.txt。


(责任编辑:IT)
------分隔线----------------------------