#!KAMAILIO # # Kamailio (OpenSER) SIP Server v5.3 # Kamailio as SIP Edge Router # April 2020 # Need help? # * Free/Official: # - Documentation: https://www.kamailio.org/w/documentation/ # - Wiki: https://www.kamailio.org/wiki/ # - Modules: https://www.kamailio.org/docs/modules/stable/ # - IRC: irc.freenode.net #kamailio # - Mailing Lists: https://www.kamailio.org/w/mailing-lists/ # * Commercial: # - LOD: https://lod.com fred@lod.com +1 (224) 334-3733 # - Business Directory: https://www.kamailio.org/w/business-directory/ ####### Define Substitutions ####### # replace with values specific to your needs #!substdef "/PRIVATEIP/10.20.20.137/" #!substdef "/PUBLICIP/12.13.14.24/" #!substdef "/PUBDOMAIN/call.now.today/" #!substdef "/PBXIP/10.10.10.22/" #!substdef "/APIKEY/thisismyvettedapikey/" ####### Define Code Blocks ######### #!define WITH_DEBUG #!define WITH_ANTIFLOOD #!define WITH_APIBAN # define WITH_SIPDEBUG ####### Global Parameters ######### ### LOG Levels: 3=DBG, 2=INFO, 1=NOTICE, 0=WARN, -1=ERR #!ifdef WITH_DEBUG debug=4 log_stderror=yes #!else debug=2 log_stderror=no #!endif memdbg=5 memlog=5 pv_buffer_size=65536 pv_cache_limit=65536 log_facility=LOG_LOCAL0 log_prefix="{$mt $proto $hdr(CSeq) $ci} " children=4 enable_tls=yes tls_max_connections=2048 tcp_connection_lifetime=3605 dns=no dns_cache_init=off dns_srv_lb=no dns_try_naptr=no maxbuffer=65536 max_while_loops=250 rev_dns=no use_dns_cache=no auto_aliases=no mhomed=0 listen=udp:PRIVATEIP:5060 listen=tls:PRIVATEIP:5061 advertise PUBLICIP:5061 alias=PRIVATEIP:5060 alias=PRIVATEIP:5061 alias=PUBLICIP:5061 alias=PUBDOMAIN:5061 port=5060 #!ifdef WITH_SIPDEBUG onsend_route_reply=yes #!endif server_header="Server: kamailio 5.8" ####### Modules Section ######## loadmodule "tls.so" loadmodule "jsonrpcs.so" loadmodule "kex.so" loadmodule "corex.so" loadmodule "tm.so" loadmodule "tmx.so" loadmodule "sl.so" loadmodule "rr.so" loadmodule "pv.so" loadmodule "maxfwd.so" loadmodule "outbound.so" loadmodule "textops.so" loadmodule "siputils.so" loadmodule "xlog.so" loadmodule "sanity.so" loadmodule "ctl.so" loadmodule "cfg_rpc.so" loadmodule "rtimer.so" loadmodule "json.so" loadmodule "http_client.so" loadmodule "jansson.so" loadmodule "htable.so" loadmodule "textopsx.so" loadmodule "rtpengine.so" loadmodule "nathelper.so" loadmodule "path.so" #!ifdef WITH_ANTIFLOOD loadmodule "pike.so" #!endif #!ifdef WITH_DEBUG loadmodule "debugger.so" #!endif # ----------------- setting module-specific parameters --------------- # ----- jsonrpcs params ----- modparam("jsonrpcs", "pretty_format", 1) # ----- ctl params ----- modparam("ctl", "binrpc", "unix:/var/run/kamailio/kamailio_ctl") modparam("ctl", "binrpc", "tcp:localhost:2046") # ----- tm params ----- modparam("tm", "failure_reply_mode", 3) modparam("tm", "noisy_ctimer", 1) modparam("tm", "cancel_b_method", 1) # ----- rr params ----- modparam("rr", "enable_full_lr", 1) modparam("rr", "append_fromtag", 1) modparam("rr", "ignore_sips", 1) modparam("rr", "enable_double_rr", 2) # ----- path ----- modparam("path", "enable_r2", 1) # ----- rtimer params ----- #!ifdef WITH_APIBAN modparam("rtimer", "timer", "name=apiban;interval=300;mode=1;") modparam("rtimer", "exec", "timer=apiban;route=APIBAN") modparam("htable", "htable", "apiban=>size=11;") modparam("htable", "htable", "apibanctl=>size=1;initval=0;") #!endif # ----- tls params ----- modparam("tls", "tls_method", "TLSv1.2+") modparam("tls", "verify_certificate", 0) modparam("tls", "require_certificate", 0) modparam("tls", "private_key", "/etc/kamailio/certs/kamailio.key") modparam("tls", "certificate", "/etc/kamailio/certs/kamailio.crt") # ----- rtpproxy params ----- modparam("rtpengine", "rtpengine_sock", "udp:127.0.0.1:2223") modparam("rtpengine", "rtpengine_disable_tout", 15) modparam("rtpengine", "rtpengine_tout_ms", 2000) modparam("rtpengine", "rtpengine_retr", 2) #!ifdef WITH_ANTIFLOOD # ----- pike params ----- modparam("pike", "sampling_time_unit", 2) modparam("pike", "reqs_density_per_unit", 16) modparam("pike", "remove_latency", 4) # ----- htable params ----- /* ip ban htable with autoexpire after 5 minutes */ modparam("htable", "htable", "ipban=>size=8;autoexpire=14400") modparam("htable", "htable", "a=>size=256;autoexpire=14400") #!endif #!ifdef WITH_DEBUG # ----- debugger params ----- modparam("debugger", "cfgtrace", 1) modparam("debugger", "log_level_name", "exec") #!endif # do not follow redirects modparam("http_client", "httpredirect", 0) modparam("http_client", "connection_timeout", 4) modparam("http_client", "verify_peer", 0) modparam("http_client", "verify_host", 0) modparam("http_client", "keep_connections", 1) ####### Routing Logic ######## request_route { #!ifdef WITH_SIPDEBUG xlog("L_INFO","[R-MAIN] SIP DEBUG: $mb\n"); #!endif # per request initial checks route(REQINIT); # CANCEL processing if (is_method("CANCEL")) { rtpengine_manage(); handle_ruri_alias(); if (!t_relay_cancel()) { xlog("L_INFO", "[MAIN] No matching transaction or other error on CANCEL\n"); sl_send_reply("500", "Internal Server Error M1"); } exit; } # handle retransmissions if (!is_method("ACK")) { if (t_precheck_trans()) { t_check_trans(); exit; } t_check_trans(); } # handle requests within SIP dialogs route(WITHINDLG); if ($si=="PBXIP") { if (!loose_route()) { switch($rc) { case -2: sl_send_reply("403", "Forbidden"); exit; } } remove_hf("Route"); force_rport(); $fs = "tls:PRIVATEIP:5061"; } else { xlog("L_INFO", "[R-MAIN] Incoming request from $si using $proto\n"); if ($si == "PRIVATEIP") { xlog("L_INFO", "[R-MAIN] Accepting internal relayed INVITE from self ($si)\n"); } else { if($si == "PBXIP") { xlog("L_INFO", "[R-MAIN] Accepting INVITE from trusted PBX ($si)\n"); } else { if(proto != TLS) { xlog("L_INFO", "[R-MAIN] rejecting non tls $ru from $si\n"); sl_send_reply("403", "Accepting TLS Only"); exit; } } } if (is_method("REGISTER")) { remove_hf("Route"); add_path(); $du = "sip:PBXIP:5060"; } else { if ($si == "PRIVATEIP") { xlog("L_INFO", "[R-MAIN] Routing internal INVITE explicitly to TLS client\n"); $du = "sip:" + $rU + "@PRIVATEIP:5061;transport=tls"; $fs = "tls:PRIVATEIP:5061"; } else { if ($rU == $null) { sl_send_reply("484", "Address Incomplete"); exit; } $ru = "sip:" + $rU + "@PBXIP:5060"; } } if ($(ct{tobody.user})!=$null) { $var(ctuser) = $(ct{tobody.user}); $var(cthost) = $si; $var(ctport) = $sp; remove_hf("Contact"); insert_hf("Contact: \r\n", "Call-ID"); } t_on_failure("MANAGE_FAILURE"); $fs = "udp:PRIVATEIP:5060"; } route(RELAY); exit; } # Wrapper for relaying requests route[RELAY] { handle_ruri_alias(); if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) { if (!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH"); } if (is_method("INVITE|SUBSCRIBE|UPDATE|REGISTER")) { if (!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY"); } if (is_method("INVITE")) { if (!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE"); } xlog("L_INFO", "[RELAY] Relaying $ru\n"); if (!t_relay()) { sl_reply_error(); } exit; } # Per SIP request initial checks route[REQINIT] { #!ifdef WITH_ANTIFLOOD # flood detection from same IP and traffic ban for a while # be sure you exclude checking trusted peers, such as pstn gateways # - local host excluded (e.g., loop to self) if (src_ip!=myself && src_ip!=PBXIP) { if ($sht(ipban=>$si)!=$null) { # ip is already blocked xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n"); exit; } if ($sht(apiban=>$si)!=$null) { # ip is blocked from apiban.org xdbg("request from apiban.org blocked IP - $rm from $fu (IP:$si:$sp)\n"); exit; } if (!pike_check_req()) { xlog("L_ALERT","[R-REQINIT]: pike blocking $rm from $fu (IP:$si:$sp)\n"); $sht(ipban=>$si) = 1; exit; } } #!endif if ($ua =~ "friendly-scanner|sipcli|VaxSIPUserAgent") { xlog("L_INFO","[R-REQINIT]: script kiddies from IP:$si:$sp - dropping and blocking\n"); route(BLOCKIP); # sl_send_reply("200", "OK"); exit; } if ($au =~ "(\=)|(\-\-)|(')|(\#)|(\%27)|(\%24)" and $au != $null) { xlog("L_INFO","[R-REQINIT]: sql injection from IP:$si:$sp - dropping\n"); route(BLOCKIP); exit; } if (!mf_process_maxfwd_header("10")) { xlog("L_INFO","[R-REQINIT]: too many hops\n"); sl_send_reply("483","R1 Too Many Hops"); exit; } if (is_method("OPTIONS")){ if (uri==myself && ($rU==$null || $rU=="kamailio")) { sl_send_reply("200","Keep on Keeping on"); exit; } } if (!sanity_check("17895", "7")) { xlog("L_INFO","[R-REQINIT]: Malformed SIP message from $si:$sp\n"); exit; } } # Handle requests within SIP dialogs route[WITHINDLG] { if (!has_totag()) return; if ($si=="PBXIP") { # && $(ru{param.value,alias})!=$null) { route(RTPMANAGE); route(RELAY); exit; } if (loose_route()) { if ( is_method("NOTIFY") ) { record_route(); } route(RTPMANAGE); route(RELAY); exit; } if ( is_method("ACK|BYE") ) { route(RTPMANAGE); route(RELAY); } sl_send_reply("404","Not here WD1"); exit; } # RTPProxy control and signaling updates for NAT traversal route[RTPMANAGE] { if (has_totag()) { if (is_method("INVITE|UPDATE|ACK") || is_method("BYE")) { if (proto==TLS) { rtpengine_manage("RTP/AVP replace-origin replace-session-connection SIP-source-address ICE=remove"); } else { rtpengine_manage("RTP/SAVP replace-origin replace-session-connection SIP-source-address ICE=remove"); } } t_on_reply("MANAGE_REPLY"); } else { if (is_method("INVITE")) { if (has_body("application/sdp")) { if (proto==TLS) { rtpengine_manage("RTP/AVP replace-origin replace-session-connection SIP-source-address ICE=remove"); } else { rtpengine_manage("RTP/SAVP replace-origin replace-session-connection SIP-source-address ICE=remove"); } } } } return; } route[BLOCKIP] { if (src_ip!=myself) { xlog("L_INFO","[R-BLOCKIP:$ci]: blocking $rm from $fu (IP:$si:$sp)\n"); $sht(ipban=>$si) = 1; } return; } # Manage outgoing branches branch_route[MANAGE_BRANCH] { xdbg("new branch [$T_branch_idx] to $ru\n"); route(RTPMANAGE); } # Manage incoming replies onreply_route[MANAGE_REPLY] { xdbg("incoming reply\n"); if ($si!="PBXIP") { if ($(ct{tobody.user})!=$null) { xlog("L_INFO","[R-M-REPLY] adding contact alias\n"); $var(ctuser) = $(ct{tobody.user}); $var(cthost) = $si; $var(ctport) = $sp; remove_hf("Contact"); insert_hf("Contact: \r\n", "Call-ID"); } } if (!is_method("REGISTER")) { if (status=~"[12][0-9][0-9]") { route(RTPMANAGE); } } } # Manage failure routing cases failure_route[MANAGE_FAILURE] { xlog("L_INFO","[R-M-FAILURE] handling failure $rs\n"); route(RTPMANAGE); if (t_is_canceled()) exit; } route[APIBAN] { #!ifdef WITH_APIBAN // check if we already have an APIBAN id... if so, get the updates and // if not, get the full list of banned ips. $var(KEY) = "APIKEY"; if ($sht(apibanctl=>ID) == 0) { $var(apiget) = "https://apiban.org/api/" + $var(KEY) + "/banned"; } else { $var(apiget) = "https://apiban.org/api/" + $var(KEY) + "/banned/" + $sht(apibanctl=>ID); } xlog("L_INFO","API SEND: $var(apiget)\n"); http_client_query("$var(apiget)", "$var(banned)"); # if we dont get a 200 OK from the webserver, kick it back if ($rc!=200) { xlog("L_INFO","API ERR: No 200 Received. $var(banned)\n"); exit; } else { xlog("L_INFO","API: $var(banned)\n"); } $var(count) = 0; jansson_array_size("ipaddress", $var(banned), "$var(size)"); while($var(count) < $var(size)) { jansson_get("ipaddress[$var(count)]", $var(banned), "$var(v)"); $sht(apiban=>$var(v)) = 1; xlog("L_INFO","API: ipaddress[$var(count)] == $var(v)\n"); $var(count) = $var(count) + 1; } jansson_get("ID", $var(banned), "$var(w)"); xlog("L_INFO","ID: $var(w)\n"); $sht(apibanctl=>ID) = $var(w); #!endif xdbg("apiban complete\n"); } event_route[htable:mod-init] { # pre load apiban route(APIBAN); } #!ifdef WITH_SIPDEBUG onsend_route { xlog("L_INFO","[ONSEND_ROUTE] SIP DEBUG: \n$snd(buf)\n"); } #!endif