我正在尝试完成以下任务:我有一个盒子,里面有一个服务正在监听虚拟接口(比如 172.16.0.1),udp 端口 5555。现在我想要做的是获取到达接口 eth0(1.1.1.1:5555)和 eth1(2.2.2.2:5555)的数据包,并将它们转发到虚拟接口上的服务,然后让回复通过它们进入的相同物理接口返回到客户端。客户端必须认为它们正在与 1.1.1.1:5555 或 2.2.2.2:5555 通信。我认为我需要混合使用 iptables 规则和数据包标记,再加上一些 iproute 规则(如果可能的话)。我尝试捕获来自 eth0 和 eth1、udp 端口 5555 的数据包,并分别用 1 和 2 标记它们,并在 connmark 中使用 --save-mark。然后我使用 DNAT 到 172.16.0.1。该服务似乎正在获取数据包。现在我不确定如何进行反向操作。对于来自盒子的数据包,似乎在路由决策之前您无法执行任何操作,但那将是恢复标记的地方,从而根据这些标记做出路由决策。这是我目前所拥有的:
iptables -t mangle -A PREROUTING -d 1.1.1.1 -p udp --port 5555 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -d 2.2.2.2 -p udp --port 5555 -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -d 1.1.1.1 -p udp --port 5555 -j CONNMARK --save-mark
iptables -t mangle -A PREROUTING -d 2.2.2.2 -p udp --port 5555 -j CONNMARK --save-mark
iptables -t nat -A PREROUTING -m mark --mark 1 -j DNAT --to-destination 172.16.0.1
iptables -t nat -A PREROUTING -m mark --mark 2 -j DNAT --to-destination 172.16.0.1
# What next?
正如我所说,我甚至不确定是否可以做到。先介绍一下背景,这是一个旧的 OpenVPN 安装,无法升级(否则我会安装一个原生支持多宿主的最新版本)。
谢谢你的帮助。
答案1
您是否尝试过直接使用 NAT(通过 REDIRECT 目标)来执行此操作?Conntrack 应该负责处理返回数据包,无需手动标记。
答案2
我想我已经让它工作了,以下是我所做的,以防将来对其他人有用:
iptables -t mangle -A PREROUTING -i eth0 -d 1.1.1.1 -p udp --dport 5555 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -i eth1 -d 2.2.2.2 -p udp --dport 5555 -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth0 -p udp --dport 5555 -j CONNMARK --save-mark
iptables -t mangle -A PREROUTING -i eth1 -p udp --dport 5555 -j CONNMARK --save-mark
# nat PREROUTING comes after mangle PREROUTING
iptables -t nat -A PREROUTING -m mark --mark 1 -j DNAT --to-destination 172.16.0.1
iptables -t nat -A PREROUTING -m mark --mark 2 -j DNAT --to-destination 172.16.0.1
# restore mark from packets originating from 172.16.0.1, as it triggers a new routing decision
iptables -t mangle -A OUTPUT -s 172.16.0.1 -p udp --sport 5555 -j CONNMARK --restore-mark
ip rule add prio 20 fwmark 1 lookup upstream0
ip rule add prio 21 fwmark 2 lookup upstream1
OpenVPN 仅绑定到 172.16.0.1(分配给接口 dummy0),并获取客户端发送到 1.1.1.1:5555 或 2.2.2.2:5555 的所有流量。
答案3
我不明白这有什么帮助:
通过将目标 IP 更改为传入接口的主地址,将数据包重定向到机器本身
传入数据包已发送到传入接口的地址(即 1.1.1.1 或 2.2.2.2)。或者我可能没有理解您的意思,如果是那样的话,请原谅。
我忘了补充,如果该解决方案看起来有些过度,那是因为我首先尝试了更简单的解决方案,即让服务监听 0.0.0.0:5555 并使用数据包标记,但我再次没有看到在哪里恢复本地生成的 UDP 数据包的标记。
如果我切换到 TCP,一切都会正常工作,甚至不需要标记(不确定具体原因);当然,我仍然需要基于源的路由规则,但这样它就“正常工作”了。如果我无法使用 UDP 使其工作,我可能会切换到 TCP(尽管 TCP 的性能最差)。我猜测 TCP 工作而 UDP 不工作的原因是因为 UDP/IP 数据包在到达路由决策时没有设置源地址,因此地址在路由后“填写”,这将选择默认路由或多路径组中的随机路由,并且不会与原始传入接口匹配(或者它会匹配,但只是偶然)。另一方面,TCP/IP 数据包在到达路由阶段时已经有一个源地址(并且它是正确的),因此可以使用基于源的路由规则。这只是一个猜测,如果有人发现一些错误,我非常乐意接受纠正。
谢谢。