diff --git a/pcscf/Dockerfile b/pcscf/Dockerfile new file mode 100644 index 0000000..0a519f1 --- /dev/null +++ b/pcscf/Dockerfile @@ -0,0 +1,31 @@ +# BSD 2-Clause License + +# Copyright (c) 2020, Supreeth Herle +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +FROM docker_kamailio + +CMD /mnt/pcscf/pcscf_init.sh && \ + mkdir -p /var/run/kamailio_pcscf && \ + kamailio -f /etc/kamailio_pcscf/kamailio_pcscf.cfg -P /kamailio_pcscf.pid -DD -E -e diff --git a/pcscf/dispatcher.list b/pcscf/dispatcher.list new file mode 100644 index 0000000..47d4d4f --- /dev/null +++ b/pcscf/dispatcher.list @@ -0,0 +1 @@ +# SBC's diff --git a/pcscf/kamailio_pcscf.cfg b/pcscf/kamailio_pcscf.cfg new file mode 100644 index 0000000..b032c89 --- /dev/null +++ b/pcscf/kamailio_pcscf.cfg @@ -0,0 +1,973 @@ +# +# TelcoSuite (V3) Proxy-CSCF +# +# Kamailio (OpenSER) SIP Server +# - web: http://www.kamailio.org +# - git: http://sip-router.org +# +# Refer to the Core CookBook at http://www.kamailio.org/dokuwiki/doku.php +# for an explanation of possible statements, functions and parameters. +# + +import_file "pcscf.cfg" + +####### Defined Values ######### +# *** Value defines - IDs used later in config +#!define DISPATCHER_LIST_SBC 1 + +#!define DISPATCHER_DST_AVP "i:1" +#!define DISPATCHER_GRP_AVP "i:2" +#!define DISPATCHER_CNT_AVP "i:3" +#!define DISPATCHER_SOCK_AVP "i:4" + +#!define RR_CUSTOM_USER_AVP "i:5" +#!define DLG_TIMEOUT_AVP "i:6" + +#!define FLT_MOBILE_ORIG 1 +#!define FLT_DIALOG 2 +#!define FLT_NAT 3 +#!define FLT_RTP 4 +#!define FLT_CAPTURE 5 + +####### Global Parameters ######### + +#!ifdef WITH_DEBUG +debug=4 +log_stderror=yes +#!else +debug=2 +log_stderror=no +#!endif + +memdbg=5 +memlog=5 + +max_while_loops=5000 + +#!ifdef WITH_XMLRPC +listen=tcp:127.0.0.1:5060 +#!endif + +# Locks all ser pages into memory making it unswappable (in general one +# doesn't want his sip proxy swapped out ) +mlock_pages=yes +# Tries to pre-fault all the shared memory, before starting. When "on", start +# time will increase, but combined with mlock_pages will guarantee ser will get +# all its memory from the beginning (no more kswapd slow downs) +shm_force_alloc=yes + +# Do SRV-Loadbalancing: +dns_srv_lb=yes +# Always prefer IPv6: +dns_try_ipv6=no +# DNS-Based failover +use_dns_failover=yes +# Query NAPTR-Records as well: +dns_try_naptr=no + +user_agent_header="User-Agent: TelcoSuite Proxy-CSCF" +server_header="Server: TelcoSuite Proxy-CSCF" + +log_facility=LOG_LOCAL0 + +fork=yes +children=4 + +#!ifndef TCP_PROCESSES +# Number of TCP Processes +#!define TCP_PROCESSES 16 +#!endif + +#!ifdef WITH_TLS +# Check, if TCP is enabled: +#!ifndef WITH_TCP +#!define WITH_TCP +#!endif +enable_tls=yes +#!endif + +#!ifdef WITH_XMLRPC +#!ifndef WITH_TCP +#!define WITH_TCP +#!endif +#!ifndef TCP_PROCESSES +# Number of TCP Processes +#!define TCP_PROCESSES 3 +#!endif +#!endif + +#!ifdef WITH_TCP +# life time of TCP connection when there is no traffic +# - a bit higher than registration expires to cope with UA behind NAT +tcp_connection_lifetime=3615 +# If a message received over a tcp connection has "alias" in its via a new tcp +# alias port will be created for the connection the message came from (the +# alias port will be set to the via one). +# +# Note: For NAT traversal of TCP clients it is better to not use +# tcp_accept_aliases but just use nathelper module and +# fix_nated_[contact|register] functions. +tcp_accept_aliases=no +# Enable SIP outbound TCP keep-alive using PING-PONG (CRLFCRLF - CRLF). +tcp_crlf_ping=yes + +#tcp_reuse_port=yes + +tcp_accept_no_cl=yes +tcp_rd_buf_size=16384 + +#!ifdef TCP_PROCESSES +tcp_children=TCP_PROCESSES +#!endif +#!else +disable_tcp=yes +#!endif + +/* uncomment the next line to disable the auto discovery of local aliases + based on reverse DNS on IPs (default on) */ +auto_aliases=no + +#phone2tel=1 + +/* uncomment and configure the following line if you want Kamailio to + bind on a specific interface/port/proto (default bind on all available) */ + +system.shutdownmode = 0 desc "System shutdown mode" +system.service = "Proxy-CSCF" desc "Function of this server" + +####### Modules Section ######## + +# set paths to location of modules +mpath="/usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/:/usr/lib/kamailio/modules_k/:/usr/lib/kamailio/modules/:/usr/lib/x86_64-linux-gnu/kamailio/modules/:/usr/local/lib64/kamailio/modules" + +# Fifo Module +# Kamailio Extensions (e.g. MI:uptime, MI:version, cfg:isflagset etc.) +loadmodule "kex" +# Transaction Module +loadmodule "tm" +loadmodule "tmx" +loadmodule "sl" +loadmodule "rr" +loadmodule "pv" +loadmodule "maxfwd" +loadmodule "textops" +loadmodule "textopsx" +# SIP-Utilities: options_reply +loadmodule "siputils" +loadmodule "sanity" +loadmodule "ctl" +loadmodule "cfg_rpc" +loadmodule "xlog" +loadmodule "auth" +loadmodule "dispatcher" +loadmodule "sctp" +loadmodule "path" +loadmodule "statistics" + +loadmodule "ims_dialog" +loadmodule "ims_usrloc_pcscf" +#!ifdef WITH_IPSEC +loadmodule "ims_ipsec_pcscf" +#!endif +loadmodule "ims_registrar_pcscf" + +#!ifdef WITH_XMLRPC +loadmodule "xmlrpc" +#!endif + +#!ifdef WITH_REGINFO +loadmodule "pua" +#!endif + +#!ifdef DB_URL +loadmodule "db_mysql" +#!ifdef DB_URL2 +loadmodule "db_cluster" +#!endif +#!endif + +#!ifdef WITH_DEBUG +loadmodule "debugger" +#!endif + +loadmodule "usrloc" +loadmodule "registrar" + +loadmodule "nathelper" + +#!ifdef WITH_ANTIFLOOD +loadmodule "pike" +#!endif + +#!ifdef WITH_TLS +loadmodule "tls" +#!endif + +#!ifdef WITH_RTPPING +loadmodule "rtpping" +#!endif + + +loadmodule "sdpops" +loadmodule "rtpengine" + +#!ifdef WITH_WEBSOCKET +loadmodule "xhttp.so" +loadmodule "websocket.so" +#!endif + +#!ifdef WITH_RX +loadmodule "cdp" +loadmodule "cdp_avp" +loadmodule "ims_qos" +#!endif + +#!ifdef CAPTURE_NODE +loadmodule "siptrace" +#!endif + +#!ifdef WITH_NATPING +loadmodule "rtimer" +loadmodule "uac" +loadmodule "sqlops" +#!endif + +# HTable as a cache: +loadmodule "htable" + +#!ifdef WITH_DEBUG +#loadmodule "debugger.so" +modparam("debugger", "mod_hash_size", 5) +modparam("debugger", "mod_level_mode", 1) +modparam("debugger", "mod_level", "rtpengine=3") +modparam("debugger", "mod_level", "ims_qos=6") +modparam("debugger", "mod_level", "ims_ipsec_pcscf=6") +modparam("debugger", "mod_level", "textops=6") +modparam("debugger", "mod_level", "ims_registrar_pcscf=6") +modparam("debugger", "mod_level", "ims_usrloc_pcscf=6") +modparam("debugger", "cfgtrace", 0) +#!endif + +loadmodule "jsonrpcs.so" +# ----- jsonrpcs params ----- +modparam("jsonrpcs", "pretty_format", 1) +/* set the path to RPC fifo control file */ +modparam("jsonrpcs", "fifo_name", "/var/run/kamailio_pcscf/kamailio_rpc.fifo") +/* set the path to RPC unix socket control file */ +modparam("jsonrpcs", "dgram_socket", "/var/run/kamailio_pcscf/kamailio_rpc.sock") + +# ----------------- setting module-specific parameters --------------- +#!ifdef DB_URL2 +# ----- db_cluster params ----- +modparam("db_cluster", "connection", DB_URL) +modparam("db_cluster", "connection", DB_URL2) +modparam("db_cluster", "cluster", "cluster1=>con1=2s2s;con2=1s1s") +#!endif + +#!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=300") +modparam("htable", "htable", "failedauth=>size=8;autoexpire=120") +#!endif + +modparam("htable", "htable", "contact=>size=8;autoexpire=20") +modparam("htable", "htable", "a=>size=8;autoexpire=20") + +#!ifdef WITH_IMS_HDR_CACHE +modparam("htable", "htable", "serviceroutes=>size=16;autoexpire=14400;") +modparam("htable", "htable", "associateduris=>size=16;autoexpire=14400;") +#!endif + +#!ifdef WITH_NATPING +modparam("htable", "htable", "natping=>size=8;autoexpire=600000;") +modparam("htable", "htable", "natpingfail=>size=8;autoexpire=600000;") +#!ifdef DB_URL2 +modparam("sqlops","sqlcon","pcscf=>cluster://cluster1") +#!else +modparam("sqlops","sqlcon", SQLOPS_DBURL) +#!endif + +modparam("uac","restore_mode","none") + +# ----------------- Settings for RTimer --------------- +# time interval set to 10 seconds +modparam("rtimer", "timer", "name=NATPING;interval=15;mode=1;") +modparam("rtimer", "exec", "timer=NATPING;route=NATPING") +#!endif + +# ----- tm params ----- +# auto-discard branches from previous serial forking leg +#modparam("tm", "failure_reply_mode", 3) +# default retransmission timeout: 3 sec +modparam("tm", "fr_timer", 3000) +# default invite retransmission timeout after 1xx: 120sec +modparam("tm", "fr_inv_timer", 120000) +# Dont reply automatically with "100 Trying" +modparam("tm", "auto_inv_100", 0) + +# ----- rr params ----- +# add value to ;lr param to cope with most of the UAs +modparam("rr", "enable_full_lr", 1) +# do not append from tag to the RR (no need for this script) +modparam("rr", "append_fromtag", 1) +# add a Username to RR-Header +modparam("rr", "add_username", 1) +# Take User from a custom AVP +modparam("rr", "custom_user_avp", "$avp(RR_CUSTOM_USER_AVP)") + +#!ifdef WITH_XMLRPC +# ----- xmlrpc params ----- +modparam("xmlrpc", "route", "XMLRPC"); +modparam("xmlrpc", "url_match", "^/RPC") +#!endif + +#!ifdef WITH_TLS +# ----- tls params ----- +modparam("tls", "config", "/etc/kamailio_pcscf/tls.cfg") +#!endif + +# ----- rtpproxy params ----- +modparam("rtpengine", "setid_default", 1) +modparam("rtpengine", "rtpengine_sock", "1 == udp:RTPENGINE_IP:2223") +#modparam("rtpengine", "rtpengine_sock", "2 == udp:localhost:2224") +modparam("rtpengine", "setid_avp", "$avp(setid)") +modparam("rtpengine", "extra_id_pv", "$avp(extra_id)") + +modparam("path", "use_received", 1) + +# ----- ctl params ----- +modparam("ctl", "binrpc", "unix:/var/run/kamailio_pcscf/kamailio_ctl") + +# ----------------- Settings for Dispatcher --------------- +modparam("dispatcher", "list_file", "/etc/kamailio_pcscf/dispatcher.list") + +# Dispatcher: Enable Failover-Support +modparam("dispatcher", "flags", 2) +# Dispatcher: Overwrite Destination address, if required. +modparam("dispatcher", "force_dst", 1) +# AVP's required for Fail-Over-Support: +#modparam("dispatcher", "dst_avp", "$avp(DISPATCHER_DST_AVP)") +#modparam("dispatcher", "grp_avp", "$avp(DISPATCHER_GRP_AVP)") +#modparam("dispatcher", "cnt_avp", "$avp(DISPATCHER_CNT_AVP)") +#modparam("dispatcher", "sock_avp", "$avp(DISPATCHER_SOCK_AVP)") + +#modparam("dispatcher", "xavp_dst", "$avp(DISPATCHER_DST_AVP)") +#modparam("dispatcher", "xavp_dst_mode", 0) +#modparam("dispatcher", "xavp_ctx", "$avp(DISPATCHER_CNT_AVP)") +#modparam("dispatcher", "xavp_ctx_mode", 0) + +# Try to recover disabled destinations every 15 seconds. +modparam("dispatcher", "ds_ping_interval", 15) +# Actively query the gateways: +modparam("dispatcher", "ds_probing_mode", 1) + +# -- usrloc params -- +#!ifdef DB_URL +#!ifdef DB_URL2 +modparam("ims_usrloc_pcscf", "db_url", "cluster://cluster1") +#!else +modparam("ims_usrloc_pcscf", "db_url", DB_URL) +#!endif +modparam("ims_usrloc_pcscf", "db_mode", 0) +#!endif +#modparam("ims_usrloc_pcscf", "hashing_type", 2) +modparam("ims_usrloc_pcscf", "enable_debug_file", 0) +modparam("ims_usrloc_pcscf", "match_contact_host_port", 1) +modparam("ims_registrar_pcscf", "is_registered_fallback2ip", 1) +modparam("ims_registrar_pcscf", "ignore_reg_state", 1) +modparam("ims_registrar_pcscf", "ignore_contact_rxport_check", 1) + +#!ifdef WITH_REGINFO +modparam("ims_registrar_pcscf", "subscribe_to_reginfo", 1) +modparam("ims_registrar_pcscf", "publish_reginfo", 1) +modparam("ims_registrar_pcscf", "pcscf_uri", PCSCF_URL) +#!else +modparam("ims_registrar_pcscf", "subscribe_to_reginfo", 0) +modparam("ims_registrar_pcscf", "publish_reginfo", 0) +#!endif + +#!ifdef WITH_IPSEC +modparam("ims_ipsec_pcscf", "ipsec_listen_addr", IPSEC_LISTEN_ADDR) +modparam("ims_ipsec_pcscf", "ipsec_client_port", IPSEC_CLIENT_PORT) +modparam("ims_ipsec_pcscf", "ipsec_server_port", IPSEC_SERVER_PORT) +modparam("ims_ipsec_pcscf", "ipsec_max_connections", 10) +modparam("htable", "htable", "ipsec_clients=>size=8;autoexpire=600000;") +#!endif + +#!ifdef WITH_RX +# -- CDP params -- +modparam("cdp","config_file","/etc/kamailio_pcscf/pcscf.xml") +# -- diameter_rx params -- +modparam("ims_qos", "rx_dest_realm", "PCRF_REALM") +modparam("ims_qos", "af_signaling_ip", RX_AF_SIGNALING_IP) +modparam("ims_qos", "include_rtcp_fd", 1) +#!endif + +# -- pua params -- +#!ifdef WITH_REGINFO +#!ifdef DB_URL +#!ifdef DB_URL2 +modparam("pua", "db_url", "cluster://cluster1") +#!else +modparam("pua", "db_url", DB_URL) +#!endif +#!endif +#!endif + +# -- ims_dialog params -- +modparam("ims_dialog", "dlg_flag", FLT_DIALOG) +modparam("ims_dialog", "timeout_avp", "$avp(DLG_TIMEOUT_AVP)") +modparam("ims_dialog", "detect_spirals", 0) +modparam("ims_dialog", "profiles_no_value", "orig ; term") +#!ifdef DB_URL +#!ifdef DB_URL2 +modparam("ims_dialog", "db_url", "cluster://cluster1") +#!else +modparam("ims_dialog", "db_url", DB_URL) +#!endif +modparam("ims_dialog", "db_mode", 0) +#!endif + +#!ifdef CAPTURE_NODE +# Destination, where to send the traffic +modparam("siptrace", "duplicate_uri", CAPTURE_NODE) +# Trace all traffic +modparam("siptrace", "trace_on", 1) +modparam("siptrace", "trace_to_database", 0) +modparam("siptrace", "trace_flag", FLT_CAPTURE) +modparam("siptrace", "hep_mode_on", 1) +#!endif + +# -- statistics params -- +modparam("statistics", "variable", "register_success") +modparam("statistics", "variable", "register_failed") +modparam("statistics", "variable", "register_time") + + +####### Routing Logic ######## + +# Main SIP request routing logic +# - processing of any incoming SIP request starts with this route +route { +##!ifdef WITH_DEBUG + xlog("$rm ($fu ($si:$sp) to $tu, $ci)\n"); +##!endif + +#!ifdef WITH_WEBSOCKET + if (($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT) && !(proto == WS || proto == WSS)) { + xlog("L_WARN", "Websocket-request received on SIP/$Rp\n"); + sl_send_reply("403", "Forbidden - Websocket-request received on SIP/$Rp"); + exit; + } +#!endif + # per request initial checks + route(REQINIT); + + #Set DLG flag to track dialogs using dialog2 + if (!is_method("REGISTER|SUBSCRIBE")) + setflag(FLT_DIALOG); + + # CANCEL processing + if (is_method("CANCEL")) { + if (t_check_trans()) { + t_relay(); + } + exit; + } + + + if (is_method("NOTIFY") && (uri==myself)) { + route(NOTIFY); + exit; + } + + # handle requests within SIP dialogs + route(WITHINDLG); + + ### only initial requests (no To tag) + + # handle retransmissions + if (!is_method("ACK")) { + if(t_precheck_trans()) { + t_check_trans(); + exit; + } + t_check_trans(); + } + #t_check_trans(); + + # Check for Re-Transmissions + t_check_trans(); + + if (is_method("UPDATE")) { + send_reply("403","Forbidden - Target refresh outside dialog not allowed"); + break; + } + if (is_method("BYE|PRACK")) { + send_reply("403","Forbidden - Originating subsequent requests outside dialog not allowed"); + break; + } + + loose_route(); +#!ifdef WITH_SBC + if (ds_is_from_list(DISPATCHER_LIST_SBC)) { + if (is_method("INVITE")) { + if (is_present_hf("C-Params")) { + remove_hf("Contact"); + remove_hf("C-Params"); + append_hf("Contact: $ct;$hdr(C-Params)\r\n"); + } + if ($route_uri =~ "sip:mo@.*") { + # prepend mo as user for record route + $avp(RR_CUSTOM_USER_AVP)="mo"; + if (is_present_hf("P-Route")) { + $du = $(hdr(P-Route){nameaddr.uri}); + remove_hf("P-Route"); + append_hf("Route: $hdr(P-Route)\r\n"); + } + t_on_reply("SBC_GET_CPARAMS"); + } + if ($route_uri =~ "sip:mt@.*") { + $du = $ru; + handle_ruri_alias(); + if ($rc == 1) { + setflag(FLT_NAT); + } + xlog("$$dP => $(dP{s.tolower}) ($du)\n"); + # prepend mo as user for record route + $avp(RR_CUSTOM_USER_AVP)="mt"; + if ($(dP{s.tolower}) == "tls") { + route(ENC_SRTP); + } else if ($(dP{s.tolower}) == "ws") { + # Even WSS is incorrectly shown as WS + route(ENC_WSS_RTP); + } else if ($(dP{s.tolower}) == "wss") { + route(ENC_WSS_RTP); + } else { + route(ENC_RTP); + } + # Handle NAT + route(NATMANAGE); + # Handle Mobile Terminated requests + route(MT); + } + } + if (is_method("REGISTER")) { + append_hf("Path: \r\n"); + } + } else { +#!endif + if ($route_uri =~ "sip:term@.*") { +#!ifdef WITH_SBC +#!ifdef WITH_SBC_CALL + if (is_method("INVITE")) { +#!endif + if (!strempty($(ct{tobody.params}))) { + append_hf("C-Params: $(ct{tobody.params})\r\n"); + } + + append_hf("SBC: mt\r\n"); + # Do some Round-Robin on the SBC's + t_on_failure("SBC_failure"); + # Choose an SBC to send the call to: + if (!ds_select_dst(DISPATCHER_LIST_SBC, "4")) { + send_reply("503", "Service Unavailable (SBC failure)"); + exit; + } +#!ifdef WITH_SBC_CALL + } +#!endif +#!else + handle_ruri_alias(); + if ($dP == "tls") { + route(ENC_SRTP); + } else if ($dP == "ws") { + route(ENC_WS_RTP); + } else if ($dP == "wss") { + route(ENC_WSS_RTP); + } else { + route(ENC_RTP); + } + if ($rc == 1) { + setflag(FLT_NAT); + } + # Handle NAT + route(NATMANAGE); + # prepend mo as user for record route + $avp(RR_CUSTOM_USER_AVP)="mt"; + route(MT); +#!endif + } else { + force_rport(); + if(is_method("INVITE|SUBSCRIBE|UPDATE|REGISTER")) { + add_contact_alias(); + } + setflag(FLT_NAT); + + if (is_method("REGISTER")) { + route(REGISTER); + exit; + } + + # prepend mo as user for record route + $avp(RR_CUSTOM_USER_AVP)="mo"; + # Set Flag for MO: + setflag(FLT_MOBILE_ORIG); + # Increase timer for inbound requests, we may have to do failover: + t_set_fr(120000, 30000); + route(MO); + if (is_method("INVITE")) { + # SRTP in RTP übersetzen + if ($pr == "tls") { + route(DEC_SRTP); + } else if ($pr == "ws") { + route(DEC_WS_RTP); + } else if ($pr == "wss") { + route(DEC_WSS_RTP); + } else { + route(DEC_RTP); + } + # Handle NAT + route(NATMANAGE); + } +#!ifdef WITH_SBC +#!ifdef WITH_SBC_CALL + if (is_method("INVITE")) { +#!endif + # Apply changes to this message + msg_apply_changes(); + # Copy Route-Header: + append_hf("P-Route: $hdr(Route)\r\n"); + if (!strempty($(ct{tobody.params}))) { + append_hf("C-Params: $(ct{tobody.params})\r\n"); + } + append_hf("SBC: mo\r\n"); + # Do some Round-Robin on the SBC's + t_on_failure("SBC_failure"); + # Choose an SBC to send the call to: + if (!ds_select_dst(DISPATCHER_LIST_SBC, "4")) { + send_reply("503", "Service Unavailable (SBC failure)"); + exit; + } +#!endif +#!ifdef WITH_SBC_CALL + } +#!endif + } +#!ifdef WITH_SBC + } +#!endif + if (is_method("INVITE|SUBSCRIBE")) { + # record routing for dialog forming requests (in case they are routed) + record_route(); + } + + # Forward request: + route(RELAY); + exit; +} + +route[SBC_GET_CPARAMS] { + if (!strempty($(ct{tobody.params}))) { + append_hf("C-Params: $(ct{tobody.params})\r\n"); + } +} + +# Per SIP request initial checks +route[REQINIT] { + # Reply to OPTIONS: + if (is_method("OPTIONS") && (uri==myself)) { + options_reply(); + exit; + } + + $var(used) = 1 - ($stat(free_size) / $stat(total_size)); + xlog("L_DBG", "Mem: Total $stat(total_size), Free $stat(free_size) [$var(used)% used]\n"); + if ($var(used) > 95) { + send_reply("503", "Server overloaded"); + exit; + } + + # Trace this message +#!ifdef CAPTURE_NODE + sip_trace(); + setflag(FLT_CAPTURE); +#!endif + +#!ifdef WITH_ANTIFLOOD + # flood dection 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 (!has_totag() && (src_ip!=myself) && !ds_is_from_list()) + { + if($sht(ipban=>$si)!=$null) + { + # ip is already blocked + xlog("request from blocked IP - $rm from $fu (IP:$si:$sp)\n"); + xlog("Blocking traffic from $si\n"); + exit; + } + if (!pike_check_req()) { + xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp, $ua)\n"); + xlog("Blocking traffic from $si\n"); + $sht(ipban=>$si) = 1; + exit; + } + } + if ((uri == myself) && is_method("INVITE|REGISTER")) { + xlog("L_ALERT","ALERT: Request to myself: $ru from $fu (IP:$si:$sp, $ua), Blocking\n"); + xlog("Blocking traffic from $si\n"); + $sht(ipban=>$si) = 1; + exit; + } +#!endif + + if (!mf_process_maxfwd_header("10")) { + sl_send_reply("483","Too Many Hops"); + exit; + } + + if(!sanity_check("1511", "7")) { + xlog("Malformed SIP message from $si:$sp\n"); + exit; + } + + # Check for shutdown mode: + if (!has_totag() && ($sel(cfg_get.system.shutdownmode) > 0)) { + send_reply("503", "Server shutting down"); + exit; + } +#!ifdef WITH_IPSEC + if (!is_method("REGISTER")) { + ipsec_forward("location"); + } +#!endif + # Ignore Re-Transmits: + if (t_lookup_request()) { + exit; + } + + if (is_method("INVITE|REGISTER")) { + send_reply("100", "Trying"); + } +} + +route[RELAY] { + if (!t_relay()) { + sl_reply_error(); + } + exit; +} + +# Handle requests within SIP dialogs +route[WITHINDLG] { + if (has_totag()) { + xnotice("Within DLG"); + if (loose_route()) { + xnotice("Within loose route"); + if(!isdsturiset()) { + handle_ruri_alias(); + #if ($rc == 1) { + # $ru = "sip:" + $rU + "@" + $dd + ":" + $dp + ";transport=" + $rP; + #} + } + if ( is_method("ACK") && ($sht(contact=>$ci) != $null) ) { + xlog("Contact of Reply: $sht(contact=>$ci) ($ci)\n"); + $ru = $sht(contact=>$ci); + } + + # sequential request withing a dialog should + # take the path determined by record-routing + + if ($route_uri =~ "sip:mt@.*") { + route(MT_indialog); + } else { + route(MO_indialog); + } + + # Handle NAT + route(NATMANAGE); + + route(RELAY); + } else { + if ( is_method("ACK") ) { + xlog("Contact of Reply: $T_rpl($ct)\n"); + if ( t_check_trans() ) { + # no loose-route, but stateful ACK; + # must be an ACK after a 487 + # or e.g. 404 from upstream server + t_relay(); + exit; + } else { + # ACK without matching transaction ... ignore and discard + exit; + } + } + sl_send_reply("404","Not here"); + } + exit; + } +} + +###################################################################### +# Negative replies to REGISTER requests: +###################################################################### +failure_route[SBC_failure] { +#!ifdef WITH_IPBLOCK + if (is_method("REGISTER") && !ds_is_from_list()) { + if (t_check_status("403|[5-6][0-9][0-9]")) { + if ($sht(failedauth=>$si) != $null) + $sht(failedauth=>$si) = $sht(failedauth=>$si) + 1; + else + $sht(failedauth=>$si) = 1; + if ($sht(failedauth=>$si) > 10) { + xlog("L_ALERT","ALERT: blocking $rm from $fu (IP:$si:$sp), more than 5 failed auth requests!\n"); + xlog("Blocking traffic from $si\n"); + $sht(ipban=>$si) = 1; + } + } + } +#!endif + # Choose another gateway, in case we + # - get a local generated "408" + # - receive a 5xx or 6xx reply from the proxy. + if (t_branch_timeout() || t_check_status("[5-6]..")) { + if (ds_next_dst()) { + # Do Failover in case problems: + t_on_failure("SBC_failure"); + t_relay(); + } else { + # Add a header, to indicate the phone should try again in 30 seconds. + append_hf("Retry-After: 30\r\n"); + send_reply("504", "Server Time-Out"); + } + exit; + } +} + +# Notify Route: # +##################################################################### +route[NOTIFY] +{ + xlog("L_DBG", "IMS: INSIDE NOTIFY\n"); + if (reginfo_handle_notify("location")) { + send_reply("200","OK - P-CSCF processed notification"); + break; + } else { + t_reply("500","Error encountered while processing notification"); + break; + } +} + +#!ifdef WITH_NATPING +# NATPING Route: # +##################################################################### +route[NATPING] { + route(preload_pcscf); + + sht_lock("natping=>natpinglock"); + sht_iterator_start("nat_iterator", "natping"); + while(sht_iterator_next("nat_iterator")) { + xlog("OPTIONS to $shtitval(nat_iterator) via $shtitkey(nat_iterator)...\n"); + $uac_req(method) = "OPTIONS"; + $uac_req(ruri) = $shtitval(nat_iterator); + $uac_req(furi) = PCSCF_URL; + $uac_req(turi) = $shtitval(nat_iterator); + $uac_req(ouri) = $shtitkey(nat_iterator); + $uac_req(evroute) = 1; + uac_req_send(); + } + sht_iterator_end("nat_iterator"); + sht_unlock("natping=>natpinglock"); +} + +event_route[uac:reply] { +##!ifdef WITH_DEBUG + xlog("request sent to $uac_req(ruri) completed with code: $uac_req(evcode), Type $uac_req(evtype)\n"); +##!endif + if (($uac_req(evtype) != 1) || ($uac_req(evcode) != 200)) { + if ($sht(natpingfail=>$uac_req(ouri)) == $null) { + $sht(natpingfail=>$uac_req(ouri)) = 1; + } else { + $sht(natpingfail=>$uac_req(ouri)) = $sht(natpingfail=>$uac_req(ouri)) + 1; + } + xlog(" request sent to $uac_req(ruri): Fail Counter is $sht(natpingfail=>$uac_req(ouri))\n"); + if ($sht(natpingfail=>$uac_req(ouri)) > 5) { + if ($(uac_req(ouri){uri.transport}) == "tcp") { + $var(alias) = "alias="+$(uac_req(ouri){uri.host})+"~"+$(uac_req(ouri){uri.port})+"~2"; + } else if ($(uac_req(ouri){uri.transport}) == "tls") { + $var(alias) = "alias="+$(uac_req(ouri){uri.host})+"~"+$(uac_req(ouri){uri.port})+"~3"; + } else { + $var(alias) = "alias="+$(uac_req(ouri){uri.host})+"~"+$(uac_req(ouri){uri.port})+"~1"; + } + xlog(" Unregistering $uac_req(ruri);$var(alias)\n"); + setdebug("9"); +#!ifdef WITH_IPSEC + #if ($sht(ipsec_clients=>$(T_req($ct){nameaddr.uri})) != $null) { + #ipsec_destroy("location"); + ipsec_destroy_by_contact("location", "$uac_req(ruri);$var(alias)", "$(uac_req(ouri){uri.host})", "$(uac_req(ouri){uri.port})"); + #} +#!endif + pcscf_unregister("location", "$uac_req(ruri);$var(alias)", "$(uac_req(ouri){uri.host})", "$(uac_req(ouri){uri.port})"); + resetdebug(); + sht_lock("natping=>natpinglock"); + $sht(natping=>$uac_req(ouri)) = $null; + sht_unlock("natping=>natpinglock"); + $sht(natpingfail=>$uac_req(ouri)) = $null; + } + } else { + $sht(natpingfail=>$uac_req(ouri)) = $null; + } +} + +event_route[htable:expired:natping] { + xlog("natping record expired $shtrecord(key) => $shtrecord(value)\n"); +} + +event_route[htable:mod-init] { + xlog("event_route[htable:mod-init] \n"); +} + +route[preload_pcscf] { + if ($shv(preload_pcscf) == 1) return; + $shv(preload_pcscf) = 1; + + sql_query("pcscf", "select aor, received, received_port, received_proto from location;", "resultset"); + xlog("Preloading NAT-PING. Rows: $dbr(resultset=>rows)\n"); + if($dbr(resultset=>rows)>0) { + $var(i) = 0; + while($var(i) < $dbr(resultset=>rows)) { + $var(ouri) = "sip:"+$dbr(resultset=>[$var(i),1])+":"+$dbr(resultset=>[$var(i),2]); + if ($dbr(resultset=>[$var(i),3]) == 2) { + $var(ouri) = $var(ouri)+";transport=tcp"; + } else if ($dbr(resultset=>[$var(i),3]) == 3) { + $var(ouri) = $var(ouri)+";transport=tls"; + } + $var(noalias) = $(dbr(resultset=>[$var(i),0]){re.subst,/^(.*);alias=.*/\1/}{nameaddr.uri}); + # xlog("$$var(noalias) => $var(noalias) (via $var(ouri))\n"); + sht_lock("natping=>natpinglock"); + $sht(natping=>$var(ouri)) = $var(noalias); + sht_unlock("natping=>natpinglock"); + $var(i) = $var(i) + 1; + } + } + sql_result_free("resultset"); +} +#!endif + +#!ifdef WITH_XMLRPC +include_file "route/xmlrpc.cfg" +#!endif +#!ifdef WITH_WEBSOCKET +include_file "route/websocket.cfg" +#!endif +include_file "route/register.cfg" +include_file "route/rtp.cfg" +include_file "route/mo.cfg" +include_file "route/mt.cfg" diff --git a/pcscf/pcscf.cfg b/pcscf/pcscf.cfg new file mode 100644 index 0000000..0c97805 --- /dev/null +++ b/pcscf/pcscf.cfg @@ -0,0 +1,124 @@ +# IP-Adress for incoming SIP-Traffic, in the following format: + +# SIP / UDP +listen=udp:PCSCF_IP:5060 +#listen=udp:PCSCF_IP:5060 advertise PCSCF_PUB_IP:5060 +# SIP / TCP +listen=tcp:PCSCF_IP:5060 +#listen=tcp:PCSCF_IP:5060 advertise PCSCF_PUB_IP:5060 +# SIP / TCP/TLS +#listen=tls:PCSCF_IP:5061 + +# IPSEC / UDP +#!define IPSEC_LISTEN_ADDR "PCSCF_IP" +##!define IPSEC_LISTEN_ADDR "PCSCF_PUB_IP" +#!define IPSEC_CLIENT_PORT 5100 +#!define IPSEC_SERVER_PORT 6100 + +# IP used in Rx_AAR_Register - IP of this P-CSCF, to be used in the flow for the AF-signaling +#!define RX_AF_SIGNALING_IP "PCSCF_IP" +# Uncomment the below line only when UE is behind double NAT (e.g. VoIP calling over WiFi/ CN behind a NAT) +##!define RX_AF_SIGNALING_IP "PCSCF_PUB_IP" + +alias=pcscf.IMS_DOMAIN + +#!define MY_WS_PORT 80 +#!define MY_WSS_PORT 443 + +#!define PCSCF_URL "sip:pcscf.IMS_DOMAIN:5060" + +#!define TCP_PROCESSES 8 + +#!subst "/NETWORKNAME/IMS_DOMAIN/" +#!subst "/HOSTNAME/pcscf.IMS_DOMAIN/" +#!subst "/PCRF_REALM/EPC_DOMAIN/" + +# SIP-Address of capturing node, if not set, capturing is disabled. +##!define CAPTURE_NODE "sip:127.0.0.1:9060" + +# Allowed IPs for XML-RPC-Queries +##!define XMLRPC_WHITELIST_1 "127.0.0.1" +##!define XMLRPC_WHITELIST_2 "127.0.0.1" +##!define XMLRPC_WHITELIST_3 "127.0.0.1" + +# Databases: +#!define DB_URL "mysql://pcscf:heslo@MYSQL_IP/pcscf" +##!define DB_URL2 "con2=>mysql://pcscf:heslo@MYSQL_IP/pcscf" + +#!define SQLOPS_DBURL "pcscf=>mysql://pcscf:heslo@MYSQL_IP/pcscf" + +#! Optional: Server-URL for Websocket-Requests +##!define WEBSOCKET_WEBSERVER "phone.ng-voice.com" + +##!define TRF_FUNCTION "trf.IMS_DOMAIN" + +# +# Several features can be enabled using '#!define WITH_FEATURE' directives: +# +# *** To run in debug mode: +# - define WITH_DEBUG +# +# *** To enable nat traversal execute: +# - define WITH_NAT +# - define the connection to the RTP-Proxy: RTPPROXY_ADDRESS +# +# *** To force alls calls through the RTP-Proxy +# - this will automagically enable NAT-Traversal +# - define FORCE_RTPRELAY +# +# *** To enable IPv4/IPv6 Translation (RTPProxy) +# - this will automagically enable NAT-Traversal +# - define WITH_RTPIPV4 +# +# *** To enable TCP support execute: +# - define WITH_TCP +# +# *** To enable TLS support execute: +# - adjust CFGDIR/tls.cfg as needed +# - define WITH_TLS +# - this will automagically enable TCP +# +# *** To enable XMLRPC support execute: +# - define WITH_XMLRPC +# - this will automagically enable TCP +# +# *** To enable anti-flood detection execute: +# - adjust pike and htable=>ipban settings as needed (default is +# block if more than 16 requests in 2 seconds and ban for 300 seconds) +# - define WITH_ANTIFLOOD +# +# *** To enable the Rx-Interface: +# - Configure Rx-Diameter-Interface in pcscf.xml +# - define WITH_RX +# +# *** To enable a Homer SIP-Capter-Node: +# - define CAPTURE_NODE with a proper address +# +# *** To enable support for the SEMS-SBC +# - define WITH_SBC +# - configure dispatcher-list with a set of SBC's + +# +# Enabled Features for this host: +##!define WITH_DEBUG +#!define WITH_NAT +#!define WITH_NATPING +#!define FORCE_RTPRELAY +##!define WITH_TLS +##!define WITH_XMLRPC +##!define WITH_IPBLOCK +##!define WITH_ANTIFLOOD +#!define WITH_RX +#!define WITH_RX_REG +#!define WITH_RX_CALL +#!define WITH_TCP +##!define WITH_RTPIPV4 +##!define WITH_SBC +##!define WITH_SBC_CALL +##!define WITH_REGINFO +##!define WITH_RTPPING +##!define WITH_WEBSOCKET +#!define WITH_IPSEC +#!define WITH_IMS_HDR_CACHE +#!define WITH_PING_UDP +#!define WITH_PING_TCP diff --git a/pcscf/pcscf.xml b/pcscf/pcscf.xml new file mode 100644 index 0000000..6179e2f --- /dev/null +++ b/pcscf/pcscf.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/pcscf/pcscf_init.sh b/pcscf/pcscf_init.sh new file mode 100755 index 0000000..4074a70 --- /dev/null +++ b/pcscf/pcscf_init.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# BSD 2-Clause License + +# Copyright (c) 2020, Supreeth Herle +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +sh -c "echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind" +sh -c "echo 1 > /proc/sys/net/ipv6/ip_nonlocal_bind" + +mkdir /etc/kamailio_pcscf +cp /mnt/pcscf/pcscf.cfg /etc/kamailio_pcscf +cp /mnt/pcscf/pcscf.xml /etc/kamailio_pcscf +cp /mnt/pcscf/kamailio_pcscf.cfg /etc/kamailio_pcscf +cp -r /mnt/pcscf/route /etc/kamailio_pcscf +cp -r /mnt/pcscf/sems /etc/kamailio_pcscf +cp /mnt/pcscf/tls.cfg /etc/kamailio_pcscf +cp /mnt/pcscf/dispatcher.list /etc/kamailio_pcscf + +while ! mysqladmin ping -h ${MYSQL_IP} --silent; do + sleep 5; +done + +# Sleep until permissions are set +sleep 5; + +# Create PCSCF database, populate tables and grant privileges +if [[ -z "`mysql -u root -h ${MYSQL_IP} -qfsBe "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='pcscf'" 2>&1`" ]]; +then + mysql -u root -h ${MYSQL_IP} -e "create database pcscf;" + mysql -u root -h ${MYSQL_IP} pcscf < /usr/local/src/kamailio/utils/kamctl/mysql/standard-create.sql + mysql -u root -h ${MYSQL_IP} pcscf < /usr/local/src/kamailio/utils/kamctl/mysql/presence-create.sql + mysql -u root -h ${MYSQL_IP} pcscf < /usr/local/src/kamailio/utils/kamctl/mysql/ims_usrloc_pcscf-create.sql + mysql -u root -h ${MYSQL_IP} pcscf < /usr/local/src/kamailio/utils/kamctl/mysql/ims_dialog-create.sql + mysql -u root -h ${MYSQL_IP} -e "grant delete,insert,select,update on pcscf.* to pcscf@$PCSCF_IP identified by 'heslo';" + mysql -u root -h ${MYSQL_IP} -e "GRANT ALL PRIVILEGES ON pcscf.* TO 'pcscf'@'%' identified by 'heslo';" + mysql -u root -h ${MYSQL_IP} -e "FLUSH PRIVILEGES;" +fi + +# if [ ! -z "$PCSCF_PUB_IP" ] +# then +# sed -i 's|#!define IPSEC_LISTEN_ADDR "PCSCF_IP"|##!define IPSEC_LISTEN_ADDR "PCSCF_IP"|g' /etc/kamailio_pcscf/pcscf.cfg +# sed -i 's|##!define IPSEC_LISTEN_ADDR "PCSCF_PUB_IP"|#!define IPSEC_LISTEN_ADDR "PCSCF_PUB_IP"|g' /etc/kamailio_pcscf/pcscf.cfg +# sed -i 's|listen=udp:PCSCF_IP:5060|#listen=udp:PCSCF_IP:5060|g' /etc/kamailio_pcscf/pcscf.cfg +# sed -i 's|#listen=udp:PCSCF_IP:5060 advertise PCSCF_PUB_IP:5060|listen=udp:PCSCF_IP:5060 advertise PCSCF_PUB_IP:5060|g' /etc/kamailio_pcscf/pcscf.cfg +# sed -i 's|#!define RX_AF_SIGNALING_IP "PCSCF_IP"|##!define RX_AF_SIGNALING_IP "PCSCF_IP"|g' /etc/kamailio_pcscf/pcscf.cfg +# sed -i 's|##!define RX_AF_SIGNALING_IP "PCSCF_PUB_IP"|#!define RX_AF_SIGNALING_IP "PCSCF_PUB_IP"|g' /etc/kamailio_pcscf/pcscf.cfg +# fi + +sed -i 's|PCSCF_IP|'$PCSCF_IP'|g' /etc/kamailio_pcscf/pcscf.cfg +sed -i 's|PCSCF_PUB_IP|'$PCSCF_PUB_IP'|g' /etc/kamailio_pcscf/pcscf.cfg +sed -i 's|IMS_DOMAIN|'$IMS_DOMAIN'|g' /etc/kamailio_pcscf/pcscf.cfg +sed -i 's|EPC_DOMAIN|'$EPC_DOMAIN'|g' /etc/kamailio_pcscf/pcscf.cfg +sed -i 's|MYSQL_IP|'$MYSQL_IP'|g' /etc/kamailio_pcscf/pcscf.cfg + +sed -i 's|PCSCF_IP|'$PCSCF_IP'|g' /etc/kamailio_pcscf/pcscf.xml +sed -i 's|IMS_DOMAIN|'$IMS_DOMAIN'|g' /etc/kamailio_pcscf/pcscf.xml +sed -i 's|EPC_DOMAIN|'$EPC_DOMAIN'|g' /etc/kamailio_pcscf/pcscf.xml + +sed -i 's|RTPENGINE_IP|'$RTPENGINE_IP'|g' /etc/kamailio_pcscf/kamailio_pcscf.cfg diff --git a/pcscf/route/mo.cfg b/pcscf/route/mo.cfg new file mode 100644 index 0000000..1df235d --- /dev/null +++ b/pcscf/route/mo.cfg @@ -0,0 +1,214 @@ +###################################################################### +# Originating, Intial Requests +###################################################################### +route[MO] +{ + # Strip Transport from RURI: + $ru = $(ru{re.subst,/;transport=[A-Za-z]*//g}); + xnotice("PCSCF MO: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + + # Process route headers, if any: + loose_route(); + if (!pcscf_is_registered("location")) { + send_reply("403","Forbidden - You must register first with a S-CSCF"); + exit; + } + + # We do not trust the user, let's remove the P-Asserted-Identity, if any: + remove_hf("P-Asserted-Identity"); + remove_hf("P-Preferred-Identity"); + + # Add P-Charging-Vector + sip_p_charging_vector("g"); + + if (is_present_hf("P-Preferred-Identity") && pcscf_assert_identity("location", "$hdr(P-Preferred-Identity)")) { + append_hf("P-Asserted-Identity: $hdr(P-Preferred-Identity)\r\n"); + } else if (is_present_hf("P-Asserted-Identity") && pcscf_assert_identity("location", "$hdr(P-Asserted-Identity)")) { + append_hf("P-Asserted-Identity: $hdr(P-Asserted-Identity)\r\n"); + } else if (pcscf_assert_identity("location", "$(fu{tobody.uri})")) { + append_hf("P-Asserted-Identity: <$(fu{tobody.uri})>\r\n"); + } else { + append_hf("P-Asserted-Identity: <$pcscf_asserted_identity>\r\n"); + } + + if (!pcscf_follows_service_routes("location")){ + #Variant 1 - deny access to the network + #send_reply("400","Bad Request - Not following indicated service routes"); + #break; + + #Variant 2 - enforce routes and let the dialog continue + pcscf_force_service_routes("location"); + } + + # add IBCF/THIG route here if required + # Check for "sec-agree" in the Require header: + if (is_present_hf("Require") && $hdr(Require) =~ ".*sec-agree.*") { + # Remove the old Require-Header: + remove_hf("Require"); + # Replace ", sec-agree" with "" + $var(new_hdr) = $(hdr(Require){re.subst,/[, ]*sec-agree//gi}); + if ($(var(new_hdr){s.len}) > 0) { + append_hf("Require: $var(new_hdr)\r\n"); + } + } + + # Check for "sec-agree" in the Proxy-Require header: + if (is_present_hf("Proxy-Require") && $hdr(Proxy-Require) =~ ".*sec-agree.*") { + # Remove the old Proxy-Require-Header: + remove_hf("Proxy-Require"); + # Replace ", sec-agree" with "" + $var(new_hdr) = $(hdr(Proxy-Require){re.subst,/[, ]*sec-agree//gi}); + if ($(var(new_hdr){s.len}) > 0) { + append_hf("Proxy-Require: $var(new_hdr)\r\n"); + } + } + remove_hf("Security-Verify"); + +#!ifdef TRF_FUNCTION + $var(trf) = TRF_FUNCTION; + # Check for "sec-agree" in the Proxy-Require header: + if (is_present_hf("Feature-Caps")) { + # Remove the old Proxy-Require-Header: + remove_hf("Feature-Caps"); + append_hf("Feature-Caps: $hdr(Feature-Caps);+g.3gpp.trf=\"\"\r\n"); + } else { + append_hf("Feature-Caps: *;+g.3gpp.trf=\"\"\r\n"); + } +#!endif + # Add a visited Network-ID-Header: + if (is_present_hf("P-Visited-Network-ID")) { + $var(new_hdr) = "NETWORKNAME, "+$hdr(P-Visited-Network-ID); + append_hf("P-Visited-Network-ID: $var(new_hdr)\r\n"); + } else { + append_hf("P-Visited-Network-ID: NETWORKNAME\r\n"); + } + set_dlg_profile("orig"); + t_on_reply("MO_reply"); +} + +###################################################################### +# Replies to Originating Initial Requests +###################################################################### +onreply_route[MO_reply] { + xnotice("PCSCF MO_reply: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + if (is_present_hf("C-Params")) { + remove_hf("Contact"); + remove_hf("C-Params"); + append_hf("Contact: $ct;$hdr(C-Params)\r\n"); + } +##!ifdef WITH_IPSEC + #if ($sht(ipsec_clients=>$(T_req($ct){nameaddr.uri})) != $null) { + #ipsec_forward("location"); + #} +##!endif + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); +#!ifdef WITH_RX + if (t_check_status("183|200") && has_body("application/sdp")){ + xlog("L_DBG", "IMS: Received 183/200 inside orig_initial_reply\n"); + + if (t_is_retr_async_reply()) { + xlog("L_DBG", "Dropping retransmitted reply which is still currently suspended\n"); + drop(); + } + + xlog("L_DBG","Diameter: Orig authorizing media via Rx\n"); + $avp(FTAG_CUSTOM_AVP)=$ft; + $avp(TTAG_CUSTOM_AVP)=$tt; + $avp(CALLID_CUSTOM_AVP)=$ci; + + if (Rx_AAR("MO_aar_reply","orig","",-1) == 0) { + exit; + } + } +} + +route[MO_aar_reply] +{ + #this is async so to know status we have to check the reply avp + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n"); + break; + default: + xlog("L_ERR", "IMS: AAR failed Orig\n"); + xlog("L_ERR", "IMS: ttag: "+ "$avp(TTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: ftag: "+ "$avp(FTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: callid: "+ "$avp(CALLID_CUSTOM_AVP)"); + #comment this if you want to allow even if Rx fails + if(dlg_get("$avp(CALLID_CUSTOM_AVP)","$avp(FTAG_CUSTOM_AVP)","$avp(TTAG_CUSTOM_AVP)")){ + dlg_terminate("all", "Sorry no QoS available"); + exit; + } + } +#!endif +} + + +###################################################################### +# In-Dialog-Mo-Requests +###################################################################### +route[MO_indialog] { + xnotice("PCSCF MO_indialog: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + setflag(FLT_MOBILE_ORIG); + t_on_reply("MO_indialog_reply"); +} + +onreply_route[MO_indialog_reply] { + xnotice("PCSCF MO_indialog_reply: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); + +#!ifdef WITH_RX + if(t_check_status("200") && is_method("INVITE")) { + if (t_is_retr_async_reply()) { + xlog("L_DBG", "Dropping retransmitted reply which is still currently suspended\n"); + drop(); + } + + xlog("L_DBG", "IMS: ORIG_SUBSEQUENT reply. This is a 200 OK to a re-INVITE\n"); + xlog("L_DBG","Diameter: Orig authorizing media via Rx\n"); + $avp(FTAG_CUSTOM_AVP)=$ft; + $avp(TTAG_CUSTOM_AVP)=$tt; + $avp(CALLID_CUSTOM_AVP)=$ci; + + if (Rx_AAR("MO_indialog_aar_reply","orig","",-1) == 0) { + exit; + } + } +} + +route[MO_indialog_aar_reply] +{ + #this is async so to know status we have to check the reply avp + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n"); + break; + default: + xlog("L_ERR", "IMS: AAR failed Orig\n"); + xlog("L_ERR", "IMS: ttag: "+ "$avp(TTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: ftag: "+ "$avp(FTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: callid: "+ "$avp(CALLID_CUSTOM_AVP)"); + #comment this if you want to allow even if Rx fails + if(dlg_get("$avp(CALLID_CUSTOM_AVP)","$avp(FTAG_CUSTOM_AVP)","$avp(TTAG_CUSTOM_AVP)")){ + dlg_terminate("all", "Sorry no QoS available"); + exit; + } + } +#!endif +} diff --git a/pcscf/route/mt.cfg b/pcscf/route/mt.cfg new file mode 100644 index 0000000..5f435fc --- /dev/null +++ b/pcscf/route/mt.cfg @@ -0,0 +1,139 @@ +###################################################################### +# Terminating, Initial requests +###################################################################### +route[MT] { + xnotice("PCSCF MT: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + set_dlg_profile("term"); +#!ifdef WITH_IPSEC + ipsec_forward("location"); +#!endif + t_on_reply("MT_reply"); +} + +###################################################################### +# Replies to Originating Initial Requests +###################################################################### +onreply_route[MT_reply] { + xnotice("PCSCF MT_reply: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + if (!strempty($(ct{tobody.params}))) { + append_hf("C-Params: $(ct{tobody.params})\r\n"); + } + + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); +#!ifdef WITH_RX + if (t_check_status("183|200") && has_body("application/sdp")){ + xnotice("PCSCF MT_reply: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + xlog("L_DBG", "IMS: Received 183 inside term_initial_reply\n"); + + xlog("L_DBG", "About to test if this is a retransmitted reply which is still currently suspended\n"); + if (t_is_retr_async_reply()) { + xlog("L_DBG", "Dropping retransmitted reply which is still currently suspended\n"); + drop(); + } + + xlog("L_DBG","Diameter: Term authorizing media via Rx\n"); + $avp(FTAG_CUSTOM_AVP)=$ft; + $avp(TTAG_CUSTOM_AVP)=$tt; + $avp(CALLID_CUSTOM_AVP)=$ci; + + if (Rx_AAR("MT_aar_reply","term","",-1) == 0) { + exit; + } + } +} + +route[MT_aar_reply] +{ + xlog("L_DBG", "IMS: TERM_SESSION_AAR_REPLY\n"); + + #this is async so to know status we have to check the reply avp + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n"); + break; + default: + xlog("L_ERR", "IMS: AAR failed Orig\n"); + xlog("L_ERR", "IMS: ttag: "+ "$avp(TTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: ftag: "+ "$avp(FTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: callid: "+ "$avp(CALLID_CUSTOM_AVP)"); + #comment this if you want to allow even if Rx fails + if(dlg_get("$avp(CALLID_CUSTOM_AVP)","$avp(FTAG_CUSTOM_AVP)","$avp(TTAG_CUSTOM_AVP)")){ + dlg_terminate("all", "Sorry no QoS available"); + exit; + } + } +#!endif +} + + +###################################################################### +# In-Dialog-MT-Requests +###################################################################### +route[MT_indialog] { + xnotice("PCSCF MT_indialog: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + #resetflag(FLT_MOBILE_ORIG); + t_on_reply("MT_indialog_reply"); +} + +onreply_route[MT_indialog_reply] { + xnotice("PCSCF MT_indialog_reply: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); + +#!ifdef WITH_RX + if(t_check_status("200") && is_method("INVITE")) { + if (t_is_retr_async_reply()) { + xlog("L_DBG", "Dropping retransmitted reply which is still currently suspended\n"); + drop(); + } + + xlog("L_DBG", "IMS: TERM_SUBSEQUENT reply. This is a 200 OK to a re-INVITE\n"); + xlog("L_DBG","Diameter: Term authorizing media via Rx\n"); + $avp(FTAG_CUSTOM_AVP)=$ft; + $avp(TTAG_CUSTOM_AVP)=$tt; + $avp(CALLID_CUSTOM_AVP)=$ci; + + if (Rx_AAR("MT_indialog_aar_reply","term","",-1) == 0) { + exit; + } + } +} + +route[MT_indialog_aar_reply] +{ + #this is async so to know status we have to check the reply avp + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n"); + break; + default: + xlog("L_ERR", "IMS: AAR failed Orig\n"); + xlog("L_ERR", "IMS: ttag: "+ "$avp(TTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: ftag: "+ "$avp(FTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: callid: "+ "$avp(CALLID_CUSTOM_AVP)"); + #comment this if you want to allow even if Rx fails + if(dlg_get("$avp(CALLID_CUSTOM_AVP)","$avp(FTAG_CUSTOM_AVP)","$avp(TTAG_CUSTOM_AVP)")){ + dlg_terminate("all", "Sorry no QoS available"); + exit; + } + } +#!endif +} diff --git a/pcscf/route/register.cfg b/pcscf/route/register.cfg new file mode 100644 index 0000000..0252252 --- /dev/null +++ b/pcscf/route/register.cfg @@ -0,0 +1,225 @@ +###################################################################### +# Route for handling Registrations: +###################################################################### +route[REGISTER] { + # Provide some statistics + if ($sht(a=>$ci::start_time) == $null || $sht(a=>$ci::start_time) == 0) { + $sht(a=>$ci::start_time) = $TV(Sn); + } + xnotice("PCSCF REGISTER: \n Destination URI: $du\n Request URI: $ru\n"); + xnotice("Source IP and Port: ($si:$sp)\n Route-URI: $route_uri\n"); + xnotice("Received IP and Port: ($Ri:$Rp)\n"); + xnotice("Contact header: $ct\n"); + + # Strip Transport from RURI: + $ru = $(ru{re.subst,/;transport=[A-Za-z]*//g}); + + if (is_present_hf("Contact")) { + pcscf_save_pending("location"); + } else { + send_reply("403", "No contact header"); + exit; + } + + $sht(ipsec_clients=>$(ct{nameaddr.uri})) = $null; + if ($hdr(Security-Client) =~ ".*ipsec-3gpp.*") { + $sht(ipsec_clients=>$(ct{nameaddr.uri})) = 1; + } + + # Strip additional Tags from RURI: + if ($rU == $null) + $ru = "sip:"+$rd; + else + $ru = "sip:"+$rU+"@"+$rd; + +#!ifdef WITH_RX + xlog("L_DBG","Subscribing to signalling bearer status\n"); + + Rx_AAR_Register("REG_AAR_REPLY", "location"); + switch ($retcode) { + case -1: + # There was an error sending the AAR-Request: + xlog("L_ERR", "Diameter: AAR failed on subscription to signalling\n"); + send_reply("403", "Can't register to QoS for signalling"); + exit; + break; + case 0: + # We are waiting for an async reply, just exit here. + exit; + break; + case 1: + # We did not need to send AAR, so just continue as normal + route(REGISTER_CONTINUE); + break; + } + exit; +} + +route[REG_AAR_REPLY] { + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: AAR success on subscription to signalling\n"); + break; + default: + xlog("L_ERR", "Diameter: AAR failed on subscription to signalling\n"); + send_reply("403", "Can't register to QoS for signalling"); + exit; + } + # Proceed with Registering: + route(REGISTER_CONTINUE); +} + +route[REGISTER_CONTINUE] { +#!endif + append_hf("Path: \r\n"); + + remove_hf("Supported"); + append_hf("Supported: path\r\n"); + remove_hf("Require"); + append_hf("Require: path\r\n"); + + # Add a visited Network-ID-Header: + if (is_present_hf("P-Visited-Network-ID")) { + $var(new_hdr) = "NETWORKNAME, "+$hdr(P-Visited-Network-ID); + append_hf("P-Visited-Network-ID: $var(new_hdr)\r\n"); + } else { + append_hf("P-Visited-Network-ID: NETWORKNAME\r\n"); + } +#!ifdef WITH_SBC +#!ifndef WITH_SBC_CALL + t_on_failure("SBC_failure"); + # Choose an SBC to send the call to: + if (!ds_select_dst(DISPATCHER_LIST_SBC, "4")) { + send_reply("503", "Service Unavailable (SBC failure)"); + exit; + } +#!else + t_on_failure("REGISTER_failure"); +#!endif +#!else + t_on_failure("REGISTER_failure"); +#!endif + t_on_reply("REGISTER_reply"); + # Forward request: + route(RELAY); + exit; +} + +# Replies for REGISTER requests: +###################################################################### +onreply_route[REGISTER_reply] +{ +#!ifdef WITH_IMS_HDR_CACHE + if (is_present_hf("Service-Route")) { + $sht(serviceroutes=>$ci) = $hdr(Service-Route); + } else { + if ($sht(serviceroutes=>$ci) != $null) { + append_hf("Service-Route: $sht(serviceroutes=>$ci)\r\n"); + msg_apply_changes(); + } + } + if (is_present_hf("P-Associated-URI")) { + $sht(associateduris=>$ci) = $hdr(P-Associated-URI); + } else { + if ($sht(associateduris=>$ci) != $null) { + append_hf("P-Associated-URI: $sht(associateduris=>$ci)\r\n"); + msg_apply_changes(); + } + } +#!endif + + if (t_check_status("200")) { +#!ifdef WITH_IPBLOCK + $sht(failedauth=>$T_req($si)) = $null; +#!endif + pcscf_save("location"); +#!ifdef WITH_NATPING +#!ifdef WITH_PING_UDP + #if ($T_req($pr) == "udp") { + if ($pr == "udp") { + sht_lock("natping=>natpinglock"); + $var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp); + $sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri}); + sht_unlock("natping=>natpinglock"); + } +#!endif +#!ifdef WITH_PING_TCP + #if ($T_req($pr) == "tcp") { + if ($pr == "tcp") { + sht_lock("natping=>natpinglock"); + $var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp)+";transport=tcp"; + $sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri}); + sht_unlock("natping=>natpinglock"); + } +#!endif +#!ifdef WITH_PING_TLS + #if ($T_req($pr) == "tls") { + if ($pr == "tls") { + sht_lock("natping=>natpinglock"); + $var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp)+";transport=tls"; + $sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri}); + sht_unlock("natping=>natpinglock"); + } +#!endif +#!endif + #update stats for register reply on success + $var(start_secs) = $(sht(a=>$ci::start_time){s.select,0,.}); + $var(start_usecs) = $(sht(a=>$ci::start_time){s.select,1,.}); + $var(diff_secs) = $TV(s) - $var(start_secs); + $var(diff_usecs) = $TV(u) - $var(start_usecs); + $var(diff_ms) = $var(diff_secs)*1000 + ($var(diff_usecs)/1000); + $sht(a=>$ci::start_time)=0; + $var(stat_add) = "+" + $var(diff_ms); + xlog("L_DBG", "REGISTER SUCCESS[$ci] took $var(stat_add)ms\n"); + update_stat("register_success", "+1"); + update_stat("register_time", "$var(stat_add)"); +#!ifdef WITH_IPSEC + #if ($sht(ipsec_clients=>$(T_req($ct){nameaddr.uri})) != $null) { + ipsec_forward("location"); + #} + } + else { + if (t_check_status("401")) { + ipsec_create("location"); + if ($sht(ipsec_clients=>$(T_req($ct){nameaddr.uri})) != $null) { + $var(sec_client) = $(T_req($hdr(Security-Client))); + xnotice("Security-Client=$var(sec_client)\n"); + $var(sc_port_c) = $(var(sec_client){re.subst,/.*port-c=([0-9]*).*$/\1/s}); + xnotice("port-c=$var(sc_port_c)\n"); + $var(sc_port_s) = $(var(sec_client){re.subst,/.*port-s=([0-9]*).*$/\1/s}); + xnotice("port-s=$var(sc_port_s)\n"); + } + xnotice("Expires=$(T_req($expires(min)))\n"); + } + #if (t_check_status("403")) { + # ipsec_destroy("location"); + #} +#!endif + } + exit; +} + +# Negative replies to REGISTER requests: +###################################################################### +failure_route[REGISTER_failure] +{ +#!ifdef WITH_IPBLOCK + if (t_check_status("403|[5-6][0-9][0-9]")) { + if ($sht(failedauth=>$si) != $null) + $sht(failedauth=>$si) = $sht(failedauth=>$si) + 1; + else + $sht(failedauth=>$si) = 1; + if ($sht(failedauth=>$si) > 10) { + xlog("L_ALERT","ALERT: blocking $rm from $fu (IP:$si:$sp), more than 5 failed auth requests!\n"); + xlog("Blocking traffic from $si\n"); + $sht(ipban=>$si) = 1; + } + update_stat("register_failed", "+1"); + } +#!endif + if (t_check_status("408")) { + send_reply("504","Server Time-Out"); + update_stat("register_failed", "+1"); + exit; + } +} diff --git a/pcscf/route/rtp.cfg b/pcscf/route/rtp.cfg new file mode 100644 index 0000000..b202032 --- /dev/null +++ b/pcscf/route/rtp.cfg @@ -0,0 +1,196 @@ +# RTPProxy control +route[ENC_SRTP] { + add_rr_param(";rm=1"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=force SRTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; +} + +route[DEC_SRTP] { + add_rr_param(";rm=2"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=force SRTP AVP"; +} + +route[ENC_WS_RTP] { + add_rr_param(";rm=3"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=force RTP AVPF"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; +} + +route[DEC_WS_RTP] { + add_rr_param(";rm=4"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=force RTP AVPF"; +} + +route[ENC_WSS_RTP] { + add_rr_param(";rm=5"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=force SRTP AVPF DTLS=passive"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; +} + +route[DEC_WSS_RTP] { + add_rr_param(";rm=6"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=force SRTP AVPF DTLS=passive"; +} + +route[ENC_RTP] { + add_rr_param(";rm=7"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=force RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; +} + +route[DEC_RTP] { + add_rr_param(";rm=8"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=force RTP AVP"; +} + +# RTPProxy control +route[NATMANAGE] { +#!ifdef WITH_DEBUG + if (is_request()) + xlog("REQUEST: $rm $ru ($si:$sp, $ci)\n"); + else + xlog("REPLY: $rs $rr ($rm, $si:$sp, $ci)\n"); + + if (is_direction("downstream")) + xlog(" downstream\n"); + else + xlog(" upstream\n"); + + xlog(" Offer: $avp(rtpproxy_offer_flags)\n"); + xlog(" Answer: $avp(rtpproxy_answer_flags)\n"); + if (isflagset(FLT_MOBILE_ORIG)) { + xlog(" mo\n"); + } else { + xlog(" mt\n"); + } +#!endif + if ((is_reply() && ($T_req($tt) != $null)) || (is_request() && has_totag())) { + xlog("L_DBG", "Request had ToTag."); + #if((is_request() && !check_route_param("rm=")) || (is_reply() && !isflagset(FLT_RTP))) { + if(!check_route_param("rm=") && !isflagset(FLT_RTP)) { + xlog("L_DBG", "No RM Param\n"); + return; + } + if (is_request()) { + if (isflagset(FLT_MOBILE_ORIG) && is_direction("downstream")) { + xlog("L_DBG", "1) add_contact_alias();"); + add_contact_alias(); + } else if (!isflagset(FLT_MOBILE_ORIG) && is_direction("upstream")) { + xlog("L_DBG", "2) add_contact_alias();"); + add_contact_alias(); + } + } else { + if (!isflagset(FLT_MOBILE_ORIG) && is_direction("downstream")) { + xlog("L_DBG", "1) ADD_contact_alias();"); + add_contact_alias(); + } else if (isflagset(FLT_MOBILE_ORIG) && is_direction("downstream")) { + xlog("L_DBG", "2) ADD_contact_alias();"); + add_contact_alias(); + } + } + } else { + if (is_reply() && !isflagset(FLT_MOBILE_ORIG)) { + xlog("L_DBG", "3) ADD_contact_alias();"); + add_contact_alias(); + } + } + + if (isflagset(FLT_MOBILE_ORIG)) { + $avp(setid) = 1; + $avp(extra_id) = "mo"; + } else { + $avp(setid) = 1; +# $avp(setid) = 2; + $avp(extra_id) = "mt"; + } + + if(!t_is_set("onreply_route")) t_on_reply("NAT_REPLY"); + if(!t_is_set("failure_route")) t_on_failure("NATMANAGE"); + + if (is_method("BYE") || t_is_failure_route()) { + rtpengine_manage(); + return; + } + + setflag(FLT_RTP); + + if (!has_body("application/sdp")) + return; + +#!ifdef REMOVE_BITALIGNED_AMR + route(REMOVE_BITALIGNED); +#!endif + +#!ifndef FORCE_RTPRELAY + if (!isflagset(FLT_NAT) || !check_route_param("rm=")) + return; +#!endif + + if ((is_reply() && ($T_req($tt) != $null)) || (is_request() && has_totag())) { + # In-Dialog requests + # Requests originating from MO or MT + if ((is_request() && isflagset(FLT_MOBILE_ORIG) && is_direction("downstream")) || (is_request() && !isflagset(FLT_MOBILE_ORIG) && is_direction("upstream"))) { + rtpengine_manage(); + } else if ((is_reply() && !isflagset(FLT_MOBILE_ORIG) && is_direction("upstream")) || (is_reply() && isflagset(FLT_MOBILE_ORIG) && is_direction("downstream"))) { + rtpengine_manage(); + } + } else { + # Initial Requests + if ($avp(rtpproxy_offer_flags) == $null) + return; + if ($avp(rtpproxy_answer_flags) == $null) + return; + + if (is_request() && isflagset(FLT_MOBILE_ORIG)) { + rtpengine_manage($avp(rtpproxy_offer_flags)); + } else if (is_reply() && !isflagset(FLT_MOBILE_ORIG)) { + rtpengine_manage($avp(rtpproxy_answer_flags)); + } + } +} + +# manage incoming replies +onreply_route[NAT_REPLY] { + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); +} + +route[REMOVE_BITALIGNED] { + if (sdp_get_line_startswith("$avp(mline)", "m=")) { + # xlog("m-line: $avp(mline)\n"); + sdp_get("$avp(sdp)"); + # xlog("\n$avp(sdp)\n"); + $var(x) = -1; + $var(remove) = ""; + $var(codec) = $(avp(mline){s.select,$var(x), }); + # xlog("$$var(codec) => $var(codec)\n"); + while ($(var(codec){s.int}) > 0) { + # xlog("$var(x)) $$var(codec) => $var(codec)\n"); + $var(s) = "a=fmtp:"+$var(codec); + # xlog("$$var(s) => $var(s)\n"); + $var(fmtp) = $(avp(sdp){line.sw,$var(s)}); + # xlog("$$var(fmtp) => $var(fmtp)\n"); + if ($var(fmtp) =~ "a=fmtp:"+$var(codec)+" mode-change-capability.*") { + # xlog("Match: $var(codec)\n"); + if ($var(remove) == "") { + $var(remove) = $var(codec); + } else { + $var(remove) = $var(remove)+","+$var(codec); + } + } + $var(codec) = $(avp(mline){s.select,$var(x), }); + $var(x) = $var(x) - 1; + } + # xlog("$$var(remove) => $var(remove)\n"); + if ($var(remove) != "") { + sdp_remove_codecs_by_id($var(remove), "audio"); + msg_apply_changes(); + } + } +} + diff --git a/pcscf/route/websocket.cfg b/pcscf/route/websocket.cfg new file mode 100644 index 0000000..1f5b70f --- /dev/null +++ b/pcscf/route/websocket.cfg @@ -0,0 +1,62 @@ +event_route[xhttp:request] { + set_reply_close(); + set_reply_no_connect(); + +#!ifdef WITH_XMLRPC + if ($hu =~ "^/RPC") { + route(XMLRPC); + exit; + } +#!endif + + if ($Rp != MY_WS_PORT +#!ifdef WITH_TLS + && $Rp != MY_WSS_PORT +#!endif + ) { + xlog("L_WARN", "HTTP request received on $Rp\n"); + xhttp_reply("403", "Forbidden - HTTP request received on $Rp", "", ""); + exit; + } + + if ($hdr(Upgrade)=~"websocket" + && in_list("Upgrade", $hdr(Connection), ",") + && $rm=~"GET") { + + # Validate Host - make sure the client is using the correct + # alias for WebSockets + if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) { + xlog("L_WARN", "Bad host $hdr(Host)\n"); + xhttp_reply("403", "Forbidden - invalid host", "", ""); + exit; + } + +#!ifdef WEBSOCKET_WEBSERVER + # Validate Origin - make sure the client is from the authorised website + if ($hdr(Origin) != "http://"+WEBSOCKET_WEBSERVER +#!ifdef WITH_TLS + && $hdr(Origin) != "https://"+WEBSOCKET_WEBSERVER +#!endif + ) { + xlog("L_WARN", "Unauthorised client $hdr(Origin)\n"); + xhttp_reply("403", "Forbidden - invalid website", "", ""); + exit; + } +#!endif + + # ws_handle_handshake() exits (no further configuration file + # processing of the request) when complete. + if (ws_handle_handshake()) { + # Optional... cache some information about the + # successful connection + exit; + } + } + + # xhttp_reply("200", "OK", "text/html", "Wrong URL $hu"); + xhttp_reply("404", "Not Found", "", ""); +} + +event_route[websocket:closed] { + xlog("L_DBG", "WebSocket connection from $si:$sp has closed\n"); +} diff --git a/pcscf/route/xmlrpc.cfg b/pcscf/route/xmlrpc.cfg new file mode 100644 index 0000000..50571c0 --- /dev/null +++ b/pcscf/route/xmlrpc.cfg @@ -0,0 +1,27 @@ +# XMLRPC routing +route[XMLRPC] { + # allow XMLRPC from localhost + if ((method=="POST" || method=="GET") +#!ifdef XMLRPC_WHITELIST_1 +&& ((src_ip == XMLRPC_WHITELIST_1) +#!ifdef XMLRPC_WHITELIST_2 + || (src_ip == XMLRPC_WHITELIST_2) +#!endif +#!ifdef XMLRPC_WHITELIST_3 + || (src_ip == XMLRPC_WHITELIST_3) +#!endif +) +#!endif +) { + # close connection only for xmlrpclib user agents (there is a bug in + # xmlrpclib: it waits for EOF before interpreting the response). + if ($hdr(User-Agent) =~ "xmlrpclib") + set_reply_close(); + set_reply_no_connect(); + dispatch_rpc(); + exit; + } + send_reply("403", "Forbidden"); + exit; +} + diff --git a/pcscf/sems/etc/methodmap.conf b/pcscf/sems/etc/methodmap.conf new file mode 100644 index 0000000..8641a01 --- /dev/null +++ b/pcscf/sems/etc/methodmap.conf @@ -0,0 +1,2 @@ +OPTIONS=>refuse_with_200 +REGISTER=>register diff --git a/pcscf/sems/etc/mo.sbcprofile.conf b/pcscf/sems/etc/mo.sbcprofile.conf new file mode 100644 index 0000000..39a2527 --- /dev/null +++ b/pcscf/sems/etc/mo.sbcprofile.conf @@ -0,0 +1,78 @@ +# transparent SBC profile +# +# This implements a transparent B2BUA - all possible options are commented + +# defaults: transparent +#RURI=$r +#From=$f +#To=sip:$rU@ims.voiceblue.com + +#Call-ID +#Call-ID=$ci-ngv + +## routing +# outbound proxy: +outbound_proxy=sip:mo@$si:$sp +# force outbound proxy (in-dialog requests)? +#force_outbound_proxy=yes +# destination IP[:port] for outgoing requests +next_hop_ip=$si +next_hop_port=$sp +# use next_hop for replies, too? +#next_hop_for_replies=yes +# outbound interface to use (interface ID) +#outbound_interface=extern + +## RTP relay +# enable RTP relaying (bridging): +enable_rtprelay=no +# force symmetric RTP (start with passive mode): +#rtprelay_force_symmetric_rtp=yes +# use symmetric RTP indication from P-MsgFlags flag 2 +#rtprelay_msgflags_symmetric_rtp=yes + +## filters: +header_filter=whitelist +header_list=Diversion,P-Asserted-Identity,Privacy,Allow,Event,Expires,Accept,User-Agent,Subscription-State,P-Access-Network-Info,P-Route,C-Params,Feature-Caps +#header_filter=blacklist +#header_list= +#header_list=P-App-Param,P-App-Name +message_filter=blacklist +message_list=SUBSCRIBE +sdp_filter=whitelist +#sdpfilter_list=g722,pcma,pcmu,gsm,amr,h264,telephone-event +sdpfilter_list=g722,pcma,pcmu,gsm,amr,amr-wb,amr-wb/16000,h264,telephone-event +codec_preference=g722,amr-wb,amr-wb/16000,pcmu,pcma,gsm,amr +sdp_anonymize=yes +#sdp_anonymize=no +# Filter A-Lines: +sdp_alines_filter=blacklist +sdp_alinesfilter_list=crypto,nortpproxy + +## Transcoding +enable_transcoder=on_missing_compatible +#enable_transcoder=always +transcoder_codecs=amr,pcma,pcmu +#transcoder_codecs=amr-wb/16000,amr-wb,g722,amr,pcma,pcmu +prefer_existing_codecs=yes +# Minimum G711! +callee_codeccaps=pcma,pcmu + +## reply translations +# translate some 6xx class replies to 4xx class: +#reply_translations="603=>488 Not acceptable here|600=>406 Not Acceptable" + +# From the mobile network +enable_aleg_session_timer=no +aleg_session_expires=120 +aleg_minimum_timer=90 +aleg_maximum_timer=180 + +# From our network +enable_session_timer=no +session_expires=120 +minimum_timer=90 +maximum_timer=7200 + +#session_refresh_method=UPDATE_FALLBACK_INVITE +#accept_501_reply=yes diff --git a/pcscf/sems/etc/monitoring.conf b/pcscf/sems/etc/monitoring.conf new file mode 100644 index 0000000..b61c1ca --- /dev/null +++ b/pcscf/sems/etc/monitoring.conf @@ -0,0 +1,20 @@ + +#run_garbage_collector=[yes | no] +# +# run garbage collection on expired session info? +# Default: no +# +run_garbage_collector = yes + +#garbage_collector_interval=10 +# +# run garbage collection every n seconds +# Default: 10 +# +#garbage_collector_interval = 20 + +# retain_samples_s=10 +# +# retain "sample" type values for n seconds +# +#retain_samples_s=20 diff --git a/pcscf/sems/etc/mt.sbcprofile.conf b/pcscf/sems/etc/mt.sbcprofile.conf new file mode 100644 index 0000000..fac9d2c --- /dev/null +++ b/pcscf/sems/etc/mt.sbcprofile.conf @@ -0,0 +1,80 @@ +# transparent SBC profile +# +# This implements a transparent B2BUA - all possible options are commented + +# defaults: transparent +#RURI=$r +#From=$f +#To=sip:$rU@$td + +#Call-ID +#Call-ID=$ci_leg2 + +## routing +# outbound proxy: +outbound_proxy=sip:mt@$si:$sp +# force outbound proxy (in-dialog requests)? +#force_outbound_proxy=yes +# destination IP[:port] for outgoing requests +#next_hop_ip=$si +#next_hop_port=$sp +# use next_hop for replies, too? +#next_hop_for_replies=yes +# outbound interface to use (interface ID) +#outbound_interface=extern + +## RTP relay +# enable RTP relaying (bridging): +enable_rtprelay=no +# force symmetric RTP (start with passive mode): +#rtprelay_force_symmetric_rtp=yes +# use symmetric RTP indication from P-MsgFlags flag 2 +#rtprelay_msgflags_symmetric_rtp=yes + +## filters: +header_filter=whitelist +header_list=Diversion,P-Asserted-Identity,Privacy,P-Route,P-NAT,P-Source,Allow,Event,Expires,Accept,User-Agent,Subscription-State,P-Route,C-Params +#header_filter=blacklist +#header_list= +#header_list=P-App-Param,P-App-Name +#message_filter=blacklist +#message_list=OPTIONS +sdp_filter=whitelist +sdpfilter_list=g722,pcma,pcmu,gsm,amr-wb,amr-wb/16000,amr,h264,telephone-event +sdp_anonymize=yes +# Filter A-Lines: +sdp_alines_filter=blacklist +sdp_alinesfilter_list=crypto,nortpproxy + +## Transcoding +enable_transcoder=on_missing_compatible +transcoder_codecs=pcma,pcmu,amr +prefer_existing_codecs=yes +callee_codeccaps=amr + +## reply translations +# translate some 6xx class replies to 4xx class: +#reply_translations="603=>488 Not acceptable here|600=>406 Not Acceptable" + +## session timer: + +# From our network +enable_aleg_session_timer=no +aleg_session_expires=120 +aleg_minimum_timer=90 +aleg_maximum_timer=7200 + +# From the mobile network +enable_session_timer=no +session_expires=120 +minimum_timer=90 +maximum_timer=180 + +#session_refresh_method=UPDATE_FALLBACK_INVITE +#accept_501_reply=yes + +## Registration Caching +enable_reg_caching=no +min_reg_expires=7200 +max_ua_expires=120 + diff --git a/pcscf/sems/etc/nocache.sbcprofile.conf b/pcscf/sems/etc/nocache.sbcprofile.conf new file mode 100644 index 0000000..ec3262d --- /dev/null +++ b/pcscf/sems/etc/nocache.sbcprofile.conf @@ -0,0 +1,38 @@ +# transparent SBC profile +# +# This implements a transparent B2BUA - all possible options are commented + +# defaults: transparent + +## routing +# outbound proxy: +outbound_proxy=sip:$si:$sp +# force outbound proxy (in-dialog requests)? +#force_outbound_proxy=yes +# destination IP[:port] for outgoing requests +#next_hop_ip=$si +#next_hop_port=$sp +# use next_hop for replies, too? +#next_hop_for_replies=yes +# outbound interface to use (interface ID) +#outbound_interface=extern + +## filters: +#header_filter=whitelist +#header_list=Diversion,P-Asserted-Identity,Privacy,P-Route,P-Destination,P-Source +#header_filter=blacklist +#header_list= +#header_list=P-App-Param,P-App-Name +#message_filter=blacklist +#message_list=OPTIONS +sdp_filter=whitelist +sdpfilter_list=g722,pcma,pcmu,isac,ilbc,gsm,telephone-event +sdp_anonymize=yes +# Filter A-Lines: +sdp_alines_filter=blacklist +sdp_alinesfilter_list=crypto,nortpproxy + +## Registration Caching +enable_reg_caching=no +min_reg_expires=60 +max_ua_expires=60 diff --git a/pcscf/sems/etc/refuse.sbcprofile.conf b/pcscf/sems/etc/refuse.sbcprofile.conf new file mode 100644 index 0000000..3ea3d62 --- /dev/null +++ b/pcscf/sems/etc/refuse.sbcprofile.conf @@ -0,0 +1 @@ +refuse_with="403 Forbidden" diff --git a/pcscf/sems/etc/refuse_with_200.sbcprofile.conf b/pcscf/sems/etc/refuse_with_200.sbcprofile.conf new file mode 100644 index 0000000..de0a306 --- /dev/null +++ b/pcscf/sems/etc/refuse_with_200.sbcprofile.conf @@ -0,0 +1 @@ +refuse_with="200 OK" diff --git a/pcscf/sems/etc/register.sbcprofile.conf b/pcscf/sems/etc/register.sbcprofile.conf new file mode 100644 index 0000000..c8f1ae2 --- /dev/null +++ b/pcscf/sems/etc/register.sbcprofile.conf @@ -0,0 +1,28 @@ +# transparent SBC profile +# +# This implements a transparent B2BUA - all possible options are commented + +# defaults: transparent + +## routing +# outbound proxy: +#outbound_proxy=sip:$si:$sp +# force outbound proxy (in-dialog requests)? +#force_outbound_proxy=yes +# destination IP[:port] for outgoing requests +#next_hop_ip=$si +#next_hop_port=$sp +# use next_hop for replies, too? +#next_hop_for_replies=yes +# outbound interface to use (interface ID) +#outbound_interface=extern + +## filters: +#header_filter=whitelist +#header_list=P-Visited-Network-ID + +## Registration Caching +enable_reg_caching=yes +min_reg_expires=120 +#min_reg_expires=57600 +max_ua_expires=120 diff --git a/pcscf/sems/etc/rurimap.conf b/pcscf/sems/etc/rurimap.conf new file mode 100644 index 0000000..867ad7e --- /dev/null +++ b/pcscf/sems/etc/rurimap.conf @@ -0,0 +1 @@ +ims.voiceblue.com=>mo diff --git a/pcscf/sems/etc/sbc.conf b/pcscf/sems/etc/sbc.conf new file mode 100644 index 0000000..dd206a5 --- /dev/null +++ b/pcscf/sems/etc/sbc.conf @@ -0,0 +1,62 @@ + +# profiles - comma-separated list of call profiles to load +# +# .sbcprofile.conf is loaded from module config +# path (the path where this file resides) +profiles=mo,mt,register + +# active call profile - comma separated list, first non-empty is used +# +# o active_profile= always use +# +# o active_profile=$(ruri.user) use user part of INVITE Request URI +# +# o active_profile=$(paramhdr) use "profile" option in P-App-Param header +# +# o any replacement pattern +# +active_profile=$H(SBC),register + +# regex_maps - comma-separated list of regex maps to load at startup, for $M() +# +# regex=>value maps for which names are given here are loaded from +# this path, e.g. src_ipmap.conf, ruri_map.conf, usermap.conf +# +#regex_maps=src_ipmap + +## RFC4028 Session Timer +# default configuration - can be overridden by call profiles + +# - enables the session timer ([yes,no]; default: no) +# +#enable_session_timer=yes + +# - set the "Session-Expires" parameter for the session timer. +# +#session_expires=120 + +# - set the "Min-SE" parameter for the session timer. +# +#minimum_timer=90 + +# session refresh (Session Timer, RFC4028) method +# +# INVITE - use re-INVITE +# UPDATE - use UPDATE +# UPDATE_FALLBACK_INVITE - use UPDATE if indicated in Allow, re-INVITE otherwise +# +# Default: UPDATE_FALLBACK_INVITE +# +#session_refresh_method=UPDATE + +# accept_501_reply - accept 501 reply as successful refresh? [yes|no] +# +# Default: yes +# +#accept_501_reply=no + +# handle OPTIONS messages in the core? (with limits etc) +# Default: no +core_options_handling=yes + + diff --git a/pcscf/sems/etc/stats.conf b/pcscf/sems/etc/stats.conf new file mode 100644 index 0000000..57babe1 --- /dev/null +++ b/pcscf/sems/etc/stats.conf @@ -0,0 +1,5 @@ +# IP of the monitoring interface: +monit_udp_ip=127.0.0.1 + +# port the statistics server should listen to: +monit_udp_port=5040 diff --git a/pcscf/sems/etc/xmlrpc2di.conf b/pcscf/sems/etc/xmlrpc2di.conf new file mode 100644 index 0000000..9c9bf05 --- /dev/null +++ b/pcscf/sems/etc/xmlrpc2di.conf @@ -0,0 +1,42 @@ +# server_ip : IP to bind XMLRPC server to +# leave empty for ANY interface +server_ip=127.0.0.1 + +# port to bind XMLRPC server to +xmlrpc_port=8090 + +# run multi-threaded server? +# Default: yes +# +# multithreaded = yes + +# threads to run - this many requests can be processed in parallel +# Default: 5 +# +# threads=5 + +# export all DI functions with the function call 'di'? +# defaults to: yes +# export_di=yes + +# +# these DI interfaces are searched for functions to +# export under their proper function names +# defaults to: none +# direct_export=di_dial;registrar_client +direct_export=sbc + +# run the XMLRPC server at all (default: yes) +# +# run_server=yes + +# timeout for client requests, in milliseconds (0 to disable) +# +# server_timeout=500 + +# print parameters of XMLRPC server calls into debug log [yes|no] +# debug_server_params=yes +# +# print result of XMLRPC server calls into debug log [yes|no] +# debug_server_result=yes +# diff --git a/pcscf/sems/sems.conf b/pcscf/sems/sems.conf new file mode 100644 index 0000000..ecae29e --- /dev/null +++ b/pcscf/sems/sems.conf @@ -0,0 +1,538 @@ +# $Id$ +# +# sems.conf.sample +# +# Sip Express Media Server (sems) +# +# sample configuration file +# +# +# whitespaces (spaces and tabs) are ignored +# comments start with a "#" and may be used inline +# +# example: option=value # i like this option +# +# @filename includes mod_config_path/filename +# @/absolute/path/to/file includes file + +############################################################ +# Network configuration + +# optional parameter: media_ip=| +# +# - this informs SEMS about the IP address or interface that +# SEMS uses to send and receive media. +# - If neither 'media_ip' nor 'sip_ip' are set, defaults +# to first non-loopback interface. If 'sip_ip' is set, +# 'media_ip' defaults to 'sip_ip. +# +# Examples: +# media_ip=10.0.0.34 +# media_ip=eth0 + +#media_ip=eth0 +media_ip=109.239.57.200 + +# optional parameter: sip_ip=| +# +# - this informs SEMS about the SIP IP where its SIP stack is +# bound to or should be bound to. This also sets +# the value used for contact header in outgoing calls and +# registrations. +# - If neither 'media_ip' nor 'sip_ip' are set, defaults +# to first non-loopback interface. If 'media_ip' is set, +# 'sip_ip' defaults to 'media_ip. +# +# Example: +# sip_ip=10.0.0.34 +# sip_ip=en0 +# + +sip_ip=127.0.0.1 + +# optional parameter: public_ip= +# +# - when running SEMS behind certain simple NAT configurations, +# you can use this parameter to inform SEMS of its public IP +# address. If this parameter is set, SEMS will write this value +# into SDP bodies. +# If this parameter is not set, the local IP address is used. +# N.B., there is no support for port translation; the local +# RTP port is advertised in SDP in either case. +# +# Example: +# public_ip=75.101.219.48 +# + +# optional parameter: sip_port= +# +# - this informs SEMS about the port where its SIP stack is +# bound to or should be bound to. SEMS needs this information +# to correctly set the contact header in outgoing calls +# and registrations. Should be set to equal the 'port' +# configuration option in ser_sems.cfg. +# +# default: 5060 +# +sip_port=5080 + +# optional parameter: outbound_proxy=uri +# +# - this sets an outbound proxy for calls and registrations initiated +# by SEMS. This does not apply to requests in a dialog that +# is initiated by someone else and incoming to SEMS. +# If this is not set (default setting), then for dialogs +# initiated by SEMS the r-uri is resolved and the request +# is sent there directly. +# This is resolved by the SIP stack with DNS if a name is given. +# Warning: If the value set here can not be resolved, no +# requests will be sent out at all! +# +# default: empty +# +# Example: +# outbound_proxy=sip:proxy.mydomain.net + +# optional parameter: force_outbound_proxy={yes|no} +# +# - forces SEMS to send any request to the outbound proxy in any +# situation, by adding an extra first Route to the outbound_proxy. +# This option will only have an effect if the outbound_proxy +# option has been set, and it will break 3261 compatibility +# in some cases; better use next_hop_ip/next_hop_port. +# +# default: no +# +# Example: +# force_outbound_proxy=yes + +# optional parameter: next_hop_ip +# - if this is set, all outgoing requests will be sent to +# this IP, regardless of R-URI etc. +# +#next_hop_ip=192.168.5.106 + +# optional parameter: next_hop_port +# defaults to 5060 +#next_hop_port=5060 + +# optional parameter:next_hop_for_replies +# - use next_hop for replies, too? +# +#next_hop_for_replies=yes + +# optional parameter: rtp_low_port= +# +# - sets lowest for RTP used port +rtp_low_port=10000 + +# optional parameter: rtp_high_port= +# +# - sets highest for RTP used port +rtp_high_port=19999 + +# Additional IFs (optional): +# additional_interfaces = +# +# additional_interfaces must be set if more than one +# interface is to be used for the same purpose (e.g. +# more than one interface for SIP). Configure additional +# interfaces if networks should be bridged or separate +# networks should be served. +# +# For each additional interface, a set of parameters +# suffixed with the interface name should be listed +# with the 'additional_interfaces' parameter. +# +# Please note that for each additional interface, +# 'sip_ip_[if_name]' is mandatory. The other +# parameters are optional. 'media_ip_[if_name]' +# is derived from 'sip_ip_[if_name]' if not set. +# 'public_ip_[ip_name]' is also based on 'sip_ip_[if_name]' +# if not set explicitly. +# +# Example: +# additional_interfaces=intern,extern +# +# sip_ip_intern=192.168.0.5 +# sip_port_intern=5060 +# media_ip_intern=192.168.10.5 +# rtp_low_port_intern=2000 +# rtp_high_port_intern=5000 +# +# sip_ip_extern=213.192.59.73 +# sip_port_extern=5060 +# media_ip_extern=213.192.59.73 +# rtp_low_port_extern=2000 +# rtp_high_port_extern=5000 +# public_ip_extern=213.192.35.73 +# + +############################################################ +# modules and application configuration +# +# Configuration of plugin (module) loading: +# - if load_plugins is set, only those are loaded. +# - if load_plugins is not set, all modules in the plugin_path +# directory are loaded, except those which are listed +# in exclude_plugins. +# + +# optional parameter: plugin_path= +# +# - sets the path to the plug-ins' binaries +# - may be absolute or relative to CWD +plugin_path=/usr/lib/sems/plug-in/ + +# optional parameter: load_plugins= +# +# semicolon-separated list of modules to load. +# If empty, all modules in plugin_path are loaded. +# +# example for announcement with only g711 and ilbc codecs +# load_plugins=wav;ilbc;announcement +load_plugins=wav;gsm;isac;ilbc;xmlrpc2di;monitoring;stats;uac_auth;session_timer;sbc + +# optional parameter: exclude_plugins= +# +# semicolon-separated list of modules to exclude from loading +# ('blacklist'). If empty, all modules in plugin_path are loaded. +# This has only effect it load_plugins is not set. +# +# o precoded_announce: no precoded sample files present +# o py_sems: conflicts with ivr (in some cases) +exclude_plugins=precoded_announce;py_sems + +# optional parameter: application +# +# This controls which application is to be executed if there +# is no explicit application requested from the SIP stack +# (i.e. unixsockctrl and second parameter of t_write_unix). +# +# This can be one of +# $(ruri.user) - user part of ruri is taken as application, +# e.g. sip:announcement@host +# $(ruri.param) - uri parameter "app", e.g. +# sip:joe@host.net;app=announcement +# $(apphdr) - the value of the P-App-Name header is used +# +# $(mapping) - regex=>application mapping is read from +# app_mapping.conf (see app_mapping.conf) +# - application name configured here, e.g. +# application=announcement +# +# examples: +# application = conference +# application = $(mapping) +# application = $(ruri.user) +# application = $(ruri.param) +application = sbc + +# parameter: plugin_config_path= +# +# - in this path configuration files of the applications +# (e.g. announcement.conf) are searched +plugin_config_path=/etc/sems/etc/ + +# optional parameter: exclude_payloads= +# +# semicolon-separated list of payloads to exclude from loading +# ('blacklist'). +# +# For example, to only use low bandwidth codecs: +# exclude_payloads=PCMU;PCMA;G726-40;G726-32;G721;L16 +# or, to use only codecs which are not CPU-intensive: +# exclude_payloads=iLBC;speex; +# only use G711 (exclude everything else): +# exclude_payloads=iLBC;speex;G726-40;G726-32;G721;G726-24;G726-16;GSM;L16 + +############################################################ +# logging and running + +# optional parameter: fork={yes|no} +# +# - specifies if sems should run in daemon mode (background) +# (fork=no is the same as -E) +fork=yes + +# optional parameter: stderr={yes|no} +# +# - debug mode: do not fork and log to stderr +# (stderr=yes is the same as -E) +stderr=no + +# optional parameter: loglevel={0|1|2|3} +# +# - sets log level (error=0, warning=1, info=2, debug=3) +# (same as -D) +loglevel=1 + +# optional parameter: syslog_facility={DAEMON|USER|LOCAL[0-7]} +# +# - sets the log facility that is used for syslog. Using this, +# the log can for example be filtered into a special file +# by the syslog daemon. +# +# Default: DAEMON +# +# Example: +# syslog_facility=LOCAL0 + +# optional parameter: log_sessions=[yes|no] +# +# Default: no +# +# If log_sessions=yes is set, INFO level log messages are generated +# for each session when it is started and stopped. +# +# log_sessions=yes + +# optional parameter: log_events=[yes|no] +# +# Default: no +# +# If log_eventy=yes is set, generic DBG level log messages are +# generated for each event that is posted into an event queue. +# +# log_events=yes + +# optional parameter: max_shutdown_time=