Hi all,
I've the following infrastructure (fake IPs)
62.128.128.68 (Telco SBC Inbound) | | 10.19.139.66 (Kamailio + RTPEngine) | | 10.19.139.69 (Asterisk 13) | | 62.128.128.68 (Telco SBC Outbound)
Test scenario is: - a mobile calls a destination; the call comes in from Telco SBC Inbound, goes through Kamailio+RTPengine and then to Asterisk which redirects the call to Telco SBC Outbound. - Asterisk box is set with canreinvite=no and nat=force_rport,comedia so it stays in the path
when a call comes in SBC Inbound, it is correctly redireted to SBC Outbound. The call is answered, and after 5 or so seconds, SBC Inbound sends a new INVITE to force codecs, which Asterisk replies correctly. the problem is that between Kamailio and SBC Inbund, when Asterisk replies to the second invite, the media port changes, resulting in audio loss: during the call, audio from destination to originator works OK but originator to destination is mute.
According to the telco's guys,this is due to the fact that Kamailio is changing during call the media port from original media port to a new one, on reply to the second Invite, and this is wrong and reason why sound from the originator to destination is lost (but not from destination to originator)
I'm lost too here.....
Any clue? Can anyone help? Resuming I need to make sure that, if during a call some INVITES are sent from SBC to Asterisk, that the reply keeps the same IP_ADDR:port from beginning to the end of the call. As it is today, the second invite changes te RTP Media port and no audi is heard....
If needed I can send PCap files.
please find below my kamailio.cfg file
#!define WITH_NAT #!define WITH_PSTN /* enables Accounting Log functions */ #!define FLT_ACC 1 /* enable Accounting of missed or failed calls */ #!define FLT_ACCMISSED 2 #!define FLT_ACCFAILED 3
/* sets the dispatcher list file path */ #!define DS_LIST "/etc/kamailio/dispatcher.list"
/* sets the RTP Engine address and port; RTP Engine is a NAT enabled RTP Proxy */ #!define RTP_ENGINE_ADDR "udp:127.0.0.1:60000" // was udp:localhost:60000
/* defines DB connection string */ #!ifndef DBURL #!define DBURL "mysql://kamailio:kamailiorw@10.19.139.110/kamailio" #!endif
# - the value for 'use_domain' parameters #!define MULTIDOMAIN 1
####### Global Parameters #########
#!ifdef WITH_DEBUG debug=4 log_stderror=yes #!else debug=2 log_stderror=no #!endif
#!define FLT_DISPATCH_SETID 1 #!define FLT_FS 10 #!define FLT_NATS 5 #!define FLB_NATB 6 #!define FLB_NATSIPPING 7
memdbg=5 memlog=5
log_facility=LOG_LOCAL0
fork=yes children=4
/* comment the next line to enable TCP */ disable_tcp=no
/* uncomment the next line to disable the auto discovery of local aliases based on revers DNS on IPs (default on) */ auto_aliases=no
/* add local domain aliases */ # alias="mysipserver.com"
port=5060
/* uncomment and configure the following line if you want Kamailio to bind on a specific interface/port/proto (default bind on all available) */ //listen=udp:10.19.139.66:5060 listen=udp:eth1:5060
sip_warning=no; ####### Modules Section ########
#set module path mpath="/usr/lib64/kamailio/modules/"
loadmodule "db_mysql.so" loadmodule "jsonrpcs.so" loadmodule "kex.so" loadmodule "tm.so" loadmodule "tmx.so" loadmodule "sl.so" loadmodule "rr.so" loadmodule "pv.so" loadmodule "maxfwd.so" /**************/ loadmodule "usrloc.so" /**************/ loadmodule "textops.so" loadmodule "siputils.so" loadmodule "xlog.so" loadmodule "sanity.so" loadmodule "ctl.so" loadmodule "acc.so" loadmodule "path.so" loadmodule "dispatcher.so" loadmodule "rtpengine.so" loadmodule "nathelper.so" loadmodule "rtimer.so" loadmodule "sqlops.so" # ----------------- setting module-specific parameters --------------- # ----- jsonrpcs params ----- modparam("jsonrpcs", "fifo_name", "/var/run/kamailio/kamailio_rpc.fifo") modparam("jsonrpcs", "pretty_format", 1)
# ----- 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)
# ----- acc params ----- modparam("acc", "failed_transaction_flag", 3) modparam("acc", "log_extra","src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;src_ip=$si")
# ----- acc params ----- /* what special events should be accounted ? */ modparam("acc", "early_media", 0) modparam("acc", "report_ack", 0) modparam("acc", "report_cancels", 0) /* by default we do not adjust the direct of the sequential requests. if you enable this parameter, be sure the enable "append_fromtag" in "rr" module */ modparam("acc", "detect_direction", 0) /* account triggers (flags) */ modparam("acc", "log_flag", FLT_ACC) modparam("acc", "log_missed_flag", FLT_ACCMISSED) modparam("acc", "log_extra","src_user=$fU;src_domain=$fd;src_ip=$si;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd") modparam("acc", "failed_transaction_flag", FLT_ACCFAILED) /* enhanced DB accounting */ modparam("acc", "db_flag", FLT_ACC) modparam("acc", "db_missed_flag", FLT_ACCMISSED) modparam("acc", "db_url", DBURL) modparam("acc", "db_extra","src_user=$fU;src_domain=$fd;src_ip=$si;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd") //;calltype=$avp(calltype)")
# ----- usrloc params ----- /* enable DB persistency for location entries */ modparam("usrloc", "db_url", DBURL) modparam("usrloc", "db_mode", 2) modparam("usrloc", "use_domain", MULTIDOMAIN)
# ----- tm params ----- # ----- the TM module enables stateful processing of SIP requests modparam("tm", "fr_timer", 2000) modparam("tm", "fr_inv_timer", 40000)
# ----- dispatcher params ----- modparam("dispatcher", "list_file", DS_LIST) modparam("dispatcher", "flags", 2) modparam("dispatcher", "dst_avp", "$avp(AVP_DST)") modparam("dispatcher", "grp_avp", "$avp(AVP_GRP)") modparam("dispatcher", "cnt_avp", "$avp(AVP_CNT)") modparam("dispatcher", "sock_avp", "$avp(AVP_SOCK)") modparam("dispatcher", "ds_hash_size", 9) modparam("dispatcher", "dstid_avp", "$avp(dsdstid)") modparam("path", "use_received", 1)
# ----- rtpproxy params ----- modparam("rtpengine", "rtpengine_sock", RTP_ENGINE_ADDR) modparam("nathelper", "received_avp", "$avp(s:rcv)")
/************************/ # ----- nathelper params ----- modparam("nathelper", "natping_interval", 30) modparam("nathelper", "ping_nated_only", 1) modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) modparam("nathelper", "sipping_from", "sip:ping@kamailio.org")
# params needed for NAT traversal in other modules modparam("usrloc", "nat_bflag", FLB_NATB) /***********************/
modparam("rtimer", "timer", "name=cdr;interval=300;mode=1;") modparam("rtimer", "exec", "timer=cdr;route=CDRS") modparam("sqlops", "sqlcon", "ca=>mysql://kamailio:**********@*************/kamailio")
####### Routing Logic ########
# main request routing logic
route { xlog("L_INFO","$rm from $si"); xlog("L_DBG","[$fU@$si:$sp]{$rm} {$ru} ");
# OPTIONS requests without a username in the Request-URI but one # of our domains or IPs are addressed to the proxy itself and # can be answered statelessly. if (is_method("OPTIONS")) // && $fU=="ping" )// && $si=="62.28.173.10" && $fU=="ping")// && strempty(@ruri.user) && (uri == myself)) { sl_send_reply("200","OK"); exit; }
# per request initial checks route(REQINIT); rtpengine_manage(); # NAT detection route(NATDETECT); # handle requests within SIP dialogs ### only initial requests (no To tag) # CANCEL processing if (is_method("CANCEL")) { if (t_check_trans()){ route(RELAY); } exit; } # handle retransmissions if (!is_method("ACK")) { if(t_precheck_trans()) { t_check_trans(); exit; } t_check_trans(); } route(WITHINDLG);
# record routing for dialog forming requests (in case they are routed) # - remove preloaded route headers xlog("L_INFO","Removing Headers"); remove_hf("Route"); if (is_method("INVITE|SUBSCRIBE")){ xlog("L_INFO","Recording Route"); record_route();
if (is_method("INVITE")) { if (has_body("application/sdp")) { if (rtpengine_offer()) t_on_reply("1"); } else { t_on_reply("2"); } } }
if (is_method("ACK") && has_body("application/sdp")) rtpengine_answer();
# account only INVITEs if (is_method("INVITE")) { setflag(FLT_ACC); # do accounting }
//route(SIPOUT);
xlog("L_INFO","Setting PRESENCE"); # handle presence related requests route(PRESENCE);
# handle registrations xlog("L_INFO","Handling REGISTRAR"); route(REGISTRAR);
if ($rU==$null) { # request with no Username in RURI sl_send_reply("484","Address Incomplete"); exit; }
# dispatch destinations route(DISPATCH);
xlog("L_INFO","**********END*************"); }
onreply_route[1] { if (has_body("application/sdp")) rtpengine_answer(); }
onreply_route[2] { if (has_body("application/sdp")) rtpengine_offer(); }
# Per SIP request initial checks route[REQINIT] { xlog("L_INFO","REQINIT Starting"); if (!mf_process_maxfwd_header("10")) { xlog("L_INFO","483 - Too Many Hops"); sl_send_reply("483","Too Many Hops"); exit; }
if(!sanity_check("1511", "7")) { xlog("Sanity Check -> Malformed SIP message from $si:$sp\n"); exit; } xlog("L_INFO","REQINIT Finishing"); }
/***********************/ # Caller NAT detection route[NATDETECT] { xlog("L_INFO","Entering NATDTECT"); #!ifdef WITH_NAT force_rport(); if (nat_uac_test("19")) { if (is_method("REGISTER")) { xlog("L_INFO","Fix Nated Register"); fix_nated_register(); } else { if(is_first_hop()) { xlog("L_INFO","Set Contact Alias"); set_contact_alias(); } } xlog("L_INFO","Set FLT_NATS" + FLT_NATS); setflag(FLT_NATS); } #!endif xlog("L_INFO","NAT Detect set FLT_NTS = " + FLT_NATS); xlog("L_INFO","Finishing NATDETECT"); return; } /***********************/
# Handle requests within SIP dialogs route[WITHINDLG] { xlog("L_INFO","Entering WITHDLG"); if (!has_totag()) return;
# sequential request withing a dialog should # take the path determined by record-routing if (loose_route()) { route(DLGURI); if (is_method("BYE")) { setflag(FLT_ACC); # do accounting ... setflag(FLT_ACCFAILED); # ... even if the transaction fails } else if ( is_method("ACK") ) { # ACK is forwarded statelessy xlog("L_INFO","Going to NATMANAGE"); route(NATMANAGE); } else if ( is_method("NOTIFY") ) { # Add Record-Route for in-dialog NOTIFY as per RFC 6665. record_route(); } route(RELAY); exit; }
if (is_method("SUBSCRIBE") && uri == myself) { # in-dialog subscribe requests route(PRESENCE); exit; } if ( is_method("ACK") ) { if ( t_check_trans() ) { # no loose-route, but stateful ACK; # must be an ACK after a 487 # or e.g. 404 from upstream server route(RELAY); exit; } else { # ACK without matching transaction. Try to route anyway - being optimistic # since it has at least a To Tag route(RELAY); exit; } } sl_send_reply("404","Not here"); xlog("L_INFO","Finishing WITHINDLG"); exit; }
# Routing to foreign domains route[SIPOUT] { xlog("L_INFO","Entering SIPOUT"); if (uri==myself) { xlog("L_INFO","URI is MySelf!"); return; }
append_hf("P-hint: outbound\r\n"); xlog("L_INFO","Finishing SIPOUT"); route(RELAY); exit; }
# Wrapper for relaying requests route[RELAY] { xlog("L_INFO","******** RELAY *******");
# enable additional event routes for forwarded requests # - serial forking, RTP relaying handling, a.s.o. if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) { if(!t_is_set("branch_route")) { xlog("L_INFO","branch_route NOT SET!"); t_on_branch("MANAGE_BRANCH"); } } if (is_method("INVITE|SUBSCRIBE|UPDATE")) { if(!t_is_set("onreply_route")) { xlog("L_INFO","onreply_route NOT SET!"); t_on_reply("MANAGE_REPLY"); } } if (is_method("INVITE")) { if(!t_is_set("failure_route")) { xlog("L_INFO","failure_route NOT SET!"); t_on_failure("MANAGE_FAILURE"); } }
if (!t_relay()) { xlog("L_INFO","t_relay returns FALSE"); sl_reply_error(); } exit; }
# URI update for dialog requests route[DLGURI] { xlog("L_INFO","Entering DLGURI"); #!ifdef WITH_NAT if(!isdsturiset()) { xlog("L_INFO","Handle ruri ALIAS"); handle_ruri_alias(); } #!endif return; }
# RTPProxy control and singaling updates for NAT traversal route[NATMANAGE] { xlog("L_INFO","Entering NATMANAGE"); #!ifdef WITH_NAT if (is_request()) { if(has_totag()) { if(check_route_param("nat=yes")) { xlog("L_INFO","nat=yes --- Setting FLB_NATB"); setbflag(FLB_NATB); } } } if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB) )) { xlog("L_INFO","NO FLT_NATS/B Set!!! Getting out of NATMANAGE"); return; } xlog("L_INFO","Starting RTPEngine"); rtpengine_manage();
if (is_request()) { if (!has_totag()) { if(t_is_branch_route()) { xlog("L_INFO","adding nat=yes"); add_rr_param(";nat=yes"); } } } if (is_reply()) { if(isbflagset(FLB_NATB)) { if(is_first_hop()) { xlog("L_INFO","Set Contact Alias"); set_contact_alias(); } } } #!endif return; }
# Handle SIP registrations route[REGISTRAR] { if(!is_method("REGISTER")) return; add_path_received(); route(DISPATCH); }
# Presence server route route[PRESENCE] { if(!is_method("PUBLISH|SUBSCRIBE")) return;
sl_send_reply("404", "Not here"); exit; }
# Dispatch requests route[DISPATCH] { xlog("L_INFO","Entering DISPATCH"); # hash over callerid dispatching on gateways group '1' if(!ds_select_dst("1", "10","4")) { xlog("L_INFO","no destination selected from dispatcher list!"); send_reply("404", "No destination"); exit; } xlog("L_INFO","going to <$ru> via <$du>\n");
t_on_failure("RTF_DISPATCH"); route(RELAY); exit; }
# Sample failure route failure_route[RTF_DISPATCH] { if (t_is_canceled()) { exit; } xlog("L_INFO", "Media server $du failed to answer, selecting other one!"); # next DST - only for 500 or local timeout if ( t_check_status("500") || (t_branch_timeout() && !t_branch_replied()) ) { #we mark the destination Inactive and Probing ds_mark_dst("ip"); if(ds_next_dst()) { t_on_failure("RTF_DISPATCH"); route(RELAY); exit; } } }
route[CDRS]{ sql_query("ca","call kamailio_cdrs();","rb"); sql_query("ca","call kamailio_rating('default');","rb"); }
Cheers,
*Sérgio *