Iptables – Conntrack is blocking UDP NAT

conntrackiptablesudp

I'm working on an application that should relay udp packets from one host to another according to some rules. It is basically NAT.

I negotiate UDP ports with both hosts and after that I need to receive from host A and send to host B with the negotiated ports.

So i'm dinamically adding and removing iptables rules.

# my address is 10.1.1.1
# A is 10.10.10.10:30590 - 10.1.1.1:36232 
# B is 10.20.20.20:30588 - 10.1.1.1:36230 

# A to B
iptables -t nat -A PREROUTING -s 10.10.10.10/32 -i eth0 -p udp -m udp --sport 30590 -j DNAT --to-destination 10.20.20.20:30588
iptables -t nat -A POSTROUTING -d 10.20.20.20/32 -p udp -m udp --dport 30588 -j SNAT --to-source 10.1.1.1:36232

# B to A
iptables -t nat -A PREROUTING -s 10.20.20.20/32 -i eth0 -p udp -m udp --sport 30588 -j DNAT --to-destination 10.10.10.10:30590
iptables -t nat -A POSTROUTING -d 10.10.10.10/32 -p udp -m udp --dport 30590 -j SNAT --to-source 10.1.1.1:36230

And this works most of the time, however, sometimes the first packets start to arrive before the rules are added. Clearing UDP "connections" makes the rules work ( conntrack -D -p udp ).

I've triyed to disable connection tracking using rules like:

iptables -t raw -A PREROUTING -j NOTRACK
iptables -t raw -A OUTPUT -j NOTRACK

# or 
iptables -t raw -A PREROUTING -j CT --notrack
iptables -t raw -A OUTPUT -j CT --notrack

But none of these seem to work.

Will the only solution be to clear the UDP connection tracking for every stream?

I need to support thousands of concurrent streams, and several being added and removed every second.


Edit 2020:

We ended up using BPF XDP to manage the streams and it is working pretty well!

Best Answer

Disabling connection tracking is not suitable as NAT depends on connection tracking, so NAT will stop working.

You must clear any relevant existing connection tracking records after the NAT rules are inserted, so that any subsequent arriving packets will check the nat table for the new DNAT/SNAT rules instead of just looking up the 'cached' result.

However, you can target it to be more specific than conntrack -D -p udp which affects all udp connection tracking records; for example, conntrack -D -p udp --src <ip> --sport <port> --dst <ip> --dport <port> would let only clear records for the specific src/dst ip and port pairs.