Hello,

I need some help in creating a stateless failover balancer for two asterisk servers using kamailio. I followed in the steps of an old project here:  https://txlab.wordpress.com/tag/xlab1/

Kamailio is running in a multihomed host, with public ip facing the internet and private ip facing the asterisk servers.

I have partial issues with nat traversal when the external device is also behind nat. All works when the device initates a call/dialog, however when the asterisk server tries to send an "OPTIONS" keep alive to the end device, Kamailio receives the packet from asterisk but tries to send it to the private IP address of the device instead of the public ip:port. Same goes for calls.

My kamailio.cfg is below. I am missing something obvious here, but can't find it.

Thanks

=== CUT====
#!KAMAILIO

################################################################
#
#  This is a front-end SIP proxy configuration for the xlab1 project
#  See for more details: https://txlab.wordpress.com/tag/xlab1/
#  The configuration requires Kamailio version 3.3.x
#
#  This work is licensed under a Creative Commons Attribution 3.0 License
#  Author: Stanislav Sinyagin <ssinaygin@k-open.com>
#
################################################################



#!define WITH_DEBUG

####### Defined Values #########

#### define DBURL "text:///opt/sipfe/etc/kamailio_db"
#!define DBURL "text:///etc/kamailio/kamailio_db"

#!define BACKEND_NET4 10.10.10.0/24
#!define BACKEND_NET6 2a02:200:8:100::/64

####### Global Parameters #########

#!ifdef WITH_DEBUG
debug=2
log_stderror=yes
#!else
debug=1
log_stderror=no
#!endif

memdbg=5
memlog=5

log_facility=LOG_LOCAL0

fork=yes
children=2

auto_aliases=no

#listen=udp:195.x.x.78:5060
# to avoid simple attacks, use unconventional port
#port=5060

# this makes it listen on all ipv6 addresses
auto_bind_ipv6=0
dns_try_ipv6=no

# let kamailio choose the right source IP address
mhomed=3

# 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

## Hardening
sip_warning=0
server_signature=no
user_agent_header="User-Agent: Kamailio Failover Balancer"

####### Modules Section ########

## NOTE:
## mpath="/opt/sipfe/lib64/kamailio/modules_k/:/opt/sipfe/lib64/kamailio/modules/"

loadmodule "db_text.so"
loadmodule "jsonrpcs.so"

#loadmodule "mi_fifo.so"
loadmodule "tm.so"
loadmodule "kex.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"
#loadmodule "mi_rpc.so"

loadmodule "path.so"
loadmodule "domain.so"
loadmodule "dispatcher.so"
loadmodule "nathelper.so"
loadmodule "rtpproxy.so"


#!ifdef WITH_DEBUG
loadmodule "debugger.so"
#!endif

# ----------------- setting module-specific parameters ---------------


#modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")


# add value to ;lr param to cope with most of the UAs
modparam("rr", "enable_full_lr", 1)
# do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)

modparam("nathelper", "received_avp", "$avp(RECEIVED)")
modparam("nathelper", "nortpproxy_str", "a=sdpmangled:yes\r\n")

modparam("path", "use_received", 1)

modparam("domain", "db_url", DBURL)

modparam("dispatcher", "db_url", DBURL)
modparam("dispatcher", "table_name", "dispatcher")

modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:22222")
#modparam("rtpproxy", "rtpproxy_sock", "unix:/var/run/rtpproxy/rtpproxy.sock")


#!ifdef WITH_DEBUG
# ----- debugger params -----
modparam("debugger", "cfgtrace", 1)
#!endif

####### Routing Logic ########


route {
    if (!sanity_check()) {
        exit;
    }

    if ( !mf_process_maxfwd_header("10") )
    {
        sl_send_reply("483","To Many Hops");
        xlog("L_NOTICE", "$si $rm $ru -- too many hops\n");
        exit;
    }

    if (af==INET)
    {
        force_rport();

        if (src_ip != BACKEND_NET4)
        {
            # SIP request packet client->backend

            if( !loose_route() )
            {
                if (!lookup_domain("$td", "dattr_")) {
                    xlog("L_ERR", "$si $rm $ru -- domain \"$td\" is not " +
                        "found in domain table\n");
                    drop();
                }

                if (!defined $avp(dattr_routeset))
                {
                    xlog("L_ERR",
                        "$si $rm $ru -- attribute \"routeset\" is " +
                        "undefined for domain $td\n");
                    drop();
                }

                if( !ds_select_dst(4000 + $avp(dattr_routeset), "1") )
                {
                    drop();
                }
            }

            if (nat_uac_test("19")) {
                xlog("L_INFO", "Routing NAT in-dialog $rm from $fu to $du\n");
                if (method=="REGISTER") {
                    fix_nated_register();
                } else {
                    fix_nated_contact();
                }
            }


            add_path_received();
            #rtpproxy_manage("cwei");
            rtpproxy_manage("cw");
            record_route();
        }
        else
        {
            # SIP request packet backend->client

            # Invites from backend contain Route field and it should be used
            # to reach the registered client
            loose_route();
            #rtpproxy_manage("cwie");
            rtpproxy_manage("cw");
            record_route();
        }
    }
    else
    {
        # IPv6: no NAT traversal, just pure routing

        if (src_ip != BACKEND_NET6)
        {
            # SIP request packet client->backend

            if( !loose_route() )
            {
                if (!lookup_domain("$td", "dattr_")) {
                    xlog("L_ERR", "$si $rm $ru -- domain \"$td\" is not " +
                        "found in domain table\n");
                    drop();
                }

                if (!defined $avp(dattr_routeset))
                {
                    xlog("L_ERR",
                        "$si $rm $ru -- attribute \"routeset\" is " +
                        "undefined for domain $td\n");
                    drop();
                }

                if( !ds_select_dst(6000 + $avp(dattr_routeset), "1") )
                {
                    drop();
                }
            }

            add_path_received();
            record_route();
        }
        else
        {
            # SIP request packet backend->client

            record_route();
        }
    }

    forward();
}


onreply_route {

    if (af==INET)
    {
        if(src_ip != BACKEND_NET4)
        {
            # SIP reply packet client->backend

            #rtpproxy_manage("cwie");
            rtpproxy_manage("cw");
            fix_nated_contact();
        }
        else
        {
            # SIP reply packet backend->client

            #rtpproxy_manage("cwei");
            rtpproxy_manage("cw");
        }
    }

    return(1);
}



# Local Variables:
# mode: sh
# sh-indent-after-if: 0
# indent-tabs-mode: nil
# tab-width: 4
# End:
====CUT=====