From 8ecc7bf1b7926b177af1f96006751a0ffe4e38a7 Mon Sep 17 00:00:00 2001 From: Mooseable Date: Thu, 13 Mar 2025 20:38:05 +0800 Subject: [PATCH 1/4] Reorder classify route, add alternate traffic filter role. --- kamailio/default.cfg | 13 +++- kamailio/extra-traffic-filter-role.cfg | 84 ++++++++++++++++++++++++++ kamailio/local.cfg | 25 ++++++++ kamailio/traffic-filter-role.cfg | 24 ++++++++ 4 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 kamailio/extra-traffic-filter-role.cfg diff --git a/kamailio/default.cfg b/kamailio/default.cfg index ac451b8..4f2799d 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -284,6 +284,11 @@ loadmodule "permissions.so" modparam("permissions", "db_url", "KAZOO_DB_URL") modparam("permissions", "db_mode", 1) +######## requires permissions module ######## +#!ifdef EXTRA_TRAFFIC_FILTER_ROLE +include_file "extra-traffic-filter-role.cfg" +#!endif + ###### local route ###### socket_workers=5 listen=tcp:127.0.0.1:5090 @@ -301,10 +306,16 @@ route route(ANTIFLOOD_LIMIT); #!endif + route(CLASSIFY_SOURCE); + #!ifdef TRAFFIC_FILTER_ROLE route(FILTER_REQUEST); #!endif + #!ifdef EXTRA_TRAFFIC_FILTER_ROLE + route(EXTRA_FILTER_REQUEST); + #!endif + #!ifdef ACL_ROLE route(ACL_CHECK); #!endif @@ -315,8 +326,6 @@ route route(LOG_REQUEST); - route(CLASSIFY_SOURCE); - #!ifdef NAT_TRAVERSAL_ROLE route(NAT_DETECT); #!endif diff --git a/kamailio/extra-traffic-filter-role.cfg b/kamailio/extra-traffic-filter-role.cfg new file mode 100644 index 0000000..8ff9b4b --- /dev/null +++ b/kamailio/extra-traffic-filter-role.cfg @@ -0,0 +1,84 @@ +####### Extra Traffic Filter Role Configuration ######## + +# Define default values for configuration options if not set in local.cfg +#!ifndef ETFR_BAN_DURATION +#!define ETFR_BAN_DURATION 1800 +#!endif + +# Define Bad User-Agent Patterns +#!ifndef ETFR_BAD_UA_PATTERNS +#!define ETFR_BAD_UA_PATTERNS "friendly-scanner|sipcli|sipsak|VaxSIPUserAgent|iWar|CSipSimple|sipvicious|sip-scan|svmap|VaxIPUserAgent|sundayddr|sipv|smap|PSYCHO|iPing|DiSipell|WebSipp|masscan|zmap|SIPBot|friendly-request|siparmyknife" +#!endif +#!substdef "!ETFR_SUBST_BAD_UA_PATTERNS!$def(ETFR_BAD_UA_PATTERNS)!g" + +# Define SQL Injection Patterns +#!ifndef ETFR_SQL_INJECTION_PATTERNS +#!define ETFR_SQL_INJECTION_PATTERNS "([';]+|(--)+|(%27)+|(%23)+|(%24)+|[;]+|[']+)" +#!endif + +# Initialize htable for banned IPs +#!substdef "!ETFR_SUBST_BAN_DURATION!$def(ETFR_BAN_DURATION)!g" +modparam("htable", "htable", "etfr_banned_ips=>size=8;autoexpire=ETFR_SUBST_BAN_DURATION") + +# Main Request Route Enhancements +# Place this code at the appropriate place in your main request_route + +route[EXTRA_FILTER_REQUEST] { + # Check if the source IP is banned + if ($sht(etfr_banned_ips=>$si)) { + xlog("L_WARN", "$ci|Fail2Ban| Dropping request from banned IP: $si\n"); + exit; + } + + # Proceed with INVITE filtering + if (is_method("INVITE")) { + # Extract the domain from the Request URI + $var(domain) = $rd; + + # Check if the domain is an IP address + if ($var(domain) =~ "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$") { + # Check if the source IP is in the carrier group + if (!(allow_source_address(1) || allow_source_address(10))) { + # Source IP is not a carrier, ban the IP + xlog("L_ALERT", "$ci|Fail2Ban| Banned IP: $si Reason: INVITE with IP domain from untrusted source\n"); + route(ETFR_BAN_IP); + } else { + xlog("L_WARN", "$ci|ETFR| Allowing Carrier IP: $si\n"); + return; + } + } + + # Check if the Request URI contains user '1000' + if ($rU == "1000") { + xlog("L_ALERT", "$ci|Fail2Ban| Banned IP: $si Reason: Attempt to call user 1000\n"); + route(ETFR_BAN_IP); + } + } + + # Check for known bad User-Agents + if ($ua =~ "(ETFR_SUBST_BAD_UA_PATTERNS)") { + xlog("L_ALERT", "$ci|Fail2Ban| Banned IP: $si Reason: Known bad User-Agent: $ua\n"); + route(ETFR_BAN_IP); + } + + # Check for SQL injection patterns in SIP message + if ($rb =~ "(ETFR_SQL_INJECTION_PATTERNS)" || $ru =~ "(ETFR_SQL_INJECTION_PATTERNS)") { + xlog("L_ALERT", "$ci|Fail2Ban| Banned IP: $si Reason: SQL injection attempt\n"); + route(ETFR_BAN_IP); + } + + return; +} + +# Ban IP Route +route[ETFR_BAN_IP] { + # Add source IP to banned IPs table with auto-expire + $sht(etfr_banned_ips=>$si) = $Ts; + + # Log the event for Fail2Ban + xlog("L_ALERT", "$ci|end| Added IP $si to etfr_banned_ips htable\n"); + + # Drop the request + exit; +} + diff --git a/kamailio/local.cfg b/kamailio/local.cfg index addef24..ad0eb18 100644 --- a/kamailio/local.cfg +++ b/kamailio/local.cfg @@ -21,6 +21,7 @@ # # #!trydef REGISTRAR_SYNC_ROLE # # #!trydef PRESENCE_NOTIFY_SYNC_ROLE # # #!trydef SIP_TRACE_ROLE +# # #!trydef EXTRA_TRAFFIC_FILTER_ROLE ################################################################################ ## SERVER INFORMATION @@ -155,3 +156,27 @@ listen=UDP_SIP listen=TCP_SIP listen=UDP_ALG_SIP listen=TCP_ALG_SIP + +################################################################################ +## Extra Traffic Filter Role Settings +################################################################################ +## These settings apply if you enable the EXTRA_TRAFFIC_FILTER_ROLE +## It will ban IPs where an IP is found in the request uri, unless it is from +## a carrier. It will also ban from usernames of 1000@ unless you allow it. +## It will also ban SQL injection attacks and bad sip clients (or older +## depreciated ones. + +# You can either define carriers here, in a file, or run a script to populate +# the address table in the database +## modparam("permissions", "address", "group=10, ip=192.168.1.100") +## modparam("permissions", "address", "group=10, ip=192.168.1.101") +## modparam("permissions", "address", "group=10, ip=192.168.1.102") + +# Define ban duration in seconds (Optional, default is 1800 seconds) +# # #!define ETFR_BAN_DURATION 1800 + +# Define Bad User-Agent Patterns (Optional, default includes a comprehensive list) +# # #!define ETFR_BAD_UA_PATTERNS "friendly-scanner|sipcli|sipsak|VaxSIPUserAgent|iWar|CSipSimple|sipvicious|sip-scan|svmap|VaxIPUserAgent|sundayddr|sipv|smap|PSYCHO|iPing|DiSipell|WebSipp|masscan|zmap|SIPBot|friendly-request|siparmyknife" + +# Define SQL Injection Patterns (Optional, default includes common patterns) +# # #!define ETFR_SQL_INJECTION_PATTERNS "([';]+|(--)+|(%27)+|(%24)+|(%23)+|[;]+|[']+|[\"+]+)" \ No newline at end of file diff --git a/kamailio/traffic-filter-role.cfg b/kamailio/traffic-filter-role.cfg index 8fe1013..a1baf4e 100644 --- a/kamailio/traffic-filter-role.cfg +++ b/kamailio/traffic-filter-role.cfg @@ -55,3 +55,27 @@ route[FILTER_TO_DOMAIN] } } +route[CCP_SECURITY_CHECKS] { +#!ifdef WITH_CCP_SECURITY_CHECKS + if (is_method("INVITE|REGISTER")) { + + if($ua =~ "(friendly-scanner|sipvicious|pplsip)") { + xlog("$ci|block|Fail2Ban blocking traffic from $si Script Kiddie trying to exploit\n"); + drop(); + exit; + } + + if($au =~ "(\=)|(\-\-)|(')|(\#)|(\%27)|(\%24)" and $au != $null) { + xlog("$ci|block|Fail2Ban blocking traffic from $si SQL Injection attack over SIP\n"); + drop(); + exit; + } + + if($(hdr(Record-Route)[0]{nameaddr.uri}) != $si and $(hdr(Record-Route)[0]{nameaddr.uri}) != $null) { + xlog("$ci|block|Fail2Ban blocking traffic from $si Spoofing attack over SIP\n"); + drop(); + exit; + } + } +#!endif +} From 1a4e4f7a03331358d3b712b1f960ccfa6fe2aae8 Mon Sep 17 00:00:00 2001 From: Mooseable Date: Thu, 13 Mar 2025 20:38:05 +0800 Subject: [PATCH 2/4] remove redundant comment --- kamailio/extra-traffic-filter-role.cfg | 3 --- 1 file changed, 3 deletions(-) diff --git a/kamailio/extra-traffic-filter-role.cfg b/kamailio/extra-traffic-filter-role.cfg index 8ff9b4b..2da483f 100644 --- a/kamailio/extra-traffic-filter-role.cfg +++ b/kamailio/extra-traffic-filter-role.cfg @@ -20,9 +20,6 @@ #!substdef "!ETFR_SUBST_BAN_DURATION!$def(ETFR_BAN_DURATION)!g" modparam("htable", "htable", "etfr_banned_ips=>size=8;autoexpire=ETFR_SUBST_BAN_DURATION") -# Main Request Route Enhancements -# Place this code at the appropriate place in your main request_route - route[EXTRA_FILTER_REQUEST] { # Check if the source IP is banned if ($sht(etfr_banned_ips=>$si)) { From 25d0dabf0b1dbdbf15b2c8e7828ae5ca684cf3af Mon Sep 17 00:00:00 2001 From: Mooseable Date: Thu, 13 Mar 2025 20:38:05 +0800 Subject: [PATCH 3/4] revert original traffic-filter-role.cfg as its redundant with the extra traffic filter role --- kamailio/traffic-filter-role.cfg | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/kamailio/traffic-filter-role.cfg b/kamailio/traffic-filter-role.cfg index a1baf4e..942037f 100644 --- a/kamailio/traffic-filter-role.cfg +++ b/kamailio/traffic-filter-role.cfg @@ -53,29 +53,4 @@ route[FILTER_TO_DOMAIN] drop(); exit; } -} - -route[CCP_SECURITY_CHECKS] { -#!ifdef WITH_CCP_SECURITY_CHECKS - if (is_method("INVITE|REGISTER")) { - - if($ua =~ "(friendly-scanner|sipvicious|pplsip)") { - xlog("$ci|block|Fail2Ban blocking traffic from $si Script Kiddie trying to exploit\n"); - drop(); - exit; - } - - if($au =~ "(\=)|(\-\-)|(')|(\#)|(\%27)|(\%24)" and $au != $null) { - xlog("$ci|block|Fail2Ban blocking traffic from $si SQL Injection attack over SIP\n"); - drop(); - exit; - } - - if($(hdr(Record-Route)[0]{nameaddr.uri}) != $si and $(hdr(Record-Route)[0]{nameaddr.uri}) != $null) { - xlog("$ci|block|Fail2Ban blocking traffic from $si Spoofing attack over SIP\n"); - drop(); - exit; - } - } -#!endif -} +} \ No newline at end of file From 5575a12e1f61230f5003db2b1195f75268ecda74 Mon Sep 17 00:00:00 2001 From: Mooseable Date: Thu, 13 Mar 2025 20:38:06 +0800 Subject: [PATCH 4/4] reorder module loading and database config to solve $kzE and other variable expansion errors with the presence roles --- kamailio/db_queries_postgres.cfg | 2 +- kamailio/default.cfg | 13 ++++++++++--- kamailio/presence-notify.cfg | 14 ++++++++++++++ kamailio/presence-role.cfg | 5 +---- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/kamailio/db_queries_postgres.cfg b/kamailio/db_queries_postgres.cfg index 4b1ce60..5733f73 100644 --- a/kamailio/db_queries_postgres.cfg +++ b/kamailio/db_queries_postgres.cfg @@ -13,7 +13,7 @@ #!substdef "!KZQ_PRESENCE_SEARCH_SUMMARY!select * from active_watchers where watcher_domain = '\$var(Domain)'!g" #!substdef "!KZQ_PRESENCE_RESET!delete from presentity where sender = '\$var(MediaUrl)'!g" -#!substdef "!KZQ_REPLACE_WATCHERS_LOG!INSERT INTO active_watchers_log (presentity_uri, watcher_username, watcher_domain, event, callid, to_user, to_domain, user_agent, time, result, sent_msg, received_msg) VALUES ('\$subs(uri)', '\$subs(watcher_username)', '\$subs(watcher_domain)', '\$subs(event)','\$subs(callid)','\$subs(to_user)','\$subs(to_domain)', '\$(subs(user_agent){s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})', \$TS, \$notify_reply(\$rs), '\$(mb{s.replace,\\\',''}{s.replace,\$\$,''})', '\$(notify_reply(\$mb){s.replace,\\\',''}{s.replace,\$\$,''})') ON CONFLICT (presentity_uri, watcher_username, watcher_domain, event) DO UPDATE SET presentity_uri = excluded.presentity_uri, watcher_username = excluded.watcher_username, watcher_domain = excluded.watcher_domain, event = excluded.event!g" +#!substdef "!KZQ_REPLACE_WATCHERS_LOG!INSERT INTO active_watchers_log (presentity_uri, watcher_username, watcher_domain, event, callid, to_user, to_domain, user_agent, time, result, sent_msg, received_msg) VALUES ('$var(subs_uri)', '$var(subs_watcher_username)', '$var(subs_watcher_domain)', '$var(subs_event)','$var(subs_callid)','$var(subs_to_user)','$var(subs_to_domain)', '$var(subs_user_agent)', \$TS, '$var(notify_reply_code)', '$var(sent_msg)', '$var(received_msg)') ON CONFLICT (presentity_uri, watcher_username, watcher_domain, event) DO UPDATE SET presentity_uri = excluded.presentity_uri, watcher_username = excluded.watcher_username, watcher_domain = excluded.watcher_domain, event = excluded.event!g" #!substdef "!KZQ_DELETE_FROM_ACTIVE_WATCHERS_WHERE_EXPIRES!DELETE FROM active_watchers WHERE expires > 0 AND to_timestamp(expires) < now() - interval '90 seconds'!g" #!substdef "!KZQ_DELETE_FROM_ACTIVE_WATCHERS_WHERE_PRESENTITY!DELETE FROM ACTIVE_WATCHERS WHERE PRESENTITY_URI='\$subs(uri)' AND EVENT='\$subs(event)' AND FROM_USER = '\$subs(from_user)' AND FROM_DOMAIN='\$subs(from_domain)' AND CALLID <> '\$subs(callid)'!g" diff --git a/kamailio/default.cfg b/kamailio/default.cfg index 4f2799d..adbc780 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -208,12 +208,19 @@ modparam("debugger", "mod_level", "core=1") ####### STATISTICS ###### loadmodule "statistics.so" -####### DATABASE module ########## -include_file "db_KAMAILIO_DBMS.cfg" - ###### kazoo bindings ###### include_file "kazoo-bindings.cfg" +#!ifdef PRESENCE_ROLE +loadmodule "presence.so" +loadmodule "presence_dialoginfo.so" +loadmodule "presence_mwi.so" +loadmodule "presence_xml.so" +#!endif + +####### DATABASE module ########## +include_file "db_KAMAILIO_DBMS.cfg" + ####### Role Configurations ########## #!ifdef AUTHORIZATION_ROLE include_file "authorization-role.cfg" diff --git a/kamailio/presence-notify.cfg b/kamailio/presence-notify.cfg index 33ca06a..d86775d 100644 --- a/kamailio/presence-notify.cfg +++ b/kamailio/presence-notify.cfg @@ -64,6 +64,20 @@ event_route[presence:notify-reply] $xavp(pres=>delete_subscription) = 0; + ###Fix issues with nested variables in specific load orders + $var(subs_uri) = $subs(uri); + $var(subs_watcher_username) = $subs(watcher_username); + $var(subs_watcher_domain) = $subs(watcher_domain); + $var(subs_event) = $subs(event); + $var(subs_callid) = $subs(callid); + $var(subs_to_user) = $subs(to_user); + $var(subs_to_domain) = $subs(to_domain); + $var(subs_user_agent) = $(subs(user_agent){s.escape.common}{s.replace,\','}{s.replace,$$,}); + $var(notify_reply_code) = $notify_reply($rs); + $var(sent_msg) = $(mb{s.replace,\','}{s.replace,$$,}); + $var(received_msg) = $(notify_reply($mb){s.replace,\','}{s.replace,$$,}); + + if($notify_reply($rs) == 200) { $sht(notify=>$ci) = $null; $sht(notify=>$ci::count) = 0; diff --git a/kamailio/presence-role.cfg b/kamailio/presence-role.cfg index df20b5c..8308461 100644 --- a/kamailio/presence-role.cfg +++ b/kamailio/presence-role.cfg @@ -34,10 +34,7 @@ modparam("nat_traversal", "keepalive_interval", 45) modparam("htable", "htable", "first=>size=32;autoexpire=3600;initval=0;") -loadmodule "presence.so" -loadmodule "presence_dialoginfo.so" -loadmodule "presence_mwi.so" -loadmodule "presence_xml.so" +### loadmodule for the presence modules have been moved to default.cfg to load them earlier modparam("presence_dialoginfo", "force_dummy_dialog", 1) modparam("presence_dialoginfo", "force_single_dialog", BLF_USE_SINGLE_DIALOG)