Hi folks
I've configured Kamailio as a simply multi-homed proxy offering NAT traversa, TCP connection management, etc to FreeSWICH behind it. FreeSWITCH acts as the registrar.
I'm trying to understand the default config and the following things don't make sense to me (I can't find documentation on these):
1. The nat=yes flag. What does it mean exactly and why is it on the RR and not on the Contact/R-URI? Also, when double RR is enabled, why does it get added to both headers?
2. The FLT_NATS and FLB_NATB flags. I'd like to know what this stands for, I guess "flag for transaction - NAT" and "flag for branch - NAT" but what do the S and the B stand for? More importantly what do these flags mean? Is it correct to say that the first indicates the UAC / A-leg / requester is behind NAT and the second that the UAS / B-leg / responder is behind NAT?
3. In the the NATMANAGE route of the default config we have:
if (is_request()) { if(has_totag()) { if(check_route_param("nat=yes")) { setbflag(FLB_NATB); } } }
Which to me means "if the message is a request inside an existing dialog ..." and I'm thinking, isn't this a bit late in the dialog to be setting NAT flags? I would expect to set the flag for the A-leg on the incoming request, and the flag for the B-leg on the incoming reply. I can't point in waiting for the ACK to try and work out whether this leg is behind NAT. And also it seem this set of if statements will also match incoming requests from the A-leg, so why are we setting a brach flag? Does that leg also also get the properties of a branch?
4. When I get a 200 OK coming from behind NAT it is not subjected to fix_nated_contact(), and this seems to be because it doesn't have the FLB_NATB flag set:
if (is_reply()) { if(isbflagset(FLB_NATB)) { fix_nated_contact(); } }
Any help clarifying would be much appreciated.
Thanks, Richard
-- Richard Brady
Hi Richard!
On 22.06.2012 01:33, Richard Brady wrote:
Hi folks
I've configured Kamailio as a simply multi-homed proxy offering NAT traversa, TCP connection management, etc to FreeSWICH behind it. FreeSWITCH acts as the registrar.
I'm trying to understand the default config and the following things don't make sense to me (I can't find documentation on these):
- The nat=yes flag. What does it mean exactly and why is it on the RR
and not on the Contact/R-URI? Also, when double RR is enabled, why does it get added to both headers?
Kamailio is not dialog-stateful. Thus, when routing an in-dialog request, Kamailio does not know if a media-relay was activated with the initial INVITE. Thus, a "record-route cookie" is used to store the information for the whole dialog.
The proper location (contact or RR) depends on the exact meaning of nat=yes, e.g. it only signal if a media relay is used or also if the client needs NAT-traversal for SIP. In the first case it is a property of the call, in the later case it is a property of the caller/callee. Thus, in the later the contact/RURI would be fine too - but there are also other aspects: for example a call is routed via 2 SIP providers. If both store data in the contact/RURI, then both use the same data location and may confuse the other SIP proxy. If you store the cookie in the RR/Route header, then the cookie will only be interpreted by the proxy which inserted the cookie.
Regarding RR: This is just an implementation thing. IIRC the topmost RR is just ignored and the second (which is relevant as it defines the outgoing socket) is used - but depending of the direction of the request you need the cookie in both Route headers.
Thus, as you see there is not a single "correct" version to do it, but this one seems to work fine.
In the early days I had an "academic" approach and activated NAT-traversal (RTP and SIP) only when really needed and stored the data more detailed using for example: nat=both, nat=caller, nat=callee and nat=none. It was nice and worked - but nowadays I choose the pragmatic approach: always enforce NAT-traversal for SIP (never trust any data provided by the client) and always activate a media relay (less support calls for customers with strange NAT routers and possibility for legal intercept). Thus, in a pragmatic approach the parameter is not needed anymore.
- The FLT_NATS and FLB_NATB flags. I'd like to know what this stands
for, I guess "flag for transaction - NAT" and "flag for branch - NAT" but what do the S and the B stand for? More importantly what do these
IIRC: s....script b....branch
flags mean? Is it correct to say that the first indicates the UAC / A-leg / requester is behind NAT and the second that the UAS / B-leg / responder is behind NAT?
yes. There can be multiple Bs (forking), thus the NAT information must be stored in a branch-flag.
In the the NATMANAGE route of the default config we have:
if (is_request()) { if(has_totag()) { if(check_route_param("nat=yes")) { setbflag(FLB_NATB); } } }
Which to me means "if the message is a request inside an existing dialog ..." and I'm thinking, isn't this a bit late in the dialog to be setting NAT flags?
No. The idea is to make NAT checks on the first INVITE, then store the results in RR-cookies. During in-dialog requests you rely on the cookies.
I would expect to set the flag for the A-leg on the incoming request, and the flag for the B-leg on the incoming reply. I can't point in waiting for the ACK to try and work out whether this leg is behind NAT. And also it seem this set of if statements will also match incoming requests from the A-leg, so why are we setting a brach flag? Does that leg also also get the properties of a branch?
For in-dialog requests it is not about A (caller) and B (callee) but more about "sender of the request" and "receiver of the request". I guess in this case it is setting the branch-flag as the existing logic for NAT traversal (during inital INVITE) is triggered on this certain branch flag. Thus, by setting this specific branch flag the existing code can be reused for in-dialog requests.
- When I get a 200 OK coming from behind NAT it is not subjected to
fix_nated_contact(), and this seems to be because it doesn't have the FLB_NATB flag set:
if (is_reply()) { if(isbflagset(FLB_NATB)) { fix_nated_contact(); } }
When processing the initial INVITE, the lookup() function returns the destination addresses of all Bs and if these Bs need NAT traversal (by setting the FLB_NATB flag for the respective branches. This flag is also available during response processing. And if set, the contact will be fixed.
Thus, if the clients needs NAT traversal, but NAT traversal is not done, this indicates that the FLB_NATB flag was not set for this client during lookup(), which indicates that the NAT flag was not set when the save() function was called which indicates that the NAT-detection logic in REGISTER handling did not detected that NAT traversal is needed.
regards Klaus
Hello,
just short clarification ...
On 6/22/12 10:07 AM, Klaus Darilion wrote:
[...]
- The FLT_NATS and FLB_NATB flags. I'd like to know what this stands
for, I guess "flag for transaction - NAT" and "flag for branch - NAT" but what do the S and the B stand for? More importantly what do these
IIRC: s....script b....branch
indeed there are script and branch flags, but in this case the defined IDs for flags followed the pattern:
FL[TYPE]_[DESC]
- TYPE was used as: T - transaction/message flags, B - branch flags, S - script flags (but none of these are used in default config) - DESC - anything that should suggest the purpose, in this case: NATS - natted source, NATB - natted outgoing branch
Feel free to improve if you want/find something more suggestive, it's what I was thinking of when I updated to use defines for flags...
Cheers, Daniel
Thanks guys, fantastic answers.
You mention that NAT detection happens before save() and the flag is set by lookup() which makes much more sense. However, if Kamailio is not the registrar, as is the case with my current project, those functions are not called, so an alternative is needed. There are clearly several options.
The solution I have gone for is to replace fix_nated_register() with fix_nated_contact() so that the REGISTER request is relayed with a modified Contact header containing the external ip:port of the client. That is then stored by the registrar (FreeSWITCH in my case) and used later to originate calls for that user. The FreeSWITCH know to send those calls to Kamailio through either use of the Path header and module in Kamailio, or through static configuration of fs_path or proxy parameters in FreeSWITCH.
The works for the first INVITE to the registered client behind NAT. But that client sends back a 200 OK with a Contact header containing its private IP address, and so fix_nated_contact() needs to be invoked on that response, and normally it would be due to FLB_NATB being set, but if Kamailio was not the registrar then that flag is not set. So I need to detect NAT on the client at the time of receiving the reply, or alternatively by having the registrar store a cookie and setting it based on that.
I suppose then my next question then is can I call nat_uac_test() on a UAS?
Thanks again for the great answers.
Regards, Richard
On 22.06.2012 13:50, Richard Brady wrote:
Thanks guys, fantastic answers.
You mention that NAT detection happens before save() and the flag is set by lookup() which makes much more sense. However, if Kamailio is not the registrar, as is the case with my current project, those functions are not called, so an alternative is needed. There are clearly several options.
The solution I have gone for is to replace fix_nated_register() with fix_nated_contact() so that the REGISTER request is relayed with a modified Contact header containing the external ip:port of the client.
The cleanest solution would be to use add_contact_alias() and handle_ruri_alias(). The do not change the contact but put the public address into a uri parameter. Thus, the URI seen by the client is always the one it sends: http://www.kamailio.org/docs/modules/3.2.x/modules_k/nathelper.html#id255043...
That is then stored by the registrar (FreeSWITCH in my case) and used later to originate calls for that user. The FreeSWITCH know to send those calls to Kamailio through either use of the Path header and module in Kamailio, or through static configuration of fs_path or proxy parameters in FreeSWITCH.
This is fine.
The works for the first INVITE to the registered client behind NAT. But that client sends back a 200 OK with a Contact header containing its private IP address, and so fix_nated_contact() needs to be invoked on that response, and normally it would be due to FLB_NATB being set, but if Kamailio was not the registrar then that flag is not set. So I need to detect NAT on the client at the time of receiving the reply, or alternatively by having the registrar store a cookie and setting it based on that.
You are correct. For in-dialog messages received from SIP clients I would always use add_contact_alias() and remove the NAT flags completely.
I suppose then my next question then is can I call nat_uac_test() on a UAS?
Today, almost any SIP clients are SIP symmetric. This means, that they receive SIP from the some port/connection where they send. Thus, skip the NAT tests completely and always use add_contact_alias() for messages receive from SIP clients and handle_ruri_alias() for messages sent to SIP clients.
Depending on if you use Freeswitch also as media relay you can also remove the media proxy stuff from the Kamailio config.
On important thing is NAT-keep-alive. This is usually done by nathelper module by querying the location table for contact with NAT-flag set. Thus, either you do NAT keep-alive by freeswitch (e.g sending OPTIONS requests) or do it in your Kamailio proxy (e.g. set the nat_bflag http://www.kamailio.org/docs/modules/3.2.x/modules_k/usrloc.html#id2541477 and call save("location","0x02") before relaying REGISTER to freeswitch. Then Kamailio will do NAT-pinging. Note, if you want to keep-alive only for successfully registered clients, you man want to call save() in the reply-route of the REGISTER request).
regards Klaus
Hello,
On 6/22/12 1:33 AM, Richard Brady wrote:
Hi folks
I've configured Kamailio as a simply multi-homed proxy offering NAT traversa, TCP connection management, etc to FreeSWICH behind it. FreeSWITCH acts as the registrar.
I'm trying to understand the default config and the following things don't make sense to me (I can't find documentation on these):
- The nat=yes flag. What does it mean exactly and why is it on the RR
and not on the Contact/R-URI? Also, when double RR is enabled, why does it get added to both headers?
it used to be in contact, but some times can get in troubles if the UA does not recognize it's address in the r-uri. Having it in record-/route headers does not interact with UAs, is just proxy's job. The parameter is used to detect if a call is natted, used mainly for re-INVITEs, where the destination user may not be present in r-uri.
- The FLT_NATS and FLB_NATB flags. I'd like to know what this stands
for, I guess "flag for transaction - NAT" and "flag for branch - NAT" but what do the S and the B stand for? More importantly what do these flags mean? Is it correct to say that the first indicates the UAC / A-leg / requester is behind NAT and the second that the UAS / B-leg / responder is behind NAT?
yes, for initial invite is the case.
In the the NATMANAGE route of the default config we have:
if (is_request()) { if(has_totag()) { if(check_route_param("nat=yes")) { setbflag(FLB_NATB); } } }
Which to me means "if the message is a request inside an existing dialog ..." and I'm thinking, isn't this a bit late in the dialog to be setting NAT flags? I would expect to set the flag for the A-leg on the incoming request, and the flag for the B-leg on the incoming reply. I can't point in waiting for the ACK to try and work out whether this leg is behind NAT. And also it seem this set of if statements will also match incoming requests from the A-leg, so why are we setting a brach flag? Does that leg also also get the properties of a branch?
B-leg behind the nat is detected based on location record. When B registers, it is detected being behind nat and FLB_NATB is saved in location and restored upon lookup(...).
- When I get a 200 OK coming from behind NAT it is not subjected to
fix_nated_contact(), and this seems to be because it doesn't have the FLB_NATB flag set:
if (is_reply()) { if(isbflagset(FLB_NATB)) { fix_nated_contact(); } }
The contact does not need a fix when it is a public address. When it is behind a nat, the fix will replace it with the ip and port of the nat router. There is another option for this, adding a parameter to the contact with the ip/port of the nat.
Cheers, Daniel
Any help clarifying would be much appreciated.
Thanks, Richard
-- Richard Brady
SIP Express Router (SER) and Kamailio (OpenSER) - sr-users mailing list sr-users@lists.sip-router.org http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users