How do I make NAT table work reliably?
constfilin at yahoo.com
Fri Aug 18 22:13:54 CEST 2006
I am developing some telephony server and - obviously - have lots of
RTP/UDP audio traffic going on through my server.
Currently, when the server is bridging two SIP telephones "T1" and "T2"
into a call, it has telephone "T1" send audio to a UDP socket "S1"
opened on the server, reads data from this socket and writes it to another
socket "S2" opened for the outgoing audio to telephone "T2" (for a reason
I cannot send RE-INVITE to the telephones and have them talk directly).
Here's a picture:
T1 at 184.108.40.206 --udp audio--> S1-server at 220.127.116.11-S2 --udp audio--> T2 at 18.104.22.168
The server does not do anything with the packets coming from "S1" -
just copies them directly to "S2". The problem with this setup is that
each packet form "T1" hits the interface on server, goes into kernel,
from there it is copied to the user space on the server application,
from there back to the kernel space for the outgoing socket "S2" and
then leaves the server. That's a lot of memory copying without real need.
What I'd like to happen is setup NAT with iptables so that all UDP packets
from "T1" hitting the network interface on server go through DNAT and SNAT
to be sent directly to "T2", without being copied into the user space.
Here's the setup of my nat table (22.214.171.124 is server's IP):
[root at ast-mv ~/Work/AsteriskPilot/asterisk/cpp]# /sbin/iptables-save -c -t nat
# Generated by iptables-save v1.3.5 on Fri Aug 18 12:43:28 2006
:PREROUTING ACCEPT [62131:9673404]
:POSTROUTING ACCEPT [12841:1191046]
:OUTPUT ACCEPT [18958:2414567]
[0:0] -A PREROUTING -s 126.96.36.199 -d 188.8.131.52 -p udp -m udp --sport 8000 --dport 23330 -j DNAT --to-destination 184.108.40.206:25590
[0:0] -A PREROUTING -s 220.127.116.11 -d 18.104.22.168 -p udp -m udp --sport 25590 --dport 21226 -j DNAT --to-destination 22.214.171.124:8000
[0:0] -A PREROUTING -s 126.96.36.199 -d 188.8.131.52 -p udp -m udp --sport 8001 --dport 23331 -j DNAT --to-destination 184.108.40.206:25591
[0:0] -A PREROUTING -s 220.127.116.11 -d 18.104.22.168 -p udp -m udp --sport 25591 --dport 21227 -j DNAT --to-destination 22.214.171.124:8001
[0:0] -A POSTROUTING -d 126.96.36.199 -p udp -m udp --dport 25590 -j SNAT --to-source 188.8.131.52:21226
[844:168800] -A POSTROUTING -d 184.108.40.206 -p udp -m udp --dport 8000 -j SNAT --to-source 220.127.116.11:23330
[0:0] -A POSTROUTING -d 18.104.22.168 -p udp -m udp --dport 25591 -j SNAT --to-source 22.214.171.124:21227
[0:0] -A POSTROUTING -d 126.96.36.199 -p udp -m udp --dport 8001 -j SNAT --to-source 188.8.131.52:23331
# Completed on Fri Aug 18 12:43:28 2006
This routing is established dynamically by writing commands to STDIN
of "/sbin/iptables-restore --noflush -t nat". Server writes these commands
after "T1" has already began sending packet to "T2" and therefore the server
also resets conntrack cache using libnetfilter_conntrack library nfct_delete_conntrack()
function after issuing the commands.
The problem is that this setup works unreliably and this can be seen
from 2 things:
1) 0 counters of NATed packets and bytes,
2) No audio on "T2".
It appears that nat table is simply not seeing the packets it has to NAT
(although tcpdump shows that the do come to the server). I've tried everything
I could think of - including automated resets of conntrack entries every
few seconds by server.
Does anybody have ideas what else can be done to nat table reliably see the
packets it has to NAT?
More information about the netfilter