## NOTE: DO NOT CHANGE THIS FILE, EDIT local.cfg ## ####### Flags ####### flags FLAG_INTERNALLY_SOURCED: 1, FLAG_ASSOCIATE_SERVER: 2, FLAG_SKIP_NAT_CORRECTION: 3, FLAG_ASSOCIATE_USER: 4, FLAG_TRUSTED_SOURCE: 5, FLAG_SESSION_PROGRESS: 6; ####### 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 = L_INFO corelog = L_ERR mem_summary = 12 log_stderror = no log_facility = LOG_LOCAL0 log_name="kamailio" ####### Alias Parameters ######### auto_aliases = yes ####### Binding Parameters ######### tos = IPTOS_LOWDELAY ####### 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 = 80000 tcp_send_timeout = 10 tcp_wq_blk_size = 2100 tcp_wq_max = 10485760 ####### UDP Parameters ######### udp4_raw = -1 ####### 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 ####### SCTP Parameters ######### disable_sctp = yes ####### Modules Section ######## mpath="/usr/lib64/kamailio/modules/" ######## Kamailio control connector module ######## loadmodule "ctl.so" ######## 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) modparam("rr", "enable_double_rr", 1) ######## Max-Forward processor module ######## loadmodule "maxfwd.so" modparam("maxfwd", "max_limit", 50) ######## SIP utilities [requires sl] ######## loadmodule "siputils.so" ######## SIP message formatting sanity checks [requires sl] ######## loadmodule "sanity.so" modparam("sanity", "default_checks", 1511) modparam("sanity", "uri_checks", 7) 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=16;autoexpire=7200") modparam("htable", "htable", "redirects=>size=16;autoexpire=5") ######## 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") ######## UAC ######## loadmodule "uac.so" ######## UAC Redirection module ######## loadmodule "uac_redirect.so" ####### DB Text module ########## loadmodule "db_text.so" modparam("db_text", "db_mode", 1) modparam("db_text", "emptystring", 1) ####### Kazoo Integration module ########## loadmodule "kazoo.so" modparam("kazoo", "node_hostname", "MY_HOSTNAME") modparam("kazoo", "amqp_connection", "MY_AMQP_URL") #!ifdef MY_AMQP_URL_SECONDARY modparam("kazoo", "amqp_connection", "MY_AMQP_URL_SECONDARY") #!endif #!ifdef MY_AMQP_URL_TERTIARY modparam("kazoo", "amqp_connection", "MY_AMQP_URL_TERTIARY") #!endif #!ifdef MY_AMQP_MAX_CHANNELS modparam("kazoo", "amqp_max_channels", MY_AMQP_MAX_CHANNELS) #!else modparam("kazoo", "amqp_max_channels", 100) #!endif modparam("kazoo", "amqp_internal_loop_count", 1); modparam("kazoo", "amqp_consumer_loop_count", 4); ####### Role Configurations ########## #!ifdef DISPATCHER-ROLE include_file "dispatcher-role.cfg" #!endif #!ifdef REGISTRAR-ROLE include_file "registrar-role.cfg" #!endif #!ifdef PRESENCE-ROLE include_file "presence-role.cfg" #!endif #!ifdef MESSAGE-ROLE include_file "message-role.cfg" #!endif #!ifdef NAT-TRAVERSAL-ROLE include_file "nat-traversal-role.cfg" #!endif #!ifdef WEBSOCKETS-ROLE include_file "websockets-role.cfg" #!endif #!ifdef TLS-ROLE include_file "tls-role.cfg" #!endif #!ifdef ACCOUNTING-ROLE include_file "accounting-role.cfg" #!endif #!ifdef ANTIFLOOD-ROLE include_file "antiflood-role.cfg" #!endif #!ifdef TRAFFIC-FILTER-ROLE include_file "traffic-filter-role.cfg" #!endif ####### Permissions module ########## loadmodule "permissions.so" modparam("permissions", "db_url", "text:///etc/kazoo/kamailio/dbtext") modparam("permissions", "db_mode", 1) ####### Routing Logic ######## route { route(SANITY_CHECK); # log the basic info regarding this call xlog("L_INFO", "$ci|start|recieved $pr 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(CLASSIFY_SOURCE); #!ifdef ANTIFLOOD-ROLE route(ANTIFLOOD_RATE_LIMIT); route(ANITFLOOD_AUTH_LIMIT); #!endif #!ifdef TRAFFIC-FILTER-ROLE route(TRAFFIC_FILTER); #!endif #!ifdef WEBSOCKETS-ROLE route(HANDLE_WEBSOCKETS); #!endif route(HANDLE_OPTIONS); route(HANDLE_NOTIFY); route(HANDLE_MESSAGE); #!ifdef PRESENCE-ROLE route(HANDLE_SUBSCRIBE); route(HANDLE_PUBLISH); #!endif #!ifdef REGISTRAR-ROLE route(HANDLE_REGISTER); #!endif route(HANDLE_IN_DIALOG_REQUESTS); route(PREPARE_INITIAL_REQUESTS); if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); exit(); } #!ifdef DISPATCHER-ROLE route(DISPATCHER_FIND_ROUTES); #!endif route(EXTERNAL_TO_INTERNAL_RELAY); } route[SANITY_CHECK] { if (!sanity_check()) { xlog("L_WARN", "$ci|end|message from $si:$sp is insane"); exit; } if (!mf_process_maxfwd_header("10")) { xlog("L_WARN", "$ci|end|too much hops, not enough barley from $si:$sp"); send_reply("483", "Too Many Hops"); exit; } if ($ua == "friendly-scanner" || $ua == "sundayddr" || $ua =~ "sipcli" ) { xlog("L_WARN", "$ci|end|dropping message with user-agent $ua from $si:$sp"); exit; } } route[CLASSIFY_SOURCE] { if (isflagset(FLAG_INTERNALLY_SOURCED) || allow_source_address(TRUSTED_ADR_GROUP) || is_myself($si)) { xlog("L_INFO", "$ci|log|request from trusted IP"); setflag(FLAG_TRUSTED_SOURCE); } #!ifdef DISPATCHER-ROLE route(DISPATCHER_CLASSIFY_SOURCE); #!endif } route[HANDLE_OPTIONS] { if (is_method("OPTIONS")) { if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); } else { #!ifdef TRAFFIC-FILTER-ROLE route(FILTER_REQUEST_DOMAIN); #!endif sl_send_reply("200", "Rawr!!"); } exit; } } route[HANDLE_NOTIFY] { if (is_method("NOTIFY")) { if (isflagset(FLAG_INTERNALLY_SOURCED)) { if (registered("location")) { lookup("location"); xlog("L_INFO", "$ci|log|routing to $ruid"); } route(INTERNAL_TO_EXTERNAL_RELAY); } else { #!ifdef TRAFFIC-FILTER-ROLE route(FILTER_REQUEST_DOMAIN); #!endif #!ifdef WEBSOCKETS-ROLE route(NAT_WEBSOCKETS_CORRECT); #!endif #!ifdef NAT-TRAVERSAL-ROLE route(NAT_TEST_AND_CORRECT); #!endif if($hdr(Event) == "keep-alive") { xlog("L_INFO", "$ci|stop|replying to keep alive"); sl_send_reply("405", "Stay Alive / Method Not Allowed"); } else { xlog("L_INFO", "$ci|stop|consuming event $hdr(Event)"); sl_send_reply("200", "Rawr!!"); } } exit; } } route[HANDLE_MESSAGE] { #!ifdef MESSAGE-ROLE if (is_method("MESSAGE")) { xlog("L_INFO", "$ci|MESSAGE from $fu to $tu"); t_on_reply("MESSAGE_REPLY"); if (isflagset(FLAG_INTERNALLY_SOURCED) || src_ip == myself) { xlog("L_INFO", "$ci| routing MESSAGE to external from $fu to $tu"); if (registered("location")) { lookup("location"); xlog("L_INFO", "$ci|log|routing to $ruid"); } route(INTERNAL_TO_EXTERNAL_RELAY); #!ifdef TRAFFIC-FILTER-ROLE } else if (!isflagset(FLAG_TRUSTED_SOURCE) && $rd =~ "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}") { xlog("L_WARN", "$ci|end|dropping MESSAGE request with IP domain"); #!endif } else { xlog("L_WARN", "$ci|end|MESSAGE $(hdr(Content-Type))"); if( $hdr(Content-Type) == "application/im-iscomposing+xml" ) { xlog("L_WARN", "$ci|end|dropping MESSAGE application/im-iscomposing+xml"); sl_send_reply("200", "OK"); } else { route(DISPATCHER_FIND_ROUTES); route(EXTERNAL_TO_INTERNAL_RELAY); } } exit(); } #!else if (is_method("MESSAGE")) { if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); } else { sl_send_reply("202", "delivered to /dev/null"); exit() } } #!endif } route[HANDLE_IN_DIALOG_REQUESTS] { if (has_totag()) { if (is_method("INVITE")) { record_route(); } if (loose_route()) { #!ifdef ACCOUNTING-ROLE if (is_method("BYE")) { setflag(FLAG_ACC); setflag(FLAG_ACCFAILED); } #!endif #!ifdef WEBSOCKETS-ROLE if ($du == $null) { handle_ruri_alias(); switch ($rc) { case -1: xlog("L_ERR", "$ci|stop|failed to handle alias of R-URI $ru\n"); send_reply("400", "Bad request"); exit; case 1: xlog("L_INFO", "$ci|log|loose_route in-dialog message with alias $du"); break; case 2: xlog("L_INFO", "$ci|log|loose_route in-dialog message with alias $du"); break; } } #!endif 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(); } # handle re-transmissions t_check_trans(); if (is_method("UPDATE")) { xlog("L_WARN", "$ci|end|update outside dialog not allowed"); send_reply("403", "Dialog does not exist"); break; } if (is_method("BYE|PRACK")) { xlog("L_WARN", "$ci|end|originating subsequent requests outside dialog not allowed"); send_reply("403", "Dialog does not exist"); break; } if (loose_route()) { xlog("L_WARN", "$ci|end|denying initial request with route-set"); sl_send_reply("403", "No pre-loaded routes"); exit(); } if (!is_method("MESSAGE")) { record_route(); } } route[RELAY] { if (isflagset(FLAG_INTERNALLY_SOURCED)) { route(INTERNAL_TO_EXTERNAL_RELAY); } else { route(EXTERNAL_TO_INTERNAL_RELAY); } exit(); } route[INTERNAL_TO_EXTERNAL_RELAY] { #!ifdef ACCOUNTING-ROLE if (is_method("INVITE")) { setflag(FLAG_ACC); setflag(FLAG_ACCFAILED); } #!endif remove_hf_re("^X-.*"); t_on_reply("EXTERNAL_REPLY"); t_set_fr(0, 10000); t_relay(); } route[EXTERNAL_TO_INTERNAL_RELAY] { #!ifdef ACCOUNTING-ROLE if (is_method("INVITE") && is_present_hf("Proxy-Authorization")) { setflag(FLAG_ACC); setflag(FLAG_ACCFAILED); } #!endif #!ifdef NAT-TRAVERSAL-ROLE if (!isflagset(FLAG_INTERNALLY_SOURCED)) { route(NAT_TEST_AND_CORRECT); } #!endif ##### CALL-PARK #### if(is_method("REFER")) { $avp(refer_to) = $hdr(Refer-To); $avp(refer_to_uri) = $rt; $avp(referred_by) = $hdr(Referred-By); } remove_hf_re("^X-.*"); 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(); } onreply_route[EXTERNAL_REPLY] { xlog("L_INFO", "$ci|log|external reply $T_reply_code"); #!ifdef WEBSOCKETS-ROLE route(NAT_WEBSOCKETS_CORRECT); #!endif #!ifdef NAT-TRAVERSAL-ROLE route(NAT_TEST_AND_CORRECT); #!endif } 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"); #!ifdef WEBSOCKETS-ROLE route(NAT_WEBSOCKETS_CORRECT); #!endif if (is_method("INVITE") && !isflagset(FLAG_SESSION_PROGRESS) && t_check_status("(180)|(183)|(200)") ) { if ($avp(AVP_REDIRECT_KEY) != $null && $sht(redirects=>$avp(AVP_REDIRECT_KEY)) != $null ) { xlog("L_INFO", "$ci|log|removing redirect mapping $avp(AVP_REDIRECT_KEY)"); $sht(redirects=>$avp(AVP_REDIRECT_KEY)) = $null; } xlog("L_INFO", "$ci|log|call setup, now ignoring abnormal termination"); setflag(FLAG_SESSION_PROGRESS); } ##### CALL-PARK #### if (is_method("REFER") && $T_reply_code == "202" ) { $sht(park=>$(avp(refer_to_uri){uri.user})@$(avp(refer_to_uri){uri.domain})) = "sip:" + $(ct{tobody.uri}{uri.host}) + ":" + $(ct{tobody.uri}{uri.port}); xlog("L_INFO", "PARK $(avp(refer_to_uri){uri.user})@$(avp(refer_to_uri){uri.domain}) = sip:$(ct{tobody.uri}{uri.host}):$(ct{tobody.uri}{uri.port})"); } if ($rs < 300) { xlog("L_INFO", "$ci|pass|$T_req($si):$T_req($sp)"); } $var(reply_reason) = $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; } # Handle redirects if (t_check_status("302")) { $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" + $T_rpl($(ct{tobody.user})) + "@" + $T_rpl($(ct{tobody.host})); if($T_rpl($hdr(X-Redirect-Server)) != $null) { $sht(redirects=>$var(redirect)) = $T_rpl($hdr(X-Redirect-Server)); xlog("L_INFO", "$ci|log|stored redirect mapping $var(redirect) to $T_rpl($hdr(X-Redirect-Server))"); } } else if (!t_check_status("407") && $avp(AVP_REDIRECT_KEY) != $null && $sht(redirects=>$avp(AVP_REDIRECT_KEY)) != $null ) { xlog("L_INFO", "$ci|log|removing redirect mapping $avp(AVP_REDIRECT_KEY)"); $sht(redirects=>$avp(AVP_REDIRECT_KEY)) = $null; } remove_hf_re("^X-.*"); # change 6xx to 4xx if (t_check_status("6[0-9][0-9]") && !t_check_status("600|603|604|606")) { $var(new_code) = "4" + $(T_reply_code{s.substr,1,0}); xlog("L_INFO", "$ci|log|sending 6XX reply as $var(new_code) $var(reply_reason)"); t_reply("$(var(new_code){s.int})", "$var(reply_reason)"); # if the failure case was something that we should recover # from then try to find a new media server } else if ("$var(reply_reason)" =~ "call barred") { xlog("L_INFO", "$ci|log|failure route ignoring call barred"); } else if (isflagset(FLAG_SESSION_PROGRESS)) { xlog("L_INFO", "$ci|log|failure route ignoring failure after session progress"); } else if (t_check_status("(401)|(407)|(486)|(403)")) { xlog("L_INFO", "$ci|log|failure route ignoring auth reply $T_reply_code $var(reply_reason)"); } else if (t_check_status("402")) { xlog("L_INFO", "$ci|log|failure route overriding reply code 402 with 486"); send_reply("486", "Insufficient Funds"); } 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"); #!ifdef DISPATCHER-ROLE route(DISPATCHER_NEXT_ROUTE); #!endif send_reply("486", "Unable to Comply"); } else { xlog("L_INFO", "$ci|log|failure route ignoring reply $T_reply_code $rr"); } xlog("L_INFO", "$ci|pass|$si:$sp"); } 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)"); $sht(associations=>$var(contact_uri))= "sip:" + $sndto(ip) + ":" + $sndto(port); } xlog("L_INFO", "$ci|pass|$sndfrom(ip):$sndfrom(port) -> $sndto(ip):$sndto(port)"); } event_route[kazoo:mod-init] { #!ifdef PRESENCE-ROLE ### use this simple form of binding a listener ### kazoo_subscribe("dialoginfo", "direct", "BLF-QUEUE-MY_HOSTNAME", "BLF-MY_HOSTNAME"); ### ### or unleash the power of rabbit to kazoo-blf ### ### 'no_ack' : 1 => needs ack, ### 'wait_for_consumer_ack' ### : 1 => when it receives, it processses on the AMQP Worker ad after that it confirms ### : 0 => when it receives, it acks then processes in the AMQP Worker ### only works if no_ack : 0 ### ### Rabbit Policy for ha-mode ### pattern : ^BLF ### definition : ha-mode: all ### ### $var(payload) = '{ "exchange" : "dialoginfo" , "type" : "direct", "queue" : "BLF-QUEUE-MY_HOSTNAME", "routing" : "BLF-MY_HOSTNAME", "auto_delete" : 0, "durable" : 1, "no_ack" : 0, "wait_for_consumer_ack" : 1 }'; kazoo_subscribe("$var(payload)"); #!endif #!ifdef MESSAGE-ROLE $var(key) = "kamailio@MY_HOSTNAME"; $var(payload) = '{ "exchange" : "sms" , "type" : "topic", "queue" : "MSG-QUEUE-MY_HOSTNAME", "routing" : "message.route.' + $(var(key){kz.encode}) + '.*", "auto_delete" : 1, "durable" : 0, "no_ack" : 0, "wait_for_consumer_ack" : 1 }'; kazoo_subscribe("$var(payload)"); #!endif #!ifdef REGISTRAR-ROLE $var(payload) = "{ 'exchange' : 'callmgr' , 'type' : 'topic', 'queue' : 'MSG-FLUSH-MY_HOSTNAME', 'routing' : 'registration.flush.*', 'auto_delete' : 1, 'durable' : 0, 'no_ack' : 1, 'wait_for_consumer_ack' : 0 }"; kazoo_subscribe("$var(payload)"); #!endif } event_route[kazoo:consumer-event] { xlog("L_INFO","unhandled AMQP event, payload: $kzE"); } event_route[kazoo:consumer-event-connection-open] { xlog("L_INFO","connection to $(kzE{kz.json,host}) opened"); } event_route[kazoo:consumer-event-connection-closed] { xlog("L_INFO","connection to $(kzE{kz.json,host}) closed"); } # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab