#!define DBURL "mysql://kamailio:kamailiorw@localhost/kamailio" #!define FLT_ACC 1 #!define FLT_ACCMISSED 2 #!define FLT_ACCFAILED 3 #!define FLT_NATS 5 #!define FLB_NATB 6 #!define FLB_NATSIPPING 7 ####### Global Parameters ######### debug=4 log_stderror=yes memdbg=5 memlog=5 log_facility=LOG_LOCAL0 fork=yes children=2 #disable_tcp=yes #auto_aliases=no listen=udp:109.120.165.144:5060 port=5060 enable_tls=no tcp_connection_lifetime=3605 ####### Modules Section ######## mpath="/usr/local/lib/kamailio/modules/" loadmodule "db_mysql.so" 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 "auth.so" loadmodule "auth_db.so" loadmodule "alias_db.so" loadmodule "presence.so" loadmodule "presence_xml.so" loadmodule "nathelper.so" loadmodule "rtpproxy.so" #loadmodule "tls.so" loadmodule "htable.so" loadmodule "pike.so" loadmodule "debugger.so" loadmodule "tsilo.so" #loadmodule "app_lua.so" loadmodule "app_python.so" loadmodule "cfgutils.so" loadmodule "msilo.so" # ----------------- setting module-specific parameters --------------- modparam("debugger", "cfgtrace", 1) # ----- 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", 10) # default invite retransmission timeout after 1xx: 120sec modparam("tm", "fr_inv_timer", 15) modparam("tm", "wt_timer", 10 ) # ----- rr params ----- # set next param to 1 to add value to ;lr param (helps with some 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) # ----- registrar params ----- modparam("registrar", "method_filtering", 1) /* uncomment the next line to disable parallel forking via location */ # modparam("registrar", "append_branches", 0) /* uncomment the next line not to allow more than 10 contacts per AOR */ #modparam("registrar", "max_contacts", 10) # max value for expires of registrations modparam("registrar", "max_expires", 3600) # set it to 1 to enable GRUU modparam("registrar", "gruu_enabled", 0) modparam("registrar", "default_expires", 120) # ----- 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 ww 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 */ #!ifdef WITH_ACCDB 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") #!endif # ----- usrloc params ----- /* enable DB persistency for location entries */ modparam("usrloc", "db_url", DBURL) modparam("usrloc", "db_mode", 5) modparam("usrloc", "use_domain", 0) # ----- auth_db params ----- modparam("auth_db", "db_url", DBURL) modparam("auth_db", "calculate_ha1", yes) modparam("auth_db", "password_column", "password") modparam("auth_db", "load_credentials", "") modparam("auth_db", "use_domain", 0) # ----- alias_db params ----- modparam("alias_db", "db_url", DBURL) modparam("alias_db", "use_domain", 0) # ----- presence params ----- modparam("presence", "db_url", DBURL) # ----- presence_xml params ----- modparam("presence_xml", "db_url", DBURL) modparam("presence_xml", "force_active", 1) # ----- rtpproxy params ----- modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:22222") # ----- nathelper params ----- modparam("nathelper", "natping_interval", 30) modparam("nathelper", "ping_nated_only", 1) modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) modparam("nathelper", "sipping_from", "sip:pinger@kamailio.org") modparam("nathelper", "sipping_method", "INFO") # params needed for NAT traversal in other modules modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)") modparam("usrloc", "nat_bflag", FLB_NATB) # ----- tls params ----- #modparam("tls", "config", "/usr/local/etc/kamailio/tls.cfg") # ----- pike params ----- modparam("pike", "sampling_time_unit", 2) modparam("pike", "reqs_density_per_unit", 16) modparam("pike", "remove_latency", 4) # ----- htable params ----- # ip ban htable with autoexpire after 5 minutes modparam("htable", "htable", "ipban=>size=8;autoexpire=300;") modparam("usrloc", "handle_lost_tcp", 1) modparam("usrloc", "close_expired_tcp", 1) modparam("htable", "htable", "vtp=>size=10;autoexpire=120;dbtable=htable;dbmode=0") modparam("htable", "htable", "pn=>size=10;autoexpire=300;dbtable=htable;dbmode=0") modparam("app_python", "script_name", "/usr/local/etc/kamailio/scripts/pn.py") modparam("app_python", "mod_init_function", "mod_init") # -- msilo params -- modparam("msilo","db_url",DBURL) modparam("msilo","from_address","sip:$rU@XXXX") modparam("msilo","contact_hdr","Contact:$rU@XXXX:5060;msilo=yes\r\n") modparam("msilo","content_type_hdr","Content-Type: text/plain\r\n") modparam("msilo","offline_message","*** User $rU is offline!") #modparam("msilo", "outbound_proxy", "sip:XXXX;transport=udp") modparam("msilo", "extra_hdrs", "X-Extra: foo\r\n") ####### Routing Logic ######## # Main SIP request routing logic request_route { # xlog("request route\n"); # per request initial checks route(REQINIT); # NAT detection route(NATDETECT); # CANCEL processing if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } exit; } # handle requests within SIP dialogs route(WITHINDLG); ### only initial requests (no To tag) # handle retransmissions if(t_precheck_trans()) { t_check_trans(); exit; } t_check_trans(); # authentication route(AUTH); # record routing for dialog forming requests (in case they are routed) # - remove preloaded route headers remove_hf("Route"); if (is_method("INVITE|SUBSCRIBE")) record_route(); # account only INVITEs if (is_method("INVITE")) { setflag(FLT_ACC); # do accounting route(INVITE); } # dispatch requests to foreign domains route(SIPOUT); ### requests for my local domains #route(REGISTRAR); # register if (is_method("REGISTER")) { route(REGISTER); } if ($rU==$null) { # request with no Username in RURI sl_send_reply("484","Address Incomplete"); exit; } # user location service route(LOCATION); } # Wrapper for relaying requests route[RELAY] { xlog("route relay\n"); # 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")) t_on_branch("MANAGE_BRANCH"); } if (is_method("INVITE|SUBSCRIBE|UPDATE")) { if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY"); } if (is_method("INVITE")) { if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE"); } if (!t_relay()) { sl_reply_error(); } exit; } # Per SIP request initial checks route[REQINIT] { #xlog("reqinit\n"); # 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($ua =~ "friendly-scanner") { sl_send_reply("200", "OK"); exit; } if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); exit; } if(is_method("OPTIONS") && uri==myself && $rU==$null) { sl_send_reply("200","Keepalive"); exit; } if(!sanity_check("1511", "7")) { xlog("Malformed SIP message from $si:$sp\n"); exit; } } # Handle requests within SIP dialogs route[WITHINDLG] { #xlog("within\n"); 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 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 ... ignore and discard exit; } } sl_send_reply("404","Not here"); exit; } # Handle SIP registrations route[REGISTRAR] { xlog("REGISTRAR\n"); if (!is_method("REGISTER")) return; if(isflagset(FLT_NATS)) { setbflag(FLB_NATB); #!ifdef WITH_NATSIPPING # do SIP NAT pinging setbflag(FLB_NATSIPPING); #!endif } if (!save("location")) sl_reply_error(); exit; } # User location service route[LOCATION] { xlog("location\n"); # search in DB-based aliases if(alias_db_lookup("dbaliases")) route(SIPOUT); $avp(oexten) = $rU; if (!lookup("location")) { $var(rc) = $rc; xlog("MESSAGE received -> storing using MSILO\n"); # MSILO - storing as offline message if (method=="MESSAGE") { if (m_store("$ru")) { xlog("MSILO: offline message stored\n"); send_reply("202", "Accepted"); }else{ xlog("MSILO: offline message NOT stored\n"); send_reply("503", "Service unavailable"); }; exit; } route(TOVOICEMAIL); t_newtran(); switch ($var(rc)) { case -1: case -3: send_reply("404", "Not Found"); exit; case -2: send_reply("405", "Method Not Allowed"); exit; } } # when routing via usrloc, log the missed calls also if (is_method("INVITE")) { setflag(FLT_ACCMISSED); } route(RELAY); exit; } # Presence server processing route[PRESENCE] { xlog("presence\n"); if(!is_method("PUBLISH|SUBSCRIBE")) return; if(is_method("SUBSCRIBE") && $hdr(Event)=="message-summary") { route(TOVOICEMAIL); # returns here if no voicemail server is configured sl_send_reply("404", "No voicemail service"); exit; } if (!t_newtran()) { sl_reply_error(); exit; } if(is_method("PUBLISH")) { handle_publish(); t_release(); } else if(is_method("SUBSCRIBE")) { handle_subscribe(); t_release(); } exit; # if presence enabled, this part will not be executed if (is_method("PUBLISH") || $rU==$null) { sl_send_reply("404", "Not here"); exit; } return; } # IP authorization and user uthentication route[AUTH] { #xlog("auth\n"); if (is_method("REGISTER") || from_uri==myself) { if ($hdr(X-Extra)=="foo") { return; } # authenticate requests if (!auth_check("$fd", "subscriber", "1")) { auth_challenge("$fd", "0"); exit; } # user authenticated - remove auth header if(!is_method("REGISTER|PUBLISH")) consume_credentials(); } # if caller is not local subscriber, then check if it calls # a local destination, otherwise deny, not an open relay here if (from_uri!=myself && uri!=myself) { sl_send_reply("403","Not relaying"); exit; } return; } # Caller NAT detection route[NATDETECT] { #xlog("natdetect\n"); force_rport(); if (nat_uac_test("19")) { if (is_method("REGISTER")) { fix_nated_register(); } else { if(is_first_hop()) set_contact_alias(); } setflag(FLT_NATS); } return; } # RTPProxy control and singaling updates for NAT traversal route[NATMANAGE] { xlog("natmanage\n"); if (is_request()) { if(has_totag()) { if(check_route_param("nat=yes")) { setbflag(FLB_NATB); } } } if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))) return; rtpproxy_manage("co"); if (is_request()) { if (!has_totag()) { if(t_is_branch_route()) { add_rr_param(";nat=yes"); } } } if (is_reply()) { if(isbflagset(FLB_NATB)) { if(is_first_hop()) set_contact_alias(); } } return; } # URI update for dialog requests route[DLGURI] { xlog("dlg\n"); if(!isdsturiset()) { handle_ruri_alias(); } return; } # Routing to foreign domains route[SIPOUT] { #xlog("sipout\n"); if (uri==myself) return; append_hf("P-hint: outbound\r\n"); route(RELAY); exit; } # PSTN GW routing route[PSTN] { xlog("pstn\n"); return; } # XMLRPC routing #!ifdef WITH_XMLRPC route[XMLRPC] { xlog("xml\n"); # allow XMLRPC from localhost if ((method=="POST" || method=="GET") && (src_ip==127.0.0.1)) { # close connection only for xmlrpclib user agents (there is a bug in # xmlrpclib: it waits for EOF before interpreting the response). if ($hdr(User-Agent) =~ "xmlrpclib") set_reply_close(); set_reply_no_connect(); dispatch_rpc(); exit; } send_reply("403", "Forbidden"); exit; } #!endif # Routing to voicemail server route[TOVOICEMAIL] { xlog("tovoice\n"); #!ifdef WITH_VOICEMAIL if(!is_method("INVITE|SUBSCRIBE")) return; # check if VoiceMail server IP is defined if (strempty($sel(cfg_get.voicemail.srv_ip))) { xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n"); return; } if(is_method("INVITE")) { if($avp(oexten)==$null) return; $ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip) + ":" + $sel(cfg_get.voicemail.srv_port); } else { if($rU==$null) return; $ru = "sip:" + $rU + "@" + $sel(cfg_get.voicemail.srv_ip) + ":" + $sel(cfg_get.voicemail.srv_port); } route(RELAY); exit; #!endif return; } # Manage outgoing branches branch_route[MANAGE_BRANCH] { xdbg("new branch [$T_branch_idx] to $ru\n"); route(NATMANAGE); } # Manage incoming replies onreply_route[MANAGE_REPLY] { xdbg("incoming reply\n"); if(status=~"[12][0-9][0-9]") route(NATMANAGE); } # Manage failure routing cases failure_route[MANAGE_FAILURE] { route(NATMANAGE); if (t_is_canceled()) { exit; } xlog("MSILO:the downstream UA doesn't support MESSAGEs\n"); # we have changed the R-URI with the contact address, ignore it now if (m_store("$ou")) { xlog("MSILO: offline message stored\n"); t_reply("202", "Accepted"); }else{ xlog("MSILO: offline message NOT stored\n"); t_reply("503", "Service Unavailable"); }; #!ifdef WITH_BLOCK3XX # block call redirect based on 3xx replies. if (t_check_status("3[0-9][0-9]")) { t_reply("404","Not found"); exit; } #!endif #!ifdef WITH_VOICEMAIL # serial forking # - route to voicemail on busy or no answer (timeout) if (t_check_status("486|408")) { $du = $null; route(TOVOICEMAIL); exit; } #!endif } # manage incoming INVITEs route[INVITE] { xlog("invite...\n"); if (!lookup("location")) { send_reply("100", "Trying suspend"); route(SUSPEND); } else { xlog("store\n"); t_relay(); ts_store(); xlog("$rU\n"); $sht(vtp=>stored::$rU) = 1; xlog("stored transaction [$T(id_index):$T(id_label)] $fU => $rU \n"); } route(SENDPUSH); } # suspend the transaction route[SUSPEND] { xlog("suspend...\n"); if (!t_suspend()) { xlog("failed suspending transaction [$T(id_index): $T(id_label)]\n"); send_reply("501", "Unknown destination (suspend)"); exit; } xlog("suspended transaction [$T(id_index):$T(id_label)] $fU => $rU\n"); $sht(vtp=>join::$rU) = "" + $T(id_index) + ":" + $T(id_label); xlog("htable key value [$sht(vtp=>join::$rU)]\n"); } route[SENDPUSH] { xlog("sendpush...\n"); $var(pnret) = 0; #if (lua_runstring("do_push([[$hdr(X-VxTo)]], [[$tU]], [[$hdr(X-VxFrom)]], [[$fU]], [[$ci]])")<0) $var(arg) = $tU + "," + $fU + "," + $ci; if ( $sht(pn=>$tU) == $null ) { #send_reply("501", "No link to destination"); #exit; xlog("no link to destination $tU\n"); } if ( python_exec("push",$var(arg)) != 1 ) { send_reply("501", "Unknown destination (sendpush)"); exit; } exit; } # manage incoming REGISTERs route[REGISTER] { xlog("register...\n"); if(isflagset(FLT_NATS)) { setbflag(FLB_NATB); #!ifdef WITH_NATSIPPING # do SIP NAT pinging setbflag(FLB_NATSIPPING); #!endif } if (!save("location")) sl_reply_error(); # MSILO - dumping user's offline messages if (m_dump()) { xlog("MSILO: offline messages dumped - if they were\n"); }else{ xlog("MSILO: no offline messages dumped\n"); }; if ( $(sht(pn=>$fU){s.len})==0 ) { xlog("pn not set for $fU\n"); #python_exec("get_token", $hdr(Contacta, $var(token))); $var(token) = $(hdr(Contact){s.select,3,;}); $var(token) = $(var(token){s.select,1,=}); xlog("token for $fU is: $var(token)\n"); $sht(pn=>$fU) = $var(token); } else { xlog("pn is set for $fU and it is: $sht(pn=>$fU)\n"); } route(PUSHJOIN); exit; } # append branches or resume the transaction route[PUSHJOIN] { xlog("pushjoin...\n"); $var(hjoin) = 0; $var(hstored) = 0; lock("$tU"); $var(hjoin) = $sht(vtp=>join::$tU); $var(hstored) = $sht(vtp=>stored::$tU); $sht(vtp=>join::$tU) = $null; unlock("$tU"); xlog("$var(hstored) $tU \n"); if ($var(hjoin)==0) { if ($var(hstored)) ts_append("location", "$tU"); # t_continue( return; } $var(id_index) = $(var(hjoin){s.select,0,:}{s.int}); $var(id_label) = $(var(hjoin){s.select,1,:}{s.int}); xlog("resuming transaction [$var(id_index):$var(id_label)] $tU ($var(hjoin))\n"); t_continue("$var(id_index)", "$var(id_label)", "INVRESUME"); } # lookup and relay after resuming transaction route[INVRESUME] { xlog("invresume...\n"); lookup("location"); t_relay(); ts_store(); $sht(vtp=>stored::$rU) = 1; xlog("stored transaction [$T(id_index):$T(id_label)] $fU => $rU\n"); }