Browse Source

break the anti-flood and traffic filter roles apart

3.19
karl anderson 11 years ago
parent
commit
ba53ccff70
5 changed files with 270 additions and 211 deletions
  1. +72
    -0
      kamailio/antiflood-role.cfg
  2. +61
    -87
      kamailio/default.cfg
  3. +1
    -0
      kamailio/local.cfg
  4. +79
    -124
      kamailio/registrar-role.cfg
  5. +57
    -0
      kamailio/traffic-filter-role.cfg

+ 72
- 0
kamailio/antiflood-role.cfg View File

@ -0,0 +1,72 @@
#!trydef ANTIFLOOD_RATE_WINDOW 2
#!trydef ANTIFLOOD_RATE_DENSITY 50
#!trydef ANTIFLOOD_RATE_EXPIRE 4
#!trydef ANTIFLOOD_FAILED_AUTH_WINDOW 120
#!trydef ANTIFLOOD_FAILED_AUTH_DENSITY 3
######## Flood Prevention Hash Tables ########
modparam("htable", "htable", "ipban=>size=8;autoexpire=300;")
modparam("htable", "htable", "failed_auth_hash=>size=8;autoexpire=125;")
######## Flood Prevention Module ########
loadmodule "pike.so"
modparam("pike", "sampling_time_unit", ANTIFLOOD_RATE_WINDOW)
modparam("pike", "reqs_density_per_unit", ANTIFLOOD_RATE_DENSITY)
modparam("pike", "remove_latency", ANTIFLOOD_RATE_EXPIRE)
route[ANTIFLOOD_RATE_LIMIT]
{
xlog("$ci|log|maybe allow $si:$sp");
if (has_totag() || isflagset(FLAG_TRUSTED_SOURCE)) {
return;
}
if($sht(ipban=>$si)!=$null) {
# ip is already blocked
xlog("$ci|log|dropping $rm request from $fu with banned IP $si:$sp");
drop();
exit;
}
# use pike to control the rates
if (!pike_check_req()) {
xlog("L_WARN", "$ci|log|pike dropping $rm from $fu due to rate of requests with source $si:$sp");
$sht(ipban=>$si) = 1;
drop();
exit;
}
}
route[ANITFLOOD_AUTH_LIMIT]
{
if (isflagset(FLAG_TRUSTED_SOURCE)) {
return(1);
}
if($sht(failed_auth_hash=>$Au::count) >= ANTIFLOOD_FAILED_AUTH_DENSITY) {
$var(exp) = $Ts - ANTIFLOOD_FAILED_AUTH_WINDOW;
if($sht(failed_auth_hash=>$Au::last) > $var(exp)){
$sht(failed_auth_hash=>$Au::last) = $Ts;
xlog("L_WARN", "$ci|log|ignoring erroneous endpoint registrations from $ct for $Au");
return(-1);
} else {
$sht(failed_auth_hash=>$Au::count) = 0;
}
}
return(1);
}
route[ANITFLOOD_FAILED_AUTH]
{
if (isflagset(FLAG_TRUSTED_SOURCE)) {
return;
}
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;
}

+ 61
- 87
kamailio/default.cfg View File

@ -113,10 +113,8 @@ loadmodule "siputils.so"
######## SIP message formatting sanity checks [requires sl] ######## ######## SIP message formatting sanity checks [requires sl] ########
loadmodule "sanity.so" loadmodule "sanity.so"
# sip_version, scheme, req_headers, cseq_method/value
# content_length, parse_uri, digest
modparam("sanity", "default_checks", 3303)
modparam("sanity", "uri_checks", 3)
modparam("sanity", "default_checks", 1511)
modparam("sanity", "uri_checks", 7)
modparam("sanity", "autodrop", 0) modparam("sanity", "autodrop", 0)
######## Text operations module ######## ######## Text operations module ########
@ -141,9 +139,6 @@ modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
######## UAC Redirection module ######## ######## UAC Redirection module ########
loadmodule "uac_redirect.so" loadmodule "uac_redirect.so"
######## DoS prevention mdule ########
loadmodule "pike.so"
####### DB Text module ########## ####### DB Text module ##########
loadmodule "db_text.so" loadmodule "db_text.so"
modparam("db_text", "db_mode", 1) modparam("db_text", "db_mode", 1)
@ -188,6 +183,12 @@ include_file "tls-role.cfg"
#!ifdef ACCOUNTING-ROLE #!ifdef ACCOUNTING-ROLE
include_file "accounting-role.cfg" include_file "accounting-role.cfg"
#!endif #!endif
#!ifdef ANTIFLOOD-ROLE
include_file "antiflood-role.cfg"
#!endif
#!ifdef TRAFFIC-FILTER-ROLE
include_file "traffic-filter-role.cfg"
#!endif
####### Permissions module ########## ####### Permissions module ##########
loadmodule "permissions.so" loadmodule "permissions.so"
@ -205,12 +206,14 @@ route
route(SANITY_CHECK); route(SANITY_CHECK);
#!ifdef DISPATCHER-ROLE
route(DISPATCHER_CLASSIFY_SOURCE);
route(CLASSIFY_SOURCE);
#!ifdef ANTIFLOOD-ROLE
route(ANTIFLOOD_RATE_LIMIT);
#!endif #!endif
#!ifdef TRAFFIC-FILTER-ROLE #!ifdef TRAFFIC-FILTER-ROLE
route(DOS_PREVENTION);
route(TRAFFIC_FILTER);
#!endif #!endif
#!ifdef WEBSOCKETS-ROLE #!ifdef WEBSOCKETS-ROLE
@ -223,8 +226,6 @@ route
route(HANDLE_MESSAGE); route(HANDLE_MESSAGE);
route(HANDLE_MOVE_REQUEST);
#!ifdef PRESENCE-ROLE #!ifdef PRESENCE-ROLE
route(HANDLE_SUBSCRIBE); route(HANDLE_SUBSCRIBE);
route(HANDLE_PUBLISH); route(HANDLE_PUBLISH);
@ -271,17 +272,28 @@ route[SANITY_CHECK]
} }
} }
route[CLASSIFY_SOURCE]
{
if (isflagset(FLAG_INTERNALLY_SOURCED) || allow_source_address(TRUSTED_ADR_GROUP) || is_myself($si)) {
xlog("L_INFO", "$ci|log|request from trusted IP");
setflag(FLAG_TRUSTED_SOURCE);
}
#!ifdef DISPATCHER-ROLE
route(DISPATCHER_CLASSIFY_SOURCE);
#!endif
}
route[HANDLE_OPTIONS] route[HANDLE_OPTIONS]
{ {
if (is_method("OPTIONS")) { if (is_method("OPTIONS")) {
if (isflagset(FLAG_INTERNALLY_SOURCED)) { if (isflagset(FLAG_INTERNALLY_SOURCED)) {
route(INTERNAL_TO_EXTERNAL_RELAY); route(INTERNAL_TO_EXTERNAL_RELAY);
#!ifdef TRAFFIC-FILTER-ROLE
} else if (!isflagset(FLAG_TRUSTED_SOURCE)
&& $rd =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") {
xlog("L_WARN", "$ci|end|dropping OPTIONS request with IP domain");
#!endif
} else { } else {
#!ifdef TRAFFIC-FILTER-ROLE
route(FILTER_REQUEST_DOMAIN);
#!endif
sl_send_reply("200", "Rawr!!"); sl_send_reply("200", "Rawr!!");
} }
exit; exit;
@ -293,12 +305,11 @@ route[HANDLE_NOTIFY]
if (is_method("NOTIFY")) { if (is_method("NOTIFY")) {
if (isflagset(FLAG_INTERNALLY_SOURCED)) { if (isflagset(FLAG_INTERNALLY_SOURCED)) {
route(INTERNAL_TO_EXTERNAL_RELAY); route(INTERNAL_TO_EXTERNAL_RELAY);
#!ifdef TRAFFIC-FILTER-ROLE
} else if (!isflagset(FLAG_TRUSTED_SOURCE)
&& $rd =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") {
xlog("L_WARN", "$ci|end|dropping OPTIONS request with IP domain");
#!endif
} else { } else {
#!ifdef TRAFFIC-FILTER-ROLE
route(FILTER_REQUEST_DOMAIN);
#!endif
sl_send_reply("200", "Rawr!!"); sl_send_reply("200", "Rawr!!");
} }
exit; exit;
@ -317,23 +328,6 @@ route[HANDLE_MESSAGE]
} }
} }
route[HANDLE_MOVE_REQUEST]
{
if (is_method("INVITE") && $rU == "*6683*") {
$var(contact_uri) = $(ct{tobody.user}) + "@" + $(ct{tobody.host});
if ($sht(associations=>$var(contact_uri)) != $null) {
$sht(associations=>$var(contact_uri)) = $null;
xlog("L_INFO", "$ci|log|removed contact association for $var(contact_uri)
with media server $sht(associations=>$var(contact_uri))");
}
send_reply("503", "Removed association");
exit;
}
}
route[HANDLE_IN_DIALOG_REQUESTS] route[HANDLE_IN_DIALOG_REQUESTS]
{ {
if (has_totag()) { if (has_totag()) {
@ -341,11 +335,12 @@ route[HANDLE_IN_DIALOG_REQUESTS]
record_route(); record_route();
} }
if (loose_route()) { if (loose_route()) {
#!ifdef ACCOUNTING-ROLE
if (is_method("BYE")) {
setflag(FLAG_ACC);
setflag(FLAG_ACCFAILED);
}
#!ifdef ACCOUNTING-ROLE
if (is_method("BYE")) {
setflag(FLAG_ACC);
setflag(FLAG_ACCFAILED);
}
#!endif #!endif
#!ifdef WEBSOCKETS-ROLE #!ifdef WEBSOCKETS-ROLE
@ -395,7 +390,7 @@ route[PREPARE_INITIAL_REQUESTS]
if (t_check_trans()) { if (t_check_trans()) {
route(RELAY); route(RELAY);
} else { } else {
sl_send_reply("481", "Call Leg/Transaction Does Not Exist");
sl_send_reply("481", "Call leg/transaction does not exist");
} }
exit(); exit();
} else if (is_method("ACK")) { } else if (is_method("ACK")) {
@ -405,8 +400,21 @@ route[PREPARE_INITIAL_REQUESTS]
exit(); exit();
} }
# handle re-transmissions
t_check_trans(); t_check_trans();
if (is_method("UPDATE")) {
xlog("L_WARN", "$ci|end|update outside dialog not allowed");
send_reply("403", "Dialog does not exist");
break;
}
if (is_method("BYE|PRACK")) {
xlog("L_WARN", "$ci|end|originating subsequent requests outside dialog not allowed");
send_reply("403", "Dialog does not exist");
break;
}
if (loose_route()) { if (loose_route()) {
xlog("L_WARN", "$ci|end|denying initial request with route-set"); xlog("L_WARN", "$ci|end|denying initial request with route-set");
sl_send_reply("403", "No pre-loaded routes"); sl_send_reply("403", "No pre-loaded routes");
@ -432,10 +440,10 @@ route[RELAY]
route[INTERNAL_TO_EXTERNAL_RELAY] route[INTERNAL_TO_EXTERNAL_RELAY]
{ {
#!ifdef ACCOUNTING-ROLE #!ifdef ACCOUNTING-ROLE
if (is_method("INVITE")) {
setflag(FLAG_ACC);
setflag(FLAG_ACCFAILED);
}
if (is_method("INVITE")) {
setflag(FLAG_ACC);
setflag(FLAG_ACCFAILED);
}
#!endif #!endif
remove_hf_re("X-.*"); remove_hf_re("X-.*");
@ -450,10 +458,10 @@ route[INTERNAL_TO_EXTERNAL_RELAY]
route[EXTERNAL_TO_INTERNAL_RELAY] route[EXTERNAL_TO_INTERNAL_RELAY]
{ {
#!ifdef ACCOUNTING-ROLE #!ifdef ACCOUNTING-ROLE
if (is_method("INVITE") && is_present_hf("Proxy-Authorization")) {
setflag(FLAG_ACC);
setflag(FLAG_ACCFAILED);
}
if (is_method("INVITE") && is_present_hf("Proxy-Authorization")) {
setflag(FLAG_ACC);
setflag(FLAG_ACCFAILED);
}
#!endif #!endif
#!ifdef NAT-TRAVERSAL-ROLE #!ifdef NAT-TRAVERSAL-ROLE
@ -473,39 +481,6 @@ route[EXTERNAL_TO_INTERNAL_RELAY]
t_relay(); t_relay();
} }
route[DOS_PREVENTION]
{
# allow request from internal network or from whitelist
if (isflagset(FLAG_INTERNALLY_SOURCED) || allow_source_address(TRUSTED_ADR_GROUP) || is_myself($si)) {
xlog("L_INFO", "$ci|log|request from trusted IP");
setflag(FLAG_TRUSTED_SOURCE);
return;
}
# drop requests with no To domain or IP To domain (friendly-scanner)
if (is_method("REGISTER|SUBSCRIBE|OPTIONS") &&
($td == $null || $td=~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}")) {
xlog("L_WARN", "$ci|log|dropping request with IP domain in To header");
exit;
}
# drop Invite with IP auth realm
if (is_method("INVITE") && is_present_hf("Proxy-Authorization") &&
$ar =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}" ) {
xlog("L_WARN", "$ci|log|dropping request with IP domain in Proxy-Authorization header");
exit;
}
# use pike check for the others
if (!pike_check_req()) {
# If it is a new flood, emit a log
if($rc == -2) {
xlog("L_WARN", "$ci|log|dropping due to rate of requests from IP");
}
exit;
}
}
onreply_route[EXTERNAL_REPLY] onreply_route[EXTERNAL_REPLY]
{ {
xlog("L_INFO", "$ci|log|external reply $T_reply_code"); xlog("L_INFO", "$ci|log|external reply $T_reply_code");
@ -559,7 +534,6 @@ failure_route[INTERNAL_FAULT]
# cancelled then we are complete # cancelled then we are complete
if (t_is_canceled()) { if (t_is_canceled()) {
xlog("L_INFO", "$ci|log|transaction was cancelled"); xlog("L_INFO", "$ci|log|transaction was cancelled");
exit; exit;
} }


+ 1
- 0
kamailio/local.cfg View File

@ -11,6 +11,7 @@ debug = L_INFO
#!trydef NAT-TRAVERSAL-ROLE #!trydef NAT-TRAVERSAL-ROLE
#!trydef REGISTRAR-ROLE #!trydef REGISTRAR-ROLE
#!trydef PRESENCE-ROLE #!trydef PRESENCE-ROLE
#!trydef ANTIFLOOD-ROLE
## Disabled Roles - remove all but the last '#' to enable ## Disabled Roles - remove all but the last '#' to enable
# # #!trydef TRAFFIC-FILTER-ROLE # # #!trydef TRAFFIC-FILTER-ROLE


+ 79
- 124
kamailio/registrar-role.cfg View File

@ -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

+ 57
- 0
kamailio/traffic-filter-role.cfg View File

@ -0,0 +1,57 @@
route[TRAFFIC_FILTER]
{
# allow request from internal network or from whitelist
if (isflagset(FLAG_TRUSTED_SOURCE)) {
return;
}
# drop requests with no To domain or IP To domain (friendly-scanner)
if (is_method("REGISTER|SUBSCRIBE") {
route(FILTER_TO_DOMAIN);
route(FILTER_FROM_DOMAIN);
}
# drop Invite with IP auth realm
if (is_method("INVITE") {
route(FILTER_REQUEST_DOMAIN);
route(FILTER_AUTHORIZATION_DOMAIN);
}
}
route[FILTER_REQUEST_DOMAIN]
{
if ($rd =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") {
xlog("L_WARN", "$ci|end|dropping $rm request with IP domain");
drop();
exit();
}
}
route[FILTER_AUTHORIZATION_DOMAIN]
{
if (is_present_hf("Proxy-Authorization") &&
$ar =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}" ) {
xlog("L_WARN", "$ci|log|dropping request with IP domain in Proxy-Authorization header");
drop();
exit;
}
}
route[FILTER_TO_DOMAIN]
{
if ($fd =~ "([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})") {
xlog("L_WARN", "$ci|end|dropping request with IP domain in From header");
drop();
exit;
}
}
route[FILTER_FROM_DOMAIN]
{
if ($td =~ "([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})") {
xlog("L_WARN", "$ci|end|dropping request with IP domain in To header");
drop();
exit;
}
}

Loading…
Cancel
Save