# ========================================================================== # # opensips.cfg.tt - OpenSIPS load balancer configuration # # Chase Venters # # ========================================================================== # # ========================================================================== # # ============================ Import Variables ============================ # # ========================================================================== # [% SET pwd_mysql = cfg.Password.MYSQL_OPENSIPS %] [% SET ip_public1 = cfg.Interface.UTM_PUBLIC.IpDef.IVR1 %] [% SET ip_public2 = cfg.Interface.UTM_PUBLIC.IpDef.IVR2 %] [% SET ip_private_ivr = cfg.VlanByIfDef.IVR.IpAddress %] #============================================================================# #=============================== Configuration ==============================# #============================================================================# # No debugging, do fork 4 children debug=3 fork=yes children=4 log_stderror=yes # Accept traffic on our public IPs via UDP or TLS, and on our private IP listen=udp:[% ip_public1 %]:5060 listen=udp:[% ip_public2 %]:5060 listen=udp:[% ip_private_ivr %]:5060 # Do not blacklist peers if they report temporary failure disable_dns_blacklist=yes # Security settings check_via=1 server_signature=no # Don't do any DNS lookups on myself dns=no rev_dns=no # Module path mpath="/usr/lib64/opensips/modules/" #============================================================================# #================================== Modules =================================# #============================================================================# loadmodule "sl.so" loadmodule "tm.so" loadmodule "rr.so" loadmodule "maxfwd.so" loadmodule "avpops.so" loadmodule "uac.so" loadmodule "db_mysql.so" loadmodule "textops.so" loadmodule "options.so" loadmodule "uri.so" loadmodule "mi_datagram.so" loadmodule "nathelper.so" loadmodule "acc.so" loadmodule "dialog.so" loadmodule "load_balancer.so" loadmodule "signaling.so" loadmodule "cfgutils.so" loadmodule "sst.so" #============================================================================# #================================ Parameters ================================# #============================================================================# # Database connection for avpops modparam("avpops", "db_url", "mysql://opensipsd:[% pwd_mysql %]@localhost/opensips") # For compatibility modparam("rr", "enable_full_lr", 1) # Encrypt original From header modparam("uac", "restore_passwd", "[% cfg.Password.OPENSIPS_FROM %]") # Store dialogs in the database, as this might eventually be used to sync # call state across UTMs, and could make debugging easy modparam("dialog", "db_url", "mysql://opensipsd:[% pwd_mysql %]@localhost/opensips") modparam("dialog", "db_mode", 1) modparam("dialog", "timeout_avp", "$avp(s:d_timeout)") # Create a group-accessible control socket that the media-dispatcher can talk # to modparam("mi_datagram", "socket_name", "/etc/supervise/opensipsd/runtime/opensipsd.sock") modparam("mi_datagram", "unix_socket_mode", 0660) # RTPProxy socket modparam("nathelper", "rtpproxy_sock", "udp:127.0.0.1:9999") modparam("nathelper", "nortpproxy_str", "") # ACC modparam("acc", "log_flag", 2) modparam("acc", "report_cancels", 1) #modparam("acc", "log_extra", # "uaA=$hdr(User-Agent);to=$hdr(To);from=$hdr(From);si=$si;ruri=$ruri") # Load balancer modparam("load_balancer", "db_url", "mysql://opensipsd:[% pwd_mysql %]@localhost/opensips") modparam("load_balancer", "db_table", "destinations") modparam("load_balancer", "probing_interval", 0) # Set up SIP Session Timers to help drop old calls modparam("sst", "sst_flag", 5) modparam("sst", "timeout_avp", "$avp(s:d_timeout)") modparam("sst", "min_se", 2400) # Set more aggressive timeouts modparam("tm", "fr_timer", 3) modparam("tm", "fr_inv_timer", 60) # ========================================================================== # # ================================== Route ================================= # # ========================================================================== # route { # Hop count sanity check if (!mf_process_maxfwd_header("10")) { xlog("LOOPWARN: Message from \"$fu\" ($si:$sp) to \"$tu\" had more than 10 hops\n"); setflag(2); sl_send_reply("483", "Too many hops"); return; } # Message size sanity check if (msg:len >= 8192) { xlog("SIZEWARN: Message from \"$fu\" ($si:$sp) to \"$tu\" had more than 8192 bytes\n"); setflag(2); sl_send_reply("513", "Message too large"); return; } # Handle OPTIONS requests... don't bother logging them since they are # used as high frequency pings! if (uri == myself) { if (method == "OPTIONS") { options_reply(); exit; } } # All further messages should be sent through our system record_route(); # Enable logging setflag(2); # Handle loose routing if (loose_route()) { # Make sure we're not being used for toll fraud if (!has_totag()) { xlog("SECURITY: Rejected initial loose-routing attempt from \"$fu\" ($si:$sp) to \"$tu\"\n"); sl_send_reply("403", "Initial Loose-Routing Rejected"); setflag(2); exit; } # Add routing hint append_hf("P-hint: rr-enforced\r\n"); # Activate rtpproxy?? if (method == "ACK" && has_body("application/sdp")) { route("rtpproxy_answer"); } # Relay message if (!t_relay()) { sl_reply_error(); } # Disengage RTP proxy at the end of the call if (method == "CANCEL" || method == "BYE") { route("cleanup"); exit; } exit; } # Handle cancel and re-transmissions if (method == "CANCEL") { unforce_rtp_proxy(); if (t_check_trans()) { t_relay(); } exit; } # Handle INVITE requests if (method == "INVITE") { # Consume retransmissions t_check_trans(); # Check SST if (sstCheckMin("1")) { xlog("422 Session Timer Too Small reply sent for call from \"$fu\" ($si:$sp) to \"$tu\"\n"); exit; } setflag(5); # Sanitize to and from for DB query $avp(s:from) = $fU; $avp(s:to) = $rU; avp_subst("$avp(s:from)", "/[^0-9]//g"); avp_subst("$avp(s:to)", "/[^0-9]//g"); # Check to see if we should be recording or simulating a failure mode avp_db_query( "SELECT `recording_enabled`,`recording_probability`,`failmode` FROM `callctrl` WHERE (`from`='$avp(s:from)' OR `to`='$avp(s:to)') AND ((`from`='$avp(s:from)' AND `to`='$avp(s:to)') OR `from` IS NULL OR `to` IS NULL)", "$avp(s:rec_enabled);$avp(s:rec_prob);$avp(s:failmode)"); if ($avp(s:failmode) == "503") { sl_send_reply("503", "Service Disabled"); exit; } else if ($avp(s:failmode) == "500") { sl_send_reply("500", "Service Disabled"); exit; } else if ($avp(s:failmode) == "drop") { exit; } avp_delete("$avp(s:failmode)"); # To prevent retransmits, let the caller know we're working sl_send_reply("100", "Trying"); # Create a dialog to track call parameters create_dialog(); # Apply probability to recording if ($avp(s:rec_enabled) > 0 && $avp(s:rec_prob) > 0) { # Run probability function. $var(prob) = $RANDOM % 100; if ($var(prob) >= $avp(s:rec_prob)) { $avp(s:rec_enabled) = 0; } } if ($avp(s:rec_enabled) > 0) { $dlg_val(record) = "y"; $var(recording) = "RECORDING\n"; } else { $dlg_val(record) = "n"; $var(recording) = "\n"; } avp_delete("$avp(s:rec_enabled)"); avp_delete("$avp(s:rec_prob)"); avp_delete("$avp(s:from)"); avp_delete("$avp(s:to)"); # Calls are proxied in both directions. Which way are we going? $var(srcnet) = $(si{s.substr,0,8}); $dlg_val(old_ru) = $ru; if ($var(srcnet) != "10.[% cfg.NetNum %].20.") { # Incoming call from the Internet. Pick out an IVR to receive # the call force_send_socket([% ip_private_ivr %]:5060); $dlg_val(lbdir) = "in"; load_balance("101", "calls", "1"); $var(lbret) = $retcode; } else { # Outgoing call to the Internet. Pick out an upstream provider to # handle the call force_send_socket([% ip_public1 %]:5060); $dlg_val(lbdir) = "out"; load_balance("201", "calls", "1"); $var(lbret) = $retcode; } # Make sure we got a destination set if ($var(lbret) < 0) { sl_send_reply("503", "Service full"); xlog("ACC: $dlg_val(dir) $si $ci $fu -> $ru FAILED Service full\n"); exit; } # Cache the original request URI incase we have to rewrite it # multiple times $dlg_val(orig_to) = $rU; route("sendcall"); exit; } else { # Other methods are not allowed sl_send_reply("405", "Method not allowed"); exit; } } #============================================================================# # Sends a call route["sendcall"] { # Rewrite RURI host based on what the load balancer gave us $rd = $dd; # Check for, and apply, any necessary prefix avp_db_query("SELECT `prefix` FROM `destinations` WHERE dst_uri='sip:$dd'", "$avp(s:prefix)"); $rU = $avp(s:prefix) + $dlg_val(orig_to); avp_delete("$avp(s:prefix)"); # Log call if ($dlg_val(record) == "y") { $var(recording) = "RECORDING\n"; } else { $var(recording) = "\n"; } if ($dlg_val(lbdir) == "in") { $var(dir) = "[in] "; } else { $var(dir) = "[out]"; } xlog("ACC: $var(dir) $si $ci $fu -> $dlg_val(old_ru) $ru $var(recording)"); # Use the RTP proxy if (has_body("application/sdp")) { if (route("rtpproxy_offer")) { t_on_reply("do_rtpproxy_answer"); } } else { t_on_reply("do_rtpproxy_offer"); } t_on_failure("invite_failure"); # Send the call if (!t_relay("0x01")) { sl_reply_error(); route("cleanup"); exit; } exit; } #============================================================================# # Invokes rtpproxy for an answer section route["rtpproxy_answer"] { if (dst_ip == [% ip_private_ivr %]) { rtpproxy_answer("FIEW"); } else { rtpproxy_answer("FEIW"); } return($retcode); } #============================================================================# # Invokes rtpproxy for an offer section route["rtpproxy_offer"] { if ($dlg_val("sent_rtpproxy_offer") == "yes") { return(1); } $dlg_val("sent_rtpproxy_offer") = "yes"; if (dst_ip == [% ip_private_ivr %]) { rtpproxy_offer("FIEW"); $var(ret) = $retcode; } else { rtpproxy_offer("FEIW"); $var(ret) = $retcode; } if ($var(ret) && $dlg_val(record) == "y") { xlog("Starting recording for $ci\n"); start_recording(); } return($var(ret)); } #============================================================================# # onReply 1: We activated rtpproxy on the SDP already onreply_route["do_rtpproxy_answer"] { if (has_body("application/sdp")) { route("rtpproxy_answer"); } } #============================================================================# # onReply 2: We haven't activated rtpproxy yet but we need to onreply_route["do_rtpproxy_offer"] { if (has_body("application/sdp")) { route("rtpproxy_offer"); } } #============================================================================# # failure 1: We need to stop the RTP proxy failure_route["invite_failure"] { xlog("ACC: txn fail: call_id=$ci;status=$T_reply_code\n"); if (t_check_status("([45][0-9][0-9])")) { # Certain 4xx/5xx codes really do pertain to the PSTN endpoint # but most of the others are probably related to a SIP peering # misconfiguration or temporary failure. But the codes that # really can occur from a normal PSTN condition (eg, noanswer # or busy) shouldn't generate an additional call immediately. if (t_check_status("404|408|410|480|482|486|487")) { route("cleanup"); exit; } # Try additional load balancing destinations if ($dlg_val(lbdir) == "in") { load_balance("101", "calls", "1"); $var(lbret) = $retcode; } else if ($dlg_val(lbdir) == "out") { load_balance("201", "calls", "1"); $var(lbret) = $retcode; } else { t_reply("503", "Internal Server Error"); route("cleanup"); exit; } # Make sure we got a destination set if ($var(lbret) < 0) { t_reply("503", "Internal Server Error"); xlog("ACC: giving up: $ci\n"); route("cleanup"); exit; } route("sendcall"); exit; } route("cleanup"); } #============================================================================# # cleans up the call route["cleanup"] { unforce_rtp_proxy(); avp_delete("*"); exit; } #============================================================================#