我在 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
使 netcat 连接再次起作用。但是,我不明白为什么 wlan0 接口(IP 为 192.168.0.10)会影响环回接口?
有关信息,我正在使用 ArchLinux
这是一个有根据的猜测。该
MASQUERADE
选项将 IP 数据包中的源 IP 地址替换为它决定使用的地址。我认为在这种情况下,它将源地址替换为默认网关可达的接口地址。因此,如果您的默认网关是
192.168.0.1
,则数据包的源地址将替换为192.168.0.1
。目的地是127.0.0.1
,这不能正常工作。您应该
MASQUERADE
仅限于传出接口是指向默认网关的数据包。您可以使用以下命令执行此操作:
我不知道这是错误还是故意的回退行为,但从我这里可以看到,它与
wlan0
您提到的本地路由或所有默认网关等等都没有任何关系(没有冒犯,但它几乎对我来说没有意义)在另一个/“正确”答案中说明。通常
MASQUERADE
工作原理是,它为它执行的源 NAT选择在出站接口上配置的地址(由路由确定,因此是)。POSTROUTING
(如果接口上分配了多个地址,它可能会选择第一个或在相应路由中设置为首选源地址的地址;我不太熟悉,这里超出范围反正)。与默认路由的下一跳/网关地址无关。(无论如何,源 NAT 不是这样工作的。)但是,当涉及到界面时
lo
,事情似乎变得有些棘手。更准确地说,它似乎与接口本身无关(除了它将是出站接口,因为目标是本地地址),而是127.0.0.0/8
块中的地址不是范围global
。虽然我不知道幕后发生了什么,但如果主机没有global
配置范围 IP 地址但尝试MASQUERADE
.我在这里看到的是,即使您只是在任何接口(包括)上配置了一个适用于范围
global
(例如)的地址,您也会看到它再次起作用。(您提到的本地路线将自动添加。但我没有看到仅添加路线在这里有效。)192.168.0.10/32
lo
值得一提的是,地址和接口在 Linux 中并没有紧密地绑定在一起(不是以直接的方式,只有当它们的目标地址与入站接口上配置的地址匹配时,它才会回复流量,即使 IP 转发是不关心)。所以它可能与此有关:如果
MASQUERADE
无法global
从出站接口上配置的内容中选择范围地址,它只会从任何中选择一个(我怀疑优先级与默认路由有关),如果仍然不,它只是拒绝以某种方式工作。如果您确实需要
MASQUERADE
在所有接口上启用的规则,但是lo
,您可以拥有:除了其他答案,我还做了一些其他的实验。请注意,以下只是我的结论,我没有在内核源中搜索(但如果你有文档,请分享)。
lo
的确,界面似乎又127.0.0.1
遵循着自己的规则。对于其他接口,这是我认为源 IP 分配给数据包的方式(不涉及 MASQUERADE 或原始套接字之类的东西):
当尝试向目标 IP 发送数据包时,linux 将搜索添加的匹配路由规则,例如:
如果
src
提供了参数(这似乎意味着像ip route add local <SRC_IP> dev <INTERFACE_YY>
以前一样添加规则。请注意,INTERFACE_XX 和 INTERFACE_YY 不必相同非常令人惊讶),那么数据包将在INTERFACE_XX
以SRC_IP
为源 IP 的接口上发送。如果
src
未提供该参数,它将发送数据包,INTERFACE_XX
并通过从第一个启动的接口到最后一个接口上的第一个有效 IP 搜索来选择源地址(在 lo 的例外情况下)。如果没有找到 IP,则源 IP 设置为 0.0.0.0。如果一个接口有多个 IP,则选择第一个。非常令人惊讶的是,这意味着数据包不一定具有它发送到的输出接口的 IP。我猜 MASQUERADE 以类似的方式选择源 IP。
请纠正我是你认为有人认为是错误的。