Linux

使用 iptables 和 PREROUTING 將 UDP 數據包設置到兩個不同的目的地

  • November 23, 2019

我正在嘗試使用 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。

感謝您的任何幫助或建議。

簡單的使用者空間工具

首先,我建議使用在伺服器 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

使用核心(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

使用這種方法,即使 A 和 B 的回复都可以發送回 C(它會認為它們都來自同一個初始目的地),如果這仍然有意義的話。因此,如果 A或B上沒有任何東西在偵聽,則無法訪問的ICMP 目標埠將被發送到源 C,它可能會選擇中止:可能應該在某處添加額外的防火牆來避免這種情況。

引用自:https://unix.stackexchange.com/questions/553334