#!trydef REGISTRAR_NAT_PING_INTERVAL 30 #!trydef REGISTRAR_NAT_PING_WORKERS 5 #!trydef REGISTRAR_MIN_EXPIRES 300 #!trydef REGISTRAR_MAX_EXPIRES 3600 ######## Generic Hash Table container in shared memory ######## modparam("htable", "htable", "auth_cache=>size=16;autoexpire=7200;") ####### Authentication Interface module ########## loadmodule "auth.so" #!ifdef OPENBTS_AUTH_ROLE loadmodule "auth_openbts.so" modparam("auth", "qop", "") modparam("auth", "secret", "OPENBTS_AUTH_SECRET") modparam("auth_openbts", "challenge_attr", "$avp(digest_challenge)") #!endif ####### User Location Implementation module ########## loadmodule "usrloc.so" modparam("usrloc", "db_update_as_insert", 0) modparam("usrloc", "use_domain", 1) modparam("usrloc", "nat_bflag", FLB_NATB) modparam("usrloc", "db_url", "KAZOO_DB_URL") modparam("usrloc", "db_mode", 1) modparam("usrloc", "handle_lost_tcp", 1) modparam("usrloc", "xavp_contact", "ulattrs") modparam("usrloc", "db_check_update", 1) modparam("usrloc", "timer_interval", 30) modparam("usrloc", "timer_procs", 1) ######## NAT Traversal module - signaling functions ######## #!ifdef NAT_TRAVERSAL_ROLE #!trydef NATHELPER_LOADED loadmodule "nathelper.so" modparam("nathelper", "natping_interval", REGISTRAR_NAT_PING_INTERVAL) modparam("nathelper", "ping_nated_only", 0) modparam("nathelper", "natping_processes", REGISTRAR_NAT_PING_WORKERS) modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) #!endif ####### SIP Registrar implementation module ########## loadmodule "registrar.so" modparam("registrar", "received_avp", "$avp(AVP_RECV_PARAM)") modparam("registrar", "min_expires", REGISTRAR_MIN_EXPIRES) modparam("registrar", "max_expires", REGISTRAR_MAX_EXPIRES) modparam("registrar", "xavp_cfg", "regcfg") modparam("registrar", "gruu_enabled", 1) modparam("registrar", "outbound_mode", 1) modparam("registrar", "regid_mode", 1) modparam("registrar", "path_mode", 1) modparam("registrar", "use_path", 1) modparam("registrar", "received_param", "") modparam("registrar", "xavp_rcd", "ulrcd") ####### Registrar Logic ######## route[HANDLE_REGISTER] { if (is_method("REGISTER")) { #!ifdef NAT_TRAVERSAL_ROLE if (nat_uac_test("3")) { xlog("L_INFO", "$ci|log|correcting NATed contact in registration\n"); force_rport(); } fix_nated_register(); ## KAZOO-1846: Cisco SPA8000 freaks out on options pings if (!($ua =~ "Linksys/SPA8000" || $ua =~ "OpenBTS" || $ua =~ "SIPp" || (af==INET6) )) { setbflag(FLB_NATB); setbflag(FLB_NATSIPPING); } #!endif route(ATTEMPT_AUTHORIZATION); } } route[AUTHORIZATION_CHECK] { if (!is_method("MESSAGE|NOTIFY|SUBSCRIBE|PUBLISH")) return; if(has_totag()) return; if (isflagset(FLAG_INTERNALLY_SOURCED)) return; if (isflagset(FLAG_TRUSTED_SOURCE)) return; $xavp(regcfg=>match_received) = $su; if(!(registered("location", "$fu", 2, 1) == 1 && $(xavp(ulattrs=>custom_channel_vars){s.len}) > 1)) { xlog("L_INFO", "$ci|log|not authorized $fu from $si:$sp\n"); send_reply("503", "Not Registered"); exit; # route(ATTEMPT_AUTHORIZATION); } } route[ATTEMPT_AUTHORIZATION] { $var(nonce) = $(uuid(g){s.rm,-}); #!ifdef OPENBTS_AUTH_ROLE if($ua =~ "OpenBTS" && $sht(auth_cache=>$Au::nonce) != $null ) { $var(nonce) = $sht(auth_cache=>$Au::nonce); } #!endif $xavp(regcfg=>match_received) = $su; if($sht(auth_cache=>$Au) != $null && registered("location", "$rz:$Au", 2, 1) == 1 && $(xavp(ulattrs=>custom_channel_vars){s.len}) > 1) { $var(password) = $sht(auth_cache=>$Au); route(SAVE_LOCATION); } if( is_present_hf("Authorization")) { route(KAZOO_AUTHORIZATION); } #!ifdef OPENBTS_AUTH_ROLE if($ua =~ "OpenBTS") { openbts_auth_challenge("$fd", "$var(nonce)"); } else { #!endif auth_challenge("$fd", "0"); #!ifdef OPENBTS_AUTH_ROLE } #!endif xlog("L_INFO", "$ci|end|issued auth challenge to new registration for $fu $si:$sp\n"); exit; } route[KAZOO_AUTHORIZATION] { $var(nonce) = $adn; $var(amqp_payload_request) = $_s({"Event-Category" : "directory" , "Event-Name" : "authn_req", "Method" : "REGISTER", "Auth-Nonce" : "$adn", "Auth-Realm" : "$fd", "Auth-User" : "$fU", "From" : "$fu", "To" : "$tu", "Orig-IP" : "$si", "Orig-Port" : "$sp", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci" }); $var(amqp_routing_key) = "authn.req." + $(fd{kz.encode}); $avp(kz_timeout) = 2500; if (!t_newtran()) { sl_reply_error(); exit(); } if(kazoo_async_query("callmgr", $var(amqp_routing_key), $var(amqp_payload_request), "KAZOO_AUTHORIZATION_OK", "KAZOO_AUTHORIZATION_ERROR") != 1) { xlog("L_INFO", "$ci|log|failed to send Kazoo query for authentication credentials for $Au $si:$sp\n"); append_to_reply("Retry-After: 60\r\n"); send_reply("503", "Retry Later"); exit; } } route[KAZOO_AUTHORIZATION_OK] { $var(password) = $(kzR{kz.json,Auth-Password}); $var(nonce) = $adn; #!ifdef OPENBTS_AUTH_ROLE if( $(kzR{kz.json,Auth-Nonce}) != "" && $var(nonce) != $(kzR{kz.json,Auth-Nonce})) { xlog("L_INFO", "$ci|log|nonce replace $var(nonce) with $(kzR{kz.json,Auth-Nonce})\n"); $var(nonce) = $(kzR{kz.json,Auth-Nonce}); $sht(auth_cache=>$Au::nonce) = $var(nonce); } #!endif if( $(kzR{kz.json,Event-Name}) == "authn_err" ) { auth_challenge("$fd", "0"); xlog("L_INFO", "$ci|end|issued auth challenge to registration attempt for $Au $si:$sp\n"); exit; } else { $xavp(ulattrs=>custom_channel_vars) = $(kzR{kz.json,Custom-Channel-Vars}); xlog("L_INFO", "$ci|log|authenticating $Au via Kazoo query response\n"); route(CHECK_AUTHORIZATION); } } route[KAZOO_AUTHORIZATION_ERROR] { xlog("L_INFO", "$ci|log|failed to query Kazoo for authentication credentials for $Au $si:$sp\n"); append_to_reply("Retry-After: 60\r\n"); send_reply("503", "Retry Later"); exit; } route[CHECK_AUTHORIZATION] { if($ua =~ "OpenBTS") { xlog("L_INFO", "$ci|end|OPENBTS attempt for $Au $si:$sp\n"); } else { if($var(password) == $null || $var(password) == "") { auth_challenge("$fd", "0"); xlog("L_INFO", "$ci|end|issued auth challenge to registration attempt for $Au $si:$sp\n"); exit; } if (!pv_auth_check("$fd", "$var(password)", "0", "0")) { #!ifdef ANTIFLOOD_ROLE route(ANITFLOOD_FAILED_AUTH); #!endif auth_challenge("$fd", "0"); xlog("L_INFO", "$ci|end|issued auth challenge to failed registration attempt for $Au $si:$sp\n"); exit; } } #!ifdef ANTIFLOOD_ROLE route(ANTIFLOOD_SUCCESSFUL_AUTH); #!endif # user authenticated - remove auth header consume_credentials(); route(SAVE_LOCATION); } route[SAVE_LOCATION] { if ($sht(auth_cache=>$Au) == $null) { xlog("L_INFO", "$ci|log|caching sip credentials for $Au\n"); }; $sht(auth_cache=>$Au) = $var(password); #!ifdef OPENBTS_AUTH_ROLE if($ua =~ "OpenBTS") { $sht(auth_cache=>$Au::nonce) = $var(nonce); } #!endif $var(save_result) = save("location", "0x04"); if($var(save_result) == -1) { auth_challenge("$fd", "0"); xlog("L_INFO", "$ci|end|issued auth challenge after failed attempt to save contact for $Au $si:$sp\n"); exit; } else { if($var(save_result) == 1) { $var(new_reg) = "true"; } else { $var(new_reg) = "false"; } } if(@contact.expires) { $var(expires) = @contact.expires; } else { if(is_present_hf("Expires")) { $var(expires) = $hdr(Expires); } else { $var(expires) = REGISTRAR_MIN_EXPIRES; } } if($var(expires) == 0) { xlog("L_INFO", "$ci|end|unregister request from $Au $si:$sp\n"); $var(Status) = "Unregistered"; } else { $var(Status) = "Registered"; if($var(Expires) < REGISTRAR_MIN_EXPIRES) { $var(Expires) = REGISTRAR_MIN_EXPIRES; } else if($var(Expires) > REGISTRAR_MAX_EXPIRES) { $var(Expires) = REGISTRAR_MAX_EXPIRES; } } $var(ip) = $Ri; if(af==INET6) { $var(ip) = "[" + $Ri + "]"; } $var(amqp_payload_request) = $_s({"Event-Category" : "directory", "Event-Name" : "reg_success", "Status" : "$var(Status)", "Event-Timestamp" : $TS, "Expires" : $(var(expires){s.int}), "First-Registration" : $var(new_reg), "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci", "Realm" : "$fd", "Username" : "$fU", "From-User" : "$fU", "From-Host" : "$fd", "To-User" : "$tU", "To-Host" : "$td", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})" , "Custom-Channel-Vars" : $xavp(ulattrs=>custom_channel_vars), "Proxy-Path" : "sip:$var(ip)", "RUID" : "$xavp(ulrcd=>ruid)", "Source-IP": "$si", "Source-Port": "$sp" }); $var(amqp_routing_key) = "registration.success." + $(fd{kz.encode}) + "." + $(fU{kz.encode}); kazoo_publish("registrar", $var(amqp_routing_key), $var(amqp_payload_request)); xlog("L_INFO", "$ci|end|successful $(var(Status){s.tolower}) with contact $ct\n"); #!ifdef PUSHER_ROLE route(PUSHER_ON_REGISTRATION); #!endif exit; } ## kazoo event route , {"directory", "reg_flush") => reg-flush by kamailio limitations ## when a Event-Category or Event-Name has a underscore (_) we need to declare it with a dash (-) event_route[kazoo:consumer-event-directory-reg-flush] { $var(user) = $(kzE{kz.json,Username}) + "@" + $(kzE{kz.json,Realm}); if ($sht(auth_cache=>$var(user)) != $null) { xlog("L_INFO", "log|removing SIP credentials cache for $var(user)\n"); $sht(auth_cache=>$var(user)) = $null; } #!ifdef ANTIFLOOD_ROLE route(ANTIFLOOD_RESET_AUTH); #!endif } # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab