我有host1
一个 WAN 接口eth0
( 1.2.3.4
) 和一个 LAN 接口eth1
( 10.41.82.1
)。局域网里面是一个host2
带有IP地址的10.41.82.2
。
传入的连接1.2.3.4:22
被转发到host2
使用以下 iptables 规则host1
:
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
规则。我现在已经这样做了(请注意,我已经添加了host2
for的 LAN 地址-d
,因为此规则适用于POSTROUTING
数据包的目的地已更改的位置):
root@host1:~# iptables -t nat -A POSTROUTING -d 10.41.82.2 -p tcp --dport 22 -j SNAT --to 10.41.82.1
不幸的是,这并没有解决问题,一切仍然和上面描述的一样。有趣的SNAT
是,根据运行时显示的计数器,该规则似乎永远不会匹配iptables -t nat -nvL
。
更新 2:
我发现当我运行时tcpdump -i eth1
,即使我使用与这种情况无关的参数运行它,例如tcpdump -i eth1 port 34238
,它也会突然起作用。但只有 whiletcpdump
正在运行。
到目前为止我没有提到因为我认为它无关紧要的是它eth1
实际上是一座桥梁,并且host2
是一个 Xen 域。我开始怀疑我的问题可能与此有关。
之所以失败,原来是与
eth1
实际上是桥接接口有关。实际上,host2
它是一个运行在 Xen 虚拟机上的虚拟机host1
,eth1
是一个桥梁,用于主机和来宾之间的通信。我通过调用
bridge link set dev vif2.0 hairpin on
(或替代brctl hairpin eth1 vif2.0 on
)解决了这个问题。vif2.0
是 Xen 创建的虚拟网络接口,是eth1
网桥的一部分。因此,为了使发夹 NAT 在网桥接口上工作,请确保为数据包传入的接口(即网桥的一部分)启用网桥发夹。
SNAT
最终没有必要添加规则。systemd-networkd
还有一个指令可以在 *.network 文件中启用发夹:在我的情况下,我不确定是将它添加到
eth1.network
还是添加到vif2.0.network
(通常不存在),但最终它们都没有工作。您正在尝试做的事情称为发夹式 NAT。将 host2 连接到 host1 会更好。
如果您想让它工作,请使用 SNAT 和 DNAT 来处理源自本地网络的流量,这些流量会流向外部 IP。
另一个可行的解决方案是将主机 2 的路由添加到主机 1,该路由将流量路由到路由器而不是本地网络。