我有一个host1有一个WAN接口eth0 ( 1.2.3.4 )和一个LAN接口eth1 ( 10.41.82.1 )。 在局域网内是一个host2 ,IP地址为10.41.82.2 。
到1.2.3.4:22入站连接使用host1上的以下iptables规则转发给host2 :
root@host1:~# iptables -t nat -A OUTPUT -d 1.2.3.4 -p tcp --dport 22 -j DNAT --to 10.41.82.2:22 root@host1:~# iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp --dport 22 -j DNAT --to 10.41.82.2:22
这工作正常,除了当host2试图访问1.2.3.4:22 :
root@host2:~# telnet 1.2.3.4 22 Trying 1.2.3.4... root@host2:~# ping 1.2.3.4 PING 1.2.3.4 56(84) bytes of data. 64 bytes from 1.2.3.4: icmp_seq=1 ttl=64 time=0.125 ms 64 bytes from 1.2.3.4: icmp_seq=2 ttl=64 time=0.279 ms root@host2:~# tcptraceroute 1.2.3.4 22 traceroute to 1.2.3.4, 30 hops max, 60 byte packets 1 * * * 2 * * * 3 * * * 4 * * * 5 * * * (and so on)
看来数据包正在被转发一圈。 正如你所看到的,ping是有效的,所以路由和IP转发设置正确。
我做错了什么,我该如何解决这个问题?
更新:
正如BillThor的回应中提到的,正如在DNAT的frozentux教程中所描述的,我需要添加一个SNAT规则。 我现在这样做了(请注意,我已经为-d添加了host2的局域网地址,因为这个规则被应用在数据包的目的地已经被改变的POSTROUTING中):
root@host1:~# iptables -t nat -A POSTROUTING -d 10.41.82.2 -p tcp --dport 22 -j SNAT --to 10.41.82.1
不幸的是,这并没有解决这个问题,一切都和上面描述的一样。 有趣的是,根据运行iptables -t nat -nvL时显示的计数器, SNAT规则似乎从不匹配。
更新2:
我发现,当我运行tcpdump -i eth1 ,甚至当我用与这种情况无关的参数(例如tcpdump -i eth1 port 34238运行它时,它突然起作用。 但只有在tcpdump正在运行的时候。
到目前为止我没有提到,因为我认为这是无关紧要的, eth1实际上是一个桥梁, host2是一个Xen域。 我开始怀疑我的问题可能与此有关。
你正在做的是被称为发夹NAT。 host2只是连接到host1会更好。
如果你想这个工作,使用SNAT以及DNAT来发送本地networking上的stream量到外部IP。
另一个可行的解决scheme是将host2的路由添加到host1,该路由将stream量路由到路由器而不是本地networking。
它之所以失败,是因为eth1实际上是一个桥接接口。 实际上, host2是在host1上运行的Xen虚拟机,而eth1是用于主机和guest虚拟机之间通信的网桥。
我通过调用bridge link set dev vif2.0 hairpin on (或者brctl hairpin eth1 vif2.0 on )解决了这个问题。 vif2.0是由Xen创build的虚拟networking接口,是eth1网桥的一部分。
因此,为了使发夹式NAT在网桥接口上工作,请确保为数据包进入的接口(即网桥的一部分)启用网桥发夹。
最后不需要添加SNAT规则。
systemd-networkd也有一个指令来启用* .network文件中的发夹:
[Bridge] HairPin=true
我不确定是否将它添加到eth1.network或vif2.0.network (通常不存在)在我的情况,但最终没有一个工作。