基于 WordPress | 主题由 mg12 提供 | 通过 XHTML 1.1CSS 3 验证
  • iptables 同网段端口转发问题

    昨天遇到了 iptables 同网段端口转发的问题,记录一下。

    环境描述

    内网网段:192.168.96.0/24
    网关外网地址(eth1):116.228.1.1 (虚构)
    网关内网地址(eth0):192.168.96.253

    网关上已经做好了 SNAT,同时做了两个 DNAT 116.228.1.1:18080–>192.168.96.55:8080

    奇怪的是,这个端口映射外部的用户都可以访问到,内部非192.168.96.0/24的用户也可以访问到。但就是 192.168.96.0/24 网段的设备无法访问。

    搜到了一篇帖子,详细解释了这个问题:http://linux.chinaunix.net/bbs/archiver/?tid-884706.html 。其中 ssffzz1 的一段解释非常详细,贴于此处:

    我压根就没听说什么重导,导什么啊.
    我都发了1000遍了,你却不用搜索.我只好在发一遍.

    另外还有别的解决办法,我没有更新到此帖上来,不过原理大同小异.

    看到论坛内很多弟兄做了DNAT,外网正常访问,内网却无法访问.现将原因总结如下:
    设网络结构如下:

    外网某机器为W1,路由器为R1,内网服务器为S1,内网某机器为C1,设服务为80
    地址分布如下:
    R1:外(eth0):192.168.0.5 内(eth1):192.168.1.254
    S1:192.168.1.5
    C1:192.168.1.8

    原因如下:
    外网为什么能成功:
    当W1以某IP端口80访问R1的外网地址192.168.0.5时,数据包到达192.168.0.5的接口eth0,ROS根据DNAT规则做了到 S1 192.168.1.5的转发,S1 192.168.1.5收到来自某IP的包后S1会发出正确的相应,此响应的目的IP为W1的IP,根据默认网关(R1的 eth1)192.168.1.254规则把回应包发到R1,因为R1先前DNAT的关系(有DNAT的记录),R1回做一个反方向的NAT转发,从而数据包能够正确的到达W1,因此能够正确通信。
    内网为什么不能成功:
    1、 DNAT规则是针对eth0口配置的:
    设R1的DNAT规则:iptables –t nat –A PREROUTING –i eth0 –p tcp –m tcp –d 192.168.0.5 –dport 80 –j DNAT –-to-destinstion 192.168.1.5
    当C1以192.168.0.5为目的IP访问80服务的时候,数据包从192.168.1.254口传入,R1根据路由规则,会把目的 192.168.0.5的地址直接送到上层接口,而不会经过R1为eth0接口配置的DNAT规则,那么此时192.168.0.5开了80服务了吗?很显然没有,因此无法访问。

    2、 DNAT的规则是全局的:
    设R1的DNAT规则:iptables –t nat –A PREROUTING –p tcp –m tcp –d 192.168.0.5 –dport 80 –j DNAT –-to-destinstion 192.168.1.5
    当C1以192.168.0.5为目的IP访问80服务的时候,数据包从192.168.1.254口传入,R1根据DNAT规则会把此数据包DNAT到正确的S1服务器192.168.1.5,当S1收到包的时候S1会根据自己的路由表不经过R1的转发而会直接把数据发到C1,因为C1和S1是在同一个网络,这时候C1回收到S1的回应,按说此时应该能正常通信。但不幸的是我们忽略了源IP的问题。C1是把数据包发给的是R1的外网IP 192.168.0.5,而收到的IP的源地址却是S1的IP192.168.1.5,虽然数据包的除IP外所有的都是正确的,但C1仍然不会接受,会把这个包丢弃的。因此通信还是无法进行。

    解决办法:
    1、 从DNS入手,在内网设置自己的DNS,或者编辑client的hosts表把S1的地址不要解析成外网的IP,这样就变成内网的通信,还不占用ROS的带宽。这是我首推的方法。
    2、 如果一定要走ROS,首先你要为每个可能进入的接口配置相应的DNAT策略,当然使用我上面举例的全局策略就完全可以的,那么我们下面应该如何设置呢?又有两种情况:
    1) 如果可以把服务器放到一个单独的网段请你及时这样做。因为这样可以避免攻击,便于控制等等好处N多了。麻烦就是需要ROS多加一个网卡当然如果你配置多地址的话,网卡都可以省了,不过这么省不太好吧。当然还需要配置正确的SNAT。
    2) 有些人说我就不能放到单独的网段,那我也有办法,这是我最不赞成的方法,就是请你删掉S1上到192.168.1.0网络的路由表项目,这样会强制S1到C1的数据包走R1,这样R1就可以实施相反的转换,当然也就可以正常通信了。
    route del –net 192.168.1.0 netmask 255.255.255.0 gw * dev eth1

    以上是我对所谓的回流问题的个人见解。你看后有3种情况:
    1、 写的不好没法看,或我都知道了不用看,请别拿石头丢我,我很脆弱。不过有错误尽管提,我很虚心。
    2、 和你想的差不多,那恭喜你,我先写出来了。
    3、 看不懂。没法子,我语文很差,逻辑很差,英文很差。你将就将就吧。

    最后请原谅我不能提供相应的ROS命令,因为这个东西我实在不懂,我只能提供IPTABLES和标准的LINUX命令。

    结合到我的实际情况就是:

    当 192.168.96.1 请求访问 116.228.1.1:18080 时,数据从 网关eth0网卡进入,网关发现116.228.1.1为本机地址,则不将数据从 eth1 口发出,而直接返回 DNAT 信息。此时数据包从 eth0进,也从 eth0 出。当 192.168.96.55:8080 收到请求之后,直接将数据返回给 192.168.96.1 (因为 iptables 规则里面并没有根据 eth0 出来做 SNAT)。当 192.168.96.1 收到 192.168.96.55 返回信息时,则会丢弃,因为他请求的是 116.228.1.1。

    这样,解决这个问题的点在于:

    1. DNAT 动作要能接受所有网卡流入的信息。如果原来的 DNAT 写了 -i eth1 ,则肯定会出错了。
    2. 在上文所述情况下 eth0 出的数据,应该再做 SNAT,将 SNAT 设置为网关地址。让 192.168.96.55 将数据返回到 网关,由网关转发。

    那么写这两句:

    -A PREROUTING -p tcp -m tcp –dport 18080 -j DNAT –to-destination 192.168.96.55:8080
    -A POSTROUTING -o eth0 -j SNAT –to-source 192.168.96.253

    第一句不指定访问 ip!

    2008年9月9日17:24
目前还没有任何评论.

发表评论

XHTML: 您可以使用这些标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="">
置顶