使用 iptables 和 PREROUTING 将 UDP 数据包设置到两个不同的目的地

ipt*_*ior 3 linux ubuntu iptables udp iptables-redirect

我正在尝试使用 iptables 将数据包上的 UDP 发送到两个不同的外部/远程 IP。

目前我正在运行一个如下所示的命令:

iptables -t nat -A PREROUTING -i eth0 -p udp --dport 3070 -j DNAT --to-destination 192.111.111.111:5640
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 3070 -j DNAT --to-destination 167.111.111.111:5640
Run Code Online (Sandbox Code Playgroud)

然而,这不起作用,因为 UDP 数据包会查看 iptables 的规则,然后转到192.111.111.111:5640. 将另一个规则放在第一位会使 UDP 数据包到达第二个目的地。我尝试使用其范围功能组合实际的目的地,但数据包不会到达任何地方,因为这些范围不是内部 IP:

iptables -t nat -A PREROUTING -i eth0 -p udp --dport 3070 -j DNAT --to-destination 192.111.111.111-167.111.111.111:5640-5640

### note: I also tried
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 3070 -j DNAT --to-destination 192.111.111.111-167.111.111.111:5640-5641

where the port is increased by one on the secondary server
Run Code Online (Sandbox Code Playgroud)

我可以确认这两个命令分别工作,并且当两者位于同一规则层次结构中时,只有一个命令有效。

我也尝试过使用TEE其中一个 IP 作为另一个网关,但这也不起作用。有没有办法在 iptables 中做到这一点,或者我在创建多目标通用 UDP 转发器时错过了标记?

UDP 数据包应同时分发并复制到每个相应的服务器。目前的用例是服务器 A 和服务器 B 上的进程都需要 UDP 数据包,但从发送数据包的源端来看,它只能指向一台服务器。即:发送udp数据包的服务器C->服务器D->复制并发送数据包到服务器B和服务器A。

感谢您的任何帮助或建议。

A.B*_*A.B 7

简单的用户态工具

首先,我建议使用在服务器 D 上运行的专用工具,该工具将侦听 UDP 数据包,并发送两次副本,一次用于 A,一次用于 B。这可以通过bash 进程替换+ tee + socat来完成(例如松散地改编自udp-multi-socat.sh其方便的反向顺序,让tee立即运行),但我不知道在某些情况下是否可能不会发生某些缓冲(最好创建一个专用应用程序):

socat -U - udp4-recv:3070 | tee >(socat -u - udp4-datagram:167.111.111.111:5640) | socat -u - udp4-datagram:192.111.111.111:5640
Run Code Online (Sandbox Code Playgroud)

使用内核(iptables ... -j TEE)

也就是说,对于“内核辅助”方法,iptables 的TEE目标可以复制数据包。由于复制必须绕过正常的路由处理,因此需要将复制的数据包“疏散”到可直接访问的其他主机(--gateway参数)。如果没有这个,似乎没有好的方法来使用TEE处理复制的数据包。

公平地说,我们可以使用网络命名空间创建该主机。然后通过路由堆栈和 iptables 将重复流量重新注入到主机 D 上,现在可以以不同的方式对其进行 DNAT(因为它来自其他接口)。由于不对称路由和重复流,必须进行一些调整(虚拟接口上松散的rp_filter ,以及不同的 conntrack(原始)区域来区分流,因为conntrack只了解 IP,而不了解接口)

以下是在服务器 D 上使用的配置(可能可以避免一些重复,但可读性较差):

ip netns del dup 2>/dev/null || : # to remove previous instance, if needed
ip netns add dup

ip link add name dup1 type veth peer netns dup name eth0
ip link set dup1 up
ip -n dup link set eth0 up
ip address add 10.10.10.1/24 dev dup1
ip -n dup address add 10.10.10.2/24 dev eth0
ip -n dup route add default via 10.10.10.1
sysctl -q -w net.ipv4.conf.dup1.rp_filter=2
ip netns exec dup sysctl -q -w net.ipv4.conf.eth0.forwarding=1
iptables -t mangle -A PREROUTING -i eth0 -p udp --dport 3070 -j TEE --gateway 10.10.10.2
iptables -t raw -A PREROUTING -i dup1 -p udp --dport 3070 -j CT --zone-orig 1
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 3070 -j DNAT --to-destination 192.111.111.111:5640
iptables -t nat -A PREROUTING -i dup1 -p udp --dport 3070 -j DNAT --to-destination 167.111.111.111:5640
Run Code Online (Sandbox Code Playgroud)

使用这种方法,即使 A 和 B 的回复都可以发送回 C(C 会认为它们都来自同一个初始目的地),如果这有意义的话。因此,如果 A或B上没有任何监听,则ICMP 目标端口不可达将被发送到源 C,源 C 可能会选择中止:可能应该在某处添加额外的防火墙来避免这种情况。