我在 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 local
make netcat 连接后又可以正常工作了。但是,我不明白为什么 wlan0 接口(其 IP 为 192.168.0.10)会影响环回接口?
供参考,我正在使用 ArchLinux
答案1
我不知道这是否是一个错误或故意的后备行为,但从我在这里看到的情况来看,它与wlan0
您提到的本地路由或其他/“正确”答案中所述的所有默认网关等等(没有冒犯的意思,但对我来说几乎没有意义)都没有任何关系。
通常情况MASQUERADE
下,它会选择在出站接口(由路由决定,因此POSTROUTING
)是它执行的源 NAT。(如果在接口上分配了多个地址,它可能会选择第一个地址或在相应路由中设置为首选源地址的地址;我对此不太熟悉,而且这超出了本文的范围)。它与默认路由的下一跳/网关地址无关。(无论如何,这不是源 NAT 的工作方式。)
然而,当涉及到接口时lo
,事情似乎变得有点棘手。更准确地说,它似乎与接口本身无关(除了由于目标是本地地址,它将是出站接口这一事实),而是与块中的地址不127.0.0.0/8
属于范围这一事实有关。虽然我不知道幕后发生了什么,但如果主机没有配置范围 IP 地址,global
流量似乎无法“显示”,但会尝试显示。global
MASQUERADE
我在这里看到的是,即使你只是在任何接口(包括)上配置一个对范围global
(例如)有效的地址,你也会看到它再次起作用。(你提到的本地路由将自动添加。但我没有看到只添加路由在这里有效。)192.168.0.10/32
lo
值得一提的是,地址和接口在 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。
如果您认为某些内容有误,请纠正我。