#### Preprocessor Directives ######### #!define L_ALERT -5 #!define L_BUG -4 #!define L_CRIT2 -3 #!define L_CRIT -2 #!define L_ERR -1 #!define L_WARN 0 #!define L_NOTICE 1 #!define L_INFO 2 #!define L_DBG 3 #!define AVP_RECV_PARAM "recv_param" #!define AVP_LOG_LEVEL "log_level" #!define AVP_ROUTE_CNT "route_cnt" #!define AVP_ASSOCIATED_SERVER "associated_server" #!define AVP_ASSOCIATE_CONTACT "associate_contact" ####### Global Parameters ######### fork = yes children = 25 server_signature = no server_header = "Server: Kazoo" user_agent_header = "User-Agent: Kazoo" shm_force_alloc = yes mlock_pages = yes phone2tel = 1 max_while_loops = 500 ####### Logging Parameters ######### debug = L_INFO memdbg = 10 memlog = 10 corelog = L_ERR log_stderror = no log_facility = LOG_LOCAL0 log_name="kamailio" ####### Alias Parameters ######### auto_aliases = yes # alias = "mydomain.net" ####### Binding Parameters ######### listen = tcp:127.0.0.1:5060 listen = udp:127.0.0.1:5060 listen = tcp:127.0.0.1:5080 listen = udp:127.0.0.1:5080 listen = tcp:127.0.0.1:7000 listen = udp:127.0.0.1:7000 tos = IPTOS_LOWDELAY ## NOTE: Uncomment on a multihomed host # mhomed = 1 ####### TCP Parameters ######### tcp_children = 25 disable_tcp = no tcp_max_connections = 4096 tcp_connection_lifetime = 3605 tcp_accept_aliases = no tcp_async = yes tcp_connect_timeout = 10 tcp_conn_wq_max = 65536 tcp_crlf_ping = yes tcp_delayed_ack = yes tcp_fd_cache = yes tcp_keepalive = yes tcp_keepcnt = 3 tcp_keepidle = 30 tcp_keepintvl = 10 tcp_linger2 = 30 tcp_rd_buf_size = 4096 tcp_send_timeout = 10 tcp_wq_blk_size = 2100 tcp_wq_max = 10485760 ####### UDP Parameters ######### udp4_raw = -1 ## NOTE: You must MATCH this to your network adapter!! ## If they do not match, all UDP packets over ## this limit WILL FAIL! ## E.g.: Add MTU=1472 to the /etc/sysconfig/network-scripts/XXX # udp4_raw_mtu = 1472 ####### DNS Parameters ######### dns = no rev_dns = no dns_try_ipv6 = no use_dns_cache = on dns_cache_del_nonexp = no dns_cache_flags = 1 dns_cache_gc_interval = 120 dns_cache_init = 1 dns_cache_mem = 1000 dns_cache_negative_ttl = 60 dns_try_naptr = no use_dns_failover = off dns_srv_lb = off ####### TLS Parameters ######### enable_tls = yes ####### SCTP Parameters ######### disable_sctp = yes ####### Custom Parameters ######### ####### Modules Section ######## mpath="/usr/lib64/kamailio/modules/" ####### Flags ####### flags FLAG_INTERNALLY_SOURCED: 1, FLAG_ASSOCIATE_SERVER: 2, FLAG_SKIP_NAT_CORRECTION: 3, FLAG_ASSOCIATE_USER: 4; #!define FLB_NATB 1 #!define FLB_NATSIPPING 2 #!define FLB_UAC_REDIRECT 3 ######## Kamailio core extensions module ######## loadmodule "kex.so" ######## Transaction (stateful) module ######## loadmodule "tm.so" loadmodule "tmx.so" modparam("tm", "auto_inv_100", 1) modparam("tm", "auto_inv_100_reason", "Attempting to connect your call") modparam("tm", "cancel_b_method", 2) modparam("tm", "ruri_matching", 0) modparam("tm", "failure_reply_mode", 3) # modparam("tm", "fr_timer", 30000) # modparam("tm", "fr_inv_timer", 120000) ######## Stateless replier module ######## loadmodule "sl.so" ######## Record-Route and Route module ######## loadmodule "rr.so" modparam("rr", "enable_full_lr", 1) ######## Max-Forward processor module ######## loadmodule "maxfwd.so" ######## SIP utilities [requires sl] ######## loadmodule "siputils.so" ######## SIP message formatting sanity checks [requires sl] ######## loadmodule "sanity.so" # sip_version, scheme, req_headers, cseq_method/value # content_length, parse_uri, digest modparam("sanity", "default_checks", 3303) modparam("sanity", "uri_checks", 3) modparam("sanity", "autodrop", 0) ######## Text operations module ######## loadmodule "textops.so" loadmodule "textopsx.so" ######## Generic Hash Table container in shared memory ######## loadmodule "htable.so" modparam("htable", "htable", "associations=>size=10;") modparam("htable", "htable", "auth_cache=>size=10;") modparam("htable", "htable", "dbkp=>size=4;autoexpire=7200") ######## Pseudo-Variables module ######## loadmodule "pv.so" ######## Advanced logger module ######## loadmodule "xlog.so" ####### FIFO support for Management Interface ######## loadmodule "mi_fifo.so" modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo") ####### Dispatcher module ######## loadmodule "dispatcher.so" modparam("dispatcher", "list_file", "/etc/kazoo/kamailio/dispatcher.list") modparam("dispatcher", "flags", 2) modparam("dispatcher", "use_default", 0) modparam("dispatcher", "force_dst", 1) modparam("dispatcher", "dst_avp", "$avp(ds_dst)") modparam("dispatcher", "attrs_avp", "$avp(ds_attrs)") modparam("dispatcher", "grp_avp", "$avp(ds_grp)") modparam("dispatcher", "cnt_avp", "$avp(ds_cnt)") modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") # modparam("dispatcher", "setid_pvar", "$var(setid)") modparam("dispatcher", "ds_ping_method", "OPTIONS") modparam("dispatcher", "ds_ping_from", "sip:sipcheck@127.0.0.1") modparam("dispatcher", "ds_ping_interval", 10) # modparam("dispatcher", "ds_ping_sock", "udp:{{SIP_IP}}:{{SIP_PORT}}") modparam("dispatcher", "ds_probing_threshhold", 3) modparam("dispatcher", "ds_probing_mode", 1) modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") ######## UAC Redirection module ######## loadmodule "uac_redirect.so" ####### Authentication Interface module ########## loadmodule "auth.so" loadmodule "auth_db.so" modparam("auth_db", "use_domain", 1) modparam("auth_db", "version_table", 0) modparam("auth_db", "calculate_ha1", 1) modparam("auth_db", "password_column", "password") modparam("auth_db", "load_credentials", "$avp(password)=password") ####### User Location Implementation module ########## loadmodule "usrloc.so" modparam("usrloc", "db_mode", 1) modparam("usrloc", "db_update_as_insert", 1) modparam("usrloc", "use_domain", 1) modparam("usrloc", "nat_bflag", FLB_NATB) ####### SIP Registrar implementation module ########## loadmodule "registrar.so" ######## NAT Traversal module - signaling functions ######## loadmodule "nathelper.so" modparam("nathelper|registrar", "received_avp", "$avp(AVP_RECV_PARAM)") modparam("nathelper", "natping_interval", 30) modparam("nathelper", "ping_nated_only", 1) modparam("nathelper", "natping_processes", 5) modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) modparam("nathelper", "sipping_from", "sip:sipcheck@127.0.0.1") # modparam("nathelper", "natping_socket", "127.0.0.1:5060") ######## Presence User Agent module ######## loadmodule "pua_dialoginfo.so" modparam("pua_dialoginfo", "library_mode", 1) ######## Presence server module ######## loadmodule "presence.so" loadmodule "presence_dialoginfo.so" modparam("presence", "subs_db_mode", 1) modparam("presence", "expires_offset", 60) modparam("presence", "publ_cache", 0) ####### Kazoo Integration module ########## loadmodule "db_kazoo.so" # NOTE: The hostname that should be advertised to Kazoo modparam("db_kazoo", "node_hostname", "kamailio.2600hz.com") # If you want a certain fs_path to be sent Kazoo, uncomment the next line and set the right value # modparam("db_kazoo", "register_fs_path", "127.0.0.1:5060") ####### Common Module Parameters ########## modparam("auth_db|usrloc", "db_url", "kazoo://guest:guest@127.0.0.1:5672/callmgr") modparam("presence", "db_url", "kazoo://guest:guest@127.0.0.1:5672/dialoginfo") ####### Routing Logic ######## route { # log the basic info regarding this call xlog("L_INFO", "$ci|start|recieved $oP request $rm $ou"); xlog("L_INFO", "$ci|log|source $si:$sp"); xlog("L_INFO", "$ci|log|from $fu"); xlog("L_INFO", "$ci|log|to $tu"); route(SANITY_CHECK); route(CLASSIFY_SOURCE); route(HANDLE_OPTIONS); route(HANDLE_PRESENCE); route(HANDLE_IN_DIALOG_REQUESTS); route(PREPARE_INITIAL_REQUESTS); if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); exit(); } route(HANDLE_MOVE_REQUEST); route(FIND_ROUTES); $avp(route_attempts) = 1; route(EXTERNAL_TO_INTERNAL_RELAY); } route[SANITY_CHECK] { if (!mf_process_maxfwd_header("10")) { xlog("L_WARN", "$ci|end|max-forward limit reached"); sl_send_reply("483", "Too Many Hops"); exit; } if (!sanity_check()) { xlog("L_WARN", "$ci|end|message is insane"); exit; } } route[CLASSIFY_SOURCE] { if (ds_is_from_list("1") || ds_is_from_list("3")) { xlog("L_INFO", "$ci|log|originated from internal sources"); setflag(FLAG_INTERNALLY_SOURCED); } else { xlog("L_INFO", "$ci|log|originated from external sources"); } } route[HANDLE_OPTIONS] { if (is_method("OPTIONS")) { if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); } else { sl_send_reply("200", "Rawr!!"); } exit; } } route[HANDLE_PRESENCE] { if (is_method("SUBSCRIBE")) { if (!t_newtran()) { sl_reply_error(); exit; } handle_subscribe(); t_release(); exit; } if (is_method("PUBLISH")) { if (!t_newtran()) { sl_reply_error(); exit; } handle_publish(); t_release(); exit; } } route[HANDLE_IN_DIALOG_REQUESTS] { if (has_totag()) { if (loose_route()) { xlog("L_INFO", "$ci|log|loose_route in-dialog message"); # Called on in-dialog requests # If the request in an Invite for on hold from external to internal, # associate the contact with the media server # if Invite for on hold, we need to associate the contact URI with the next hop if (is_method("INVITE") && !isflagset(FLAG_INTERNALLY_SOURCED) && is_audio_on_hold()) { setflag(FLAG_ASSOCIATE_USER); } route(RELAY); } else if (isflagset(FLAG_INTERNALLY_SOURCED)) { xlog("L_INFO", "$ci|log|relay internally sourced in-dialog message without loose_route"); route(RELAY); } else if (t_check_trans()) { xlog("L_INFO", "$ci|log|allow message for a known transaction"); route(RELAY); } else { xlog("L_INFO", "$ci|log|message had a to-tag but can't be loose routed"); sl_send_reply("481", "Call Leg/Transaction Does Not Exist"); } exit(); } } route[PREPARE_INITIAL_REQUESTS] { if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } else { sl_send_reply("481", "Call Leg/Transaction Does Not Exist"); } exit(); } else if (is_method("ACK")) { if (t_check_trans()) { route(RELAY); } exit(); } t_check_trans(); if (loose_route()) { sl_send_reply("403", "No pre-loaded routes"); exit(); } if (is_method("REGISTER")) { if (nat_uac_test("3")) { xlog("L_INFO", "$ci|log|Correcting NATed contact in registration\n"); force_rport(); setbflag(FLB_NATB); setbflag(FLB_NATSIPPING); fix_nated_register(); } if (is_present_hf("Authorization")) { if ($sht(auth_cache=>$Au) != $null && pv_auth_check("$fd", "$sht(auth_cache=>$Au)", "0", "0")) { xlog("L_INFO", "$ci|log|Authenticated $Au via cached SIP creds\n"); } else { ## RABBITMQ - Credentials fetch if (!auth_check("$fd", "subscriber", "1")) { auth_challenge("$fd", "0"); xlog("L_INFO", "$ci|log|Issued new auth challenge to failed registration attempt\n"); exit; } else { xlog("L_INFO", "$ci|log|Caching SIP credentials for $Au\n"); $sht(auth_cache=>$Au) = $avp(password); } } } else { auth_challenge("$fd", "0"); xlog("L_INFO", "$ci|log|Issued new auth challenge to new registration attempt\n"); exit; } # user authenticated - remove auth header consume_credentials(); save("location"); exit; } else if (!is_method("MESSAGE")) { record_route(); } } # Take the routes from dispatcher - hash over callid # If prefered route defined, reorder the destionations route[FIND_ROUTES] { # alg 0 = hash(Callid) if (!ds_select_dst("1", "0")) { xlog("L_ERR", "$ci|end|no servers avaliable"); sl_send_reply("480", "All servers busy"); exit; } # Handle the case when a prefered route is set $var(contact_uri) = $(ct{tobody.user}) + "@" + $(ct{tobody.host}); if ($sht(associations=>$var(contact_uri)) != $null) { $var(prefered_route) = $sht(associations=>$var(contact_uri)); xlog("L_INFO", "$ci|log|should route to $var(prefered_route)"); route(REORDER_ROUTES); } } route[REORDER_ROUTES] { $var(i) = 0; $var(found) = 0; while($(avp(ds_dst)[$var(i)]) != $null) { if($(avp(ds_dst)[$var(i)]) != $var(prefered_route)) { $avp(tmp_ds_dst) = $(avp(ds_dst)[$var(i)]); } else { $var(found) = 1; } $var(i) = $var(i) + 1; } if ($var(found)) { xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to keep associated server first"); $(avp(ds_dst)[*]) = $null; $var(i) = 0; while($(avp(tmp_ds_dst)[$var(i)]) != $null) { $avp(ds_dst) = $(avp(tmp_ds_dst)[$var(i)]); $var(i) = $var(i) + 1; } $avp(ds_dst) = $var(prefered_route); $du = $var(prefered_route); $(avp(tmp_ds_dst)[*]) = $null; } else { xlog("L_INFO", "$ci|log|associated media server is inactive, moving to $rd"); $sht(associations=>$var(contact_uri)) = $null; } } route[HANDLE_MOVE_REQUEST] { if (is_method("INVITE") && $rU == "*6683*") { $var(contact_uri) = @from.uri.user + "@" + @from.uri.host; if ($sht(associations=>$var(contact_uri)) != $null) { xlog("L_INFO", "$ci|log|remove association for user $var(contact_uri) with media server $sht(associations=>$var(contact_uri))\n"); $sht(associations=>$var(contact_uri)) = $null; } send_reply("503", "Removed association"); xlog("L_INFO", "$ci|log|removed association for user $var(contact_uri) with media server $sht(associations=>$var(contact_uri))\n"); exit; } } route[RELAY] { if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); } else { route(EXTERNAL_TO_INTERNAL_RELAY); } exit(); } route[INTERNAL_TO_EXTERNAL_RELAY] { remove_hf("X-AUTH-IP"); t_on_reply("EXTERNAL_REPLY"); t_set_fr(0, 10000); t_relay(); } route[EXTERNAL_TO_INTERNAL_RELAY] { if (!isflagset(FLAG_INTERNALLY_SOURCED)) { route(NAT_TEST_AND_CORRECT); } remove_hf("X-AUTH-IP"); append_hf("X-AUTH-IP: $si\r\n"); t_on_reply("INTERNAL_REPLY"); t_on_failure("INTERNAL_FAULT"); t_set_fr(0, 1000); t_relay(); } route[LOG_DESTINATION] { if (isdsturiset()) { $var(port) = $dp; $var(domain) = $dd; } else { $var(port) = $rp; $var(domain) = $rd; } if ($(var(port){s.len}) <= 0) { $var(port) = "5060"; } xlog("L_INFO", "$ci|pass|$var(domain):$var(port)"); } route[NAT_TEST_AND_CORRECT] { if (is_present_hf("Record-Route")) { $var(i) = $rr_count; while($var(i) > 0) { $var(i) = $var(i) - 1; $var(rr) = $(hdr(Record-Route)[$var(i)]); if (!is_myself("$(var(rr){nameaddr.uri})")) { setflag(FLAG_SKIP_NAT_CORRECTION); } } } else if ($Rp == "5080") { setflag(FLAG_SKIP_NAT_CORRECTION); } if (isflagset(FLAG_SKIP_NAT_CORRECTION)) { return(); } if (nat_uac_test("3")) { force_rport(); fix_nated_contact(); } if (has_body("application/sdp") && nat_uac_test("8")) { fix_nated_sdp("10"); } } onreply_route[EXTERNAL_REPLY] { xlog("L_INFO", "$ci|log|external reply $T_reply_code"); route(NAT_TEST_AND_CORRECT); } onreply_route[INTERNAL_REPLY] { # this route handles replies that are comming from our media server xlog("L_INFO", "$ci|start|recieved internal reply $T_reply_code $rr"); xlog("L_INFO", "$ci|log|source $si:$sp"); if ($rs < 300) { xlog("L_INFO", "$ci|pass|$T_req($si):$T_req($sp)"); } # change 6xx to 4xx if (t_check_status("6[0-9][0-9]")) { $var(new_code) = "4" + $(T_reply_code{s.substr,1,0}); change_reply_status("$var(new_code)", "$rr"); } } failure_route[INTERNAL_FAULT] { # this branch handles failures (>=300) to our media servers, # which we can sometimes overcome by routing to another server # if the failure cause was due to the transaction being # cancelled then we are complete if (t_is_canceled()) { xlog("L_INFO", "$ci|log|transaction was cancelled"); exit; } # if the failure case was something that we should recover # from then try to find a new media server if (t_check_status("(401)|(407)")) { xlog("L_INFO", "$ci|log|failure route ignoring auth reply $T_reply_code $rr"); exit; } else if (t_check_status("403")) { xlog("L_INFO", "$ci|log|failure route overriding reply code 403 with 503"); xlog("L_INFO", "$ci|pass|$si:$sp"); send_reply("503", "Error: Services Unavailable. Try Later"); exit; } else if (t_check_status("402")) { xlog("L_INFO", "$ci|log|failure route overriding reply code 402 with 486"); xlog("L_INFO", "$ci|pass|$si:$sp"); send_reply("486", "Insufficient Funds"); exit; } else if (t_check_status("(4[0-9][0-9])|(5[0-9][0-9])")) { xlog("L_INFO", "$ci|start|received failure reply $T_reply_code $rr"); # try to find a new media server to send the call to if ($avp(route_attempts) < 3 && ds_next_domain()) { xlog("L_INFO", "$ci|log|attempting retry $avp(route_attempts) of failed request"); xlog("L_INFO", "$ci|log|routing call to next media server $rd:$rp"); # reset the final reply timer $avp(final_reply_timer) = 3; t_on_reply("INTERNAL_REPLY"); t_on_failure("INTERNAL_FAULT"); # relay the request to the new media server route(EXTERNAL_TO_INTERNAL_RELAY); $avp(route_attempts) = $avp(route_attempts) + 1; } else if (t_check_status("404")) { xlog("L_ERR", "$ci|log|no other media servers avaliable, sending 486"); send_reply("486", "Not found"); exit; } else { xlog("L_ERR", "$ci|log|no other media servers avaliable"); exit; } } else if (t_check_status("302")) { ## TODO - test this ## get_redirects("*"); if($T_rpl($hdr(X-Redirect-Server)) != $null) { $var(contact_uri) = @from.uri.user + "@" + @from.uri.host; $sht(associations=>$var(contact_uri)) = $T_rpl($hdr(X-Redirect-Server)); xlog("L_INFO", "$ci|log|stored redirect mapping for $var(contact_uri) to $T_rpl($hdr(X-Redirect-Server))"); remove_hf("X-Redirect-Server"); } } else { xlog("L_INFO", "$ci|log|failure route ignoring reply $T_reply_code $rr"); exit; } route(LOG_DESTINATION); } onsend_route { if (isflagset(FLAG_ASSOCIATE_USER)) { $var(contact_uri) = $(ct{tobody.user}) + "@" + $(ct{tobody.host}); xlog("L_INFO", "$ci|log|associate user $var(contact_uri) with media server sip:$sndto(ip):$sndto(port)\n"); $sht(associations=>$var(contact_uri))= "sip:" + $sndto(ip) + ":" + $sndto(port); } xlog("L_INFO", "$ci|pass|$sndfrom(ip):$sndfrom(port) -> $sndto(ip):$sndto(port)"); } ## vim:set tabstop=4 softtabstop=4 shiftwidth=4 expandtab