我正在尝试使用 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
然而,这不起作用,因为 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
我可以确认这两个命令分别工作,并且当两者位于同一规则层次结构中时,只有一个命令有效。
我也尝试过使用TEE
其中一个 IP 作为另一个网关,但这也不起作用。有没有办法在 iptables 中做到这一点,或者我在创建多目标通用 UDP 转发器时错过了标记?
UDP 数据包应同时分发并复制到每个相应的服务器。目前的用例是服务器 A 和服务器 B 上的进程都需要 UDP 数据包,但从发送数据包的源端来看,它只能指向一台服务器。即:发送udp数据包的服务器C->服务器D->复制并发送数据包到服务器B和服务器A。
感谢您的任何帮助或建议。
答案1
简单的用户态工具
首先,我建议使用在服务器 D 上运行的专用工具,该工具将侦听 UDP 数据包,并发送两次副本,一次用于 A,一次用于 B。这可以通过以下方式完成bash 进程替换+球座+索卡特(示例大致改编自udp-multi-socat.sh
以其方便的相反顺序,有球座立即运行),但我不知道在某些情况下是否可能不会发生某些缓冲(最好创建一个专用应用程序):
socat -U - udp4-recv:3070 | tee >(socat -u - udp4-datagram:167.111.111.111:5640) | socat -u - udp4-datagram:192.111.111.111:5640
使用内核(iptables ... -j TEE)
也就是说,对于“内核辅助”方法,有 iptables 的球座可以复制数据包的目标。由于复制必须绕过正常的路由处理,因此需要将复制的数据包“撤离”到其他可直接访问的主机(--网关范围)。如果没有这个,似乎没有好的方法来处理复制的数据包球座。
公平地说,我们可以使用网络命名空间创建该主机。然后通过路由堆栈和 iptables 将重复流量重新注入到主机 D 上,现在可以以不同的方式对其进行 DNAT(因为它来自其他接口)。由于不对称路由和重复流程,必须进行一些调整(宽松rp_过滤器在虚拟接口上,以及不同的 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
使用这种方法,即使 A 和 B 的回复都可以发送回 C(C 会认为它们都来自同一个初始目的地),如果这有意义的话。因此,如果 A 上没有监听任何内容或者乙,一个ICMP 目标端口不可达将被发送到源 C,源 C 可能会选择中止:可能应该在某处添加额外的防火墙来避免这种情况。