Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!KAMAILIO
- #!define WITH_MYSQL
- #!define WITH_AUTH
- #!define WITH_IPAUTH
- #!define WITH_UAC
- #!define WITH_USRLOCDB
- #!define WITH_ACCDB
- #!define WITH_DROUTE
- #!define WITH_DEBUG
- #!define WITH_NAT
- #!define WITH_DISPATCHER
- #!define WITH_CALLLIMIT
- ##!define WITH_SERVERNAT
- #!define WITH_MULTIDOMAIN
- #!define WITH_TELEBLOCK
- #!define WITH_ANTIFLOOD
- ##!define WITH_DBCLUSTER
- #!define WITH_LCR
- #!define WITH_TLS
- #!define WITH_WEBSOCKETS
- ##!define WITH_DMQ
- #!define WITH_MSTEAMS
- #
- #!substdef "!INTERNAL_IP_ADDR!X.X.X.X!g"
- #!substdef "!INTERNAL_IP_NET!X.X.X.*!g"
- #!substdef "!EXTERNAL_IP_ADDR!X.X.X.X!g"
- #!substdef "!EXTERNAL_FQDN!sbc.yyyyy.com!g"
- #!substdef "!SIP_PORT!5060!g"
- #!substdef "!SIPS_PORT!5061!g"
- #!substdef "!DMQ_PORT!5090!g"
- #!substdef "!WSS_PORT!4443!g"
- ####### Include Local Config If Exists #########
- import_file "kamailio-local.cfg"
- ####### Defined Values #########
- # - database URL - used to connect to database server by modules
- #!ifdef WITH_MYSQL
- #!ifdef WITH_DBCLUSTER
- #!define DBURL "cluster://dbcluster"
- #!define SQLCONN_KAM "kam=>mysql://kamailio:somerandompassword@localhost:3306/kamailio"
- #!define SQLCONN_AST "asterisk=>mysql://kamailio:somerandompassword@localhost:3306/kamailio"
- #!else
- #!define DBURL "mysql://kamailio:somerandompassword@localhost:3306/kamailio"
- #!define SQLCONN_KAM "kam=>mysql://kamailio:somerandompassword@localhost:3306/kamailio"
- #!define SQLCONN_AST "asterisk=>mysql://kamailio:somerandompassword@localhost:3306/kamailio"
- #!endif
- #!endif
- #!ifdef WITH_MULTIDOMAIN
- # - the value for 'use_domain' parameters
- #!define MULTIDOMAIN 1
- #!else
- #!define MULTIDOMAIN 0
- #!endif
- # - flags
- # FLT_ - per transaction (message) flags
- # FLB_ - per branch flags
- #!define FLT_ACC 1
- #!define FLT_ACCMISSED 2
- #!define FLT_ACCFAILED 3
- #!define FLT_NATS 5
- #!define FLB_NATB 6
- #!define FLB_NATSIPPING 7
- #!define FLT_CARRIER 8
- #!define FLT_PBX 9
- #!define FLT_DOMAINROUTING 10
- #!define FLT_PBX_AUTH 11
- #!define FLT_CARRIER_AUTH 12
- #!define FLT_EXTERNAL_AUTH 13
- #!define FLT_PASSTHRU_AUTH 14
- #!define FLT_FAILOVER 15
- #!define FLT_DIALOG 16
- #!define FLT_SRC_SIP 17
- #!define FLT_SRC_WS 18
- #!define FLB_WS_DEVICE 19
- #!define FLT_USE_RTPE 20
- #!define FLT_SERVERNAT 21
- #!define FLT_MSTEAMS 22
- #!define FLB_SRC_MSTEAMS 23
- #!define FLB_DST_MSTEAMS 24
- #!define FLT_OUTBOUND 8000
- #!define FLT_INBOUND 9000
- #!define NOTIFICATION_OVERLIMIT "0"
- #!define NOTIFICATION_GWFAILURE "1"
- ####### Global Parameters #########
- ### LOG Levels: 3=DBG, 2=INFO, 1=NOTICE, 0=WARN, -1=ERR
- #!ifdef WITH_DEBUG
- debug=3
- log_stderror=no
- #!else
- debug=2
- log_stderror=no
- #!endif
- memdbg=5
- memlog=5
- log_facility=LOG_LOCAL0
- fork=yes
- children=1
- # increase loop limit to allow 10000 DID checks for inbound calls
- max_while_loops=10000
- # uncomment the next line to disable TCP (default on)
- #disable_tcp=yes
- # uncomment the next line to disable the auto discovery of local aliases
- # based on reverse DNS on IPs (default on)
- #auto_aliases=no
- # add local domain aliases
- #alias="INTERNAL_IP_ADDR:SIP_PORT"
- # SNGREP
- listen=udp:127.0.1.1:9061
- # configure interface/port/proto kamailio will bind on
- #!ifdef WITH_SERVERNAT
- listen=udp:INTERNAL_IP_ADDR:SIP_PORT advertise EXTERNAL_IP_ADDR:SIP_PORT
- listen=tcp:INTERNAL_IP_ADDR:SIP_PORT advertise EXTERNAL_IP_ADDR:SIP_PORT
- listen=udp:127.0.0.1:SIP_PORT
- listen=tcp:127.0.0.1:SIP_PORT
- #!ifdef WITH_WEBSOCKETS
- listen=tls:INTERNAL_IP_ADDR:WSS_PORT advertise EXTERNAL_IP_ADDR:WSS_PORT
- #!endif
- #!else
- listen=udp:INTERNAL_IP_ADDR:SIP_PORT
- listen=tcp:INTERNAL_IP_ADDR:SIP_PORT advertise EXTERNAL_IP_ADDR:SIP_PORT
- listen=udp:127.0.0.1:SIP_PORT
- listen=tcp:127.0.0.1:SIP_PORT
- #!ifdef WITH_WEBSOCKETS
- listen=tls:INTERNAL_IP_ADDR:WSS_PORT
- #!endif
- #!endif
- #!ifdef WITH_DMQ
- listen=udp:INTERNAL_IP_ADDR:DMQ_PORT
- #!endif
- # port to listen to
- # - can be specified more than once if needed to listen on many ports
- port=SIP_PORT
- #!ifdef WITH_TLS
- enable_tls=yes
- #!ifdef WITH_SERVERNAT
- listen=tls:INTERNAL_IP_ADDR:SIPS_PORT advertise EXTERNAL_FQDN:SIPS_PORT
- #!else
- listen=tls:INTERNAL_IP_ADDR:SIPS_PORT advertise EXTERNAL_FQDN:SIPS_PORT
- #!endif
- tcp_accept_no_cl=yes
- tcp_rd_buf_size=16384
- #!endif
- # 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=3605
- # this parameter controls the “Server” header in any locally generated message.
- # we disable it by default
- server_signature=no
- ####### Custom Parameters #########
- # These parameters can be modified runtime via RPC interface
- # - see the documentation of 'cfg_rpc' module.
- #
- # Format: group.id = value 'desc' description
- # Access: $sel(cfg_get.group.id) or @cfg_get.group.id
- #
- #!ifdef WITH_PSTN
- # PSTN GW Routing
- #
- # - pstn.gw_ip: valid IP or hostname as string value, example:
- # pstn.gw_ip = "10.0.0.101" desc "My PSTN GW Address"
- #
- # - by default is empty to avoid misrouting
- pstn.gw_ip = "" desc "PSTN GW Address"
- pstn.gw_port = "" desc "PSTN GW Port"
- #!endif
- #!ifdef WITH_VOICEMAIL
- # VoiceMail Routing on offline, busy or no answer
- #
- # - by default Voicemail server IP is empty to avoid misrouting
- voicemail.srv_ip = "" desc "VoiceMail IP Address"
- voicemail.srv_port = "5060" desc "VoiceMail Port"
- #!endif
- #!ifdef WITH_TELEBLOCK
- teleblock.gw_enabled = 0 desc "Enable Teleblock support"
- teleblock.gw_ip = "62.34.24.22" desc "Teleblock IP"
- teleblock.gw_port = "5066" desc "Teleblock Port"
- teleblock.media_ip = "" desc "Teleblock media ip"
- teleblock.media_port = "" desc "Teleblock media port"
- #!endif
- # Define the role of the server
- # "" - default behavior
- # outbound - outbound only (no domain routing)
- # inout - inbound and outbound only (no domain routing)
- server.role = "" desc "Role of the server in the topology"
- # Rename who we are
- server_header="dSIPRouter Project"
- # Local calling maximum digits for the initiating PBX - PBX sending the INVITE
- server.pbx_max_local_digits = 5 desc "Maximum digits for local pbx extensions"
- # PBX INVITE Timeout (msecs) to support having a Primary and Secondary PBX
- server.pbx_invite_timeout = 16000 desc "The default PBX INVITE timeout"
- # PBX INVITE Timeout (msecs) if a SIP 100/180/181/183 message is received
- server.pbx_invite_timeout_aftertry = 52000 desc "PBX INVITE timeout value if a SIP 100 message is received"
- # DSIPRouter API Server Settings
- server.api_server = "https://127.0.0.1:5000" desc "URL to the DSIPRouter API Server"
- server.api_token = "somerandomtoken" desc "API Token for DSIPRouter API Server"
- ####### Modules Section ########
- # set paths to location of modules (to sources or installation folders)
- #!ifdef WITH_SRCPATH
- mpath="/usr/lib/x86_64-linux-gnu/kamailio/modules/"
- #!else
- mpath="/usr/lib/x86_64-linux-gnu/kamailio/modules/"
- #!endif
- #!ifdef WITH_MYSQL
- loadmodule "db_mysql.so"
- #!endif
- loadmodule "kex.so"
- loadmodule "corex.so"
- loadmodule "tm.so"
- loadmodule "tmx.so"
- loadmodule "sl.so"
- loadmodule "rr.so"
- loadmodule "path.so"
- loadmodule "pv.so"
- loadmodule "maxfwd.so"
- loadmodule "usrloc.so"
- loadmodule "registrar.so"
- loadmodule "dsiprouter.so"
- loadmodule "sdpops.so"
- loadmodule "textops.so"
- loadmodule "textopsx.so"
- loadmodule "siputils.so"
- loadmodule "xlog.so"
- loadmodule "sanity.so"
- loadmodule "ctl.so"
- loadmodule "cfg_rpc.so"
- loadmodule "acc.so"
- loadmodule "xhttp.so"
- loadmodule "jsonrpcs.so"
- loadmodule "http_async_client.so"
- # Load the SIPTRACE module
- loadmodule "siptrace.so"
- modparam("siptrace", "duplicate_uri", "sip:127.0.0.1:9061")
- modparam("siptrace", "trace_to_database", 0)
- modparam("siptrace", "hep_mode_on", 1)
- modparam("siptrace", "hep_version", 3)
- modparam("siptrace", "trace_flag", 24)
- modparam("siptrace", "hep_capture_id", 234)
- modparam("siptrace", "trace_mode", 1)
- #!ifdef WITH_DMQ
- loadmodule "dmq.so"
- loadmodule "dmq_usrloc.so"
- #!endif
- # must be loaded after dmq
- loadmodule "htable.so"
- loadmodule "dialog.so"
- # -- for siremis CDRs --------------
- loadmodule "rtimer.so"
- loadmodule "sqlops.so"
- #!ifdef WITH_AUTH
- loadmodule "auth.so"
- loadmodule "auth_db.so"
- #!ifdef WITH_IPAUTH
- loadmodule "permissions.so"
- #!endif
- #!ifdef WITH_UAC
- loadmodule "uac.so"
- #!endif
- #!endif
- #!ifdef WITH_ALIASDB
- loadmodule "alias_db.so"
- #!endif
- #!ifdef WITH_SPEEDDIAL
- loadmodule "speeddial.so"
- #!endif
- #!ifdef WITH_MULTIDOMAIN
- loadmodule "domain.so"
- #!endif
- #!ifdef WITH_PRESENCE
- loadmodule "presence.so"
- loadmodule "presence_xml.so"
- #!endif
- #!ifdef WITH_NAT
- loadmodule "nathelper.so"
- loadmodule "rtpengine.so"
- #!endif
- #!ifdef WITH_TLS
- loadmodule "tls.so"
- #!endif
- #!ifdef WITH_ANTIFLOOD
- loadmodule "pike.so"
- #!endif
- #!ifdef WITH_XMLRPC
- loadmodule "xmlrpc.so"
- #!endif
- #!ifdef WITH_DEBUG
- loadmodule "debugger.so"
- #!endif
- #!ifdef WITH_DROUTE
- loadmodule "drouting.so"
- #!endif
- #!ifdef WITH_DBCLUSTER
- loadmodule "db_cluster"
- #!endif
- #!ifdef WITH_DISPATCHER
- loadmodule "keepalive.so"
- loadmodule "dispatcher.so"
- #!endif
- #!ifdef WITH_WEBSOCKETS
- loadmodule "websocket.so"
- #!endif
- # ----------------- setting module-specific parameters ---------------
- # ---- htable global params ----
- modparam("htable", "db_url", DBURL)
- # ---- dispatcher params ----
- #!ifdef WITH_DISPATCHER
- modparam("dispatcher", "flags", 2)
- modparam("dispatcher", "db_url", DBURL)
- modparam("dispatcher", "table_name", "dispatcher")
- modparam("dispatcher", "ds_probing_mode", 1) # 1 means to probe each gateway
- modparam("dispatcher", "ds_ping_latency_stats", 1) # 1 means to provide latency stats
- modparam("dispatcher", "ds_ping_method", "OPTIONS")
- modparam("dispatcher", "ds_ping_interval", 10) # How often to ping destinations to check status
- modparam("dispatcher", "xavp_dst", "dispatcher_dst") # Will contain selected destination info
- modparam("dispatcher", "xavp_dst_mode", 0) # What attributes to set in the xavp
- modparam("dispatcher", "xavp_ctx", "dispatcher_ctx") # Will contain current dispatcher context info
- modparam("dispatcher", "xavp_ctx_mode", 0) # What attributes to set in the xavp
- #!endif
- # ----- db_cluster params ----
- # connection: set for each db connection uri
- # cluster: s == serial, r == roundrobin, p == parallel (write/only)
- #!ifdef WITH_DBCLUSTER
- modparam("db_cluster", "connection", "c1=>mysql://kamailio:[email protected]/kamailio")
- modparam("db_cluster", "connection", "c2=>mysql://kamailio:[email protected]/kamailio")
- modparam("db_cluster", "connection", "c3=>mysql://kamailio:[email protected]/kamailio")
- modparam("db_cluster", "connection", "c4=>mysql://kamailio:[email protected]/kamailio")
- modparam("db_cluster", "cluster", "dbcluster=>c1=9r9r;c2=9r9r;c3=9r9r;c4=9r9r")
- modparam("db_cluster", "inactive_interval", 180)
- #!endif
- # ----- jsonrpcs params -----
- modparam("jsonrpcs", "pretty_format", 1)
- modparam("jsonrpcs", "fifo_name", "/var/run/kamailio/kamailio_rpc.fifo")
- modparam("jsonrpcs", "transport", 3)
- #modparam#("jsonrpcs", "dgram_socket", "/var/run/kamailio/kamailio_rpc.sock")
- # ----- ctl params -----
- modparam("ctl", "binrpc", "unix:/var/run/kamailio/kamailio_ctl")
- # ----- tm params -----
- # auto-discard branches from previous serial forking leg
- modparam("tm", "failure_reply_mode", 3)
- # default retransmission timeout: 25sec
- modparam("tm", "fr_timer", 25000)
- # default invite retransmission timeout after 1xx: 120sec
- modparam("tm", "fr_inv_timer", 120000)
- # ----- rr params -----
- # set next param to 1 to add value to ;lr param (helps with some UAs)
- modparam("rr", "enable_full_lr", 0)
- # append from tag to the RR (no need for this script)
- modparam("rr", "append_fromtag", 0)
- # ----- registrar params -----
- modparam("registrar", "method_filtering", 1)
- /* uncomment the next line to disable parallel forking via location */
- # modparam("registrar", "append_branches", 0)
- /* uncomment the next line not to allow more than 10 contacts per AOR */
- #modparam("registrar", "max_contacts", 10)
- # max value for expires of registrations
- modparam("registrar", "max_expires", 3600)
- # set it to 1 to enable GRUU
- modparam("registrar", "gruu_enabled", 0)
- # ----- acc params -----
- # what special events should be accounted?
- modparam("acc", "early_media", 0)
- modparam("acc", "report_ack", 0)
- modparam("acc", "report_cancels", 0)
- # by default ww do not adjust the direction of the sequential requests
- # if you enable this parameter, be sure the enable "append_fromtag" in "rr" module
- modparam("acc", "detect_direction", 0)
- modparam("acc", "log_flag", FLT_ACC)
- modparam("acc", "log_missed_flag", FLT_ACCMISSED)
- modparam("acc", "log_extra",
- "src_user=$fU;src_domain=$fd;src_ip=$si;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;"
- "calltype=$avp(calltype);src_gwgroupid=$avp(src_gwgroupid);dst_gwgroupid=$avp(dst_gwgroupid)")
- modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)
- # enhanced DB accounting
- #!ifdef WITH_ACCDB
- modparam("acc", "db_flag", FLT_ACC)
- modparam("acc", "db_missed_flag", FLT_ACCMISSED)
- modparam("acc", "db_url", DBURL)
- modparam("acc", "db_extra",
- "src_user=$fU;src_domain=$fd;src_ip=$si;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;"
- "calltype=$avp(calltype);src_gwgroupid=$avp(src_gwgroupid);dst_gwgroupid=$avp(dst_gwgroupid)")
- #!endif
- # ----- usrloc params -----
- /* enable DB persistency for location entries */
- #!ifdef WITH_USRLOCDB
- modparam("usrloc", "db_url", DBURL)
- modparam("usrloc", "db_mode", 3)
- modparam("usrloc", "use_domain", MULTIDOMAIN)
- modparam("usrloc", "handle_lost_tcp", 1)
- #!endif
- # ----- auth_db params -----
- #!ifdef WITH_AUTH
- modparam("auth_db", "db_url", DBURL)
- modparam("auth_db", "calculate_ha1", yes)
- modparam("auth_db", "password_column", "password")
- # We use the rpid field of the subscriber table to track the assigned gwgroup (type of endpoint or carrier)
- modparam("auth_db", "load_credentials", "$avp(s:src_gwgroupid)=rpid;")
- modparam("auth_db", "use_domain", MULTIDOMAIN)
- # ----- permissions params -----
- #!ifdef WITH_IPAUTH
- modparam("permissions", "db_url", DBURL)
- modparam("permissions", "db_mode", 1)
- #!endif
- #!endif
- # ----- alias_db params -----
- #!ifdef WITH_ALIASDB
- modparam("alias_db", "db_url", DBURL)
- modparam("alias_db", "use_domain", MULTIDOMAIN)
- #!endif
- # ----- speeddial params -----
- #!ifdef WITH_SPEEDDIAL
- modparam("speeddial", "db_url", DBURL)
- modparam("speeddial", "use_domain", MULTIDOMAIN)
- #!endif
- # ----- domain params -----
- #!ifdef WITH_MULTIDOMAIN
- modparam("domain", "db_url", DBURL)
- # register callback to match myself condition with domains list
- modparam("domain", "register_myself", 0)
- #!endif
- #!ifdef WITH_PRESENCE
- # ----- presence params -----
- modparam("presence", "db_url", DBURL)
- # ----- presence_xml params -----
- modparam("presence_xml", "db_url", DBURL)
- modparam("presence_xml", "force_active", 1)
- #!endif
- #!ifdef WITH_NAT
- # ----- rtpengine params -----
- modparam("rtpengine", "rtpengine_sock", "udp:127.0.0.1:7722")
- # ----- nathelper params -----
- modparam("nathelper", "natping_interval", 30)
- modparam("nathelper", "ping_nated_only", 1)
- modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
- modparam("nathelper", "sipping_from", "sip:[email protected]")
- # params needed for NAT traversal in other modules
- modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)")
- modparam("usrloc", "nat_bflag", FLB_NATB)
- #!endif
- #!ifdef WITH_TLS
- # ----- tls params -----
- modparam("tls", "config", "//etc/kamailio/tls.cfg")
- #!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;dmqreplicate=1;")
- #!endif
- #!ifdef WITH_XMLRPC
- # ----- xmlrpc params -----
- modparam("xmlrpc", "route", "XMLRPC");
- modparam("xmlrpc", "url_match", "^/RPC")
- #!endif
- #!ifdef WITH_DEBUG
- # ----- debugger params -----
- modparam("debugger", "cfgtrace", 1)
- modparam("debugger", "log_level_name", "exec")
- #!endif
- #!ifdef WITH_UAC
- # ----- uac params -----
- modparam("uac", "restore_mode", "none")
- modparam("uac", "reg_db_url", DBURL)
- modparam("uac", "reg_db_table", "uacreg")
- modparam("uac", "reg_timer_interval", 60)
- modparam("uac", "reg_retry_interval", 120)
- modparam("uac", "reg_keep_callid", 1)
- modparam("uac", "reg_gc_interval", 30)
- modparam("uac", "credential", "username:domain:password")
- modparam("uac", "auth_realm_avp", "$avp(arealm)")
- modparam("uac", "auth_username_avp", "$avp(auser)")
- modparam("uac", "auth_password_avp", "$avp(apass)")
- modparam("uac", "reg_contact_addr", "EXTERNAL_IP_ADDR:5060")
- #!endif
- #!ifdef WITH_DROUTE
- # ----- drouting params -----
- modparam("drouting", "db_url", DBURL)
- modparam("drouting", "ruri_avp", "$avp(dr_ruri)")
- # we are storing the gwid,gwtype in the attrs column, so the matched gwid and gwtype is available
- modparam("drouting", "attrs_avp", "$avp(dr_attrs)")
- # don't match on domain (per group) only use routing group
- modparam("drouting", "use_domain", 0)
- # do not resolve DNS names during load (will blindly try them)
- modparam("drouting", "force_dns", 0)
- # a gateway will be randomly selected (from each group delimeted by ';')
- modparam("drouting", "sort_order", 2)
- # htable for maintenance mode
- modparam("htable", "htable", "maintmode=>size=8;autoexpire=0;dmqreplicate=1;dbtable=dsip_maintmode;cols='ipaddr,gwid';")
- #modparam("drouting", "enable_keepalive", 1)
- #!endif
- #!ifdef WITH_LCR
- # ----- htable params for from/to prefix lookup -----
- modparam("htable", "htable", "tofromprefix=>size=8;autoexpire=0;dmqreplicate=1;dbtable=dsip_lcr;cols='pattern,dr_groupid';")
- #!endif
- # ----- rtimer params -----
- modparam("rtimer", "timer", "name=cdr;interval=300;mode=1;")
- modparam("rtimer", "exec", "timer=cdr;route=CDRS")
- # ----- sqlops params -----
- # Kamailio Connection
- modparam("sqlops", "sqlcon", SQLCONN_KAM)
- # Asterisk Realtime Connection
- modparam("sqlops", "sqlcon", SQLCONN_AST)
- # ----- dialog params -----
- modparam("dialog", "db_url", DBURL)
- modparam("dialog", "db_mode", 0)
- modparam("dialog", "enable_stats", 1)
- modparam("dialog", "dlg_flag", 1)
- modparam("dialog", "hash_size", 4096)
- modparam("dialog", "detect_spirals", 1)
- modparam("dialog", "track_cseq_updates", 1)
- #!ifdef WITH_DMQ
- # ---- dmq params ----
- modparam("dmq", "server_address", "sip:INTERNAL_IP_ADDR:DMQ_PORT")
- modparam("dmq", "notification_address", "sip:local.cluster:DMQ_PORT")
- modparam("dmq", "multi_notify", 1)
- modparam("dmq", "num_workers", 4)
- modparam("dmq", "ping_interval", 15)
- modparam("dmq_usrloc", "enable", 1)
- # ---- dmq-related params ----
- modparam("dialog", "enable_dmq", 1)
- modparam("htable", "enable_dmq", 1)
- # only valid for kam ver >= 5.2
- modparam("htable", "dmq_init_sync", 1)
- #!endif
- #!ifdef WITH_CALLLIMIT
- modparam("dialog", "profiles_with_value", "gwgroup")
- modparam("htable", "htable", "calllimit=>size=8;autoexpire=0;dmqreplicate=1;initval=-1;dbtable=dsip_calllimit;cols='gwgroupid,limit';")
- #!endif
- # gw2gwroup is used to lookup gwgroupid
- modparam("htable", "htable", "gw2gwgroup=>size=8;autoexpire=0;dmqreplicate=1;dbtable=dsip_gw2gwgroup;cols='gwid,gwgroupid';")
- # inbound_hardfwd is used to lookup did and dr_groupid for forwarding calls unconditionally
- modparam("htable", "htable", "inbound_hardfwd=>size=8;autoexpire=0;dmqreplicate=1;dbtable=dsip_hardfwd;cols='dr_ruleid,did,dr_groupid';")
- # inbound_failfwd is used to lookup did and dr_groupid for forwarding calls on failover
- modparam("htable", "htable", "inbound_failfwd=>size=8;autoexpire=0;dmqreplicate=1;dbtable=dsip_failfwd;cols='dr_ruleid,did,dr_groupid';")
- # inbound_prefixmap is used to lookup dr_ruleid for a prefix
- modparam("htable", "htable", "inbound_prefixmap=>size=8;autoexpire=0;dmqreplicate=1;dbtable=dsip_prefix_mapping;cols='prefix,ruleid,priority';")
- # ----- http_async_client params -----
- modparam("http_async_client", "workers", 1)
- modparam("http_async_client", "connection_timeout", 500)
- modparam("http_async_client", "hash_size", 2048)
- #!ifdef WITH_DEBUG
- modparam("http_async_client", "curl_verbose", 1)
- #!endif
- #!ifdef WITH_TLS
- modparam("http_async_client", "tls_client_cert", "/etc/kamailio/certs/client.pem")
- modparam("http_async_client", "tls_client_key", "/etc/kamailio/certs/client.key")
- modparam("http_async_client", "tls_ca_path", "/etc/kamailio/certs/ca/")
- #!endif
- ####### Routing Logic ########
- # Main SIP request routing logic
- # - processing of any incoming SIP request starts with this route
- # - note: this is the same as route { ... }
- request_route {
- # handle DMQ messages
- route(DMQ);
- # per request initial checks
- route(REQINIT);
- # NAT detection
- route(NATDETECT);
- if (remove_hf("Allow")){
- append_hf("Allow: INVITE,ACK,OPTIONS,CANCEL,BYE,NOTIFY\r\n");
- }
- # CANCEL processing
- route(HANDLE_CANCEL);
- # handle requests within SIP dialogs
- route(WITHINDLG);
- # handle retransmissions
- route(HANDLE_RETRANS);
- # handle unregister requests
- route(UNREGISTER);
- # authentication
- route(AUTH);
- # handle presence related requests
- route(PRESENCE);
- # handle registrations
- route(REGISTRAR);
- # dispatch to local endpoints that registered thru the proxy
- route(LOCATION);
- # Reformat US Based RURI's into a canonical format of 10 digits
- #route(REFORMATRURI);
- # route the call to the next hop
- route(NEXTHOP);
- }
- route[HANDLE_CANCEL] {
- if (is_method("CANCEL")) {
- if (t_check_trans()) {
- route(RELAY);
- }
- exit;
- }
- }
- route[HANDLE_RETRANS] {
- if (t_precheck_trans()) {
- t_check_trans();
- exit;
- }
- t_check_trans();
- }
- route[DMQ] {
- #!ifdef WITH_DMQ
- if ($rm == "KDMQ" && $rp == DMQ_PORT) {
- dmq_handle_message();
- exit;
- }
- #!else
- return;
- #!endif
- }
- route[REFORMATRURI] {
- xlog("L_DBG", "[REFORMATRURI] <$ci> original rU <$rU> and original tU <$tU>\n");
- # This is to deal with those who are used to dialing 7 digits
- # assuming that the 7 digit number being dialed is in the same area code as the FROM number
- if ($(rU{s.len}) == 7) {
- if ($(fU{s.len}) == 10) {
- $rU = $(fU{s.substr,0,3}) + $rU;
- }
- else {
- $rU = $(fU{s.substr,0,4}) + $rU;
- }
- $tU = $rU;
- }
- else if ($(rU{s.len}) > 10) {
- # Check for +1 and remove it from the RURI and the To header
- if ($(rU{s.substr,0,2}) == "+1") {
- $rU = $(rU{s.substr,2,0});
- $tU = $rU;
- }
- # Check for 1 and remove it from the RURI and the To header
- else if ($(rU{s.substr,0,1}) == "1") {
- $rU = $(rU{s.substr,1,0});
- $tU = $rU;
- }
- }
- xlog("L_DBG", "[REFORMATRURI] <$ci> modified rU <$rU> and modified tU <$tU>\n");
- }
- route[ENRICH_SIPHEADER] {
- if (!strempty($xavp(ra=>sipdomain))) {
- append_hf("X-SIPDOMAIN: $xavp(ra=>sipdomain)\r\n");
- }
- }
- # Route the call to the next hop, which can be a PBX or Carrier
- route[NEXTHOP] {
- ######################################
- # Endpoint to PBX via Domain Routing #
- ######################################
- # Route to a single PBX with PASS THRU AUTH (aka Acting as a Location Server only)
- if (isflagset(FLT_DOMAINROUTING) && !isflagset(FLT_EXTERNAL_AUTH)) {
- #Grab the value of the avp that contains the domain_pbx_ip.
- #This is where requests for that domain should be routed
- $rd = $(avp(domain_pbx_ip){s.select,0,:});
- $rp = $(avp(domain_pbx_ip){s.select,1,:});
- xlog("L_INFO", "[NEXTHOP-DOMAINROUTING] <$ci> should be routed to $rd:$rp\n");
- #We are going to pass this request on to the backend server
- record_route();
- #Fix NAT'd contact so that calls are routed back correctly when a BYE occurs
- #fix_nated_contact();
- #subst_hf("Contact", "/@.*;/@$si:$sp;/", "f");
- route(RELAY);
- exit;
- }
- #Route to one PBX using an algorithm with External Authentication
- #(aka We are acting as a Registration and Location Server)
- else if (isflagset(FLT_DOMAINROUTING) && isflagset(FLT_EXTERNAL_AUTH) && !is_method("REGISTER")) {
- xlog("L_INFO", "[NEXTHOP-DOMAINROUTING] <$ci> Routing for $fd via dispatcher set $avp(domain_dispatcher_set_id)\n");
- if (!strempty($avp(domain_dispatcher_set_id))) {
- #Set the algoritm to load balancing if not set
- if (strempty($avp(domain_dispatcher_alg))) {
- $avp(domain_dispatcher_alg)=4;
- }
- record_route();
- route(ENRICH_SIPHEADER);
- route(DISPATCHER_SELECT);
- route(RELAY);
- }
- exit;
- }
- #!ifdef WITH_DROUTE
- # Enrich inbound calls from carriers
- route(ENRICH_CARRIER_INBOUND);
- # Check if this is coming from carrier
- if (allow_source_address(FLT_CARRIER)) {
- # DEBUG:
- xlog("L_INFO", "[NEXTHOP] <$ci> The call coming from $si is from a carrier\n");
- # Route to PBX
- xlog("L_DBG", "[NEXTHOP-DROUTING] <$ci> Logic for routing to PBX\n");
- append_hf("P-hint: inbound\r\n");
- $avp(calltype) = "inbound";
- # don't overwrite fwding info if we already set it
- if (!isflagset(FLT_FAILOVER)) {
- route(SET_CALLFWD_INFO);
- }
- # don't overwrite dr_groupid if this is n'th time in this route
- if ($avp(dr_groupid) == $null) {
- # check for hard fwd, then set did and dr_groupid accordingly
- if ($avp(hardfwdinfo) != $null) {
- # allow DID to be unchanged
- if (!strempty($(avp(hardfwdinfo){s.select,0,,}))) {
- $rU = $(avp(hardfwdinfo){s.select,0,,});
- }
- $avp(dr_groupid) = $(avp(hardfwdinfo){s.select,1,,}{s.int});
- }
- # otherwise we are using inbound mapping rules
- else {
- $avp(dr_groupid) = FLT_INBOUND;
- }
- }
- # route based on rules in dr_rules table
- if (do_routing($avp(dr_groupid))) {
- # Check if routing to MSTeams
- if ($avp(dr_attrs) != $null) {
- $avp(dst_msteams_domain) = $(avp(dr_attrs){s.select,2,,});
- if ($(avp(dst_msteams_domain){s.len}) > 0) {
- record_route_preset("$avp(dst_msteams_domain):5061;transport=tls", "EXTERNAL_IP_ADDR:SIP_PORT");
- setbflag(FLB_DST_MSTEAMS);
- }
- }
- route(MAINTMODE_CHECK);
- #!ifdef WITH_SERVERNAT
- # Create a Record Route based on the destination network
- $var(local_subnet) = "INTERNAL_IP_NET";
- # Replace the dots with \.
- $var(local_subnet) = $(var(local_subnet){s.replace,.,\.});
- # Repace the 0 with .*
- $var(local_subnet) = $(var(local_subnet){s.replace,*,.*});
- if ($rd=~$var(local_subnet)) {
- record_route_advertised_address("INTERNAL_IP_ADDR");
- }
- else {
- record_route();
- }
- #!else
- record_route();
- #!endif
- # Set INVITE max lifetime to ensure Primary and Secondary PBX server feature works.
- $var(pbx_invite_timeout) = (int)$sel(cfg_get.server.pbx_invite_timeout);
- t_set_max_lifetime($var(pbx_invite_timeout), 0);
- route(RELAY);
- exit;
- }
- # No rules defined for the phone number
- else {
- xlog("L_WARN", "[NEXTHOP] <$ci> No rules defined for $rU coming from this carrier endpoint: $si\n");
- sl_reply("500", "No rules defined for number");
- }
- }
- else if (allow_source_address(FLT_PBX) || isflagset(FLT_PBX_AUTH) || allow_source_address(FLT_MSTEAMS)) {
- # DEBUG:
- xlog("L_INFO", "[NEXTHOP] <$ci> The call coming from $si is from a pbx\n");
- if (allow_source_address(FLT_MSTEAMS))
- setbflag(FLB_SRC_MSTEAMS);
- # Route to Carrier
- xlog("L_DBG", "[NEXTHOP-DROUTING] <$ci> Logic for routing to Carriers\n");
- append_hf("P-hint: outbound\r\n");
- $avp(calltype) = "outbound";
- #!ifdef WITH_LCR
- # LCR Routing
- # - route based on from prefix and to prefix
- # - match selection is similar to dRouting module from longest to shortest match
- # Logic Summary:
- # 1. iterate through htable matching entries starting with prefixes
- # 2. find diff between match and lookup (must be absolute value)
- # 3. if diff is less than previous overwrite match
- # 4. if a match is present attempt to set carrier group and relay
- # TODO:
- # we could store and iterate through all matches if we use dispatcher instead
- # this would allow failover in LCR Routing to shorter prefixes (if we wanted that)
- $var(lookup) = $(fU{s.unescape.user}) + "-" + $(tU{s.unescape.user});
- $avp(lcr_match_group) = $null;
- $var(lcr_match_diff) = 1000;
- $var(diff) = 1000;
- sht_iterator_start("iter", "tofromprefix");
- while(sht_iterator_next("iter")) {
- $var(regex) = $(shtitkey(iter){s.select,0,-}{re.subst,/(\+|\*|\#)/\\\1/g}) + "([0-9])*-" +
- $(shtitkey(iter){s.select,-1,-}{re.subst,/(\+|\*|\#)/\\\1/g}) + "([0-9])*";
- if ($var(lookup) =~ $var(regex)) {
- xlog("L_DBG", "[NEXTHOP-LCR] <$ci> LCR match on $shtitkey(iter)\n");
- $var(diff) = $(var(lookup){s.len}) - $(shtitkey(iter){s.len});
- # bitwise absolute value: ( mask = n>>31; (mask^n) - mask )
- # we are assuming 32 bit integers
- $var(mask) = $var(diff) >> 31;
- $var(diff) = ($var(mask) ^ $var(diff)) - $var(mask);
- if ($var(diff) < $var(lcr_match_diff)) {
- xlog("L_DBG", "[NEXTHOP-LCR] <$ci> LCR prefix closer match diff=$var(diff)\n");
- $avp(lcr_match_group) = $shtitval(iter);
- $var(lcr_match_diff) = $var(diff);
- }
- }
- }
- sht_iterator_end("iter");
- if ($avp(lcr_match_group) > 0) {
- $avp(carrier_groupid) = $avp(lcr_match_group);
- }
- else {
- $avp(carrier_groupid) = FLT_OUTBOUND;
- }
- #!else
- $avp(carrier_groupid) = FLT_OUTBOUND;
- #!endif
- if (do_routing($avp(carrier_groupid))) {
- $avp(dst_gwid) = $(avp(dr_attrs){s.select,0,,});
- $avp(dst_gwtype) = $(avp(dr_attrs){s.select,1,,});
- $avp(dst_gwgroupid) = $sht(gw2gwgroup=>$avp(dst_gwid));
- $var(original_rU) = $rU;
- # Checking if the carrier is using username/password auth
- if (uac_reg_request_to($avp(dst_gwgroupid), 0)) {
- xlog("L_INFO", "Found remote user [$fU]. username: $avp(auser)");
- }
- $rU = $var(original_rU);
- route(ENRICH_CARRIER_OUTBOUND);
- record_route();
- route(RELAY);
- exit;
- }
- # No rules defined for the phone number
- else {
- xlog("L_WARN", "[NEXTHOP] <$ci> No rules defined for $fu going to $tu\n");
- sl_reply("500", "No rules defined for number");
- }
- }
- else {
- sl_send_reply("407", "Proxy Authentication Required. Add the PBX or Carrier IP using GUI");
- }
- #!endif
- }
- # MaintMode Check - recursive function for checking if a number is in maintmode
- route[MAINTMODE_CHECK] {
- xlog("L_DBG", "[MAINTMODE_CHECK] <$ci> The request domain $rd before maintmode check\n");
- if ($sht(maintmode=>$rd)!=$null) {
- xlog("L_DBG", "[MAINTMODE_CHECK] <$ci> $rd is in maintenance mode\n");
- # The selected endpoint is in maintenance mode, try next endpoint
- # If there is only one endpoint then immmediately return Service not Available
- # Otherwise, select the next gateway and see if it is in maintenance mode
- if (!use_next_gw()) {
- xlog("L_DBG", "[MAINTMODE_CHECK] <$ci> $rd no other gateway\n");
- sl_send_reply("503", "Service not available");
- exit;
- }
- else {
- route(MAINTMODE_CHECK);
- }
- }
- }
- # TeleBlock routing
- route[TELEBLOCK] {
- # Only route if is PBX
- if (!allow_source_address(FLT_PBX)) {
- xlog("L_WARN", "[TELEBLOCK] <$ci> $si not in allowed addresses\n");
- return;
- }
- # TODO: This should be dynamic
- # Only route to teleblock if User-to-User header is present
- # if (!is_present_hf("User-to-User")) {
- # xlog("L_DBG", "[TELEBLOCK] <$ci> User-to-User header not found\n");
- # return;
- # }
- # Change source address to this proxy server
- $fu = "sip:" + $fU + "@" + $Ri + ":" + $Rp;
- # Send Invite to TeleBlock with header fields:
- # Number == To Username
- # CPN == From Username
- # BTN == Billing Number (optional)
- # Zipcode == US Postal Code (optional)
- # refkey == Record ID (optional)
- $ru = "sip:" + $rU + "@" + $sel(cfg_get.teleblock.gw_ip) + ":" + $sel(cfg_get.teleblock.gw_port);
- xlog("L_DBG", "[TELEBLOCK] <$ci> From Username: $fU\n");
- xlog("L_DBG", "[TELEBLOCK] <$ci> To Username: $tU\n");
- xlog("L_DBG", "[TELEBLOCK] <$ci> Request URI: $ru\n");
- # set failure route
- if (is_method("INVITE")) {
- t_on_failure("TELEBLOCK_FAILURE");
- }
- }
- failure_route[TELEBLOCK_FAILURE] {
- if (t_is_canceled()) {
- exit;
- }
- xlog("L_DBG", "[TELEBLOCK_FAILURE] <$ci> Processing reply for: $rU\n");
- # Check if a media server is setup for teleblock
- if (strempty($sel(cfg_get.teleblock.media_ip)) || strempty($sel(cfg_get.teleblock.media_port))){
- $avp(s:teleblock_media_enabled) = "0";
- }
- else {
- $avp(s:teleblock_media_enabled) = "1";
- }
- # interpret teleblock response
- if (t_check_status("499")) {
- $rU = $tU;
- if (do_routing(FLT_OUTBOUND)) {
- record_route();
- t_relay();
- }
- }
- else {
- xlog("L_DBG", "[TELEBLOCK_FAILURE] <$ci> Relaying to: $sel(cfg_get.teleblock.media_ip):$sel(cfg_get.teleblock.media_port)\n");
- if (t_check_status("403|433")) {
- if ($avp(s:teleblock_media_enabled) == "1") {
- # make sure media server can route back to kamailio
- record_route();
- $ru = "sip:" + $rU + "@" + $sel(cfg_get.teleblock.media_ip) + ":" + $sel(cfg_get.teleblock.media_port);
- if (!t_relay()) {
- t_reply("403", "Do-Not-Contact");
- }
- }
- else {
- if (!t_relay()) {
- t_reply("403", "Do-Not-Contact");
- }
- }
- }
- else {
- if ($avp(s:teleblock_media_enabled) == "1") {
- # make sure media server can route back to kamailio
- record_route();
- $ru = "sip:" + $rU + "@" + $sel(cfg_get.teleblock.media_ip) + ":" + $sel(cfg_get.teleblock.media_port);
- if (!t_relay()) {
- t_reply("500", "Connection Failure");
- }
- }
- }
- }
- exit;
- }
- # Wrapper for relaying requests
- route[RELAY] {
- # Enable the RTPEngine if required
- route(IS_RTPE_REQUIRED);
- # Check TeleBlock Blacklist
- #!ifdef WITH_TELEBLOCK
- # Check if Teleblock is enabled
- if ($sel(cfg_get.teleblock.gw_enabled) == 1)
- route(TELEBLOCK);
- #!endif
- # enable additional event routes for forwarded requests
- # - serial forking, RTP relaying handling, a.s.o.
- if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
- if (!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
- }
- if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
- if((sdp_get_line_startswith("$avp(active)", "a=inactive")) && !t_is_set("onreply_route")) {
- xlog("inactive-line: $avp(active)\n");
- t_on_reply("MANAGE_INACTIVE_SDP");
- }
- else if !t_is_set("onreply_route"){
- t_on_reply("MANAGE_REPLY");
- }
- }
- if (is_method("INVITE")) {
- if (!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
- }
- #!ifdef WITH_CALLLIMIT
- # Manage call limits for gwgroups
- # check if dst gwgroup could be an endpoint and set values for call limit checking
- # TODO: we only support checking dst gwgroup if drouting was used
- # we need to support other routing methods such as domain routing, dispatcher routing, etc..
- if ($avp(dr_attrs) != $null) {
- $avp(dst_gwid) = $(avp(dr_attrs){s.select,0,,});
- $avp(dst_gwtype) = $(avp(dr_attrs){s.select,1,,});
- $avp(dst_gwgroupid) = $sht(gw2gwgroup=>$avp(dst_gwid));
- }
- xlog("L_DBG", "[RELAY-CALLLIMIT] dst_gwtype: $avp(dst_gwtype), dst_gwid: $avp(dst_gwid), dst_gwgroupid: $avp(dst_gwgroupid) src_gwtype: $avp(src_gwtype), src_gwid: $avp(src_gwid), src_gwgroupid: $avp(src_gwgroupid)\n");
- # if src and dst gwgroup is the same only increment one call
- if (($avp(src_gwtype) == FLT_PBX) && ($avp(dst_gwtype) == FLT_PBX) && ($avp(src_gwgroupid) == $avp(dst_gwgroupid))) {
- $avp(gwgroups_equivalent) = 1;
- }
- else {
- $avp(gwgroups_equivalent) = 0;
- }
- if (($avp(src_gwtype) == FLT_PBX) || ($avp(gwgroups_equivalent) == 1)) {
- $var(limit) = $sht(calllimit=>$avp(src_gwgroupid));
- xlog("L_INFO", "[RELAY-CALLLIMIT] <$ci> Call limit for src endpoint group $avp(src_gwgroupid) is $var(limit)\n");
- if ($var(limit) != -1 && get_profile_size("gwgroup","$avp(src_gwgroupid)","$avp(size)")) {
- if ($avp(size) < $var(limit)) {
- set_dlg_profile("gwgroup","$avp(src_gwgroupid)");
- dlg_manage();
- }
- else {
- sl_reply("480","Over call limit");
- $avp(notification_type) = NOTIFICATION_OVERLIMIT;
- $avp(notification_gwid) = $avp(src_gwid);
- $avp(notification_gwgroupid) = $avp(src_gwgroupid);
- route(SEND_NOTIFICATION);
- exit;
- }
- }
- }
- if (($avp(dst_gwtype) == FLT_PBX) && ($avp(gwgroups_equivalent) == 0)) {
- $var(limit) = $sht(calllimit=>$avp(dst_gwgroupid));
- xlog("L_INFO", "[RELAY-CALLLIMIT] <$ci> Call limit for dst endpoint group $avp(dst_gwgroupid) is $var(limit)\n");
- if ($var(limit) != -1 && get_profile_size("gwgroup","$avp(dst_gwgroupid)","$avp(size)")) {
- if ($avp(size) < $var(limit)) {
- set_dlg_profile("gwgroup","$avp(dst_gwgroupid)");
- dlg_manage();
- }
- else {
- sl_reply("480","Over call limit");
- $avp(notification_type) = NOTIFICATION_OVERLIMIT;
- $avp(notification_gwid) = $avp(dst_gwid);
- $avp(notification_gwgroupid) = $avp(dst_gwgroupid);
- route(SEND_NOTIFICATION);
- exit;
- }
- }
- }
- #!endif
- # do accounting only for INVITE's
- if (is_method("INVITE")) {
- setflag(FLT_ACC);
- }
- xlog("L_INFO","[RELAY] <$ci> Attempting to route call to $ru\n");
- if (!t_relay()) {
- sl_reply_error();
- }
- exit;
- }
- # Per SIP request initial checks
- route[REQINIT] {
- # Enable tracing for SNGREP
- sip_trace();
- setflag(24);
- #!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 ((src_ip != myself) && !allow_source_address_group()) {
- if ($sht(ipban=>$si) != $null) {
- # ip is already blocked
- xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");
- exit;
- }
- if (!pike_check_req()) {
- xlog("L_ALERT", "[REQINIT] <$ci> pike blocking $rm from $fu (IP:$si:$sp)\n");
- $sht(ipban=>$si) = 1;
- exit;
- }
- }
- if ($ua =~ "friendly-scanner") {
- sl_send_reply("200", "OK");
- exit;
- }
- #!endif
- if (!mf_process_maxfwd_header("10")) {
- sl_send_reply("483","Too Many Hops");
- exit;
- }
- # Only reply to option messages if the endpoint or the carrier is defined
- if (is_method("OPTIONS") && allow_source_address_group()) {
- sl_send_reply("200","Keepalive");
- exit;
- }
- if (!sanity_check("1511", "7")) {
- xlog("L_WARN", "[REQINIT] <$ci> Malformed SIP message from $si:$sp\n");
- exit;
- }
- # request with no Username in RURI
- if ($rU == $null) && is_method("INVITE") {
- sl_send_reply("484","Address Incomplete");
- exit;
- }
- # Check the type of UAC
- if ($pr == "ws" || $pr == "wss"){
- setflag(FLT_SRC_WS);
- }
- else {
- setflag(FLT_SRC_SIP);
- }
- }
- # Handle requests within SIP dialogs
- route[WITHINDLG] {
- if (!has_totag()) return;
- # sequential request withing a dialog should
- # take the path determined by record-routing
- if (loose_route()) {
- route(DLGURI);
- if (is_method("REFER|SUBSCRIBE")) {
- # record routing for dialog-forming requests
- # INVITE | REFER | SUBSCRIBE --> RFC 4538, Section 1
- # and remove preloaded route headers
- remove_hf("Route");
- record_route();
- }
- #else
- if (is_method("BYE")) {
- # do accounting even if the transaction fails
- # we grab the gwgroup info from the initiating INVITE's record
- sql_xquery("kam", "select src_gwgroupid, dst_gwgroupid from acc where callid = '$ci' and method = 'INVITE' limit 1", "rb");
- if (!strempty($xavp(rb=>src_gwgroupid))) {
- $avp(src_gwgroupid) = $xavp(rb=>src_gwgroupid);
- $avp(dst_gwgroupid) = $xavp(rb=>dst_gwgroupid);
- }
- sql_result_free("rb");
- setflag(FLT_ACC);
- setflag(FLT_ACCFAILED);
- }
- else if (is_method("ACK")) {
- # ACK is forwarded statelessy
- xlog("L_DBG", "[WITHINDLG] <$ci> Method is: ACK|UPDATE\n");
- route(NATMANAGE);
- }
- else if (is_method("NOTIFY")) {
- # Add Record-Route for in-dialog NOTIFY as per RFC 6665.
- record_route();
- }
- route(RELAY);
- exit;
- }
- if (is_method("SUBSCRIBE") && uri == myself) {
- # in-dialog subscribe requests
- route(PRESENCE);
- exit;
- }
- if ( is_method("ACK|UPDATE|INVITE|BYE") ) {
- #!ifdef WITH_NAT
- if ( is_method("BYE|INVITE") ) {
- handle_ruri_alias();
- }
- #!endif
- if ( t_check_trans() ) {
- # no loose-route, but stateful ACK;
- # must be an ACK after a 487
- # or e.g. 404 from upstream server
- route(RELAY);
- exit;
- }
- else {
- # ACK without matching transaction. Try to route anyway - being optimistic
- # since it has at least a To Tag
- route(RELAY);
- exit;
- }
- }
- sl_send_reply("404","Not here");
- exit;
- }
- # Handle SIP registrations
- route[REGISTRAR] {
- if (!is_method("REGISTER"))
- return;
- # Set the device type if a WS device
- if (isflagset(FLT_SRC_WS))
- setbflag(FLB_WS_DEVICE);
- if (isflagset(FLT_NATS)) {
- setbflag(FLB_NATB);
- #!ifdef WITH_NATSIPPING
- # do SIP NAT pinging
- setbflag(FLB_NATSIPPING);
- #!endif
- }
- if (isflagset(FLT_PBX_AUTH)) {
- # Handle Register Event - We are now acting as a REGISTRAR.
- if (!save("location"))
- sl_reply_error();
- xlog("L_DBG","[REGISTRAR] <$ci> update the gwgroup $avp(src_gwgroupid) to use the register ip:port:transport of $su\n");
- # Remove the sip: from the front of the $su
- $var(su) = $(su{s.substr,4,0});
- sql_query("kam","select gwid from dr_gateways where address='$var(su)' and description like '%gwgroup:$avp(src_gwgroupid)%'","rb");
- if ($dbr(rb=>rows) == 0) {
- sql_query("kam","insert into dr_gateways values (null,9,'$var(su)',0,'','','name:autoregister,gwgroup:$avp(src_gwgroupid)')");
- sql_query("kam","update dr_gw_lists set gwlist=concat(LAST_INSERT_ID(),',',gwlist) where id=$avp(src_gwgroupid)");
- }
- jsonrpc_exec('{"jsonrpc": "2.0", "method": "drouting.reload", "id": 1}');
- sql_result_free("rb");
- exit;
- }
- if (isflagset(FLT_DOMAINROUTING) && !isflagset(FLT_EXTERNAL_AUTH)) {
- # Save the location, but DON'T send a 200 reply back.
- # Let the upstream PBX authenticate the UAC (aka endpont)
- if (!save("location", "0x02"))
- sl_reply_error();
- #Grab the value of the avp that contains the domain_pbx_ip.
- #This is where requests for that domain should be routed
- $var(rd) = $(avp(domain_pbx_ip){s.select,0,:});
- $var(rp) = $(avp(domain_pbx_ip){s.select,1,:});
- $rd = $var(rd);
- $rp = $var(rp);
- #Rewrite Contact based on the domain being routed to
- #sips:[email protected];rtcweb-breaker=no;transport=wss
- if ( subst_hf("Contact", "/(.*)?<(sips?):([0-9]+)@(.*)/<\2:\3@$fd>/", "f") ) {
- xlog("L_INFO", "[REGISTRAR] <$ci> changed contact to match From domain\n");
- msg_apply_changes();
- };
- if (isbflagset(FLB_WS_DEVICE)) {
- add_path();
- }
- else {
- #Add the Path header for SIP UAC's - so that we know how to route back
- add_path_received($fU);
- }
- #We are going to pass this request on to the backend server
- route(RELAY);
- exit;
- }
- else if (isflagset(FLT_DOMAINROUTING) && isflagset(FLT_EXTERNAL_AUTH)) {
- if (!save("location")) {
- sl_reply_error();
- }
- exit;
- }
- # #Forward the registration onto one of the servers in the cluster
- # if (!strempty($avp(domain_dispatcher_set_id))) {
- # if (!strempty($avp(domain_dispatcher_reg_alg))) {
- # #Set the registration algoritm
- # $avp(domain_dispatcher_alg)=$avp(domain_dispatcher_reg_alg);
- # }
- # else {
- # #Set the dispatcher algorthim to round robin by default
- # $avp(domain_dispatcher_alg)=4;
- # }
- #
- # route(DISPATCHER_SELECT);
- # route(RELAY);
- # }
- # exit;
- #}
- }
- route[UNREGISTER] {
- if (!is_method("REGISTER")) return;
- # Check if this is a Register Expire request
- if ($sel(contact.expires) == "0" ) {
- route(REGISTRAR);
- }
- }
- #route[UNREGISTER] {
- # if (!is_method("REGISTER")) return;
- #
- # # Check if this is a Register Expire request
- # if ($sel(contact.expires) == "0" ) {
- #
- # unregister("location","$tu");
- # xlog("L_DBG", "[UNREGISTER] <$ci> Unregistering $su\n");
- #
- # # Remove from dr_routing module
- # $var(su) = $(su{s.substr,4,0});
- #
- # if (sql_xquery("kam","select gwid from dr_gateways where address='$var(su)'","ra") == 1) {
- # xlog("L_DBG","[UNREGISTER] <$ci> num of rows: $sqlrows(kam)\n");
- #
- # while($xavp(ra) != $null) {
- # # Get the Gateway Group ID
- # if (sql_xquery("kam","select id from dr_gw_lists where gwlist like '%$xavp(ra=>gwid)%'","rb") == 1) {
- # while($xavp(rb) != $null) {
- # xlog("L_DBG","[UNREGISTER] <$ci> gwgroupid: $xavp(rb=>id)\n");
- # # Remove gwid with from gwlist in dr_gw_lists
- # sql_query("kam","update dr_gw_lists set gwlist=TRIM(LEADING ',' FROM REGEXP_REPLACE(gwlist, '([,\s])?$xavp(ra=>gwid)', '')) where id=$xavp(rb=>id)");
- # # Delete the gateway
- # sql_query("kam","delete from dr_gateways where address='$var(su)'");
- # pv_unset("$xavp(rb)");
- # }
- # }
- # pv_unset("$xavp(ra)");
- # }
- # jsonrpc_exec('{"jsonrpc": "2.0", "method": "drouting.reload", "id": 1}');
- # }
- #
- # sl_send_reply("200","OK");
- # exit();
- # }
- #}
- # Dispatcher request load balancing (we don't route here)
- route[DISPATCHER_SELECT] {
- # round robin dispatching on dispatcher gateways set
- if (!ds_select_dst($avp(domain_dispatcher_set_id),$avp(domain_dispatcher_alg))) {
- xlog("L_INFO", "[DISPATCHER_SELECT] <$ci> no destination selected for domain: $fd\n");
- send_reply("404", "No destination");
- exit;
- }
- if (strempty($xavp(dispatcher_dst>uri)) && $avp(domain_dispatcher_alg) == 12)
- xlog("L_DBG", "[DISPATCHER_SELECT] <$ci> sending to multiple servers in parallel\n");
- else if (!strempty($xavp(dispatcher_dst>uri)))
- xlog("L_DBG", "[DISPATCHER_SELECT] <$ci> dispatcher selected $xavp(dispatcher_dst>uri)\n");
- t_on_failure("DISPATCHER_NEXT");
- return;
- }
- failure_route[DISPATCHER_NEXT] {
- # try next destionations in failure route
- if (t_is_canceled()) {
- exit;
- }
- # next DST - only for 500 or local timeout
- if (t_check_status("4[0-9][0-9]|5[0-9][0-9]") or (t_branch_timeout() and !t_branch_replied())) {
- if (ds_next_dst()) {
- xlog("L_DBG", "[DISPATCHER_NEXT] <$ci> dispatcher selected $xavp(dispatcher_dst>uri)\n");
- t_on_failure("DISPATCHER_NEXT");
- t_reset_retr();
- route(RELAY);
- return;
- }
- else {
- # Drop the replies if this is a REGISTER
- if (is_method('REGISTER')) {
- t_drop_replies();
- t_reply("401", "Unauthorized");
- }
- }
- }
- }
- # User location service
- route[LOCATION] {
- # Return immediately if the source address if not a PBX. Only PBX's should be trying to route to endpoints
- if !(allow_source_address(FLT_PBX))
- return;
- # Emergency calls should return immediately so that it can be routed to a carrier
- # The regular expression will call the North American (911), UK(999) and any number in between
- if ($rU=~"^9[1-9][1-9]$")
- return;
- # Return if the rU is more then local calling maximum digits for the initiating PBX
- if ($(rU{s.len}) > $sel(cfg_get.server.pbx_max_local_digits))
- return;
- $avp(oexten) = $rU;
- # Lookup the location of the endpoint by username@from_domain
- if (!lookup("location","sip:$rU@$rd")) {
- $var(rc) = $rc;
- route(TOVOICEMAIL);
- t_newtran();
- switch ($var(rc)) {
- case -1:
- case -3:
- send_reply("404", "Not Found");
- exit;
- case -2:
- send_reply("405", "Method Not Allowed");
- exit;
- }
- }
- if ($rU == "2000") {
- if (isflagset(FLB_WS_DEVICE))
- $var(WS_DEVICE)=1;
- else
- $var(WS_DEVICE)=0;
- xlog("L_INFO","[LOCATION] ru: $ru, nh(u): $nh(u), WS:$var(WS_DEVICE)");
- }
- # when routing via usrloc, log the missed calls also
- if (is_method("INVITE")) {
- setflag(FLT_ACCMISSED);
- }
- #Set the INVITE timeout for sending calls to invites
- t_set_fr(120000,10000);
- #Add record_route to ensure that extensions know how to route back thru the proxy
- record_route();
- route(RELAY);
- exit;
- }
- # Presence server processing
- route[PRESENCE] {
- if (!is_method("PUBLISH|SUBSCRIBE"))
- return;
- if (is_method("SUBSCRIBE") && $hdr(Event)=="message-summary") {
- route(TOVOICEMAIL);
- # returns here if no voicemail server is configured
- sl_send_reply("404", "No voicemail service");
- exit;
- }
- #!ifdef WITH_PRESENCE
- if (!t_newtran()) {
- sl_reply_error();
- exit;
- }
- if (is_method("PUBLISH")) {
- handle_publish();
- t_release();
- }
- else if (is_method("SUBSCRIBE")) {
- handle_subscribe();
- t_release();
- }
- exit;
- #!endif
- # if presence enabled, this part will not be executed
- if (is_method("PUBLISH") || $rU==$null) {
- sl_send_reply("404", "Not here");
- exit;
- }
- return;
- }
- # IP authorization and user authentication
- route[AUTH] {
- #!ifdef WITH_AUTH
- # AUTH route logic summary:
- # 1) attempt domain auth
- # 2) Check if request is coming from a carrier that's using username/password auth (remote or local)
- # 3) attempt IP auth
- # 4) attempt username/password auth against local subscriber database
- ###############
- # Domain AUTH #
- ###############
- # Check if this is any type of SIP request from a known domain only if the role of the server is not "inout".
- # The role of "inout" means that the role of this Kamailio instance is to just route calls inbound and outbound
- # using only IP auth or username/password auth
- if (lookup_domain("$fd", "domain_") && ($sel(cfg_get.server.role) != 'inout')) {
- # Turn on domain routing by setting the FLT_DOMAINROUTING flag
- setflag(FLT_DOMAINROUTING);
- if (!strempty($avp(domain_pbx_ip))) {
- # If the domain is mapped to single PBX then route to the PBX IP for authentication
- setflag(FLT_PASSTHRU_AUTH);
- xlog("L_INFO", "[AUTH-DOMAIN_AUTH] <$ci> $tU@$fd will be routed to $avp(domain_pbx_ip)\n");
- return;
- }
- #Check if the domain is configured to route to a cluster of PBX's by checking if the dispatcher set_id is set
- #If so, we need to auth the user against an external database or local subscriber database
- #This will allow INVITE requests to be sent to any backend PBX's because we have validated the user
- #Hence, the backend PBX's should be setup only to trust SIP connections from dSIPRouter instances
- else if (!strempty($avp(domain_dispatcher_set_id))) {
- if (is_method("REGISTER|INVITE") || from_uri==myself) {
- # Each domain has a auth type thats external to the backend destination server
- # 1 = Kamailo Subscriber table
- # 2 = Asterisk DB
- setflag(FLT_EXTERNAL_AUTH);
- xlog("L_INFO", "[AUTH-DOMAIN_AUTH] <$ci> Generic Domain Routing for $tU@$fd - the defined auth type for $fd is $avp(domain_domain_auth)\n");
- if ($avp(domain_domain_auth) == "realtime") {
- xlog("L_INFO","[AUTH-DOMAIN_AUTH] <$ci> Asterisk Realtime auth is being used\n");
- # Load data needed for custom SIP headers
- if ($avp(domain_enrich_headers) == 1)
- $var(query) = "select sippasswd,sipdomain from sipusers where name=$fU";
- else
- $var(query) = "select sippasswd from sipusers where name=$fU";
- #Let's auth against the database defined by the domain attributes
- sql_xquery("asterisk","$var(query)","ra");
- xlog("L_DBG","[AUTH: DOMAIN AUTH]: The password for user $fU@$fd is $xavp(ra=>sippasswd)\n");
- if (!pv_auth_check("$fd", "$xavp(ra=>sippasswd)", "2","0")) {
- auth_challenge("$fd", "0");
- exit;
- }
- }
- if ($avp(domain_domain_auth) == "local") {
- xlog("L_INFO", "[AUTH-DOMAIN_AUTH] <$ci> Local auth is being used\n");
- if (!auth_check("$fd", "subscriber", "3")) {
- auth_challenge("$fd", "0");
- exit;
- }
- }
- }
- # user authenticated - remove auth header
- if (!is_method("REGISTER|PUBLISH")) {
- xlog("L_INFO", "[AUTH-DOMAIN_AUTH] <$ci> $tU@$fd was authenticated\n");
- consume_credentials();
- }
- return;
- }
- }
- #!ifdef WITH_IPAUTH
- # If domain not known, then check IP AUTH to see if the user if allowed to connect
- # Changed from allow_source_address to allow_source_addess_group because it will allow any addresses within any address group.
- # This means that both carriers and pbx's will be allowed to access the proxy with one function call
- if ((!is_method("REGISTER")) && allow_source_address_group()) {
- # source IP allowed
- route(SET_CALLINFO);
- return;
- }
- #!endif
- if (is_method("REGISTER|INVITE") || from_uri==myself) {
- # authenticate requests
- if (!auth_check("$fd", "subscriber", "3")) {
- auth_challenge("$fd", "0");
- exit;
- }
- # user authenticated - remove auth header
- if (!is_method("REGISTER|PUBLISH")) {
- consume_credentials();
- }
- # Set a flag denoting that a PBX has authenticated with username/password
- setflag(FLT_PBX_AUTH);
- route(SET_CALLINFO);
- }
- #!endif
- return;
- }
- route[SET_CALLINFO] {
- # defaults to null
- $avp(src_gwid) = $null;
- $avp(src_gwtype) = $null;
- $avp(src_gwgroupid) = $null;
- # Set call info for tracking call limits for username/pass auth
- if (isflagset(FLT_PBX_AUTH)) {
- sql_xquery("kam","select rpid as gwgroupid from subscriber where username='$au'","rb");
- if (!strempty($xavp(rb=>gwgroupid))) {
- sql_xquery("kam","select gwid from dr_gateways where address = '$si:$sp'","rc");
- if (!strempty($xavp(rc=>gwid))) {
- $avp(src_gwid) = $xavp(rc=>gwid);
- }
- $avp(src_gwtype) = FLT_PBX;
- $avp(src_gwgroupid) = $xavp(rb=>gwgroupid);
- xlog("L_INFO", "[SET_CALLINFO] <$ci> user/pass - gwgroupid: $avp(src_gwgroupid), gatewaytype: $avp(src_gwtype)\n");
- sql_result_free("rc");
- }
- }
- # Set call info for tracking call limits for ip auth
- else {
- sql_xquery("kam","select type, gwid from dr_gateways where address like '$si%'","rb");
- if (!strempty($xavp(rb=>gwid))) {
- $avp(src_gwid) = $xavp(rb=>gwid);
- $avp(src_gwtype) = $xavp(rb=>type);
- $avp(src_gwgroupid) = $sht(gw2gwgroup=>$avp(src_gwid));
- xlog("L_INFO", "[SET_CALLINFO] <$ci> ip auth - gwgroupid: $avp(src_gwgroupid), gatewaytype: $avp(src_gwtype)\n");
- }
- }
- # dst gateway info is unknown until routed
- $avp(dst_gwid) = $null;
- $avp(dst_gwtype) = $null;
- $avp(dst_gwgroupid) = $null;
- $avp(inbound_gwgroupid) = $null;
- # set call forwarding info to null by default
- $avp(hardfwdinfo) = $null;
- $avp(failfwdinfo) = $null;
- sql_result_free("rb");
- return;
- }
- # TODO: we should avoid recreating the drouting algo here and instead check hardfwd and failfwd dr_group by default
- # drouting would be called 3 times by default in this case, satisfying the following logic:
- # 1. check hardfwd dr_group for prefix matches
- # 2. check default dr_group for prefix matches (pbx or carrier)
- # 3. check failfwd dr_group for prefix matches
- # this would avoid prefix match prediction as we do below and support time criteria by default
- route[SET_CALLFWD_INFO] {
- # we need to know what prefix drouting will match before it runs
- # this only checks against inbound rules, this shouldn't be used for outbound
- # TODO: this algorithm ignores time criteria of the dr_rule
- # which could lead to false positives if using this setting in drouting
- $avp(dr_ruleid) = $null; # dr_ruleid matched
- $var(prefix_match_diff) = 1000; # last match prefix diff
- $var(diff) = 1000; # current entry prefix diff
- $var(prefix_match_priority) = 0; # last match priority
- $var(priority) = 0; # current entry priority
- $var(lookup) = $(rU{s.unescape.user}); # dnid to match against
- sht_iterator_start("iter", "inbound_prefixmap");
- while(sht_iterator_next("iter")) {
- # TODO: for now we use a literal prefix but we should change to supporting patterns
- # this would require updating drouting module to support pattern matching
- $var(regex) = $(shtitkey(iter){re.subst,/(\+|\*|\#)/\\\1/g}) + "([0-9])*";
- if ($var(lookup) =~ $var(regex)) {
- xlog("L_DBG", "[SET_CALLFWD_INFO] <$ci> prefix match on $shtitkey(iter)\n");
- # if priority is less than last match we don't update match
- $var(priority) = $(shtitval(iter){s.select,1,,}{s.int});
- if ($var(priority) >= $var(prefix_match_priority)) {
- # get the difference between prefix and match
- $var(diff) = $(var(lookup){s.len}) - $(shtitkey(iter){s.len});
- # bitwise absolute value: ( mask = n>>31; (mask^n) - mask )
- # we are assuming 32 bit integers
- $var(mask) = $var(diff) >> 31;
- $var(diff) = ($var(mask) ^ $var(diff)) - $var(mask);
- # if priority is greater than last match or priority is equal and
- # diff is less than last match (closer match) we update match
- if ($var(priority) > $var(prefix_match_priority) || $var(diff) < $var(prefix_match_diff)) {
- xlog("L_DBG", "[SET_CALLFWD_INFO] <$ci> prefix closer match priority=$var(priority) diff=$var(diff)\n");
- $avp(dr_ruleid) = $(shtitval(iter){s.select,0,,});
- $var(prefix_match_priority) = $var(priority);
- $var(prefix_match_diff) = $var(diff);
- }
- }
- }
- }
- sht_iterator_end("iter");
- if ($avp(dr_ruleid) != $null) {
- $avp(hardfwdinfo) = $sht(inbound_hardfwd=>$avp(dr_ruleid));
- $avp(failfwdinfo) = $sht(inbound_failfwd=>$avp(dr_ruleid));
- }
- return;
- }
- # Caller NAT detection
- route[NATDETECT] {
- #!ifdef WITH_NAT
- if (nat_uac_test("19")) {
- if (isflagset(FLT_SRC_SIP))
- #fix_nated_contact();
- force_rport();
- if (is_method("REGISTER") && isflagset(FLT_SRC_WS)) {
- t_on_reply("WS_REPLY");
- fix_nated_register();
- }
- else
- fix_nated_register();
- #else {
- # if (is_first_hop()) {
- # set_contact_alias();
- # }
- #}
- setflag(FLT_NATS);
- }
- #!endif
- #!ifdef WITH_SERVERNAT
- setflag(FLT_NATS);
- #!endif
- return;
- }
- route[SERVERNATDETECT] {
- #!ifdef WITH_SERVERNAT
- # Detect if Kamailio is configured behind NAT
- if ("INTERNAL_IP_ADDR" != "EXTERNAL_IP_ADDR") {
- setflag(FLT_SERVERNAT);
- }
- else {
- return;
- }
- # If so, calculate the Local Subnet
- #Build a regular expression for figuring out if the request is going towards a local machine
- $var(local_subnet) = "INTERNAL_IP_NET";
- # Replace the dots with \.
- $var(local_subnet) = $(var(local_subnet){s.replace,.,\.});
- # Replace the 0 with .*
- $avp(local_subnet) = $(var(local_subnet){s.replace,*,.*});
- #!endif
- return;
- }
- route[IS_RTPE_REQUIRED] {
- # Sets the flag to show if RTPEngine is required
- if (isbflagset(FLB_WS_DEVICE) || isbflagset(FLB_SRC_MSTEAMS) || isbflagset(FLB_DST_MSTEAMS)) {
- # WebRTC destination or MSTEAMS source
- setflag(FLT_USE_RTPE);
- }
- else if (allow_source_address(FLT_MSTEAMS)) {
- setbflag(FLB_SRC_MSTEAMS);
- setflag(FLT_USE_RTPE);
- }
- else if (isflagset(FLT_SRC_SIP)) {
- # Turn on NAT if behind NAT
- # Check SDP for rfc1918 addresses - some natted SIP user devices need RTPEngine
- #if (nat_uac_test("8") || isbflagset(FLT_NATS))
- setflag(FLT_USE_RTPE);
- }
- else {
- setflag(FLT_USE_RTPE);
- }
- }
- route[RTPENGINEOFFER] {
- if (isflagset(FLT_SRC_WS) && isbflagset(FLB_WS_DEVICE)) {
- # - Web to web
- $var(reflags) = "trust-address replace-origin replace-session-connection SDES-off ICE=force";
- }
- else if (isflagset(FLT_SRC_WS)) {
- # - Web to SIP
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-demux ICE=remove RTP/AVP";
- }
- else if (isbflagset(FLB_WS_DEVICE)) {
- # - SIP to web
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-offer ICE=force transcode-PCMU transcode-G722 SDES-off UDP/TLS/RTP/SAVP";
- }
- else if (isbflagset(FLB_SRC_MSTEAMS)) {
- # - MSTEAMS to SIP using RTP/AVP
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-offer ICE=remove RTP/AVP";
- }
- else if (isbflagset(FLB_DST_MSTEAMS)) {
- # - SIP to MSTEAMS
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-offer ICE=force transcode-PCMU transcode-G722 RTP/SAVP";
- }
- else {
- # - SIP to SIP
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-demux ICE=remove RTP/AVP";
- }
- rtpengine_offer("$var(reflags)");
- }
- route [RTPENGINEANSWER] {
- if (isflagset(FLT_SRC_WS) && isbflagset(FLB_WS_DEVICE)) {
- $var(reflags) = "trust-address replace-origin replace-session-connection SDES-off ICE=force";
- }
- else if (isflagset(FLT_SRC_WS)) {
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-require ICE=force RTP/SAVPF";
- }
- else if (isbflagset(FLB_DST_MSTEAMS)) {
- # - MSTEAMS to SIP using RTP/AVP
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-offer ICE=remove RTP/AVP";
- }
- else if (isbflagset(FLB_SRC_MSTEAMS)) {
- # - SIP to MSTEAMS
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-require ICE=remove SDES-off RTP/SAVP";
- #$var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-offer ICE=force SDES-off RTP/SAVP";
- }
- else {
- # - SIP to SIP
- $var(reflags) = "trust-address replace-origin replace-session-connection rtcp-mux-demux ICE=remove RTP/AVP";
- }
- rtpengine_answer("$var(reflags)");
- }
- # RTPProxy control and signaling updates for NAT traversal
- route[NATMANAGE] {
- #!ifdef WITH_NAT
- if (is_request()) {
- if (has_totag() && check_route_param("nat=yes")) {
- setbflag(FLB_NATB);
- }
- }
- else if (has_body("application/sdp") && is_reply()) {
- if (nat_uac_test("8")) {
- fix_nated_sdp("10");
- setflag(FLB_NATB);
- }
- }
- if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB)))
- return;
- if (is_request()) {
- if (!has_totag()) {
- if(t_is_branch_route()) {
- add_rr_param(";nat=yes");
- }
- }
- }
- if (is_reply()) {
- if(isbflagset(FLB_NATB)) {
- if(is_first_hop())
- set_contact_alias();
- }
- }
- return;
- #!endif
- }
- # URI update for dialog requests
- route[DLGURI] {
- #!ifdef WITH_NAT
- if(!isdsturiset()) {
- handle_ruri_alias();
- }
- #!endif
- return;
- }
- # Routing to foreign domains
- route[SIPOUT] {
- if (uri==myself) return;
- append_hf("P-hint: outbound\r\n");
- route(RELAY);
- exit;
- }
- # PSTN GW routing
- route[PSTN] {
- #!ifdef WITH_PSTN
- # check if PSTN GW IP is defined
- if (strempty($sel(cfg_get.pstn.gw_ip))) {
- xlog("L_ERR", "[PSTN] <$ci> pstn routing enabled but pstn.gw_ip not defined\n");
- return;
- }
- # route to PSTN dialed numbers starting with '+' or '00' (international format)
- # - update the condition to match your dialing rules for PSTN routing
- if (!($rU=~"^(\+|00)[1-9][0-9]{3,20}$"))
- return;
- # only local users allowed to call
- if (from_uri!=myself) {
- sl_send_reply("403", "Not Allowed");
- exit;
- }
- if (strempty($sel(cfg_get.pstn.gw_port))) {
- $ru = "sip:" + $rU + "@" + $sel(cfg_get.pstn.gw_ip);
- }
- else {
- $ru = "sip:" + $rU + "@" + $sel(cfg_get.pstn.gw_ip) + ":"
- + $sel(cfg_get.pstn.gw_port);
- }
- route(RELAY);
- exit;
- #!endif
- return;
- }
- # XMLRPC routing
- #!ifdef WITH_XMLRPC
- route[XMLRPC] {
- # allow XMLRPC from localhost
- if ((method=="POST" || method=="GET") && (src_ip==127.0.0.1)) {
- # 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;
- }
- #!endif
- # Routing to voicemail server
- route[TOVOICEMAIL] {
- #!ifdef WITH_VOICEMAIL
- if (!is_method("INVITE|SUBSCRIBE"))
- return;
- # check if VoiceMail server IP is defined
- if (strempty($sel(cfg_get.voicemail.srv_ip))) {
- xlog("L_ERR", "[TOVOICEMAIL] <$ci> VoiceMail routing enabled but IP not defined\n");
- return;
- }
- if (is_method("INVITE")) {
- if ($avp(oexten)==$null)
- return;
- $ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
- + ":" + $sel(cfg_get.voicemail.srv_port);
- }
- else {
- if ($rU==$null)
- return;
- $ru = "sip:" + $rU + "@" + $sel(cfg_get.voicemail.srv_ip)
- + ":" + $sel(cfg_get.voicemail.srv_port);
- }
- route(RELAY);
- exit;
- #!endif
- return;
- }
- # ======================================================
- # Populate CDRs Table of Siremis
- # ======================================================
- route[CDRS] {
- sql_query("kam","call kamailio_cdrs()","rb");
- # we are not using billing features
- #sql_query("kam","call kamailio_rating('default')","rb");
- }
- # send async http request for notifications
- # required: $avp(notification_type)
- # required: $avp(notification_gwgroupid)
- # optional: $avp(notification_gwid)
- route[SEND_NOTIFICATION] {
- if ($avp(notification_type) != $null && $avp(notification_gwgroupid) != $null) {
- $http_req(method) = "POST";
- $http_req(hdr) = "User-Agent: http_async_client";
- $http_req(hdr) = "Authorization: Bearer " + $sel(cfg_get.server.api_token);
- $http_req(body) = '{"gwgroupid":' + $avp(notification_gwgroupid) + ', "type":' + $avp(notification_type) +
- ', "gwid":' + $avp(notification_gwid) + ', "text_body":"Gateway Group [' + $avp(notification_gwgroupid) +
- '] triggered the following notification for Gateway [' + $avp(notification_gwid) + ']"}';
- $http_req(suspend) = 0;
- xlog("L_INFO","[SEND_NOTIFICATION] <$ci> Sending request to $sel(cfg_get.server.api_server)/api/vi/notification/gwgroup for type $avp(notification_type)\n");
- http_async_query("$sel(cfg_get.server.api_server)/api/v1/notification/gwgroup", "HTTP_REPLY");
- }
- else {
- xlog("L_ERR", "[SEND_NOTIFICATION] <$ci> avp 'notification_type' and 'notification_gwgroupid' are required for notification sending\n");
- }
- $avp(notification_type) = $null;
- $avp(notification_gwgroupid) = $null;
- $avp(notification_gwid) = $null;
- }
- route[HTTP_REPLY] {
- if ($http_ok) {
- xlog("L_INFO", "[HTTP_REPLY] <$ci> status $http_rs\n");
- xlog("L_DBG", "[HTTP_REPLY] <$ci> body $http_rb\n");
- }
- else {
- xlog("L_ERR", "[HTTP_REPLY] <$ci> error $http_err)\n");
- }
- }
- event_route[uac:reply] {
- xlog("L_DBG", "[uac:reply] <$ci> Request sent to $uac_req(ruri) [$uac_req(evcode)]\n");
- }
- event_route[xhttp:request] {
- if ($hu =~ "^/api/kamailio" && dst_ip==127.0.0.1) {
- jsonrpc_dispatch();
- }
- #!ifdef WITH_WEBSOCKETS
- else if ($Rp == WSS_PORT ) {
- if ($hdr(Upgrade)=~"websocket" && $hdr(Connection)=~"Upgrade" && $rm=~"GET") {
- if (ws_handle_handshake()) {
- # Optional... cache some information about the
- # successful connection
- exit;
- }
- }
- }
- else {
- xhttp_reply("403", "Forbidden", "text/html",
- "<html><body>Will only communicate on the local interface or WebSocket Port WSS_PORT</body></html>");
- exit;
- }
- #!endif
- return;
- }
- #!ifdef WITH_MSTEAMS
- event_route[tm:local-request] {
- if(is_method("OPTIONS") && $ru =~ "pstnhub.microsoft.com") {
- #append_hf("Contact: <sip:EXTERNAL_FQDN:SIPS_PORT;transport=tls>\r\n");
- append_hf("Contact: <sip:$fd:SIPS_PORT;transport=tls>\r\n");
- xlog("L_DBG", "Sent out tm request: $mb\n");
- }
- }
- #!endif
- # Manage outgoing branches
- branch_route[MANAGE_BRANCH] {
- if (isbflagset(FLB_WS_DEVICE))
- $var(FLB_WS_DEVICE)=1;
- else
- $var(FLB_WS_DEVICE)=0;
- xdbg("new branch [$T_branch_idx] to $ru with WS:$var(FLB_WS_DEVICE)\n");
- #route(NATMANAGE);
- if (isflagset(FLT_USE_RTPE) && $rm=="INVITE" && has_body("application/sdp"))
- route(RTPENGINEOFFER);
- }
- # Manage incoming replies with a=inactive in SDP
- onreply_route[MANAGE_INACTIVE_SDP] {
- xlog("L_DBG","[MANAGE_INACTIVE_SDP_REPLY] In the reply\n");
- xdbg("incoming reply $si\n");
- if (remove_hf("Allow")){
- append_hf("Allow: INVITE,ACK,OPTIONS,CANCEL,BYE,NOTIFY\r\n");
- }
- # Rewrite the SDP on incoming replies
- if (t_check_status("183|180|200") && has_body("application/sdp")) {
- if(search_body("a=sendrecv")) {
- subst_body('/^a=sendrecv/a=inactive/');
- msg_apply_changes();
- }
- route(RTPENGINEANSWER);
- }
- if (t_check_status("100|180|181|183") && $avp(calltype) == "inbound") {
- # Increase the lifetime of the current INVITE to pbx_invite_timeout_aftertry if endpoint returns 100/180/181/183.
- # This means that the endpoint is at least trying to establish the call. So, we will extend the timeout.
- $var(pbx_invite_timeout) = (int)$sel(cfg_get.server.pbx_invite_timeout_aftertry);
- t_set_max_lifetime($var(pbx_invite_timeout), 0);
- xlog("L_DBG","[MANAGE_REPLY] Increasing the Invite Timeout for <$ci> to <$var(pbx_invite_timeout)>\n");
- }
- }
- # Manage incoming replies
- onreply_route[MANAGE_REPLY] {
- xdbg("incoming reply $si\n");
- if (remove_hf("Allow")){
- append_hf("Allow: INVITE,ACK,OPTIONS,CANCEL,BYE,NOTIFY\r\n");
- }
- # Rewrite the SDP on incoming replies
- if (t_check_status("183|180|200") && has_body("application/sdp")) {
- route(RTPENGINEANSWER);
- }
- ##!ifdef WITH_NAT
- # if (status=="200" && !allow_source_address(FLT_CARRIER)) {
- # fix_nated_contact();
- # }
- ##!endif
- # TODO: rewriting to external ip should be the default
- # we should only rewrite to internal on servernat
- #!ifdef WITH_SERVERNAT
- #TODO: Need to evaluate this when running in AWS with an External SIP UAC
- #if (status=="200" && allow_source_address(FLT_CARRIER)) {
- # subst_hf("Record-Route","/EXTERNAL_IP_ADDR/INTERNAL_IP_ADDR/","f");
- #}
- if (status=="200" && allow_source_address(FLT_PBX)) {
- subst_hf("Record-Route","/INTERNAL_IP_ADDR/EXTERNAL_IP_ADDR/","f");
- }
- #!endif
- #TODO: Marked for removal
- #if (status=~"[12][0-9][0-9]") {
- # Invoke NATMANAGE when it's not a UPDATE
- # if (!is_method("UPDATE")) {
- # route(NATMANAGE);
- # }
- #}
- if (t_check_status("100|180|181|183") && $avp(calltype) == "inbound") {
- # Increase the lifetime of the current INVITE to pbx_invite_timeout_aftertry if endpoint returns 100/180/181/183.
- # This means that the endpoint is at least trying to establish the call. So, we will extend the timeout.
- $var(pbx_invite_timeout) = (int)$sel(cfg_get.server.pbx_invite_timeout_aftertry);
- t_set_max_lifetime($var(pbx_invite_timeout), 0);
- xlog("L_DBG","[MANAGE_REPLY] Increasing the Invite Timeout for <$ci> to <$var(pbx_invite_timeout)>\n");
- }
- }
- # Manage failure routing cases
- failure_route[MANAGE_FAILURE] {
- route(NATMANAGE);
- if (t_is_canceled()) {
- exit;
- }
- if (t_branch_timeout()) {
- t_drop_replies();
- }
- if (t_check_status("401|407") && !strempty($avp(carrier_groupid))) {
- t_drop_replies();
- xlog("L_INFO", "[MANAGE_FAILURE-PROXY_AUTH] Remote asked for authentication");
- rtpengine_offer("ICE=remove");
- uac_auth();
- if (!t_relay()) {
- xlog("L_INFO", "[MANAGE_FAILURE-PROXY_AUTH] Authentication failed. Sending back 503 to UA");
- t_reply("503","Service not available");
- }
- exit;
- }
- # if using pass thru auth relay the reply
- if (t_check_status("401|407") && isflagset(FLT_PASSTHRU_AUTH)) {
- t_relay();
- exit;
- }
- #!ifdef WITH_DROUTE
- if (t_check_status("[0-6][0-9][0-9]")) {
- #!ifdef WITH_CALLLIMIT
- # Remove the existing call from the dialog before trying another gateway
- if (($avp(src_gwtype) == FLT_PBX) || ($avp(gwgroups_equivalent) == 1)) {
- unset_dlg_profile("gwgroup","$avp(src_gwgroupid)");
- }
- if (($avp(dst_gwtype) == FLT_PBX) && ($avp(gwgroups_equivalent) == 0)) {
- unset_dlg_profile("gwgroup","$avp(dst_gwgroupid)");
- }
- #!endif
- if (use_next_gw()) {
- # Set INVITE max lifetime to ensure Primary and Secondary PBX server feature works.
- if (allow_source_address(FLT_CARRIER)) {
- $var(pbx_invite_timeout) = (int)$sel(cfg_get.server.pbx_invite_timeout);
- t_set_max_lifetime($var(pbx_invite_timeout), 0);
- }
- route(RELAY);
- exit;
- }
- else {
- # Only intervene on a request from the Carrier
- if (allow_source_address(FLT_CARRIER)) {
- # check for failover fwd, then set did and dr_groupid accordingly
- if (($avp(failfwdinfo) != $null) && !isflagset(FLT_FAILOVER)) {
- # flag to make sure we don't loop endlessly
- setflag(FLT_FAILOVER);
- # allow DID to be unchanged
- if (!strempty($(avp(failfwdinfo){s.select,0,,}))) {
- $rU = $(avp(failfwdinfo){s.select,0,,});
- }
- $avp(dr_groupid) = $(avp(failfwdinfo){s.select,1,,}{s.int});
- route(NEXTHOP);
- }
- # none of the routes worked, send back error
- else {
- t_reply("503","Service not available");
- # we can only send notification if mapped to endpoint group
- if ($avp(src_gwtype) == FLT_PBX) {
- $avp(notification_type) = NOTIFICATION_GWFAILURE;
- $avp(notification_gwgroupid) = $avp(src_gwgroupid);
- $avp(notification_gwid) = $avp(src_gwid);
- route(SEND_NOTIFICATION);
- }
- else if ($avp(dst_gwtype) == FLT_PBX) {
- $avp(notification_type) = NOTIFICATION_GWFAILURE;
- $avp(notification_gwgroupid) = $avp(dst_gwgroupid);
- $avp(notification_gwid) = $avp(dst_gwid);
- route(SEND_NOTIFICATION);
- }
- }
- }
- exit;
- }
- }
- #!endif
- #!ifdef WITH_BLOCK3XX
- # block call redirect based on 3xx replies.
- if (t_check_status("3[0-9][0-9]")) {
- t_reply("404","Not found");
- exit;
- }
- #!endif
- #!ifdef WITH_VOICEMAIL
- # serial forking
- # - route to voicemail on busy or no answer (timeout)
- if (t_check_status("486|408")) {
- $du = $null;
- route(TOVOICEMAIL);
- exit;
- }
- #!endif
- }
- onreply_route[WS_REPLY] {
- if (nat_uac_test(64)) {
- # Do NAT traversal stuff for replies to a WebSocket connection
- # - even if it is not behind a NAT!
- # This won't be needed in the future if Kamailio and the
- # WebSocket client support Outbound and Path.
- add_contact_alias();
- }
- }
- # TODO: dynamically get user_tn / pilot_tn from user configs
- # Carrier Enrichment for CenturyLink
- # validated SIP carriers:
- # voip.centurylink.com
- # 65.149.22.7, 65.149.23.7, 65.149.24.7, 65.149.25.7
- # 216.206.64.7, 216.206.64.71, 216.206.64.91
- # 216.206.66.7, 216.206.66.71, 216.206.66.91
- route[ENRICH_CARRIER_CENTURYLINK_OUTBOUND] {
- $var(domain) = "voip.centurylink.com";
- $var(user_tn) = "6467687570";
- $var(pilot_tn) = "6467687572";
- if ($rd =~ "$var(domain).*|65.149.22.7.*|65.149.23.7.*|65.149.24.7.*|65.149.25.7.*|216.206.64.7.*|216.206.64.71.*|216.206.64.91.*|216.206.66.7.*|216.206.66.71.*|216.206.66.91.*") {
- xlog("L_INFO", "[ENRICH_CARRIER_CENTURYLINK] centurylink carrier match\n");
- $du = $ru;
- $rd = $var(domain);
- # Remove the port
- $rp = "";
- # Change the from and to domain to match the carrier domain name
- $td = $var(domain);
- $fd = $var(domain);
- # Uncomment this line if you need to change the from user to the user_tn
- #$fU = $var(user_tn);
- # Uncomment this line if you need to change the domain of the contact - this is not recommended
- #subst('/^Contact: <sip:([0-9]+)@(.*)$/Contact: <sip:\[email protected]>/ig')
- # Add P-Asserted-Identity per the carriers requirement
- append_hf("P-Asserted-Identity: <sip:$var(pilot_tn)@$var(domain)>\r\n");
- msg_apply_changes();
- }
- }
- route[ENRICH_CARRIER_SIGNALWIRE_INBOUND] {
- $var(domain) = ".+sip.signalwire.com";
- xlog("L_DBG", "[ENRICH_CARRIER_SIGNALWIRE] before transform:\n$mb\n");
- if ($td =~".+sip.signalwire.com") {
- xlog("L_INFO", "[ENRICH_CARRIER_SIGNALWIRE] signalwire carrier match\n");
- # Change the "request username" to "to username"
- $rU = $tU;
- msg_apply_changes();
- xlog("L_DBG", "[ENRICH_CARRIER_SIGNALWIRE] after transform:\n$mb\n");
- }
- }
- route[ENRICH_CARRIER_SIGNALWIRE_OUTBOUND] {
- $var(domain) = "sip.signalwire.com";
- $var(user) = $fU;
- xlog("L_DBG", "[ENRICH_CARRIER_SIGNALWIRE_OUTBOUND] before transform:\n$mb\n");
- if ($rd =~".+sip.signalwire.com") {
- xlog("L_INFO", "[ENRICH_CARRIER_SIGNALWIRE_OUTBOUND] signalwire carrier match\n");
- # Change the from domain to the request domain
- $fd = $rd;
- # Change the from user to the authenticated user
- $fU = $avp(auser);
- # Add the callerid
- append_hf("P-Asserted-Identity: <sip:$var(user)@$var(domain)>\r\n");
- msg_apply_changes();
- xlog("L_DBG", "[ENRICH_CARRIER_SIGNALWIRE_OUTBOUND] after transform:\n$mb\n");
- }
- }
- route[ENRICH_CARRIER_INBOUND] {
- route(ENRICH_CARRIER_SIGNALWIRE_INBOUND);
- }
- # Carrier Enrichment
- route[ENRICH_CARRIER_OUTBOUND] {
- route(ENRICH_CARRIER_CENTURYLINK_OUTBOUND);
- route(ENRICH_CARRIER_SIGNALWIRE_OUTBOUND);
- }
- ####### CUSTOM_ROUTING_START #########
- # add custom routes here
- ####### CUSTOM_ROUTING_END #########
Add Comment
Please, Sign In to add comment