[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