From ccf812853f5b6c43ce23cb7db3b6a72f5fb1c97f Mon Sep 17 00:00:00 2001 From: karl anderson Date: Mon, 13 Oct 2014 18:32:10 -0400 Subject: [PATCH] break the anti-flood and traffic filter roles apart --- kamailio/antiflood-role.cfg | 72 +++++++++++ kamailio/default.cfg | 148 ++++++++++------------ kamailio/local.cfg | 1 + kamailio/registrar-role.cfg | 203 ++++++++++++------------------- kamailio/traffic-filter-role.cfg | 57 +++++++++ 5 files changed, 270 insertions(+), 211 deletions(-) create mode 100644 kamailio/antiflood-role.cfg create mode 100644 kamailio/traffic-filter-role.cfg diff --git a/kamailio/antiflood-role.cfg b/kamailio/antiflood-role.cfg new file mode 100644 index 0000000..3ba827e --- /dev/null +++ b/kamailio/antiflood-role.cfg @@ -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; +} diff --git a/kamailio/default.cfg b/kamailio/default.cfg index 29c2340..b66348b 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -113,10 +113,8 @@ loadmodule "siputils.so" ######## SIP message formatting sanity checks [requires sl] ######## 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) ######## Text operations module ######## @@ -141,9 +139,6 @@ modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo") ######## UAC Redirection module ######## loadmodule "uac_redirect.so" -######## DoS prevention mdule ######## -loadmodule "pike.so" - ####### DB Text module ########## loadmodule "db_text.so" modparam("db_text", "db_mode", 1) @@ -188,6 +183,12 @@ include_file "tls-role.cfg" #!ifdef ACCOUNTING-ROLE include_file "accounting-role.cfg" #!endif +#!ifdef ANTIFLOOD-ROLE +include_file "antiflood-role.cfg" +#!endif +#!ifdef TRAFFIC-FILTER-ROLE +include_file "traffic-filter-role.cfg" +#!endif ####### Permissions module ########## loadmodule "permissions.so" @@ -205,12 +206,14 @@ route route(SANITY_CHECK); - #!ifdef DISPATCHER-ROLE - route(DISPATCHER_CLASSIFY_SOURCE); + route(CLASSIFY_SOURCE); + + #!ifdef ANTIFLOOD-ROLE + route(ANTIFLOOD_RATE_LIMIT); #!endif #!ifdef TRAFFIC-FILTER-ROLE - route(DOS_PREVENTION); + route(TRAFFIC_FILTER); #!endif #!ifdef WEBSOCKETS-ROLE @@ -223,8 +226,6 @@ route route(HANDLE_MESSAGE); - route(HANDLE_MOVE_REQUEST); - #!ifdef PRESENCE-ROLE route(HANDLE_SUBSCRIBE); 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] { if (is_method("OPTIONS")) { if (isflagset(FLAG_INTERNALLY_SOURCED)) { 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 { + #!ifdef TRAFFIC-FILTER-ROLE + route(FILTER_REQUEST_DOMAIN); + #!endif + sl_send_reply("200", "Rawr!!"); } exit; @@ -293,12 +305,11 @@ route[HANDLE_NOTIFY] if (is_method("NOTIFY")) { if (isflagset(FLAG_INTERNALLY_SOURCED)) { 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 { + #!ifdef TRAFFIC-FILTER-ROLE + route(FILTER_REQUEST_DOMAIN); + #!endif + sl_send_reply("200", "Rawr!!"); } 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] { if (has_totag()) { @@ -341,11 +335,12 @@ route[HANDLE_IN_DIALOG_REQUESTS] record_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 #!ifdef WEBSOCKETS-ROLE @@ -395,7 +390,7 @@ route[PREPARE_INITIAL_REQUESTS] if (t_check_trans()) { route(RELAY); } else { - sl_send_reply("481", "Call Leg/Transaction Does Not Exist"); + sl_send_reply("481", "Call leg/transaction does not exist"); } exit(); } else if (is_method("ACK")) { @@ -405,8 +400,21 @@ route[PREPARE_INITIAL_REQUESTS] exit(); } + # handle re-transmissions 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()) { xlog("L_WARN", "$ci|end|denying initial request with route-set"); sl_send_reply("403", "No pre-loaded routes"); @@ -432,10 +440,10 @@ route[RELAY] route[INTERNAL_TO_EXTERNAL_RELAY] { #!ifdef ACCOUNTING-ROLE - if (is_method("INVITE")) { - setflag(FLAG_ACC); - setflag(FLAG_ACCFAILED); - } + if (is_method("INVITE")) { + setflag(FLAG_ACC); + setflag(FLAG_ACCFAILED); + } #!endif remove_hf_re("X-.*"); @@ -450,10 +458,10 @@ route[INTERNAL_TO_EXTERNAL_RELAY] route[EXTERNAL_TO_INTERNAL_RELAY] { #!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 #!ifdef NAT-TRAVERSAL-ROLE @@ -473,39 +481,6 @@ route[EXTERNAL_TO_INTERNAL_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] { xlog("L_INFO", "$ci|log|external reply $T_reply_code"); @@ -559,7 +534,6 @@ failure_route[INTERNAL_FAULT] # cancelled then we are complete if (t_is_canceled()) { xlog("L_INFO", "$ci|log|transaction was cancelled"); - exit; } diff --git a/kamailio/local.cfg b/kamailio/local.cfg index 7a11ed1..3313f7d 100644 --- a/kamailio/local.cfg +++ b/kamailio/local.cfg @@ -11,6 +11,7 @@ debug = L_INFO #!trydef NAT-TRAVERSAL-ROLE #!trydef REGISTRAR-ROLE #!trydef PRESENCE-ROLE +#!trydef ANTIFLOOD-ROLE ## Disabled Roles - remove all but the last '#' to enable # # #!trydef TRAFFIC-FILTER-ROLE diff --git a/kamailio/registrar-role.cfg b/kamailio/registrar-role.cfg index d71c1de..5b677ad 100644 --- a/kamailio/registrar-role.cfg +++ b/kamailio/registrar-role.cfg @@ -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 ######## -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 ########## loadmodule "auth.so" @@ -16,17 +20,17 @@ modparam("usrloc", "nat_bflag", FLB_NATB) #!ifdef NAT-TRAVERSAL-ROLE #!trydef NATHELPER-LOADED loadmodule "nathelper.so" -modparam("nathelper", "natping_interval", 30) +modparam("nathelper", "natping_interval", REGISTRAR_NAT_PING_INTERVAL) 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) #!endif ####### SIP Registrar implementation module ########## loadmodule "registrar.so" 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 ######## @@ -34,10 +38,6 @@ route[HANDLE_REGISTER] { if (is_method("REGISTER")) { - #!ifdef TRAFFIC-FILTER-ROLE - route(DOMAIN_FORMAT_CHECK); - #!endif - #!ifdef NAT-TRAVERSAL-ROLE if (nat_uac_test("3")) { xlog("L_INFO", "$ci|log|correcting NATed contact in registration"); @@ -53,143 +53,98 @@ route[HANDLE_REGISTER] #!endif 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 { 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; } + } +} - # 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="; - - ## 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 { - $var(fs_contact) = ""; - } - - 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; } -} -# 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="; - 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) = ""; } + $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 diff --git a/kamailio/traffic-filter-role.cfg b/kamailio/traffic-filter-role.cfg new file mode 100644 index 0000000..e6a22a6 --- /dev/null +++ b/kamailio/traffic-filter-role.cfg @@ -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; + } +} +