Iptables 指南 1.1.19(中文版)(四)
时间:2005-05-23 来源:KindGeorge
转from http://iptables-tutorial.frozentux.net/cn/iptables-tutorial-cn-1.1.19.html
Chapter 7. 防火墙配置实例 rc.firewall
在本章里,我们将要建立一个防火墙,并且详细地说明了如何去阅读、理解它。在这个例子中,我们使用的是最基本的配置,对其工作方式和我们在里面做了些什么都有深入的解释。这个例子应该能在某些方面给你提供基本的思路,比如,如何解决不同的问题(当然是网络方面的),再如,在真正把脚本应用于工作之前应该考虑些什么,等等。对本例中的变量值做些修改就可能在实际的网络中使用,但不建议你这样做,因为你的网络配置和我在例子中使用的情况可能不一样哦。但只要你有了这个基本的防火墙规则集,很可能只需要少量的调整就可以把它用于实际了。
可能有效率更高的方法来建立规则集,但这个脚本就是为易读而写的,所以每个人都能理解它,即使没有多少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
注意,本文使用的脚本都是用类似命令装入模块,这可能会引起装载失败(有错误信息显示)。原因是多方面的,但如果较基本的模块也失败的话,那最大的可能是哪个模块或相应的功能已被静态地编译进内核了。进一步的信息可以看看附录常见问题与解答中的模块装载问题。 |
接下来的一行是装载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地址)。
如果你在通过防火墙使用mIRC DCC时遇到了问题,但和其他IRC客户沟通很正常,看看附录常见问题与解答里的 关于mIRC DCC的问题 吧。 |
在这个例子中,我们在这儿装载支持FTP和IRC协议的模块。有关连接跟踪和nat的详细信息,请查看附录 常见问题与解答。在patch-o-matic中,还有H.323 conntrack helper等其他象NAT helper的模块。但为了使用它们,你需要使用patch-o-matic提供的补丁,还需要编译内核。详细的操作信息可以查看章节准备阶段 。
注意,为了能对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
注意,何时何地打开这个功能才算合适是值得好好考虑的一个问题。在本文所用的脚本中,我都是在创建IP过滤器(在本文里就是指iptables的过滤规则)之前打开它的。这可能引起这样一种情况,就是在一小段时间内(时间的长短随脚本的复杂程度和机子的性能高低而变化,可能只有一毫秒,也可能会长达一分钟),防火墙可以转发任何包(译者注:因为这时防火墙的过滤规则还没有被装入)。这种情况又会导致安全方面的问题,不怀好意的人可能会趁此通过防火墙破坏我们的网络。也就是说,我们应该在创建所有防火墙的规则之后再打开IP转发功能,我这样做只是为了保正所有脚本的兼容性。(译者注:我们在实际应用中一定要注意这一点,尽量不要先开IP转发功能) |
万一你使用的是SLIP、PPP或DHCP,也就是说你是动态获取IP的,那还要用下面的命令打开ip_dynaddr:
echo "1" > /proc/sys/net/ipv4/ip_dynaddr
如果你还要打开其他的proc选项,也是用类似的方法,但有关那些选项的具体介绍以不是本文的内容,你可以看看其他相关的文章。在附录其他资源和链接里就有一些介绍了内核proc系统的短小精干的文章。如果你在本文中找不到想要的资料,就可以到附录其他资源和链接去看看,你会有所收获的。
在本文所用的脚本中还包含了一个名为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}]
每一条链的策略都是用来处理那些在相应的链里没被规则匹配的包。也就是说,如果有一个包没有被规则集中的任何规则匹配,那策略就有用武之地了。
要谨慎地设置其他表里的链的策略,因为它们不是用来过滤包的,这就可能引起很怪异的行为发生。 |
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查询广播包,那就启用这条规则吧。
注意,我把最后这两条规则也注释掉了,因为有些人可能想看看相关的记录。如果你正经历“合法日志过多”的痛苦,就试试丢弃那些包吧。其实,在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状态的规则放行。
如果一个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。
注意,我阻塞了所有我不想接受的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链的详细信息在章节表和链中。
千万注意,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。
Chapter 8. 例子简介
本章的目的是对指南提到的每个脚本都给以简单明了的说明,以及提供一个关于这些脚本的框架,描述它们提供的服务。这些脚本不是任何情况都能用的,它们可能并不符合你的意图。也就是说,为了能满足你的需要,还是要取决于你自己。在这方面,下面的内容可能会给你很大的帮助。第一小节介绍了这些脚本的结构,你会发现我们在这些脚本里使用的处理方式还是比较容易的。
8.1. rc.firewall.txt脚本的结构
本指南所有的脚本都是依据一个特定的结构来写的。理由嘛,就是这样可以使它们彼此相似,便于我们查找不同之处。本章将要对这个结构做一个很好的说明,而且还会简单地阐述这些脚本为什么会按照现在这种样子来写,以及我为什么选择一直使用这种结构。
注意,即使我选择了这种结构,你也不一定非要用它,对你来说,它可能并不是最好的。我选择它只是因为它易读,而且能很好地符合我的逻辑。 |
8.1.1. 脚本结构
这就是本指南所有脚本遵循的脚本结构。如果有不同于此的地方,可能就是我出错了,除非我特意说明为什么要打破这种结构。
-
Configuration —— 首先是一个配置选项区,里面的变量在脚本中会用到。几乎任何脚本(shell-script)的第一部分都是配置选项区。
-
Internet —— 有关Internet连接的配置。如果我们没有任何Internet连接,这一部分就可以跳过去。注意,相比我们列出来的,这一部分可能会包含更多小节,虽然我们这里只有了了几个,但足够应对我们已有的各种Internet连接了。
-
DHCP —— 如果脚本用到了DHCP,我们就要在此添加相应的配置。
-
PPPoE —— 如果想把脚本用于PPPoE连接,就要在此添加相应的配置。
-
-
LAN —— 如果防火墙后有局域网,就要使用这里的配置了。大部分情况下都会用到这儿,因为局域网几乎总是存在的。
-
DMZ —— 对非军事区(DMZ zone)的配置。大部分脚本不会用到这个设置,因为这些脚本针对的主要是一些普通的家庭网络,或小企业的网络。
-
Localhost —— 本地(local-host)的有关设置。虽然我把它们写成变量的形式,但一般不会被改变,也不应该有什么理由要改变它们。
-
iptables —— 有关iptables的设置。大部分情况下,这里只设置一个变量,用来指向iptables程序的位置。
-
Other —— 如果还有什么信息,首先应该把它们放在相应的小节里,实在没有相应的小节,就放这儿吧。
-
-
Module loading —— 脚本应该维护一个模块列表。它分为两部分,第一部分包含必需的模块,同时第二部分要包含不必要的模块的列表。
注意,这些模块可能会提高安全性,或为管理者、客户添加某些服务,还有一些模块不是必需的,但它们可能也被加入了列表。不过,在本例中,我已经注意了这个问题。
-
Required modules —— 这里装载的是必要的模块,它们可能会提高安全性或为管理者、客户增加某些服务。
-
Non-required modules —— 这里列出的是不必要的模块,所以它们都被注释掉了。如果你用到了它们提供的功能,就可以启用它们。
-
-
proc configuration —— 这儿关心的是有关proc系统的设置。如果一些选项是必须的,我们就启用它,如果不是,就把它注释掉。大部分有用的proc配置都列在这儿了,但远远不是全部的。
-
Required proc configuration —— 包含了使脚本能正常工作的所有必需的proc配置,它也可以包含一些能提高安全性或为管理者、客户增加特定服务的选项。
-
Non-required proc configuration —— 这里提到的选项不是必需的,虽然它们可能很有用。因此,我把它们都注释掉了。当然,这里并没有包括所有这样的选项。
-
-
rules set up —— 现在,应该添加规则了。我把所有的规则都明确地分配到了与表、链相应的小节里。所有自定义的规则都写在系统内建的链之前(译者注:当然要写在前面了,因为后面要调用它们哦)。另外,我是按照命令iptables -L输出的顺序来安排此脚本里表与链的出现顺序的(译者注:这样,便于我们查看哦)。
-
Filter table —— 首先是filter表,而且我们先要设置策略。
-
Set policies —— 为所有系统内建的链设置策略。通常,我会设置 DROP,对于允许使用的服务或流会在后面明确地给以ACCEPT。这样,我们就可以方便地排除所有我们不想让人们使用的端口。
-
Create user specified chains —— 在这里创建所有以后会用到的自定义链。如果没有事先建立好,后面是不能使用它们的,所以我们要尽早地建立这些链。
-
Create content in user specified chains —— 建立自定义链里使用的规则。其实你也可以在后面的某个地方写这些规则,之所以写在这儿,唯一的原因是这样做规则和链会离得近些,便于我们查看。
-
INPUT chain —— 创建INPUT链的规则。
从这里开始,我就是遵循iptables -L的输出格式来创建规则的,这样做的唯一原因就是为了便于阅读,避免混淆。
-
FORWARD chain —— 为FORWARD链创建规则。
-
OUTPUT chain —— 为OUTPUT链创建规则。其实,在这里要建的规则很少。
-
-
nat table —— 在处理完filter表之后,该设置nat表了。我们这样做是有一定原因的。首先,我们不想太早地打开转发机制(译者注:注意,filter表设定的是过滤机制,而不是转发)和NAT功能,因为它们可能导致数据会在错误的时间(也就是这样的时刻:我们打开了NAT,但过滤规则还没有运行)通过防火墙。还有,我把nat表看作是围绕filter表的一个层。也就是说,filter表是核心, nat表是它外部的一个层,mangle表是第二层。从某些观点来看,这可能有点不对,但也八九不离十了。
-
Set policies —— 与filter一样,我们先来设置策略。一般说来,缺省的策略,即ACCEPT,就很好。这个表不应该被用来做任何过滤,而且我们也不应该在这儿丢弃任何包,因为对我们假设的网络情况来说,可能会发生一些难以应付的事情。我把策略设为ACCEPT,因为没有什么原因不这样做。
-
Create user specified chains —— 在这儿创建nat表会用到的自定义链。一般情况下,我没有任何规则要在这儿建立,但我还是保留了这个小节,以防万一罢了。注意,在被系统内建链调用之前一定要建好相应的自定义链。
-
Create content in user specified chains —— 建立自定义链的规则。
-
PREROUTING chain —— 要对包做DNAT操作的话,就要用到此链了。大部分脚本不会用到这条链,或者是把里面的规则注释掉了,因为我们不想在不了解它的情况下就在防火墙上撕开一个大口子,这会对我们的局域网造成威胁。当然,也有一些脚本默认使用了这条链,因为那些脚本的目的就是提供这样的服务。
-
POSTROUTING chain —— 如果使用SNAT操作,就要在此建立规则。你可能有一个或多个局域网需要防火墙的保护,而我就是依据这样的情况来写此脚本的,所以这个脚本中使用的 POSTROUTING链是相当实用的。大部分情况下,我们会使用SNAT target,但有些情况,如PPPoE,我们不得不使用MASQUERADE target。
-
OUTPUT chain —— 不管什么脚本都几乎不会用到这个链。迄今为止,我还没有任何好的理由使用它,如果你有什么理由用它了的话,麻烦你把相应的规则也给我一份,我会把它加到本指南里的。
-
-
mangle table —— 最后要做的就是处理mangle表了。通常,我不会使用这个表,因为一般情况下,它不会被任何人要到,除非他们有什么特殊的需要,比如为了隐藏一条连接后的多台机子,我们要统一设置TTL或TOS等。在这个脚本里,此表是空白的。但在此指南中还是有个小小的例子说明了mangle表的用处。
-
Set policies —— 设置策略。这里的情形和nat表几乎完全相同。这里不应该做过滤,也不应该丢弃任何包。在任何脚本里我都不会把mangle表的策略设为其他的值,也不鼓励你这样做。
-
Create user specified chains —— 建立自定义链。我几乎不会用到这个链,所以没有建立任何规则。保留此小节,只是已备后用。
-
Create content in user specified chains —— 建立自定义链的规则。
-
PREROUTING —— 本指南的所有脚本都未在此链建立规则。
-
INPUT chain —— 本指南的所有脚本都未在此链建立规则。
-
FORWARD chain —— 本指南的所有脚本都未在此链建立规则。
-
OUTPUT chain —— 本指南的所有脚本都未在此链建立规则。
-
POSTROUTING chain —— 本指南的所有脚本都未在此链建立规则。
-
-
这应该可以较详细地解释每个脚本的结构是怎样的以及它们为什么要使用这个结构了。
注意,上面的描述其实还是非常简单的,应该被看作一个摘要,它简要地解释了脚本为什么要按照这种松散的结构来写。千万注意,我可没有说过这种结构是唯一的、最好的。 |
8.2. rc.firewall.txt
脚本rc.firewall.txt是核心,第七章防火墙配置实例 rc.firewall对它已经做了很详细的解释,其他的脚本都是以它为基础得到的。这个脚本主要是针对具有两个连接的家庭网络而设计的,如一个局域网连接,一个Internet连接。我们假设的情况是你有一个静态IP地址,不需要DHCP,PPP, SLIP或其他什么协议为你动态分配IP。如果你想要的恰恰是使用这些协议的脚本,就到rc.DHCP.firewall.txt看看吧。
脚本rc.firewall.txt要完全发挥作用,系统必需要有下面列出的功能,你可以把它们编译进内核,也可以编译成模块。如果你改变了脚本,就要加入相应的功能模块或把它们编进内核。
-
CONFIG_NETFILTER
-
CONFIG_IP_NF_CONNTRACK
-
CONFIG_IP_NF_IPTABLES
-
CONFIG_IP_NF_MATCH_LIMIT
-
CONFIG_IP_NF_MATCH_STATE
-
CONFIG_IP_NF_FILTER
-
CONFIG_IP_NF_NAT
-
CONFIG_IP_NF_TARGET_LOG
8.3. rc.DMZ.firewall.txt
脚本rc.DMZ.firewall.txt所针对的情况是这样的:有一个可信任的内网,一个DMZ,还有一个Internet连接。这里的DMZ是通过设置一对一的NAT 操作得到的,它需要IP别名(就是在一块网卡上设置多个IP地址)的支持。我们还有其他的方法来实现 DMZ:如果你有一个整个的网段,可划分子网,然后把某个子网分给DMZ,再为防火墙配置相应的内网与外网 IP地址(译者注:第一种方法是针对有多个网段的情况,即内网一个网段,DMZ一个网段,第二种方法是把一个网段划分成几个子网,这样就和第一种情况一样了)。注意,这种方法会多消耗两个IP,一个是网络地址,一个是广播地址(译者注:具体细节请上网搜索子网划分的相关信息,这个指南并不包含此类信息)。以上两种方法用哪一个就要你自己决定了。本指南会给你实现防火墙与NAT的手段或叫做技术,但具体如何去做,没有完全的说明,因为这已经超出本文的范围了。
这个脚本需要以下模块,也可能它们已被编译进内核了。
-
CONFIG_NETFILTER
-
CONFIG_IP_NF_CONNTRACK
-
CONFIG_IP_NF_IPTABLES
-
CONFIG_IP_NF_MATCH_LIMIT
-
CONFIG_IP_NF_MATCH_STATE
-
CONFIG_IP_NF_FILTER
-
CONFIG_IP_NF_NAT
-
CONFIG_IP_NF_TARGET_LOG
从图中可以看出,此脚本假设你有两个内网,一个是可信任的内网,使用地址192.168.0.0/24,另一个是 DMZ(我们正是对它做一对一的NAT),使用地址192.168.1.0/24。如果有人从Internet向我们的DNS_IP发送一个包,我们就要对它使用DNAT,之后,此包的目的地址就指向DMZ 里的DNS服务器了,它也就可以到达真正的DNS服务器。否则,DNS服务器不会看到这个包,也就没有应答之说了。下面是实现上述DNAT功能的语句:
$IPTABLES -t nat -A PREROUTING -p TCP -i $INET_IFACE -d $DNS_IP --dport 53 -j DNAT --to-destination $DMZ_DNS_IP
我们可以看出,这个规则要放在nat表的PREROUTING链中,包要满足的条件是:使用 TCP协议且使用53号端口,从接口$INET_IFACE进入,而且要以$DNS_IP为目的。被匹配的包要交给DNAT target来处理,它会把包的目的地址改为由--to-destination指定的地址$DMZ_DNS_IP。这就是 DNAT的工作流程。当相应的应答包被发送到防火墙时,会自动地被un-DNAT。
现在,你应该完全可以读懂这个脚本了。如果有什么你不明白的东西在脚本的其他部分没有被用到,那可能就是我的错误了,要告诉我哦。
8.4. rc.DHCP.firewall.txt
脚本rc.DHCP.firewall.txt适用于那些使用DHCP、PPP或SLIP连接Internet的情况,它和原始的脚本rc.firewall.txt几乎一样,主要的区别在于这里不再使用变量STATIC_IP。原因很简单了,就是它不能和动态的IP一起使用。此脚本相对于原始脚本的改变是很少的,但还是有一些人发信问我做了什么改变。经过大家的考验,这个脚本应该是一个很好的解决方案了。
它需要如下功能模块。
-
CONFIG_NETFILTER
-
CONFIG_IP_NF_CONNTRACK
-
CONFIG_IP_NF_IPTABLES
-
CONFIG_IP_NF_MATCH_LIMIT
-
CONFIG_IP_NF_MATCH_STATE
-
CONFIG_IP_NF_FILTER
-
CONFIG_IP_NF_NAT
-
CONFIG_IP_NF_TARGET_MASQUERADE
-
CONFIG_IP_NF_TARGET_LOG
我做的改变主要是删除了变量STATIC_IP以及和它相关的所有东西。以前,主要的过滤工作是基于变量STATIC_IP的,现在是INET_IFACE 了。也就是说,在这个脚本里,我们不再把-d $STATIC_IP作为过滤的条件,而是用 -i $INET_IFACE。这几乎是唯一的改变,也是必需的改变。
可还是有一些问题要考虑。现在,我们不能再在INPUT链依据某些条件,比如--in-interface $LAN_IFACE --dst $INET_IP来进行过滤(译者注:因为这时已无固定的INET_IP)。这强迫我们只能基于Internet接口进行包的过滤,在这种情况下,内网必须访问那个可变的 Internet的IP。这会出现一些问题,有个例子可以说明这一点,就是我们在防火墙上运行HTTP服务。如果我们访问这个网站(其中,主页包含了一个指向HTTP服务器的静态连接,这可能是某个动态的DNS解决方案),问题就暴露了。经过NAT操作的机子会向DNS查询HTTP服务器的IP,然后再试着访问这个IP。万一我们是基于接口和IP做的过滤,这台机子就不能访问到HTTP了,因为INPUT链会 DROP掉这个包(译者注:还是因为Internet接口的IP不固定)。在某种情况下,这也会发生在你有静态IP的时候,但在那种情况下,我们可以增加一条规则,以检查LAN接口的包是否是发往INET_IP的,若是,则ACCEPT。
如果你看过以前的内容,得到或写一个可以获取动态IP的脚本可能会是个解决问题的好办法。比如,我们可以写一个脚本,它紧随着Internet连接的启动而运行,而且它能从命令ifconfig的输出中提取IP,再把这个IP赋给某个变量。较好的办法是使用一些程序自带的脚本,如 pppd带的脚本ip-up。也有一些网站,如linuxguruz.org,提供了很多有用的脚本,你可以在附录其他资源和链接找到它的链接。
这个脚本比rc.firewall.txt的安全性要差一点。我明确地建议你尽可能使用后者,因为前者的开放性大了点,所以外部攻击的威胁就大了。 |
还有一种方法可获得IP,就是在脚本里加上类似这样的语句:
INET_IP=`ifconfig $INET_IFACE | grep inet | cut -d : -f 2 | cut -d ' ' -f 1`
上面这句话的作用是从ifconfig的输出里提取接口$INET_IFACE的IP,再赋给$INET_IP。更好的办法是使用脚本 retreiveip.txt。但要注意,这个方法可能会引起一些不正常的情况,比如使防火墙和内网之间已有的连接停止。下面就说明一下最常见的问题。
-
如果这个脚本的代码是在另一个脚本内运行的,而那个脚本又是由PPP daemon启动的,就会因为NEW not SYN rules(具体信息查看未设置SYN的NEW状态包)的原因而挂起所以当前活动的连接。如果你删掉那个规则,可能会没有事,但还是不保险。
-
如果你不想改动已有的规则,而又要添加或删除规则,还要不损害已有的规则,这就没法做了。比如,你又想阻塞所有局域网里的机子访问防火墙,又想让它们能控制防火墙上的PPP daemon,如果不删除那个用来阻塞的规则,怎么能完成这样的事?
- 事情可能也不必这么复杂,就像上面说的,这会导致一些安全问题。但如果这个脚本能保持简单,维持规则的顺序与发现问题都是很容易的。
8.5. rc.UTIN.firewall.txt
脚本rc.UTIN.firewall.txt适用于这样的情况:我们不信任任何与防火墙连接的网络,包括内网。我们只允许内网使用POP3、HTTP 和FTP。至于从Internet来的连接,权限和其他脚本一样。
此脚本需要以下功能模块。
-
CONFIG_NETFILTER
-
CONFIG_IP_NF_CONNTRACK
-
CONFIG_IP_NF_IPTABLES
-
CONFIG_IP_NF_MATCH_LIMIT
-
CONFIG_IP_NF_MATCH_STATE
-
CONFIG_IP_NF_FILTER
-
CONFIG_IP_NF_NAT
-
CONFIG_IP_NF_TARGET_LOG
这个脚本遵循的原则是不要相信任何人,包括我们自己的员工。这是个令人悲痛的现实,大部分破坏和攻击确实是来自我们内部的。这个脚本只是在加强防火墙方面给了你一个例子。它和 rc.firewall.txt并没有太多的不同,只是少了一些允许通行的规则。
8.6. rc.test-iptables.txt
这个脚本用来测试iptables里所有的链。当然,这要根据你的配置情况做些操作,如打开ip_forwarding或是设置masquerading,等等。只要你的安装了基本的 iptables,就可以使用它。其实这个脚本只使用了LOG,以便能记录所有的ping请求与应答。通过这种方式,我们就可以了解哪些链被穿越了以及被穿越的顺序。使用方法如下,先运行这个脚本,再发布一个ping命令,如:
ping -c 1 host.on.the.internet
然后用命令tail -n 0 -f /var/log/messages就可看到用了哪些链以及是什么顺序,除非记录因某些原因被替换了。
此脚本仅仅是为测试而写的。也就是说,不要使用类似这样的规则,它记录某一类包的所有信息,这会很快地占满你的日志分区,而且它会成为一个有效的DoS攻击。它还可能导致在最初的DoS攻击之后,无法记录真正的攻击信息。 |
8.7. rc.flush-iptables.txt
rc.flush-iptables.txt不应该被称作脚本,它只是重置并清空所有的表、链。它先把filter表的INPUT、OUTPUT和 FORWARD链的策略设为缺省的ACCEPT,然后是nat表的PREROUTING 、POSTROUTING和OUTPUT链。我们这样做就不必为被关闭的连接和没有通过的包而操心。这个脚本就是为防火墙设置和除错用的,因此我们只关心打开所有的东西并恢复它们的缺省值就行了。
之后,我们清空filter表里所有的链,紧接着是NAT表的。这样,就不会有什么不应该存在的规则了。这个做完后就该删除filter表和NAT表里的自定义链了。这时,脚本的工作就应该完成了。当然,如果你用到了mangle表,可以在这个脚本里添加相应的清空规则。(译者注:其实作者已经这样做了)
最后再说明一下,有些人写信建议我把这个脚本放到rc.firewall脚本里面,而且是用Red Hat Linux脚本的语法,这样当rc.firewall启动时,这个脚本也可以启动。但我不会这样做的,因为这是一个指南,主要是用来学习iptables的使用方法的,不应该有过多的shell脚本特有的语法。加入shell脚本特有的语法会使阅读的难度大大增加,这就远离了我的初衷。这个指南是按照易读的标准来写的,以后我会继续这样做。 |
8.8. Limit-match.txt
这个脚本是用来测试limit match的,也会让你明白limit match是如何工作的。装入这个脚本,再用不同的时间间隔发送ping数据包,可以看出哪个包可以通过,这些包又是以什么频率通过的。你应该可以看出,在limit的burst值再次到达之前,所有的echo replies都会被阻塞。
8.9. Pid-owner.txt
这个脚本说明了如何使用PID owner match。它其实什么都没做,但你可以运行一下,命令iptables -L -v的输出会说明它确实匹配了些东西。
8.10. Sid-owner.txt
说明SID owner match如何使用的一个例子。同样,它也是什么都没做,但你可以运行一下,命令iptables -L -v的输出会说明它确实匹配了些东西。
8.11. Ttl-inc.txt
一个小小的例子,说明了如何隐藏我们的防火墙或路由器,以使跟踪路由程序看不到,这样就可以对可能的攻击者隐藏很多信息。
8.12. Iptables-save ruleset
这只是一个输出的例子,它在规则的保存与恢复里被用来说明 iptables-save命令是如何使用的。所以,它没有任何用处,只是一个参考而已。
附录 A. 常用命令详解
A.1. 查看当前规则集的命令
查看当前正在使用的规则集是一个十分常用的操作,使用iptables的什么命令还记得吗?我们可是在规则是如何练成的这一章里介绍过啊,虽然到时说得简单了点。再复习一下吧,命令语法如下:
iptables -L
这个命令会尽可能地以易读的形式显示当前正在使用的规则集。比如,它会尽量用文件/etc/services里相应的名字表示端口号,用相应的DNS记录表示IP地址。但后者可能会导致一些问题,例如,它想尽力把LAN的IP地址(如192.168.1.1)解析成相应的名字。但192.168.0.0/16这个网段是私有的,也就是说,它只能用在局域网里,而不能在Internet里使用,所以它不会被Internet上的DNS服务器解析。因此,当解析这个地址时,命令就好像停在那儿了。为了避免这种情况的发生,我们就要使用选项:
iptables -L -n
如果你想看看每个策略或每条规则、每条链的简单流量统计,可以在上面的命令后再加一个verbose标志,如下:
iptables -L -n -v
不要忘了,iptables -L命令还可以查看nat表和mangle表的内容哦(更不要忘了,默认的表是filter),只需要使用-t选项,比如我们只想看nat表的规则,就用下面的命令:
iptables -L -t nat
在/proc里,可能还有一些文件你会感兴趣。比如,你可以在连接跟踪记录表里看到当前有哪些连接。这个表包含了当前的所有连接,你还可以通过它了解到每个连接处于什么状态。要注意,这个表是不能编辑的,即使可以,也不应该更改它。可以用下面的命令查看这个表:
cat /proc/net/ip_conntrack | less
此命令会显示当前所有被跟踪的连接,但要读懂那些记录可是有些难度哦。
A.2. 修正和清空iptables的命令
即使你把iptables弄的一塌糊涂,我们也有非常有效的命令来处理,而不必重新启动计算机。我接到过很多关于这个问题的询问,所以我想最好在这儿回答一下。如果你增加的规则有问题,要想删掉它,只要把命令中的-A改为-D即可。这样,iptables就会找到那个错误的规则并删掉它,但如果在你的规则里有好几条同样的规则,它只能删掉找到的第一条。如果你不想这样的事情发生,那就试试用序号来删除。如,你想删除INPUT链的第10条规则,可以使用 iptables -D INPUT 10。
还有一种情况,就是要清空整个链,这就要使用选项-F。比如,我们要清空整个 INPUT链,使用的命令就是iptables -F INPUT。但是要注意,选项-F并不改变链的缺省策略。所以,如果被我们清空的那条INPUT链的策略是DROP,它还是会阻塞所有的包。那怎么才能重置策略呢?还记得策略DROP是如何设置的吧,还是用那个方法啊。比如,我们把INPUT链的策略改为ACCEPT,就用iptables -P INPUT ACCEPT。
我已经写了一个用来清空并重置iptables的脚本,叫做rc.flush- iptables.txt(附录里有它的代码),在你写自己的防火墙脚本时,很可能会用到。但如果你在mangle表里乱试乱改而导致问题的话,这个脚本就帮不上忙了。因为在脚本rc.firewall.txt里,我没有用到mangle表,所以在 rc.flush-iptables.txt里也就没有添加相应的恢复功能。
附录 B. 常见问题与解答
B.1. 模块装载问题
装载模块时,你可能会遇到几个问题,比如,有错误提示说明没有你指定名字的那种模块:
insmod: iptable