<?xml version="1.0" encoding='ISO-8859-1'?> <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [ <!-- Include general documentation entities --> <!ENTITY % docentities SYSTEM "../../../docbook/entities.xml"> %docentities; ]> <!-- Module User's Guide --> <chapter> <title>&adminguide;</title> <section> <title>Overview</title> <para>This module provides C-API functions to enable &kamailio; to be used as an outbound Edge Proxy (see RFC 5626 section 5).</para> <para>The <emphasis>path</emphasis> and <emphasis>rr</emphasis> will bind to this module if it is loaded before they are.</para> <section> <title>Edge Proxy Keep-Alives (STUN)</title> <para>Outbound Edge Proxies MUST support STUN NAT keep-alives on their SIP UDP ports. &kamailio; supports this though the <quote>stun</quote> module.</para> </section> <section> <title>Flow Timer</title> <para>The maximum interval at which a User Agent must send a keep-alive may be specified by the Registrar using the Flow-Timer: header in 2xx responses to REGISTERs.</para> <para>When using TCP or TLS as the SIP transport care should be taken to set the <quote>tcp_connection_lifetime</quote> on the Edge Proxy to a value slightly larger than the interval the Registrar is using for flow timer. Setting <quote>tcp_connection_lifetime</quote> to less than the interval could cause connections to be lost, and setting it to a value much larger than the interval will keep connections open far longer than is required (which is wasteful).</para> <para>Application-layer keep-alives are optional when the underlying transport already has a keep-alive mechanism. The WebSocket transport has a transport-layer keep-alive. When using the WebSocket transport the <quote>keepalive_timeout</quote> should be set to a value a little greater than the Registrar flow timer interval and a little less than the <quote>tcp_connection_lifetime</quote>. </para> </section> <example> <title>Edge Proxy Configuration</title> <programlisting><![CDATA[ #!KAMAILIO # # Edge proxy configuration # #!subst "/REGISTRAR_IP/192.168.122.3/" #!subst "/REGISTRAR_PORT/5060/" #!substdef "/FLOW_TIMER/20/" ####### Global Parameters ######### debug=2 log_stderror=no log_facility=LOG_LOCAL0 fork=yes children=4 alias="example.com" mpath="/usr/lib64/kamailio/modules" tcp_connection_lifetime=30 # FLOW_TIMER + 10 force_rport=yes ####### Modules Section ######## loadmodule "tm.so" loadmodule "sl.so" loadmodule "outbound.so" loadmodule "rr.so" loadmodule "path.so" loadmodule "pv.so" loadmodule "maxfwd.so" loadmodule "xlog.so" loadmodule "sanity.so" loadmodule "ctl.so" loadmodule "mi_rpc.so" loadmodule "mi_fifo.so" loadmodule "textops.so" loadmodule "siputils.so" loadmodule "stun.so" # ----------------- setting module-specific parameters --------------- # ----- mi_fifo params ----- modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo") # ----- tm params ----- modparam("tm", "failure_reply_mode", 3) # ----- rr params ----- modparam("rr", "append_fromtag", 0) ####### Routing Logic ######## request_route { route(REQINIT); if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } exit; } route(WITHINDLG); t_check_trans(); if (is_method("REGISTER")) { remove_hf("Route"); add_path(); $du = "sip:REGISTRAR_IP:REGISTRAR_PORT"; } else { if (is_method("INVITE|SUBSCRIBE")) record_route(); if (@via[2] == "") { # From client so route to registrar... if ($rU == $null) { sl_send_reply("484", "Address Incomplete"); exit; } remove_hf("Route"); $du = "sip:REGISTRAR_IP:REGISTRAR_PORT"; } else { # From registrar so route using "Route:" headers... if (!loose_route()) { switch($rc) { case -2: sl_send_reply("403", "Forbidden"); exit; default: xlog("L_ERR", "in request_route\n"); sl_reply_error(); exit; } } t_on_failure("FAIL_OUTBOUND"); } } route(RELAY); } route[RELAY] { if (!t_relay()) { sl_reply_error(); } exit; } route[REQINIT] { if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); exit; } if(!sanity_check("1511", "7")) { xlog("Malformed SIP message from $si:$sp\n"); exit; } } route[WITHINDLG] { if (has_totag()) { if (!loose_route()) { switch($rc) { case -2: sl_send_reply("403", "Forbidden"); exit; default: if (is_method("ACK")) { if ( t_check_trans() ) { route(RELAY); exit; } else { exit; } } sl_send_reply("404","Not Found"); } } else { if (is_method("NOTIFY")) { record_route(); } route(RELAY); } exit; } } onreply_route { if (!t_check_trans()) { drop; } if ($rm == "REGISTER" && $rs >= 200 && $rs <= 299) { remove_hf("Flow-Timer"); if ($(hdr(Require)[*])=~"outbound") insert_hf("Flow-Timer: FLOW_TIMER\r\n", "Call-ID"); } } failure_route[FAIL_OUTBOUND] { if (t_branch_timeout() || !t_branch_replied()) { send_reply("430", "Flow Failed"); } } ]]></programlisting> </example> <example> <title>Registrar Configuration</title> <programlisting><![CDATA[ MAILIO # # Registrar configuration # ####### Global Parameters ######### debug=2 log_stderror=no log_facility=LOG_LOCAL0 fork=yes children=4 alias="example.com" mpath="/usr/lib64/kamailio/modules" ####### Modules Section ######## loadmodule "tm.so" loadmodule "tmx.so" loadmodule "sl.so" loadmodule "rr.so" loadmodule "pv.so" loadmodule "maxfwd.so" loadmodule "xlog.so" loadmodule "sanity.so" loadmodule "ctl.so" loadmodule "mi_rpc.so" loadmodule "mi_fifo.so" loadmodule "textops.so" loadmodule "siputils.so" loadmodule "usrloc.so" loadmodule "registrar.so" # ----------------- setting module-specific parameters --------------- # ----- mi_fifo params ----- modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo") # ----- tm params ----- modparam("tm", "failure_reply_mode", 3) modparam("tm", "restart_fr_on_each_reply", 0) modparam("tm", "contact_flows_avp", "tm_contact_flows") modparam("tm", "contacts_avp", "tm_contacts") # ----- rr params ----- modparam("rr", "append_fromtag", 0) # ----- registrar params ----- modparam("registrar", "use_path", 1) modparam("registrar", "gruu_enabled", 1) modparam("registrar", "outbound_mode", 1) ####### Routing Logic ######## request_route { route(REQINIT); if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } exit; } route(WITHINDLG); t_check_trans(); remove_hf("Route"); if (is_method("INVITE|SUBSCRIBE")) record_route(); route(REGISTRAR); if ($rU==$null) { xlog("L_INFO", "Address Incomplete\n"); send_reply("484","Address Incomplete"); exit; } route(LOCATION); } route[RELAY] { if (!t_relay()) { xlog("L_ERR", "t_relay() failed\n"); sl_reply_error(); } exit; } route[REQINIT] { if (!mf_process_maxfwd_header("10")) { xlog("L_INFO", "Too Many Hops\n"); send_reply("483","Too Many Hops"); exit; } if(!sanity_check("1511", "7")) { xlog("Malformed SIP message from $si:$sp\n"); exit; } } route[WITHINDLG] { if (has_totag()) { if (loose_route()) { if (is_method("NOTIFY")) { record_route(); } route(RELAY); } else { if (is_method("ACK")) { if (t_check_trans()) { route(RELAY); exit; } else { exit; } } xlog("L_INFO", "Not Found"); send_reply("404","Not Found"); } exit; } } route[REGISTRAR] { if (is_method("REGISTER")) { if (!save("location")) { xlog("L_ERR", "Unable to save location\n"); sl_reply_error(); } exit; } } route[LOCATION] { if (!lookup("location")) { $var(rc) = $rc; 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 (!t_load_contacts() || !t_next_contacts()) { xlog("L_ERR", "t_(load|next)_contacts() failed\n"); sl_reply_error(); exit; } t_on_failure("FAIL_TRANSACTION"); t_on_branch_failure("FAIL-BRANCH"); route(RELAY); exit; } onreply_route { if (!t_check_trans()) { drop; } } failure_route[FAIL_TRANSACTION] { if (!t_check_status("6[0-9][0-9]")) { if (t_next_contacts()) { t_relay(); exit; } } if (t_check_status("430")) { t_reply("480", "Temporarily Unavailable"); exit; } } event_route[tm:branch-failure:FAIL-BRANCH] { if (t_check_status("403|430") || (t_branch_timeout() && !t_branch_replied())) { unregister("location", "$tu", "$T_reply_ruid"); if (t_next_contact_flow()) { t_on_branch_failure("FAIL-BRANCH"); t_relay(); } } } ]]></programlisting> </example> </section> <section> <title>Dependencies</title> <section> <title>&kamailio; Modules</title> <para> The following modules must be loaded before this module: <itemizedlist> <listitem> <para><emphasis>None</emphasis></para> </listitem> </itemizedlist> </para> </section> <section> <title>External Libraries or Applications</title> <para> The following libraries must be installed before running &kamailio; with this module loaded: <itemizedlist> <listitem> <para><emphasis>OpenSSL</emphasis>.</para> </listitem> </itemizedlist> </para> </section> </section> <section> <title>Parameters</title> <section> <title><varname>force_outbound_flag</varname> (integer)</title> <para>A flag which, if set for a request, will force <emphasis>path</emphasis> and <emphasis>rr</emphasis> to add flow tokens to Path: and Record-Route: headers regardless of the request contents.</para> <para><emphasis>Default value is -1.</emphasis></para> <example> <title>Set <varname>force_outbound_flag</varname> parameter </title> <programlisting format="linespecific"> ... modparam("outbound", "force_outbound_flag", 1) ... </programlisting> </example> </section> <section> <title><varname>force_no_outbound_flag</varname> (integer)</title> <para>A flag which, if set for a request, will force <emphasis>path</emphasis> and <emphasis>rr</emphasis> not to add flow tokens to Path: and Record-Route: headers regardless of the request contents.</para> <para><emphasis>Default value is -1.</emphasis></para> <example> <title>Set <varname>force_no_outbound_flag</varname> parameter </title> <programlisting format="linespecific"> ... modparam("outbound", "force_no_outbound_flag", 2) ... </programlisting> </example> </section> </section> <section> <title>Functions</title> <para><emphasis>None</emphasis></para> </section> <section> <title>MI Commands</title> <para><emphasis>None</emphasis></para> </section> </chapter>