From d0adf5af20701f077f0fc3eb90802ac33d99c06d Mon Sep 17 00:00:00 2001 From: karl anderson Date: Mon, 5 Aug 2013 20:48:45 -0700 Subject: [PATCH 01/11] correct copy/paste error --- kamailio/dispatcher-role.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kamailio/dispatcher-role.cfg b/kamailio/dispatcher-role.cfg index 8a5ed0f..713ac74 100644 --- a/kamailio/dispatcher-role.cfg +++ b/kamailio/dispatcher-role.cfg @@ -63,6 +63,7 @@ route[DISPATCHER_REORDER_ROUTES] { $var(i) = 0; $var(found) = 0; + $var(prefered_route) = $sht(associations=>$var(association)); while($(avp(ds_dst)[$var(i)]) != $null) { if($(avp(ds_dst)[$var(i)]) != $var(prefered_route)) { $avp(tmp_ds_dst) = $(avp(ds_dst)[$var(i)]); @@ -91,7 +92,7 @@ route[DISPATCHER_REORDER_ROUTES] } else { xlog("L_INFO", "$ci|log|associated media server is inactive, moving to $rd"); - $sht(associations=>$var(contact_uri)) = $null; + $sht(associations=>$var(association)) = $null; } } From ed4ae26a01ccb3b04de5fa071511ead9564023cf Mon Sep 17 00:00:00 2001 From: karl anderson Date: Mon, 19 Aug 2013 15:52:51 -0400 Subject: [PATCH 02/11] fix kamailio role dependencies, add more async IO workers, and constrain erlang ports --- bigcouch/vm.args | 4 +++- kamailio/default.cfg | 3 ++- kamailio/nat-traversal-role.cfg | 4 ---- kamailio/registrar-role.cfg | 4 ++++ vm.args | 4 +++- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/bigcouch/vm.args b/bigcouch/vm.args index 066ca4a..df3b062 100644 --- a/bigcouch/vm.args +++ b/bigcouch/vm.args @@ -16,12 +16,14 @@ +K true # Start a pool of asynchronous IO threads -+A 16 ++A 25 # Set the max port value to be the same as limits.d/bigcouch.limits # +Q 65536 -env ERL_MAX_PORTS 65536 +-kernel inet_dist_listen_min 11500 inet_dist_listen_max 11999 + # Comment this line out to enable the interactive Erlang shell on startup +Bd -noinput -detached diff --git a/kamailio/default.cfg b/kamailio/default.cfg index 87136b5..f4f214c 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -130,6 +130,7 @@ modparam("rr", "enable_double_rr", 0) ######## Max-Forward processor module ######## loadmodule "maxfwd.so" +modparam("maxfwd", "max_limit", 50) ######## SIP utilities [requires sl] ######## loadmodule "siputils.so" @@ -427,7 +428,7 @@ failure_route[INTERNAL_FAULT] remove_hf("X-Redirect-Server"); } - } else if (t_check_status("(401)|(407)")) { + } else if (t_check_status("(401)|(407)|(486)")) { xlog("L_INFO", "$ci|log|failure route ignoring auth reply $T_reply_code $rr"); exit; diff --git a/kamailio/nat-traversal-role.cfg b/kamailio/nat-traversal-role.cfg index b8a03b6..e65fcfe 100644 --- a/kamailio/nat-traversal-role.cfg +++ b/kamailio/nat-traversal-role.cfg @@ -3,10 +3,6 @@ loadmodule "nathelper.so" #!endif modparam("nathelper", "received_avp", "$avp(AVP_RECV_PARAM)") -modparam("nathelper", "natping_interval", 30) -modparam("nathelper", "ping_nated_only", 1) -modparam("nathelper", "natping_processes", 5) -modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) ####### NAT Traversal Logic ######## route[NAT_TEST_AND_CORRECT] diff --git a/kamailio/registrar-role.cfg b/kamailio/registrar-role.cfg index 9d853a0..ef267ba 100644 --- a/kamailio/registrar-role.cfg +++ b/kamailio/registrar-role.cfg @@ -23,6 +23,10 @@ modparam("usrloc", "nat_bflag", FLB_NATB) #!ifdef NAT-TRAVERSAL-ROLE #!trydef NATHELPER-LOADED loadmodule "nathelper.so" +modparam("nathelper", "natping_interval", 30) +modparam("nathelper", "ping_nated_only", 1) +modparam("nathelper", "natping_processes", 5) +modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) #!endif ####### SIP Registrar implementation module ########## diff --git a/vm.args b/vm.args index 22e79d7..5cbe898 100644 --- a/vm.args +++ b/vm.args @@ -9,7 +9,9 @@ +K true # Start a pool of asynchronous IO threads -+A 2 ++A 25 + +-kernel inet_dist_listen_min 11500 inet_dist_listen_max 11999 # Comment this line out if you want the Erlang shell +Bd From 028555440f29a1be2ffaa9b2306665c3ce3fad30 Mon Sep 17 00:00:00 2001 From: karl anderson Date: Mon, 19 Aug 2013 21:46:45 -0400 Subject: [PATCH 03/11] increase rabbits file descriptors --- rabbitmq/rabbitmq-env.conf | 1 + system/security/limits.d/rabbitmq.limits.conf | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 system/security/limits.d/rabbitmq.limits.conf diff --git a/rabbitmq/rabbitmq-env.conf b/rabbitmq/rabbitmq-env.conf index 0b46f76..6253901 100644 --- a/rabbitmq/rabbitmq-env.conf +++ b/rabbitmq/rabbitmq-env.conf @@ -3,3 +3,4 @@ NODE_IP_ADDRESS=0.0.0.0 NODE_PORT=5672 LOG_BASE=/var/log/rabbitmq MNESIA_BASE=/var/lib/rabbitmq/mnesia +ERL_MAX_PORTS=65536 diff --git a/system/security/limits.d/rabbitmq.limits.conf b/system/security/limits.d/rabbitmq.limits.conf new file mode 100644 index 0000000..057ed1e --- /dev/null +++ b/system/security/limits.d/rabbitmq.limits.conf @@ -0,0 +1,2 @@ +rabbitmq soft nofile 65536 +rabbitmq hard nofile 65536 From 267d3472eb6815b942524b0feddeb5d6260115d9 Mon Sep 17 00:00:00 2001 From: Anca Vamanu Date: Tue, 3 Sep 2013 21:51:44 +0300 Subject: [PATCH 04/11] dispatcher extensions - distribute also Register and Subscribes to groups 20 and 30 respectively - for Invites introduce a backup group 2 to be used in case in group 1 there are less than 3 available gateways --- kamailio/dispatcher-role.cfg | 45 ++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/kamailio/dispatcher-role.cfg b/kamailio/dispatcher-role.cfg index 713ac74..b9fd1fd 100644 --- a/kamailio/dispatcher-role.cfg +++ b/kamailio/dispatcher-role.cfg @@ -40,12 +40,49 @@ route[DISPATCHER_FIND_ROUTES] return; } - if (!ds_select_dst("1", "0")) { - xlog("L_ERR", "$ci|end|no servers avaliable"); + if (is_method("SUBSCRIBE")) { + $var(ds_group) = 20; + } else + if (is_method("REGISTER")) { + $var(ds_group) = 30; + } else { + $var(ds_group) = 1; + } + + if (!ds_select_dst("$var(ds_group)", "0")) { + xlog("L_ERR", "$ci|end|no servers avaliable in group $var(ds_group)"); + + # if we selected from group 1, try again in group 2 + if ($var(ds_group) == 1 ) { + + if (!ds_select_dst("2", "0")) { + xlog("L_ERR", "$ci|end|no servers avaliable in group 2"); + sl_send_reply("480", "All servers busy"); + exit; + } + + } else { + + sl_send_reply("480", "All servers busy"); + exit; - sl_send_reply("480", "All servers busy"); + } + } else { + + # if we selected from group 1 and there are less than 3 available servers, choose from group 2 + if ($var(ds_group) == 1 && $var(ds_cnt)< 3) { + + # clear $avp(ds_dst) and search in group 2 + $(avp(ds_dst)[*]) = $null; + + if (!ds_select_dst("2", "0")) { + xlog("L_ERR", "$ci|end|no servers avaliable in group 2"); + sl_send_reply("480", "All servers busy"); + exit; + } + + } - exit; } $var(contact_uri) = $(ct{tobody.user}) + "@" + $(ct{tobody.host}); From 7f5ac5a17b33613499a7a0f3b5bcf277d337fe3c Mon Sep 17 00:00:00 2001 From: Anca Vamanu Date: Tue, 3 Sep 2013 21:55:25 +0300 Subject: [PATCH 05/11] default.cfg - introduced DOS prevention Use pike module to drop the SIP requests in case of a DOS attack. --- kamailio/default.cfg | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/kamailio/default.cfg b/kamailio/default.cfg index f4f214c..a25563d 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -164,6 +164,9 @@ modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo") ######## UAC Redirection module ######## loadmodule "uac_redirect.so" +######## DoS prevention mdule ######## +loadmodule "pike.so" + ####### Role Configurations ########## #!ifdef DISPATCHER-ROLE include_file "dispatcher-role.cfg" @@ -198,6 +201,8 @@ route route(DISPATCHER_CLASSIFY_SOURCE); #!endif + route(DOS_PREVENTION); + route(HANDLE_OPTIONS); route(HANDLE_MOVE_REQUEST); @@ -373,6 +378,18 @@ route[EXTERNAL_TO_INTERNAL_RELAY] t_relay(); } +route[DOS_PREVENTION] +{ + if (!isflagset(FLAG_INTERNALLY_SOURCED)) { + if (!pike_check_req()) { + if( $rc == -2) { + xlog("L_ERR", "DOS detected: $rm to $ru from $fu, UA $ua, IP $si\n"); + } + exit; + } + } +} + onreply_route[EXTERNAL_REPLY] { xlog("L_INFO", "$ci|log|external reply $T_reply_code"); From 033eeb46f445f24ae8d5d19b0b3815459884fe2b Mon Sep 17 00:00:00 2001 From: Anca Vamanu Date: Wed, 4 Sep 2013 00:31:21 +0300 Subject: [PATCH 06/11] default.cfg:disable replys to Options from outside --- kamailio/default.cfg | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kamailio/default.cfg b/kamailio/default.cfg index a25563d..2de85c3 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -251,9 +251,10 @@ route[HANDLE_OPTIONS] if (is_method("OPTIONS")) { if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); - } else { - sl_send_reply("200", "Rawr!!"); } +# else { +# sl_send_reply("200", "Rawr!!"); +# } exit; } } @@ -484,4 +485,4 @@ onsend_route { xlog("L_INFO", "$ci|pass|$sndfrom(ip):$sndfrom(port) -> $sndto(ip):$sndto(port)"); } -## vim:set tabstop=4 softtabstop=4 shiftwidth=4 expandtab +# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab From f48ad99a3fdb172e322b7535121560e49310e22d Mon Sep 17 00:00:00 2001 From: Anca Vamanu Date: Wed, 4 Sep 2013 00:32:16 +0300 Subject: [PATCH 07/11] registrar-role.cfg: DOS prevention - reject Register to IP domain - check for brute force attack - allow only two consecutive attempts to authenticate. If both failed block the account for 2 minutes. --- kamailio/registrar-role.cfg | 51 ++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/kamailio/registrar-role.cfg b/kamailio/registrar-role.cfg index ef267ba..24d0697 100644 --- a/kamailio/registrar-role.cfg +++ b/kamailio/registrar-role.cfg @@ -2,6 +2,7 @@ ######## 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;") ####### Authentication Interface module ########## loadmodule "auth.so" @@ -37,6 +38,9 @@ modparam("registrar", "received_avp", "$avp(AVP_RECV_PARAM)") route[HANDLE_REGISTER] { if (is_method("REGISTER")) { + + route(DOMAIN_FORMAT_CHECK); + #!ifdef NAT-TRAVERSAL-ROLE if (nat_uac_test("3")) { xlog("L_INFO", "$ci|log|Correcting NATed contact in registration\n"); @@ -50,11 +54,18 @@ route[HANDLE_REGISTER] #!endif if (is_present_hf("Authorization")) { + + if (!route(PREVENT_BRUTEFORCE)) { + auth_challenge("$fd", "0"); + exit; + } + 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\n"); } else { ## RABBITMQ - Credentials fetch if (!auth_check("$fd", "subscriber", "1")) { + route(FAILED_AUTH_COUNT); auth_challenge("$fd", "0"); xlog("L_INFO", "$ci|log|Issued new auth challenge to failed registration attempt\n"); exit; @@ -77,4 +88,42 @@ route[HANDLE_REGISTER] } } -## vim:set tabstop=4 softtabstop=4 shiftwidth=4 expandtab +# AUTH: check to see if user if present in failed_auth_hash +route[PREVENT_BRUTEFORCE] +{ + if($sht(failed_auth_hash=>$Au::count) >= 2) { + $var(exp) = $Ts - 120; + if($sht(failed_auth_hash=>$Au::last) > $var(exp)){ + xlog("L_ERR", "Possible password brute force, from $ct on user $Au"); + return(-1); + } else { + $sht(failed_auth_hash=>$Au::count) = 0; + } + } + return(1); +} + + +#AUTH: add to failed_auth_hash in case of authentication password error +route[FAILED_AUTH_COUNT] +{ + 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; + } +} + +route[DOMAIN_FORMAT_CHECK] +{ + 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}" ) { + send_reply("403", "Forbidden"); + exit; + } + +} + +# vim:tabstop=4 softtabstop=4 shiftwidth=4 expandtab From 410b972bc7ac11732df314bd4a0215691091909f Mon Sep 17 00:00:00 2001 From: Anca Vamanu Date: Thu, 5 Sep 2013 00:33:43 +0300 Subject: [PATCH 08/11] default.cfg Improved DOS protection - use permissions module to have the equivalent of a white list, a list of IPs that are trusted. This module is used together with db_text and the list of IPs and IP ranges will be specified in the address dbtext file. - drop requests that have no To domain or a To domain consisting of an IP. - reply to Options from outside only if the RURI domain is not IP. --- kamailio/default.cfg | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/kamailio/default.cfg b/kamailio/default.cfg index 2de85c3..844e41a 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -28,6 +28,8 @@ flags #!define FLB_NATSIPPING 2 #!define FLB_UAC_REDIRECT 3 +#!define TRUSTED_ADR_GROUP 1 + ####### Global Parameters ######### fork = yes children = 25 @@ -186,6 +188,13 @@ include_file "nat-traversal-role.cfg" loadmodule "db_kazoo.so" #!endif +loadmodule "db_text.so" +loadmodule "permissions.so" +modparam("db_text", "db_mode", 1) +modparam("permissions", "db_url", "text:///etc/kamailio/dbtext") +modparam("permissions", "db_mode", 1) + + ####### Routing Logic ######## route { @@ -236,7 +245,12 @@ route[SANITY_CHECK] { if (!mf_process_maxfwd_header("10")) { xlog("L_WARN", "$ci|end|Too much hops, not enough barley"); - sl_send_reply("483", "Too Many Hops"); + send_reply("483", "Too Many Hops"); + exit; + } + + if ( msg:len > 6144 ) { + send_reply("513", "Message too large"); exit; } @@ -252,9 +266,12 @@ route[HANDLE_OPTIONS] if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); } -# else { -# sl_send_reply("200", "Rawr!!"); -# } + else + if ($rd=~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") { + xlog("L_ERR", "Possible attack- Options: to $ru from $fu, UA $ua, IP $si\n"); + } else { + sl_send_reply("200", "Rawr!!"); + } exit; } } @@ -381,10 +398,21 @@ route[EXTERNAL_TO_INTERNAL_RELAY] route[DOS_PREVENTION] { + if (allow_source_address(TRUSTED_ADR_GROUP)) { + xlog("L_DBG", "Request from trusted IP $rm $si\n"); + return; + } + + # drop requests with no To domain or IP To domain (friendly-scanner) + if ($td == $null || $td=~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") { + xlog("L_ERR", "Possible attack- wrong td: $rm to $ru from $fu, UA $ua, IP $si\n"); + exit; + } + if (!isflagset(FLAG_INTERNALLY_SOURCED)) { if (!pike_check_req()) { if( $rc == -2) { - xlog("L_ERR", "DOS detected: $rm to $ru from $fu, UA $ua, IP $si\n"); + xlog("L_ERR", "DOS attack: $rm to $ru from $fu, UA $ua, IP $si\n"); } exit; } From 35bb43c7548fda8411fb0666a5581022711a9502 Mon Sep 17 00:00:00 2001 From: Anca Vamanu Date: Thu, 5 Sep 2013 00:37:00 +0300 Subject: [PATCH 09/11] Added dbtext files. --- kamailio/dbtext/address | 2 ++ kamailio/dbtext/trusted | 1 + kamailio/dbtext/version | 3 +++ 3 files changed, 6 insertions(+) create mode 100644 kamailio/dbtext/address create mode 100644 kamailio/dbtext/trusted create mode 100644 kamailio/dbtext/version diff --git a/kamailio/dbtext/address b/kamailio/dbtext/address new file mode 100644 index 0000000..6d5674f --- /dev/null +++ b/kamailio/dbtext/address @@ -0,0 +1,2 @@ +id(int,auto) grp(int) ip_addr(string) mask(int) port(int) tag(string,null) +0:1:10.10.10.10:32:0:Known Gateway diff --git a/kamailio/dbtext/trusted b/kamailio/dbtext/trusted new file mode 100644 index 0000000..4ff5902 --- /dev/null +++ b/kamailio/dbtext/trusted @@ -0,0 +1 @@ +id(int,auto) src_ip(string) proto(string) from_pattern(string,null) tag(string,null) diff --git a/kamailio/dbtext/version b/kamailio/dbtext/version new file mode 100644 index 0000000..4f6be33 --- /dev/null +++ b/kamailio/dbtext/version @@ -0,0 +1,3 @@ +table_name(string) table_version(int) +address:6 +trusted:5 From c9c62c8bd267d7b2ca84b993c563812d11aa9fcc Mon Sep 17 00:00:00 2001 From: Anca Vamanu Date: Thu, 5 Sep 2013 01:51:27 +0300 Subject: [PATCH 10/11] default.cfg Changes in DOS Prevention - drop only REGITSER, SUBSCRIBE or OPTIONS that has an IP as a To domain or no to domain - for Invites, drop the ones that have an IP as an auth_realm. --- kamailio/default.cfg | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/kamailio/default.cfg b/kamailio/default.cfg index 844e41a..fef2497 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -398,24 +398,32 @@ route[EXTERNAL_TO_INTERNAL_RELAY] route[DOS_PREVENTION] { - if (allow_source_address(TRUSTED_ADR_GROUP)) { + # allow request from internal network or from whitelist + if (isflagset(FLAG_INTERNALLY_SOURCED) || allow_source_address(TRUSTED_ADR_GROUP)) { xlog("L_DBG", "Request from trusted IP $rm $si\n"); return; } # drop requests with no To domain or IP To domain (friendly-scanner) - if ($td == $null || $td=~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") { + 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_ERR", "Possible attack- wrong td: $rm to $ru from $fu, UA $ua, IP $si\n"); exit; } - if (!isflagset(FLAG_INTERNALLY_SOURCED)) { - if (!pike_check_req()) { - if( $rc == -2) { - xlog("L_ERR", "DOS attack: $rm to $ru from $fu, UA $ua, IP $si\n"); - } - 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_ERR", "Possible attack- Invite realm $ar: to $ru from $fu, UA $ua, IP $si\n"); + exit; + } + + # use pike check for the others + if (!pike_check_req()) { + if( $rc == -2) { + xlog("L_ERR", "DOS attack: $rm to $ru from $fu, UA $ua, IP $si\n"); } + exit; } } From 3bedbc38a3d5dbf4b782bd6b08d7b55fe13a8a91 Mon Sep 17 00:00:00 2001 From: karl anderson Date: Fri, 6 Sep 2013 14:53:55 -0700 Subject: [PATCH 11/11] use manual redirects --- freeswitch/sip_profiles/sipinterface_1.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freeswitch/sip_profiles/sipinterface_1.xml b/freeswitch/sip_profiles/sipinterface_1.xml index 6aa36c6..a123386 100644 --- a/freeswitch/sip_profiles/sipinterface_1.xml +++ b/freeswitch/sip_profiles/sipinterface_1.xml @@ -36,7 +36,7 @@ - +