[SR-Users] nat_keepalive() and fix_contact() are incompatible

David kamailio.org at spam.lublink.net
Tue May 21 18:37:07 CEST 2013


Hello,

So I want to setup a Kamailio SIP Proxy(  version 4 ) that will do NAT 
signalling handling. With the help of nat_traversal and path modules.

Attached is my kamailio.cfg file.

My problem is I want to do keep alive on users who are behind NAT, so I 
called nat_keepalive();. The script will work fine, but as soon as I 
enable either add_contact_alias() or fix_contact(), the keep alive 
doesn't activate.

I modified nat_traversal.c to identify the issue and found that it is 
comparing the contact header from the request and the reply to find the 
expiration. Trouble is, the request contact header was taken from before 
I called fix_contact() and the reply header has the contact from after 
the fix_contact() call. So my traces show that on the return trip the 
callback is called, I bet the stack trace looks like this :

1. Some method in tm
2. __tm_reply_in() defined at nat_traversal.c:1358
3. get_register_expire called from nat_traversal.c:1377 and defined at 
nat_traversal.c:878
4. STR_MATCH_STR called from nat_traversal.c:937 and defined at 
nat_traversal.c:77

STR_MATCH_STR returns false because the headers are different.

I added

               else
                         {
                                 LM_ERR("failed to match because request 
%s is not reply %s", contact->uri.s, r_contact->uri.s ) ;
                         }

to the code and see :

May 21 12:18:52 kamailio-dev-nat /usr/sbin/kamailio[30163]: ERROR: 
nat_traversal [nat_traversal.c:946]: failed to match because request 
sip:username at mytld#015#012#015#012 is not reply 
sip:username at myip:59080>;expires=60;received="sip:64.18.189.196:5060"#015#012Server: 
CenseredUA 5.2-rc1#015#012Content-Length: 0#015#012#015

So as you can see the original Contact header has the server's domain 
name and the response has the IP address that set by fix_contact().

So I think that nat_keepalive() should not be comparing the Contact from 
the original request but using the contact header from the modified request.

Any ideas what to do next ?

Thanks,
David


-------------- next part --------------
#!KAMAILIO
####### Include Local Config If Exists #########
import_file "kamailio-local.cfg"

debug=2
log_stderror=no

memdbg=5
memlog=5

log_facility=LOG_LOCAL0

fork=yes
children=4

/* uncomment the next line to disable TCP (default on) */
disable_tcp=yes

/* uncomment the next line to disable the auto discovery of local aliases
   based on reverse DNS on IPs (default on) */
auto_aliases=no

/* port to listen to
 * - can be specified more than once if needed to listen on many ports */
port=5060

mpath="/usr/local/lib/kamailio/modules_k/:/usr/lib64/kamailio/modules/"

loadmodule "mi_fifo.so"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"
loadmodule "mi_rpc.so"
loadmodule "acc.so"

loadmodule "path.so"

loadmodule "htable.so"
loadmodule "pike.so"

loadmodule "nat_traversal.so"
loadmodule "nathelper.so"

# ----------------- setting module-specific parameters ---------------


# ----- mi_fifo params -----
modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")


# ----- tm params -----
# auto-discard branches from previous serial forking leg
modparam("tm", "failure_reply_mode", 3)
# default retransmission timeout: 30sec
modparam("tm", "fr_timer", 30000)
# default invite retransmission timeout after 1xx: 120sec
modparam("tm", "fr_inv_timer", 120000)


# ----- rr params -----
# add value to ;lr param to cope with most of the UAs
modparam("rr", "enable_full_lr", 1)
# do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)

modparam("nat_traversal", "keepalive_interval", 2 )
modparam("nat_traversal", "keepalive_method", "OPTIONS")
modparam("nat_traversal", "keepalive_from", "sip:keepalive at nat.mydomain.net")
modparam("nat_traversal", "keepalive_state_file", "/var/run/kamailio/keepalive_state") 


####### Routing Logic ########

# Main SIP request routing logic
# - processing of any incoming SIP request starts with this route
# - note: this is the same as route { ... }
request_route {

	# per request initial checks
	route(REQINIT);

	if ( is_method("OPTIONS"))
	{
		options_reply();
		exit ;
	}
	# Respond quickly to keep alive
	if ( is_method("NOTIFY") && $hdr(Event) == 'keep-alive' )
	{
		xlog("L_DEBUG", "Notify : Keep alive $fU\n"); 
		sl_send_reply('200', 'OK');
		exit;
	}



	# NAT detection
	route(NAT);

	if (is_method("REGISTER"))
	{
		if (!add_path()) {
			sl_send_reply("503", "Internal Path Error");
			exit;
		}
	}
	else
	{

		# handle requests within SIP dialogs
		route(WITHINDLG);

		record_route();
	}

	route(RELAY);
}

route[RELAY] {
        if (is_method("INVITE")) {
                t_on_reply("REPLY_ONE");
        }

	if ( !t_relay() )
		sl_reply_error(); 
	exit;
}

route[NAT] {

          if (client_nat_test("5")) {
               force_rport();
               append_hf("X-NAT-URI: $source_uri\r\n");
               if (method=="REGISTER") {
                    # alias in contact to work around fix_contact which breaks nat_keepalive() and rport which doesn't do anything useful
		    fix_contact();

                    xlog("L_INFO", "Requesting NAT keep alive - M=$rm RURI=$ru F=$fu T=$tu IP=$si DT=$tt FT=$ft ID=$ci\n") ;
                    nat_keepalive();
                    xlog("L_INFO", "Done requesting NAT keep alive - M=$rm RURI=$ru F=$fu T=$tu IP=$si DT=$tt FT=$ft ID=$ci\n") ;

                    #add_contact_alias();
               }
               else
               {
                    fix_contact();
               }
               if ( nat_uac_test("8") )
               {
                    fix_nated_sdp("2");
               }

     }
}
# Handle requests within SIP dialogs
route[WITHINDLG] {

     # sequential request withing a dialog should
     # take the path determined by record-routing
     if ( has_totag() )
     {
	     if (loose_route()) {
		     xlog("L_INFO", "Loose routing!- M=$rm RURI=$ru F=$fu T=$tu IP=$si DT=$tt FT=$ft ID=$ci\n");
		     route(RELAY);
	     } else {
		     if ( has_totag() && is_method("ACK") && t_check_trans() ) {
			# no loose-route, but stateful ACK;
			# must be an ACK after a 487
			# or e.g. 404 from upstream server
			     t_relay();
			     exit;
		     }
	     }
     }
}



# Caller NAT detection route
route[NAT_REPLY] {


          if (client_nat_test("5")) {
               force_rport();
               append_hf("X-NAT-URI: $source_uri\r\n");
               if (method=="REGISTER") {
                    xlog("L_INFO", "Requesting NAT keep alive - M=$rm RURI=$ru F=$fu T=$tu IP=$si DT=$tt FT=$ft ID=$ci\n") ;
                    nat_keepalive();
                    # alias in contact to work around fix_contact which breaks nat_keepalive() and rport which doesn't do anything useful
                    add_contact_alias();
               }
               else
               {
                    fix_contact();
               }
               if ( nat_uac_test("8") )
               {
                    fix_nated_sdp("2");
               }

     }
}




route[REQINIT] {
       # flood dection from same IP and traffic ban for a while
       # be sure you exclude checking trusted peers, such as pstn gateways
       # - local host excluded (e.g., loop to self)
       if(src_ip!=myself)
       {
               if($sht(ipban=>$si)!=$null)
               {
                       # ip is already blocked
                       xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");
                        exit;
                }
               if (!pike_check_req())
               {
                       xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");
                       $sht(ipban=>$si) = 1;
                       exit;
               }
        }

       if (!mf_process_maxfwd_header("10")) {
               sl_send_reply("483","Too Many Hops");
               exit;
       }

       if(!sanity_check("1511", "7"))
       {
               xlog("Malformed SIP message from $si:$sp\n");
               exit;
       }
}

# Sample onreply route
onreply_route[REPLY_ONE] {
        xdbg("incoming reply\n");

route(NAT_REPLY);

}




More information about the sr-users mailing list