|
|
|
@ -9,13 +9,20 @@ 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", "text:///etc/kazoo/kamailio/dbtext") |
|
|
|
modparam("usrloc", "db_mode", 0) |
|
|
|
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) |
|
|
|
@ -39,7 +46,13 @@ 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] |
|
|
|
@ -54,50 +67,147 @@ route[HANDLE_REGISTER] |
|
|
|
} |
|
|
|
|
|
|
|
## KAZOO-1846: Cisco SPA8000 freaks out on options pings |
|
|
|
if (!($ua =~ "Linksys/SPA8000")) { |
|
|
|
if (!($ua =~ "Linksys/SPA8000" |
|
|
|
|| $ua =~ "OpenBTS" |
|
|
|
|| $ua =~ "SIPp" |
|
|
|
|| (af==INET6) |
|
|
|
)) { |
|
|
|
setbflag(FLB_NATB); |
|
|
|
setbflag(FLB_NATSIPPING); |
|
|
|
} |
|
|
|
#!endif |
|
|
|
|
|
|
|
if (is_present_hf("Authorization")) { |
|
|
|
route(ATTEMPT_AUTHORIZATION); |
|
|
|
} else { |
|
|
|
auth_challenge("$fd", "0"); |
|
|
|
xlog("L_INFO", "$ci|end|issued auth challenge to new registration for $fu $si:$sp"); |
|
|
|
exit; |
|
|
|
} |
|
|
|
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"); |
|
|
|
send_reply("500", "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) { |
|
|
|
xlog("L_INFO", "$ci|log|authenticating $fu via cached SIP creds"); |
|
|
|
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(CHECK_AUTHORIZATION); |
|
|
|
} |
|
|
|
|
|
|
|
if( is_present_hf("Authorization")) { |
|
|
|
route(KAZOO_AUTHORIZATION); |
|
|
|
} |
|
|
|
|
|
|
|
#!ifdef OPENBTS_AUTH-ROLE |
|
|
|
if($ua =~ "OpenBTS") { |
|
|
|
openbts_auth_challenge("$fd", "$var(nonce)"); |
|
|
|
} else { |
|
|
|
$var(amqp_payload_request) = "{'Event-Category' : 'directory' , 'Event-Name' : 'authn_req', 'Method' : 'REGISTER', 'Auth-Realm' : '" + $fd + "', 'Auth-User' : '" + $fU + "', 'From' : '" + $fu + "', 'To' : '" + $tu +"' }"; |
|
|
|
$var(amqp_routing_key) = "authn.req." + $(fd{kz.encode}); |
|
|
|
sl_send_reply("100", "Attempting K query"); |
|
|
|
if(kazoo_query("callmgr", $var(amqp_routing_key), $var(amqp_payload_request))) { |
|
|
|
$var(password) = $(kzR{kz.json,Auth-Password}); |
|
|
|
$xavp(ulattrs=>custom_channel_vars) = $(kzR{kz.json,Custom-Channel-Vars}); |
|
|
|
xlog("L_INFO", "$ci|log|authenticating $Au via Kazoo query response"); |
|
|
|
} else { |
|
|
|
xlog("L_INFO", "$ci|log|failed to query Kazoo for authentication credentials for $Au $si:$sp"); |
|
|
|
append_to_reply("Retry-After: 60\r\n"); |
|
|
|
sl_send_reply("500", "Retry Later"); |
|
|
|
#!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"); |
|
|
|
exit; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
route[KAZOO_AUTHORIZATION] |
|
|
|
{ |
|
|
|
$var(nonce) = $adn; |
|
|
|
$var(amqp_payload_request) = '{"Event-Category" : "directory" , "Event-Name" : "authn_req", "Method" : "REGISTER", "Auth-Nonce" : "$adn", "Auth-Realm" : "$fd", "Auth-User" : "$fU", "From" : "$fu", "To" : "$tu" }'; |
|
|
|
$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"); |
|
|
|
append_to_reply("Retry-After: 60\r\n"); |
|
|
|
send_reply("500", "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})"); |
|
|
|
$var(nonce) = $(kzR{kz.json,Auth-Nonce}); |
|
|
|
$sht(auth_cache=>$Au::nonce) = $var(nonce); |
|
|
|
} |
|
|
|
#!endif |
|
|
|
$xavp(ulattrs=>custom_channel_vars) = $(kzR{kz.json,Custom-Channel-Vars}); |
|
|
|
xlog("L_INFO", "$ci|log|authenticating $Au via Kazoo query response"); |
|
|
|
route(CHECK_AUTHORIZATION); |
|
|
|
} |
|
|
|
|
|
|
|
route[KAZOO_AUTHORIZATION_ERROR] |
|
|
|
{ |
|
|
|
xlog("L_INFO", "$ci|log|failed to query Kazoo for authentication credentials for $Au $si:$sp"); |
|
|
|
append_to_reply("Retry-After: 60\r\n"); |
|
|
|
send_reply("500", "Retry Later"); |
|
|
|
exit; |
|
|
|
} |
|
|
|
|
|
|
|
route[CHECK_AUTHORIZATION] |
|
|
|
{ |
|
|
|
|
|
|
|
#!ifdef OPENBTS_AUTH-ROLE |
|
|
|
if($ua =~ "OpenBTS") { |
|
|
|
if($var(password) == $null) { |
|
|
|
openbts_auth_challenge("$fd", "$var(nonce)"); |
|
|
|
xlog("L_INFO", "$ci|end|issued auth challenge to registration attempt for $Au $si:$sp"); |
|
|
|
exit; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!openbts_auth_check("$fd", "$var(password)")) { |
|
|
|
#!ifdef ANTIFLOOD-ROLE |
|
|
|
route(ANITFLOOD_FAILED_AUTH); |
|
|
|
#!endif |
|
|
|
openbts_auth_challenge("$fd", "$var(nonce)"); |
|
|
|
xlog("L_INFO", "$ci|end|issued auth challenge to failed registration attempt for $Au $si:$sp"); |
|
|
|
exit; |
|
|
|
} |
|
|
|
} else { |
|
|
|
#!endif |
|
|
|
|
|
|
|
if($var(password) == $null) { |
|
|
|
auth_challenge("$fd", "0"); |
|
|
|
xlog("L_INFO", "$ci|end|issued auth challenge to registration attempt for $Au $si:$sp"); |
|
|
|
exit; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!pv_auth_check("$fd", "$var(password)", "0", "0")) { |
|
|
|
#!ifdef ANTIFLOOD-ROLE |
|
|
|
route(ANITFLOOD_FAILED_AUTH); |
|
|
|
@ -108,6 +218,12 @@ route[ATTEMPT_AUTHORIZATION] |
|
|
|
exit; |
|
|
|
} |
|
|
|
|
|
|
|
#!ifdef OPENBTS_AUTH-ROLE |
|
|
|
} |
|
|
|
#!endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#!ifdef ANTIFLOOD-ROLE |
|
|
|
route(ANTIFLOOD_SUCCESSFUL_AUTH); |
|
|
|
#!endif |
|
|
|
@ -115,12 +231,21 @@ route[ATTEMPT_AUTHORIZATION] |
|
|
|
if ($sht(auth_cache=>$Au) == $null) { |
|
|
|
xlog("L_INFO", "$ci|log|caching SIP credentials for $Au"); |
|
|
|
$sht(auth_cache=>$Au) = $var(password); |
|
|
|
#!ifdef OPENBTS_AUTH-ROLE |
|
|
|
if($ua =~ "OpenBTS") { |
|
|
|
$sht(auth_cache=>$Au::nonce) = $var(nonce); |
|
|
|
} |
|
|
|
#!endif |
|
|
|
} |
|
|
|
|
|
|
|
# user authenticated - remove auth header |
|
|
|
consume_credentials(); |
|
|
|
route(SAVE_LOCATION); |
|
|
|
} |
|
|
|
|
|
|
|
$var(save_result) = save("location", "0x04"); |
|
|
|
route[SAVE_LOCATION] |
|
|
|
{ |
|
|
|
$var(save_result) = save("location"); |
|
|
|
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"); |
|
|
|
@ -144,52 +269,32 @@ route[ATTEMPT_AUTHORIZATION] |
|
|
|
} |
|
|
|
|
|
|
|
if($var(expires) == 0) { |
|
|
|
xlog("L_INFO", "$ci|end|unregister request from $Au $si:$sp"); |
|
|
|
exit; |
|
|
|
} else if($var(expires) < REGISTRAR_MIN_EXPIRES) { |
|
|
|
$var(expires) = REGISTRAR_MIN_EXPIRES; |
|
|
|
} else if($var(expires) > REGISTRAR_MAX_EXPIRES) { |
|
|
|
$var(expires) = REGISTRAR_MAX_EXPIRES; |
|
|
|
} |
|
|
|
|
|
|
|
## Fix for wss websockets. |
|
|
|
## RFC 7118 says transport MUST be "ws" not "wss" |
|
|
|
## http://tools.ietf.org/html/rfc7118#section-5.2 |
|
|
|
if ($(proto{s.tolower}) == 'wss') { |
|
|
|
$var(transport) = "ws"; |
|
|
|
xlog("L_INFO", "$ci|end|unregister request from $Au $si:$sp"); |
|
|
|
$var(Status) = "Unregistered"; |
|
|
|
} else { |
|
|
|
$var(transport) = $(proto{s.tolower}); |
|
|
|
$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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if($var(transport) == "udp" ||$var(transport) == "tcp" || $var(transport) == "tls") { |
|
|
|
$var(return_port) = $Rp; |
|
|
|
} else { |
|
|
|
$var(return_port) = "5060"; |
|
|
|
$var(ip) = $Ri; |
|
|
|
if(af==INET6) { |
|
|
|
$var(ip) = "[" + $Ri + "]"; |
|
|
|
} |
|
|
|
|
|
|
|
$var(params) = "fs_path=<sip:" + $Ri + ":" + $var(return_port) + ";lr;received='" + $rz + ":" + $si + ":" + $sp + ";transport=" + $var(transport) + "'>"; |
|
|
|
|
|
|
|
## TODO: fix escaping, some phones send us -- reg-id=1;+sip.instance="urn:uuid:9b8bd513-0e6e-4660-ad5e-5e35d88cc68f"; |
|
|
|
## and if we can store it but not use it because it looses the escapes (that weren't there...) |
|
|
|
#if($(ct{tobody.params}) != $null) { |
|
|
|
# $var(params) = $(ct{tobody.params}{s.escape.common}) + ";" + $var(params); |
|
|
|
#} |
|
|
|
|
|
|
|
if ($avp(AVP_RECV_PARAM) == $null) { |
|
|
|
$var(fs_contact) = "<" + $(ct{tobody.uri}) + ";" + $var(params) + ">"; |
|
|
|
} else { |
|
|
|
$var(fs_contact) = "<sip:" + $(ct{tobody.user}) + "@" + $si + ":" + $sp + ";transport=" + $var(transport) + ";" + $var(params) + ">"; |
|
|
|
} |
|
|
|
|
|
|
|
$var(register_contants) = ' "Presence-Hosts" : "n/a", "Profile-Name" : "sipinterface_1", "Status" : "Registered", "Event-Timestamp" : "' + $TS + '", "Expires" : ' + $var(expires); |
|
|
|
|
|
|
|
$var(amqp_payload_request) = '{"Event-Category" : "directory", "Event-Name" : "reg_success", "First-Registration" : $var(new_reg), "Contact" : "$var(fs_contact)", "Call-ID" : "$ci", "Realm" : "$fd", "Username" : "$fU", "From-User" : "$fU", "From-Host" : "$fd", "To-User" : "$tU", "To-Host" : "$td", "User-Agent" : "$ua" , "Custom-Channel-Vars" : $xavp(ulattrs=>custom_channel_vars), $var(register_contants) }'; |
|
|
|
|
|
|
|
$var(amqp_payload_request) = '{"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})", "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})" , "Custom-Channel-Vars" : $xavp(ulattrs=>custom_channel_vars), "Proxy-Path" : "sip:$var(ip)", "RUID" : "$xavp(ulrcd=>ruid)" }'; |
|
|
|
$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 registration with contact $var(fs_contact)"); |
|
|
|
xlog("L_INFO", "$ci|end|successful $(var(Status){s.tolower}) with contact $ct"); |
|
|
|
|
|
|
|
#!ifdef PUSHER-ROLE |
|
|
|
route(PUSHER_ON_REGISTRATION); |
|
|
|
#!endif |
|
|
|
|
|
|
|
exit; |
|
|
|
} |
|
|
|
|
|
|
|
@ -206,7 +311,6 @@ event_route[kazoo:consumer-event-directory-reg-flush] |
|
|
|
#!ifdef ANTIFLOOD-ROLE |
|
|
|
route(ANTIFLOOD_RESET_AUTH); |
|
|
|
#!endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab |