1

I am trying to send a UDP on a packet to two different external/remote IPs using iptables.

Currently I am running a command that looks like this:

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

However, this does not work, because the UDP packet looks at the iptables' rules, and goes to 192.111.111.111:5640. Putting the other rule first makes the UDP packet go to that second destination. I tried combining the actual to-destinations using their range functionality, but the packet does not go anywhere, as these ranges are not internal IPs:

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

I can confirm that both commands work separately, and that only one works when both are in the same rule hierarchy.

I have also tried to use TEE to make this work, pointing to one of the IPs as another gateway, but that doesn't work either. Is there any way to do this in iptables, or am I missing the mark in creating a multi-destination general UDP forwarder?

The UDP packets should both be distributed at the same time/simultaneously and duplicated to each respective server. The use case at the moment is that the UDP packet is needed for a process on Server A as well as in Server B, but from the source side that is sending the packet, it can only point to one server. ie: Server C that sends udp packets -> Server D -> duplicate and send packet to Server B and Server A.

Thanks for any help or suggestions.

  • Hey A.B, thanks, the packets shoiuld both be distributed at the same time/simultaneously. The use case at the moment is that the UDP packet is needed for a process on Server A as well as in Server B, but from the source side that is sending the packet, it can only point to one server. ie: Server C that sends udp packets -> Server D -> duplicate and send packet to Server B and Server A Does this make sense? @A.B – iptable_warrior Nov 21 '19 at 9:08
  • I have updated the description @A.B – iptable_warrior Nov 21 '19 at 9:17
  • So did you ever try my answer? – A.B Nov 25 '19 at 23:03
  • I did, I used samplicator in the end, as it did my desired result, however using kernal with tee was another way of accomplishing the same task gracefully. Thanks for the help! I marked it as correct for posterity's sake! – iptable_warrior Nov 27 '19 at 2:46
  • Ah yes, samplicator is a nice tool. – A.B Nov 27 '19 at 6:25
0

Simple userland tools

First I would recommend using a dedicated tool running on server D that will listen for UDP packets, and will send a copy twice, one for A and one for B. This could be done for example with bash process substitution+tee+socat (example loosely adapted from udp-multi-socat.sh with its handy reversed order, to have tee immediately running) , but I don't know if some buffering might not happen in some cases (better create a dedicated application):

socat -U - udp4-recv:3070 | tee >(socat -u - udp4-datagram:167.111.111.111:5640) | socat -u - udp4-datagram:192.111.111.111:5640

Using kernel (iptables ... -j TEE)

Now that is said, for a "kernel-assisted" method, there's iptables's TEE target which can duplicate packets. Because the duplication has to bypass the normal routing handling, it requires to "evacuate" the duplicated packet to an other host directly reachable (the --gateway parameter). Without this, it appears there's no good way to handle the copied packet with TEE.

Fair enough, we can just create that host using a network namespace. Then reinject right back the duplicated traffic on host D, through the routing stack and iptables which can now DNAT it differently (because it came from an other interface). Because of the assymetric routing and the duplicate flow some adjustements have to be done (loose rp_filter on the virtual interface, and a different conntrack (origin) zone to differentiate the flows, because conntrack knows only about IPs, not interfaces)

Here's the configuration to use on Server D (some duplication could probably be avoided, but it would be less readable):

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

With this method even replies from A and B can both be sent back to C (which will think they both came from the very same initial destination), if this makes sense anyway. So if nothing is listening on A or B, an ICMP destination port unreachable will be sent to source C, which might choose to abort: additional firewalling to avoid this should probably be added somewhere.

  • Btw, the use of TEE and the additional namespace could probably be replaced with tc ... mirred egress mirror on a pair of veth interfaces staying in the host network namespace. – A.B Nov 23 '19 at 1:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.