|
|
@ -1,6 +1,10 @@ |
|
|
|
|
|
#!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 ######## |
|
|
######## Generic Hash Table container in shared memory ######## |
|
|
modparam("htable", "htable", "auth_cache=>size=16;autoexpire=7200") |
|
|
|
|
|
modparam("htable", "htable", "failed_auth_hash=>size=14;autoexpire=180;") |
|
|
|
|
|
|
|
|
modparam("htable", "htable", "auth_cache=>size=16;autoexpire=7200;") |
|
|
|
|
|
|
|
|
####### Authentication Interface module ########## |
|
|
####### Authentication Interface module ########## |
|
|
loadmodule "auth.so" |
|
|
loadmodule "auth.so" |
|
|
@ -16,17 +20,17 @@ modparam("usrloc", "nat_bflag", FLB_NATB) |
|
|
#!ifdef NAT-TRAVERSAL-ROLE |
|
|
#!ifdef NAT-TRAVERSAL-ROLE |
|
|
#!trydef NATHELPER-LOADED |
|
|
#!trydef NATHELPER-LOADED |
|
|
loadmodule "nathelper.so" |
|
|
loadmodule "nathelper.so" |
|
|
modparam("nathelper", "natping_interval", 30) |
|
|
|
|
|
|
|
|
modparam("nathelper", "natping_interval", REGISTRAR_NAT_PING_INTERVAL) |
|
|
modparam("nathelper", "ping_nated_only", 1) |
|
|
modparam("nathelper", "ping_nated_only", 1) |
|
|
modparam("nathelper", "natping_processes", 5) |
|
|
|
|
|
|
|
|
modparam("nathelper", "natping_processes", REGISTRAR_NAT_PING_WORKERS) |
|
|
modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) |
|
|
modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) |
|
|
#!endif |
|
|
#!endif |
|
|
|
|
|
|
|
|
####### SIP Registrar implementation module ########## |
|
|
####### SIP Registrar implementation module ########## |
|
|
loadmodule "registrar.so" |
|
|
loadmodule "registrar.so" |
|
|
modparam("registrar", "received_avp", "$avp(AVP_RECV_PARAM)") |
|
|
modparam("registrar", "received_avp", "$avp(AVP_RECV_PARAM)") |
|
|
modparam("registrar", "min_expires", 300) |
|
|
|
|
|
modparam("registrar", "max_expires", 3600) |
|
|
|
|
|
|
|
|
modparam("registrar", "min_expires", REGISTRAR_MIN_EXPIRES) |
|
|
|
|
|
modparam("registrar", "max_expires", REGISTRAR_MAX_EXPIRES) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
####### Registrar Logic ######## |
|
|
####### Registrar Logic ######## |
|
|
@ -34,10 +38,6 @@ route[HANDLE_REGISTER] |
|
|
{ |
|
|
{ |
|
|
if (is_method("REGISTER")) { |
|
|
if (is_method("REGISTER")) { |
|
|
|
|
|
|
|
|
#!ifdef TRAFFIC-FILTER-ROLE |
|
|
|
|
|
route(DOMAIN_FORMAT_CHECK); |
|
|
|
|
|
#!endif |
|
|
|
|
|
|
|
|
|
|
|
#!ifdef NAT-TRAVERSAL-ROLE |
|
|
#!ifdef NAT-TRAVERSAL-ROLE |
|
|
if (nat_uac_test("3")) { |
|
|
if (nat_uac_test("3")) { |
|
|
xlog("L_INFO", "$ci|log|correcting NATed contact in registration"); |
|
|
xlog("L_INFO", "$ci|log|correcting NATed contact in registration"); |
|
|
@ -53,143 +53,98 @@ route[HANDLE_REGISTER] |
|
|
#!endif |
|
|
#!endif |
|
|
|
|
|
|
|
|
if (is_present_hf("Authorization")) { |
|
|
if (is_present_hf("Authorization")) { |
|
|
#!ifdef TRAFFIC-FILTER-ROLE |
|
|
|
|
|
if (!route(PREVENT_BRUTEFORCE)) { |
|
|
|
|
|
auth_challenge("$fd", "0"); |
|
|
|
|
|
exit; |
|
|
|
|
|
} |
|
|
|
|
|
#!endif |
|
|
|
|
|
|
|
|
|
|
|
if ($sht(auth_cache=>$Au) != $null && pv_auth_check("$fd", "$sht(auth_cache=>$Au)", "0", "0")) { |
|
|
|
|
|
xlog("L_INFO", "$ci|log|authenticated $Au via cached SIP creds"); |
|
|
|
|
|
} else { |
|
|
|
|
|
## RABBITMQ - Credentials fetch |
|
|
|
|
|
$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}); |
|
|
|
|
|
if(kazoo_query("callmgr", $var(amqp_routing_key), $var(amqp_payload_request))) { |
|
|
|
|
|
$var(password) = $(kzR{kz.json,Auth-Password}); |
|
|
|
|
|
if($var(password) != $null) { |
|
|
|
|
|
if (!pv_auth_check("$fd", "$var(password)", "0", "0")) { |
|
|
|
|
|
|
|
|
|
|
|
#!ifdef TRAFFIC-FILTER-ROLE |
|
|
|
|
|
route(FAILED_AUTH_COUNT); |
|
|
|
|
|
#!endif |
|
|
|
|
|
|
|
|
|
|
|
auth_challenge("$fd", "0"); |
|
|
|
|
|
xlog("L_INFO", "$ci|end|failed registration attempt from $si:$sp for $Au"); |
|
|
|
|
|
exit; |
|
|
|
|
|
} else { |
|
|
|
|
|
xlog("L_DBG", "$ci|log|caching SIP credentials for $Au"); |
|
|
|
|
|
$sht(auth_cache=>$Au) = $var(password); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
auth_challenge("$fd", "0"); |
|
|
|
|
|
xlog("L_INFO", "$ci|log|error getting password from kazoo response"); |
|
|
|
|
|
exit; |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
auth_challenge("$fd", "0"); |
|
|
|
|
|
xlog("L_INFO", "$ci|log|error query kazoo for credentials"); |
|
|
|
|
|
exit; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
route(ATTEMPT_AUTHORIZATION); |
|
|
} else { |
|
|
} else { |
|
|
auth_challenge("$fd", "0"); |
|
|
auth_challenge("$fd", "0"); |
|
|
xlog("L_INFO", "$ci|end|issued new auth challenge to registration attempt from $Au $si:$sp"); |
|
|
|
|
|
|
|
|
xlog("L_INFO", "$ci|end|issued auth challenge to new registration for $Au $si:$sp"); |
|
|
exit; |
|
|
exit; |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
# user authenticated - remove auth header |
|
|
|
|
|
consume_credentials(); |
|
|
|
|
|
|
|
|
|
|
|
save("location"); |
|
|
|
|
|
$var(expires) = @contact.expires; |
|
|
|
|
|
if($var(expires) == $null) { |
|
|
|
|
|
$var(expires) = $hdr(Expires); |
|
|
|
|
|
} |
|
|
|
|
|
if($var(expires) == $null) { |
|
|
|
|
|
$var(expires) = 190; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$var(params) = "fs_path=<sip:MY_IP_ADDRESS:5060;lr;received='" + $rz + ":" + $si + ":" + $sp + ";transport=" + $proto + "'>"; |
|
|
|
|
|
|
|
|
|
|
|
## 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) + ">"; |
|
|
|
|
|
|
|
|
route[ATTEMPT_AUTHORIZATION] |
|
|
|
|
|
{ |
|
|
|
|
|
#!ifdef ANTIFLOOD-ROLE |
|
|
|
|
|
if (!route(ANITFLOOD_AUTH_LIMIT)) { |
|
|
|
|
|
xlog("L_WARN", "$ci|log|dropping erroneous endpoint registration for $Au $si:$sp"); |
|
|
|
|
|
drop(); |
|
|
|
|
|
exit; |
|
|
|
|
|
} |
|
|
|
|
|
#!endif |
|
|
|
|
|
|
|
|
|
|
|
if ($sht(auth_cache=>$Au) != $null) { |
|
|
|
|
|
xlog("L_INFO", "$ci|log|authenticating $Au via cached SIP creds"); |
|
|
|
|
|
$var(password) = $sht(auth_cache=>$Au); |
|
|
|
|
|
} 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}); |
|
|
|
|
|
if(kazoo_query("callmgr", $var(amqp_routing_key), $var(amqp_payload_request))) { |
|
|
|
|
|
$var(password) = $(kzR{kz.json,Auth-Password}); |
|
|
|
|
|
xlog("L_INFO", "$ci|log|authenticating $Au via Kazoo query response"); |
|
|
} else { |
|
|
} else { |
|
|
$var(fs_contact) = "<sip:" + $(ct{tobody.user}) + "@" + $si + ":" + $sp + ";transport=" + $proto + ";" + $var(params) + ">"; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xlog("L_INFO", "$ci|end|successful registration with contact $var(fs_contact)"); |
|
|
|
|
|
$var(register_contants) = ' "Presence-Hosts" : "n/a", "Profile-Name" : "sipinterface_1", "Status" : "Registered", "Event-Timestamp" : "' + $TS + '"'; |
|
|
|
|
|
|
|
|
|
|
|
if($var(expires) != $null) { |
|
|
|
|
|
$var(register_contants) = $var(register_contants) + ', "Expires" : ' + $var(expires); |
|
|
|
|
|
|
|
|
xlog("L_INFO", "$ci|log|failed to query Kazoo for authentication credentials for $Au $si:$sp"); |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
$var(amqp_payload_request) = '{"Event-Category" : "directory", "Event-Name" : "reg_success", "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 + '" ,' + $var(register_contants) + ' }'; |
|
|
|
|
|
|
|
|
|
|
|
$var(amqp_routing_key) = "registration.success." + $(fd{kz.encode}) + "." + $fU; |
|
|
|
|
|
|
|
|
if($var(password) == $null) { |
|
|
|
|
|
auth_challenge("$fd", "0"); |
|
|
|
|
|
xlog("L_INFO", "$ci|end|issued auth challenge to registration attempt for $Au $si:$sp"); |
|
|
|
|
|
exit; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
kazoo_publish("callmgr", $var(amqp_routing_key), $var(amqp_payload_request)); |
|
|
|
|
|
|
|
|
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"); |
|
|
exit; |
|
|
exit; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
# AUTH: check to see if user if present in failed_auth_hash |
|
|
|
|
|
route[PREVENT_BRUTEFORCE] |
|
|
|
|
|
{ |
|
|
|
|
|
if (isflagset(FLAG_TRUSTED_SOURCE)) { |
|
|
|
|
|
return(1); |
|
|
|
|
|
|
|
|
if ($kzR != $null) { |
|
|
|
|
|
xlog("L_DBG", "$ci|log|caching SIP credentials for $Au"); |
|
|
|
|
|
$sht(auth_cache=>$Au) = $avp(password); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if($sht(failed_auth_hash=>$Au::count) >= 2) { |
|
|
|
|
|
$var(exp) = $Ts - 120; |
|
|
|
|
|
if($sht(failed_auth_hash=>$Au::last) > $var(exp)){ |
|
|
|
|
|
xlog("L_WARN", "$ci|log|possible password brute force, from $ct on user $Au"); |
|
|
|
|
|
return(-1); |
|
|
|
|
|
} else { |
|
|
|
|
|
$sht(failed_auth_hash=>$Au::count) = 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return(1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
# user authenticated - remove auth header |
|
|
|
|
|
consume_credentials(); |
|
|
|
|
|
save("location"); |
|
|
|
|
|
|
|
|
#AUTH: add to failed_auth_hash in case of authentication password error |
|
|
|
|
|
route[FAILED_AUTH_COUNT] |
|
|
|
|
|
{ |
|
|
|
|
|
if (isflagset(FLAG_TRUSTED_SOURCE)) { |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
$var(expires) = @contact.expires; |
|
|
|
|
|
if($var(expires) == $null) { |
|
|
|
|
|
$var(expires) = $hdr(Expires); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if ($rc == -2) { |
|
|
|
|
|
if($sht(failed_auth_hash=>$Au::count) == $null) { |
|
|
|
|
|
$sht(failed_auth_hash=>$Au::count) = 0; |
|
|
|
|
|
} |
|
|
|
|
|
$sht(failed_auth_hash=>$Au::count) = $sht(failed_auth_hash=>$Au::count) + 1; |
|
|
|
|
|
$sht(failed_auth_hash=>$Au::last) = $Ts; |
|
|
|
|
|
|
|
|
if($var(expires) == $null) { |
|
|
|
|
|
$var(expires) = REGISTRAR_MIN_EXPIRES; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
route[DOMAIN_FORMAT_CHECK] |
|
|
|
|
|
{ |
|
|
|
|
|
if (isflagset(FLAG_TRUSTED_SOURCE)) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
$var(params) = "fs_path=<sip:MY_IP_ADDRESS:5060;lr;received='" + $rz + ":" + $si + ":" + $sp + ";transport=" + $proto + "'>"; |
|
|
|
|
|
|
|
|
if ($rd =~ "([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})" || |
|
|
|
|
|
$td =~ "([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})" ) { |
|
|
|
|
|
xlog("L_WARN", "$ci|end|denying request with IP domain in From or To header"); |
|
|
|
|
|
send_reply("403", "Forbidden"); |
|
|
|
|
|
exit; |
|
|
|
|
|
|
|
|
## 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=" + $proto + ";" + $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", "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 + '" ,' + $var(register_contants) + ' }'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kazoo_publish("callmgr", $var(amqp_routing_key), $var(amqp_payload_request)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xlog("L_INFO", "$ci|end|successful registration with contact $var(fs_contact)"); |
|
|
|
|
|
|
|
|
|
|
|
exit; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab |
|
|
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab |