[VoiceOps] OpenSIPS/Kamailio serving far end nat traversal

Alex Balashov abalashov at evaristesys.com
Thu May 26 19:49:02 EDT 2011


On 05/26/2011 07:17 PM, IP Phone Guy wrote:

> Would mind giving me a run down of how it works and possibly some
> example configurations?  I've done this with an ACME packet before
> but never done it with an open source product... I can't find any
> information on the respective websites and was hoping I could get
> some information out of the list here.

Sure.  So, there are two aspects to far-end NAT traversal;  the first is 
dealing with signaling, the second is dealing with media.

In the case of signaling, you can either assume all the SIP endpoints 
are NAT'd, or you can use the 'nathelper' module's NAT detection 
routines to attempt to pinpoint them.

 
http://www.kamailio.org/docs/modules/3.1.x/modules_k/nathelper.html#id2603175

Its NAT test functions work by (1) looking for obvious instances of RFC 
1918 private IPs in some combination of the Via header, Contact URI (if 
applicable) and the media endpoint address in the SDP body, depending on 
which of these are applicable, and (2) looking for inconsistencies 
between the endpoint addresses announced in the message body and the 
source addresses and ports from which the message is actually received 
on the network and transport layer.  There are flags provided as 
arguments to nat_uac_test() that can be AND'd together to meet your needs.

The nat_uac_test() approach is generally a fine way to proceed if you 
have a mixture of NAT'd and directly reachable devices, but can bite you 
if you have directly reachable devices on a private RFC 1918 subnet, 
since a lot of those tests will take the mere presence of those 
addresses as evidence of a NAT'd endpoint.

Next, you call some functions exported by 'nathelper' to apply some 
"fixups" to the private or inconsistent addresses seen in Via, Contact, 
etc.  Which should be applied depends on the type of request that you 
are handling;  in the case of REGISTER, you should probably use 
fix_nated_register() and for INVITEs, fix_nated_contact().  You can, of 
course, use fix_nated_contact() on AOR bindings in REGISTER too.  The 
"fixups" substitute the actual Layer 3 & 4 received address:port 
combination for the private addresses declared in the message body.

The media is a slightly different issue, and depends on what kind of 
far-end signaling agent and media gateway element your endpoints are 
talking to.

Almost all media endpoints today require symmetrical RTP, which means 
they expect to receive RTP on the same port from which they send it, and 
that's also the port they advertise in the SDP offer/answer.  The 
problem is that almost no NAT gateway/CPE out there (including 
supposedly intelligent SIP ALGs) understands SIP, and especially SDP 
semantics or keeps state enough to create the appropriate stateful 
connection tracking/NAT mappings for the port actually advertised in the 
SDP.

Thus, you'll get a scenario where some private endpoint like, say, 
192.168.1.10 will advertise port 27910 in its SDP offer when making an 
outbound call, and the NAT router will pass that SDP body through 
unadulterated.  But in reality, when the endpoint actually starts 
sending media, the NAT router will remap the source port to say, 52500. 
  If the far end follows the SDP offer, it will attempt to send RTP 
_back_ to external.ip:27910 (which is the extent of what you will have 
told it to do just with signaling fixups alone), which of course will 
not work since the NAT gateway is unaware that external.ip:27910 is 
supposed to be mapped back to 192.168.1.10:27910.

The workaround is, of course, for the media gateway to ignore the port 
in the SDP and instead listen for the genuine source port of the media 
on the transport layer, and use that to send media back.  If you happen 
to have a media gateway on the far end that can do this draft-comedia 
style NAT detection, you're set.  Most commercial equipment out there 
has the capability to do this, but it isn't necessarily enabled.  If you 
have a softswitch or SBC or what have you that can do it, do it.

However, if you're routing this traffic to, say, most Tier 1 ITSPs and 
CLECs' edge equipment, they are not going to do this for you for a 
variety of technical and policy reasons.  Thus, you're going to need 
some sort of media relay which has the intelligence to perform the 
aforementioned sensing for you.  Asterisk's 'nat=yes' option enables in 
this functionality.

Kamailio and OpenSIPS work with a variety of third-party media relays 
via various API control sockets.  The media relays don't necessarily 
have to be on the same host as the SIP proxy, and you can have multiple 
ones.

The major ones are 'rtpproxy' by Maxim Sabolev and MediaProxy from AG 
Projects, as well as the newer 'iptrtpproxy' from the 
Kamailio/sip-router side.  The latter two are Linux kernel-bound and use 
netfilter conntrack APIs for forwarding, which will get you closest to 
wire speed.  'rtpproxy' in contrast is a userspace process and won't 
perform quite as well, but can still deliver a respectable 1000+ calls 
per box on the right hardware.  It is also by far the simplest to set 
up, use and administer for a relatively low call volume, which is why I 
recommend it.

In that case, instead of using fix_nated_sdp() in 'nathelper', you just 
use the 'rtpproxy' module and engage the 'rtpproxy' as appropriate in 
SDP-bearing requests and replies:

    http://www.kamailio.org/docs/modules/3.1.x/modules_k/rtpproxy.html

You don't want to blindly engage it for all requests and replies;  I'd 
definitely ensure they have an SDP payload:

    if(search("Content-Type: application/sdp")) ...

And, of course, it goes without saying that you'll need to associate 
(stateful/TM) reply handlers with your initial request handlers to make 
this work.  You'll also need to shut down the rtpproxy relay for the 
given dialog once it's torn down, i.e. on BYE, and when it's aborted, on 
CANCEL (you will have already engaged 'rtpproxy' at that point on the 
initial INVITE request and subsequent non-100 1xx provisional reply, so 
as to handle in-band ringback, etc.).

There are various config examples bundled with the package, though they 
strike me as being a bit out of date and at times, somewhat facile and 
incomplete.  Still, they convey the general idea:

 
http://git.sip-router.org/cgi-bin/gitweb.cgi?p=sip-router;a=blob;f=examples/kamailio/nathelper.cfg;h=56c0caec4d2f1402ad8fa642bbd6d5df74c1ec71;hb=HEAD

Possible complications:

1. Re-invites, especially where the media stream pivots;  you'll need to 
handle sequential (in-dialog / loose_route()'d / To-tag-having) INVITEs 
and their replies and pivot the 'rtpproxy' stream with them.

2. Dumb consumer NAT router ALGs that throw a wrench in your plans by 
trying to 'help' you on the near end, and screwing all your NAT 
detection and traversal up in the process.  If at all possible, all SIP 
ALGs on the customer side should be disabled;  without question, they do 
more harm than good.

3. Firewall/routing issues surrounding all this;  there needs to be full 
UDP reachability to and from the media relay from both the far and near 
ends, which can be a problem if you use a lot of stateful firewall rules 
reliant on not admitting arbitrarily-appearing non-connection-oriented 
streams from third parties, e.g. ESTABLISHED,RELATED 'iptables' rules 
with Linux.

Best of luck.  Please let me know if there are any other questions or 
specifics I can provide.

Cheers,

-- Alex

-- 
Alex Balashov - Principal
Evariste Systems LLC
260 Peachtree Street NW
Suite 2200
Atlanta, GA 30303
Tel: +1-678-954-0670
Fax: +1-404-961-1892
Web: http://www.evaristesys.com/


More information about the VoiceOps mailing list