网络拓扑如下:hostA/B/C处于同一个局域网:
hostA:
eth0:192.168.0.2
----------------------
hostB:
eth0:192.168.0.1
eth1:10.0.0.1
----------------------
hostC:
eth0:192.168.0.3
eth1:10.0.0.3
----------------------
hostA-route
10.0.0.0/24(-net) 192.168.0.1(gw)
---------------------
hostB-iptables
FORWARD(DROP)
-A FORWARD -d 10.0.0.3 -j ACCEPT
---------------------
在hostA上ping 10.0.0.3竟然通了,说明hostB的规则没有起作用?或者说iptables有问题?其实不是的,数据可以从10.0.0.1也就是hostB走,但是回应却不一定非要原路返回啊,更何况三台机器在一个交换机上插着,因此数据到达hostC之后,回应时根据源地址hostA的eth0查找路由,发现和自己在一个网络中,于是直接从eth0出去了,而不是原路回去,因此可以ping通,如果想使得事情更不混乱一点,只需要在hostB上配置一条nat即可:
-A POSTROUTING -o eth1 -j MASQUERADE
这样数据就不能不原路返回了,肯定ping不通了,但是加上下面一条规则就又通了:
-A INPUT -m state --state ESTABLISHED -j ACCEPT
上述的网络拓扑非常糟糕,在共享式局域网络中配置不同的子网会带来很多隐含的问题,查起来很困难,需要你对网络十分精通才可以,因此最好不要这么配置。
ESTABLISHED状态的连接是一个双向有数据的连接,用于方便配置防火墙。由于linux的iptables中的filter表是基于包而非连接的,如果你只在一个方向允许数据通过的话,该数据包所属连接的回应数据将被阻止在防火墙,因此需要配置一个反方向允许的策略,如此一来,整个filter表就会扩大一倍。实际上只需要配置下面一条策略就可以了:
-A INPUT -m state --state ESTABLISHED -j ACCEPT
原理是--state是基于ip_conntrack的,而conntrack在filter表的策略之前起作用,而conntrack只要看见回应的数据包就会将此数据包所属的连接状态设置为ESTABLISHED,从而使得上述配置生效。总之,上述配置需要第一个正向数据包可以通过防火墙,之后的两个方向的数据包自然也就都可以通过了。