为什么 MASQUERADE SNAT 可以阻止本地主机连接?

为什么 MASQUERADE SNAT 可以阻止本地主机连接?

我在 Linux 上观察到一个奇怪的行为:

首先,我清理所有路由和 iptables 规则:

ip route flush table main
ip route flush table default
ip route flush table local
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -t nat -F
iptables -t mangle -F
iptables -F
iptables -X
ip6tables -P INPUT ACCEPT
ip6tables -P FORWARD ACCEPT
ip6tables -P OUTPUT ACCEPT
ip6tables -t nat -F
ip6tables -t mangle -F
ip6tables -F
ip6tables -X

然后我添加一条本地路线:

ip route add local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 table local

然后,我在一台终端上打开一个端口nc -lp 12345,在另一台终端上连接到该端口nc 127.0.0.1 12345,这样我就可以在 netcat 服务器和客户端之间发送和接收数据。所以现在一切都很好。

现在,从它并终止之前的 netcat 服务器和客户端之后,如果我运行:

iptables -t nat -A POSTROUTING -j MASQUERADE

然后我重启了 netcat 服务器,客户端就无法连接了。你知道为什么吗?

我注意到添加ip route add local 192.168.0.10 dev wlan0 proto kernel scope host src 192.168.0.10 table localmake netcat 连接后又可以正常工作了。但是,我不明白为什么 wlan0 接口(其 IP 为 192.168.0.10)会影响环回接口?

供参考,我正在使用 ArchLinux

答案1

我不知道这是否是一个错误或故意的后备行为,但从我在这里看到的情况来看,它与wlan0您提到的本地路由或​​其他/“正确”答案中所述的所有默认网关等等(没有冒犯的意思,但对我来说几乎没有意义)都没有任何关系。

通常情况MASQUERADE下,它会选择在出站接口(由路由决定,因此POSTROUTING)是它执行的源 NAT。(如果在接口上分配了多个地址,它可能会选择第一个地址或在相应路由中设置为首选源地址的地址;我对此不太熟悉,而且这超出了本文的范围)。它与默认路由的下一跳/网关地址无关。(无论如何,这不是源 NAT 的工作方式。)

然而,当涉及到接口时lo,事情似乎变得有点棘手。更准确地说,它似乎与接口本身无关(除了由于目标是本地地址,它将是出站接口这一事实),而是与块中的地址不127.0.0.0/8属于范围这一事实有关。虽然我不知道幕后发生了什么,但如果主机没有配置范围 IP 地址,global流量似乎无法“显示”,但会尝试显示。globalMASQUERADE

我在这里看到的是,即使你只是在任何接口(包括)上配置一个对范围global(例如)有效的地址,你也会看到它再次起作用。(你提到的本地路由将自动添加。但我没有看到只添加路由在这里有效。)192.168.0.10/32lo

值得一提的是,地址和接口在 Linux 中并没有紧密绑定在一起(不是以一种直接的方式,例如,只有当流量的目标地址与入站接口上配置的地址匹配时,它才会回复流量,即使 IP 转发不是问题)。所以它可能与此有关:如果MASQUERADE无法从出站接口上配置的范围地址中选择一个global,它只会从任意一个中选择一个(我怀疑优先级与默认路由有关),如果仍然没有,它只是以某种方式拒绝工作。

如果你确实需要一条MASQUERADE在所有接口上启用的规则lo,你可以:

iptables -t nat -A POSTROUTING ! -o lo -j MASQUERADE

答案2

这是有根据的猜测。该MASQUERADE选项将 IP 数据包中的源 IP 地址替换为其决定使用的地址。我认为在这种情况下,它将源地址替换为可到达默认网关的接口地址。

因此,如果您的默认网关是192.168.0.1,数据包的源地址将被替换为192.168.0.1。目的地是127.0.0.1,这无法正常工作。

您应该限制MASQUERADE仅传出接口是朝向默认网关的数据包。

您可以使用以下命令执行此操作:

iptables -t nat -A POSTROUTING -o <if> -j MASQUERADE

答案3

除了其他答案之外,我还做了一些其他实验。请注意,以下只是我的结论,我没有在内核源代码中搜索(但如果你有文档,请分享)。

确实,看起来界面lo遵循127.0.0.1其自己的规则。

对于其他接口,我认为源 IP 分配给数据包的方式如下(不讨论 MASQUERADE 或原始套接字之类的东西):

当尝试将数据包发送到目标 IP 时,Linux 将搜索添加的匹配路由规则,例如:

ip route add <NETWORK>/<PREFIX> dev <INTERFACE_XX> [src <SRC_IP>]

如果提供了参数src(这似乎意味着像以前一样添加一条规则ip route add local <SRC_IP> dev <INTERFACE_YY>。请注意,INTERFACE_XX 和 INTERFACE_YY 不必相同,这很令人惊讶),则数据包将在以源 IPINTERFACE_XX为接口上发送。SRC_IP

如果不提供该参数src,它将发送数据包 INTERFACE_XX,并通过从第一个启动的接口到最后一个接口(lo 除外)搜索接口上的第一个有效 IP 来选择源地址。如果没有找到 IP,则将源 IP 设置为 0.0.0.0。如果接口有多个 IP,它将选择第一个。令人惊讶的是,这意味着数据包不一定具有它发送到的输出接口的 IP。

我猜测 MASQUERADE 以类似的方式选择源 IP。

如果您认为某些内容有误,请纠正我。

相关内容