前言
在之前的学习中对iptables的语法有了一定的了解,对于在不太复杂的网络结构中的一些简单的语句可以进行简单的分析了。当然,如果对语句和相关架构不清楚的可以参考:(Linux防火墙之Netfilter)http://waringid.blog.51cto.com/65148/402648以及(iptables之语法初步)http://waringid.blog.51cto.com/65148/403931和(linux防火墙之牛刀小试)http://waringid.blog.51cto.com/65148/410265。这些文中详细介绍了linux下iptables防火墙的基础情况。
测试
当你已经完全了解了iptables的语法规则后,那么看看下面的几个测验题你能否通过,先介绍测试环境中的网络情况,如下图所示:
网络环境中的路由器使用RouterOS,共使用三块网卡,其中一块为连接internet,IP地址自动获取;第二块网卡使用11.0.0.1/8,第三块网卡使用173.16.0.1/16;测试的两台机器均为linux操作系统;安装有iptables软件,IP地址分别为10.0.200/8和173.16.0.200/16;在关闭iptables的情况下,各主机可以相互通讯。网络的详细设定可参考:(ESX搭建网络测试环境)http://waringid.blog.51cto.com/65148/385767。
问题一
如果11(指11.0.0.200下同)做以下规则:
iptables -F
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -L
当173(指173.16.0.200下同)的防火墙设定以下规则允许icmp包进入(允许其它机器ping它)时,
iptables -F
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables �Ct filter �CA INPUT �Cp icmp �Cj ACCEPT
iptables -L
那么在PC机11上执行
ping 173.16.0.200
此时机器能ping通吗?为什么?如果在173.16.0.200上启用SSH服务端应用程序,同时关闭173.16.0.200防火墙服务;那么在11.0.0.200上运行SSH客户端的服务能够正常连到173.16.0.200这台机器吗?
结果一
不管答案是怎么样的,我们还是看看实际情况是怎么样的吧(这里只给出ping测试的截图,SSH的测试可以自行参考实现)。
如上图所示,在11.0.0.200这台机上是没办法ping通173.16.0.200的。那么是不是意味着173.16.0.200拒绝了11.0.0.200的ping请求呢,我们可以查看173.16.0.200在被ping时的实际连接,使用以下命令:
netstat -s |more
结果如下图所示。
从上图可知,对于173.16.0.200这台机来说它是接收到了icmp的包的,但11.0.0.200提示无法ping通。那么问题出在哪呢?同样的SSH的应用也无法连接。
答案
首先,假设173.16.0.200机器上启动SSH服务,并且正常服务在TCP 22号端口的位置,接着在11.0.0.200上启动SSH客户端,假设客户端使用的是TCP 12345号端口,然后,11.0.0.200使用TCP 12345向173.16.0.200的TCP 22号端口发出服务请求,这个请求包一定可以成功送到173.16.0.200这台机上,因为11.0.0.200的OUTPUT没有限制,只是此时当173.16.0.200收到这个请求包时就会以TCP 22回应11.0.0.200在TCP 12345上的请求,那么,11.0.0.200的INPUT策略允许这个包通过TCP 12345进来吗?如果INPUT没有开放这个端口那么这个请求就无法在11.0.0.200上响应。ping的情况也是如此。如下图所示。
也许有人会认为直接在INPUT中把TCP 12345开启不就可以了!但实际情况是:客户端的应用程序所使用的端口多为动态端口,所以不可能事先预知客户端的应用程序会使用哪一个端口,也就不可能预先把客户端的端口开好等客户端使用。
在以前的Ipchains防火墙时代,要解决这种问题的做法是将1024以上的端口都打开,只要确定客户端应用程序使用的端口大于1024就行。这种解决办法当然也适用现在的netfilter/iptables防火墙,但这样做就无法确保安全。在netfilter/iptables时代,可以通过启用state(状态)模决来解决这样的问题,它主要由xt_state.ko模块提供。
需要注意的是在标准和tcp/ip规范中,连接状态分为12种,详情可以参考RFC文档(http://www.ietf.org/rfc/rfc793.txt)。而iptables中的连接状态只有4种,分别是ESTABLISHED、NEW、RELATED、INVALID。不能将TCP/IP规范中的连接状态和这个混在一起,因为这个两个完全不同的定义。例如,在TCP/IP规范描述下,UDP和ICMP封包是没有连接状态的,但在state模块的描述下,任何包都是有连接状态的。
ESTABLISHED
以下图为例解决上面所提出的问题。ESTABLISHED状态与TCP、UDP及ICMP协议的关系解释也用下图描述。假设图右边为一台设定有单机防火墙的主机,并且在这台主机上分别执行以下3个实验。
TCP包相关:先在防火墙主机执行SSH客户端,对网络上的SSH服务提出服务请求,而这时送出的第一个数据包就是服务请求数据包,如果这个数据包能够“成功穿越防火墙”,那么接下来①②方向的所有数据包状态都会是ESTABLISHED。
UDP包相关:在防火墙主机上以firefox应用程序来浏览网页,而浏览网页的动作需要DNS解析才能顺利浏览到网页,因此,firefox会送出一个UDP的数据包给DNS服务器,以请求域名解析服务;如果这个数据包能够“成功穿越防火墙”,那么接下来③④方向的所有数据包状态都会是ESTABLISHED。
ICMP包相关:在防火墙主机上以ping命令来检测网络上其它主机是,ping送出的第一个icmp数据包这个数据包能够“成功穿越防火墙”,那么接下来⑤⑥方向的所有数据包状态都会是ESTABLISHED。
所以,只要数据包能成功穿越防火墙,那么之后的所有封包(包含反向的所有数据包)状态都会是ESTABLISHED。
解法一
出现上面的问题后,只需要在11.0.0.200这台机器上开放ESTABLISHED状态的连接就可以解决问题一了。如下面的命令所示:
iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
iptables -L