我有以下 iptables 规则:
iptables -t mangle -A PREROUTING -p udp -m udp --dport 10000 -j MARK --set-xmark 0x4/0xffffffff
它在目标端口 10000 的所有 udp 数据包上设置 fwmark 4。我使用基于策略的路由将其转发到隧道(没有任何 nat):
[root@localhost ~]# ip rule
0: from all fwmark 0x4/0x4 lookup 87
32765: from all lookup local
32766: from all lookup main
32767: from all lookup default
[root@localhost ~]# ip route show table 87
default dev tunnel scope link
如果数据包来自普通 NIC(eth0
等),则一切正常,但在环回接口上传输的数据包(lo
例如使用 生成的数据包socat -u - UDP:localhost:10000
)似乎会跳过PREROUTING
链后的路由决策,并被本地主机接收(实际上它通过lo
接口回复 ICMP 端口不可达数据包)。
这是预期的行为吗?如果是这样我该如何解决这个问题?我需要数据包对于不同的输入设备没有不同的路径,因为我想用它lo
来测试更复杂的 iptables 规则集(也就是说,带有 nat 的额外规则对我来说不是一个解决方案)。
答案1
这里涉及到一些事情。
本地框的输出使用OUTPUT
表,而不是PREROUTING
.PREROUTING
用于流经盒子的流量。
iptables 规则仅在数据包发送时匹配。当客户端打开连接时,它必须在生成单个数据包之前绑定到一个地址。当它绑定时,它根据路由规则选择源地址,而不咨询 iptables。
当您测试使用127.0.0.1
作为目的地并发送数据包时,它会尝试使用127.0.0.1
作为源地址发送,默认情况下内核不允许路由。
如果解决了这个问题,当数据包离开接口并且具有远程系统不知道如何返回的源地址时,您将遇到另一个问题。
因此解决方案是三件事:
1)将规则添加到OUTPUT表中:
iptables -t mangle -A OUTPUT -p udp -m udp --dport 10000 -j MARK --set-xmark 0x4/0xffffffff
2) 启用本地网络路由:
sysctl -w net.ipv4.conf.$iface.route_localnet=1
$iface
你的隧道接口在哪里。
3) 添加一条MASQUERADE
规则,以便重写离开接口的流量的源地址:
iptables -t nat -A POSTROUTING -o $iface -m addrtype --src-type LOCAL -j MASQUERADE
但请注意,在测试将流量发送到 时127.0.0.1
,您仍然可能会遇到问题。没有任何东西会重写目标地址,因此它会被路由出去,$iface
目的地为127.0.0.1
。远程系统可能会拒绝此流量。