[Kamailio-Users] [sr-dev] Inbound NAT detection and fix_nated_register() very poorly documented
Alex Balashov
abalashov at evaristesys.com
Thu Nov 26 14:45:25 CET 2009
I sent this message to K-users and sr-dev, and only saw it appear on
sr-dev. Was it delivered to K-users? Also, I wrote a reply to myself
following up and it appeared on neither list.
Alex Balashov wrote:
> Greetings,
>
> I was faced with the following problem in Kamailio 1.5.2: I was using
> nathelper + rtpproxy + registrar and needed to relay media for calls
> going inbound to a NAT'd registrant through rtpproxy - only if the
> registrant is NAT'd.
>
> Here is the scenario:
>
> Media gateway Kamailio
> (on public IP) ----> registrar -----> NAT'd registrant
> (w/nathelper)
>
> I was handling registrations from NAT'd endpoints like this:
>
> if(nat_uac_test("1")) {
> force_rport();
> fix_nated_contact();
> }
>
> I was aware of fix_nated_register() but was not clear on its
> relationship to the 'received_param' parameter stored in 'location' and
> set as a modparam to both the 'registrar' and 'nathelper' modules, so I
> was not using it.
>
> Very quickly I ran into an obvious problem: if the contact stored in
> the 'contact' column in 'location' is already fixed up with the received
> IP:port, there is no way to know that the endpoint to which the call is
> going is behind NAT -- when lookup() is called, the RURI is set to the
> public IP:port. There are no flags of any kind that one can set during
> save() that persist while the contact binding is present for that AOR
> and can be resurrected on lookup().
>
> Anyway, I eventually figured out how to fix this problem by empirical
> means, with no clear help from the nathelper documentation. It turns
> out that if I set the 'received_param' as a modparam to 'nathelper' and
> 'registrar' and handle registrations from NAT'd endpoints with
> fix_nated_register() instead, it will magically work.
>
> I made the following discoveries to arrive at this conclusion, both of
> which are not documented. This is why it will work:
>
> 1) When the original (RFC1918) 'contact' is stored in the 'location'
> table (if using DB, which I am), the 'received' parameter is stored
> alongside it and contains the public IP:port.
>
> When lookup() is called, the RURI domain is set to private address, e.g.
>
> if(!lookup("location")) {
> # Error handling here
> exit;
> }
>
> xlog("L_INFO", "[R-2:$ci] -> Registration resolved to RURI: $ru\n"):
>
> $ru here will contain something like this: sip:s at 10.1.0.2:5060, the
> original and unmodified contact supplied by the UAC.
>
> But somehow, magically, when t_relay() is called the request will be
> relayed to a different RURI - one with the 'received' IP:port
> substituted in the domain portion. So, the request goes end up going to
> the correct place.
>
> This is, of course, because of the way the 'received' parameter is
> supposed to work when appended to a Contact URI. But the point is that
> it is not documented; nowhere in the documentation for lookup() or
> t_relay() does it say that this will transpire, and I have no way of
> knowing it except by observation.
>
> 2) For some reason, nat_uac_test("1") returns a positive result after
> the lookup() and confirms that the destination is NAT'd.
>
> This allows me to set a flag and then mangle the SDP in the reply to use
> rtpproxy for NAT traversal of media as well, e.g.
>
> route[2] {
>
> ...
>
> if(!lookup("location")) {
> # Error handling here
> exit;
> }
>
> if(nat_uac_test("1"))
> setflag(9);
>
> ...
>
> t_on_reply("1");
>
> if(!t_relay())
> sl_reply_error();
>
> ...
> }
>
> ...
>
> onreply_route[1] {
> if(t_check_status("(180|183|200)")) {
>
> if(nat_uac_test("5"))
> fix_nated_contact();
>
> if(search("Content-Type: application/sdp")) {
> if(isflagset(9)) {
> set_rtp_proxy_set("1");
> force_rtp_proxy();
> }
> }
>
> }
> }
>
> But if you examine carefully the documentation for nat_uac_test(), it
> says the following for bit flag 1:
>
> * 1- Contact header field is searched for occurrence of RFC1918
> addresses.
>
> To me this means that nat_uac_test() should not work after the lookup()
> above. The only Contact header value that is present in the inbound
> INVITE handler is the Contact URI of the media gateway, which is a
> public IP address! Yet for some reason it works, as if by magic;
> apparently it is somehow implicit that a hidden "received" attribute of
> the RURI is also part of this check.
>
> This is also not documented, and is completely counterintuitive.
>
> Is there any possibility of clearing up documentation as to this point?
> Perhaps I have done something wrong here unknowingly; I have no idea.
> I know that my solution works but I cannot justify why in terms of the
> documentation. Is it very much to ask that the documentation be
> explicit about hidden but critically important mysteries like this?
>
> Thanks!
>
> -- Alex
>
--
Alex Balashov - Principal
Evariste Systems
Web : http://www.evaristesys.com/
Tel : (+1) (678) 954-0670
Direct : (+1) (678) 954-0671
More information about the Users
mailing list