我知道这个问题已经存在十几种形式,但大多数是关于商业 wifi 路由器等的。
我有一个 Ubuntu 20.04LTS 盒子,上面有一堆接口设置为防火墙/NAT 盒,其中一个接口是 WAN 接口。
我在 WAN 接口(enp4s0f0)上有许多到不同内部主机的端口转发,规则如下(顺便说一下,下面所有规则都在“nat”链上):
-A PREROUTING -i enp4s0f0 -p tcp -m tcp --dport 8181 -j DNAT --to-destination 10.0.0.50:22
(将端口 8181 处的传入 WAN 连接转发到主机 10.0.0.50,ssh 端口)
但是,如果我在内部主机上,我也希望能够到达此端口转发,而无需明确转到其他内部主机,例如,我有一个已经指向 WAN IP 的 DNS。“开箱即用”这不起作用(我猜是因为 WAN if 的明确接口规范),所以我尝试向 iptables 添加内容,但我添加的两个额外规则似乎都不起作用:
-A PREROUTING -d -p tcp --dport 8181 -j DNAT --到目的地 10.0.0.50:22
-A PREROUTING -i enp3s0f0 -p tcp --dport 8181 -j DNAT --to-destination 10.0.0.50:22
(enp3s0f0是内网LAN接口)
我想我在这里错过了一些简单的魔法。
如果有一条“捕获所有”规则,让所有来自内部 LAN 并发往 WAN 接口的数据包都到达那里,那就太好了前WAN=>LAN 端口转发规则生效,那么每当我添加 WAN 端口转发时,我就不必担心设置新的匹配的额外规则。
更新:也许我原来的端口转发规则应该更改,现在明确指定 WAN eth 接口名称。我从许多教程中获得了此设置,它对外部客户端来说运行良好。
答案1
这个问题的通常答案是“您需要 NAT 环回/NAT 发夹”。
正如一些答案中提到的,环回 NAT 的实际问题是来源此类“环回端口转发”连接的 IP 地址(即客户端的 LAN 地址)被视为目标服务器的本地地址(位于同一个 LAN 中),这会导致直接向客户端发送回复,而不是通过路由器。
那么“发夹弯”解决方法的作用是对源地址也进行 NAT。这不仅仅是对 DNAT 规则的修改,而是一个完全独立的源地址转换需要应用于相同数据包的规则。(不过,您也需要放宽-i
DNAT 规则的匹配。)
-A POSTROUTING -o enp3s0f0 -s 10.0.0.0/24 -j MASQUERADE [或者] -A POSTROUTING -o enp3s0f0 -m conntrack --ctstate DNAT -j MASQUERADE
(如果我没记错的话,iptables 不允许-i
在 POSTROUTING 中匹配,尽管这在这里很有用。)
如果您的客户端和服务器位于不同的 LAN 子网(例如不同的 VLAN 或只是外部路由器上的不同以太网接口),则 SNAT 解决方法是不必要的,因为无论如何,它们之间的流量总是会通过路由器。
更详细地:
- 客户端发送请求“客户端→WANip”。该请求发往路由器的 MAC。
- 路由器将其 DNAT 变为“客户端→服务器”并将其转发到服务器。
- 服务器收到“客户端→服务器”请求,然后发送“服务器→客户端”回复。该回复直接发送到客户端的 MAC,绕过路由器,因此 DNAT 不会被撤销。
- 客户端收到回复“服务器→客户端”,该回复与任何已知连接都不匹配 - 客户端原本期望收到“WANip→客户端” - 因此客户端丢弃收到的回复。
使用 SNAT 解决方法:
- 客户端发送请求“客户端→WANip”。该请求发往路由器的 MAC。
- 路由器将其 DNAT 为“客户端→服务器”,然后此外SNAT 使其看起来像“路由器→服务器”,然后将其转发到服务器。
- 服务器收到“路由器→服务器”请求,并发送“服务器→路由器”回复。该回复将发送到路由器的 MAC。
- 路由器收到“服务器→路由器”的答复,将其取消 SNAT 变为“服务器→客户端”,取消 DNAT 变为“WANip→客户端”,然后转发给客户端。
- 客户端收到与原始请求匹配的回复“WANip→client”。