Kamailio (OpenSER) Deployment for Concentration

by quinnebert
13 deployments · 0 still active · last rev. 5 years ago

A stackscript designed for deploying a Kamailio node, designed to provide the concentrator and fail-smart features, meant to be deployed alongside a node created using the "Asterisk (series1.6) Deployment for Concentration" stackscript.

Compatible with: No distros currently supported
						#!/bin/bash
# <UDF name="db_password" Label="MySQL root Password" example="Used for SIP authorization process" />
# <UDF name="masteriskip" Label="Primary Asterisk IP" example="The IP of the Asterisk gateway that primarily RECEIVES users' incoming (not outgoing) calls." />
# <UDF name="asteriskips" Label="Asterisk System IPs" example="Separate multiple IPs by spaces ... You should include Primary IP in this list!" />
# <UDF name="ethernetsip" Label="Ethernet IP Address" example="Primary IP address of THIS node" />

# Import the Linode standard StackScript Library
source <ssinclude StackScriptID="1">

# Bring The System Up-to-date
system_update

# Ensure APT package list is up-to-date 
apt-get -y update

# Ensure OpenSSH Service is installed...
apt-get -y install openssh-server

# Install bulk of packages we need...
apt-get -y update
apt-get -y install bison flex make gcc g++
apt-get -y install libmysql++-dev

# MySQL Install and Configure first DB
mysql_install "$DB_PASSWORD" && mysql_tune 40

# SIP Authentication DB Installation
echo "CREATE DATABASE asterisk;

USE asterisk;

CREATE TABLE "'`'"sipusers"'`'" (
"'`'"id"'`'" int(11) NOT NULL AUTO_INCREMENT,
"'`'"name"'`'" varchar(80) NOT NULL DEFAULT '',
"'`'"host"'`'" varchar(31) NOT NULL DEFAULT '',
"'`'"nat"'`'" varchar(5) NOT NULL DEFAULT 'no',
"'`'"type"'`'" enum('user','peer','friend') NOT NULL DEFAULT 'friend',
"'`'"accountcode"'`'" varchar(20) DEFAULT NULL,
"'`'"amaflags"'`'" varchar(13) DEFAULT NULL,
"'`'"call-limit"'`'" smallint(5) UNSIGNED DEFAULT NULL,
"'`'"callgroup"'`'" varchar(10) DEFAULT NULL,
"'`'"callerid"'`'" varchar(80) DEFAULT NULL,
"'`'"cancallforward"'`'" char(3) DEFAULT 'yes',
"'`'"canreinvite"'`'" char(3) DEFAULT 'yes',
"'`'"context"'`'" varchar(80) DEFAULT NULL,
"'`'"defaultip"'`'" varchar(15) DEFAULT NULL,
"'`'"dtmfmode"'`'" varchar(7) DEFAULT NULL,
"'`'"fromuser"'`'" varchar(80) DEFAULT NULL,
"'`'"fromdomain"'`'" varchar(80) DEFAULT NULL,
"'`'"insecure"'`'" varchar(4) DEFAULT NULL,
"'`'"language"'`'" char(2) DEFAULT NULL,
"'`'"mailbox"'`'" varchar(50) DEFAULT NULL,
"'`'"md5secret"'`'" varchar(80) DEFAULT NULL,
"'`'"deny"'`'" varchar(95) DEFAULT NULL,
"'`'"permit"'`'" varchar(95) DEFAULT NULL,
"'`'"mask"'`'" varchar(95) DEFAULT NULL,
"'`'"musiconhold"'`'" varchar(100) DEFAULT NULL,
"'`'"pickupgroup"'`'" varchar(10) DEFAULT NULL,
"'`'"qualify"'`'" char(3) DEFAULT NULL,
"'`'"regexten"'`'" varchar(80) DEFAULT NULL,
"'`'"restrictcid"'`'" char(3) DEFAULT NULL,
"'`'"rtptimeout"'`'" char(3) DEFAULT NULL,
"'`'"rtpholdtimeout"'`'" char(3) DEFAULT NULL,
"'`'"secret"'`'" varchar(80) DEFAULT NULL,
"'`'"setvar"'`'" varchar(100) DEFAULT NULL,
"'`'"disallow"'`'" varchar(100) DEFAULT NULL,
"'`'"allow"'`'" varchar(100) DEFAULT NULL,
"'`'"fullcontact"'`'" varchar(80) NOT NULL DEFAULT '',
"'`'"ipaddr"'`'" varchar(15) NOT NULL DEFAULT '',
"'`'"port"'`'" mediumint(5) UNSIGNED NOT NULL DEFAULT '0',
"'`'"regserver"'`'" varchar(100) DEFAULT NULL,
"'`'"regseconds"'`'" int(11) NOT NULL DEFAULT '0',
"'`'"lastms"'`'" int(11) NOT NULL DEFAULT '0',
"'`'"username"'`'" varchar(80) NOT NULL DEFAULT '',
"'`'"defaultuser"'`'" varchar(80) NOT NULL DEFAULT '',
"'`'"subscribecontext"'`'" varchar(80) DEFAULT NULL,
"'`'"useragent"'`'" varchar(20) DEFAULT NULL,
"'`'"sippasswd"'`'" varchar(80) DEFAULT NULL,
PRIMARY KEY  ("'`'"id"'`'"),
UNIQUE KEY "'`'"name_uk"'`'" ("'`'"name"'`'")
);

CREATE TABLE "'`'"sipregs"'`'" (
"'`'"id"'`'" int(11) NOT NULL AUTO_INCREMENT,
"'`'"name"'`'" varchar(80) NOT NULL DEFAULT '',
"'`'"fullcontact"'`'" varchar(80) NOT NULL DEFAULT '',
"'`'"ipaddr"'`'" varchar(15) NOT NULL DEFAULT '',
"'`'"port"'`'" mediumint(5) UNSIGNED NOT NULL DEFAULT '0',
"'`'"username"'`'" varchar(80) NOT NULL DEFAULT '',
"'`'"regserver"'`'" varchar(100) DEFAULT NULL,
"'`'"regseconds"'`'" int(11) NOT NULL DEFAULT '0',
PRIMARY KEY  ("'`'"id"'`'"),
UNIQUE KEY "'`'"name"'`'" ("'`'"name"'`'")
);

CREATE TABLE IF NOT EXISTS "'`'"voiceboxes"'`'" (
"'`'"uniqueid"'`'" int(4) NOT NULL AUTO_INCREMENT,
"'`'"customer_id"'`'" varchar(10) DEFAULT NULL,
"'`'"context"'`'" varchar(10) NOT NULL,
"'`'"mailbox"'`'" varchar(10) NOT NULL,
"'`'"password"'`'" varchar(12) NOT NULL,
"'`'"fullname"'`'" varchar(150) DEFAULT NULL,
"'`'"email"'`'" varchar(50) DEFAULT NULL,
"'`'"pager"'`'" varchar(50) DEFAULT NULL,
"'`'"tz"'`'" varchar(10) DEFAULT 'central',
"'`'"attach"'`'" enum('yes','no') NOT NULL DEFAULT 'yes',
"'`'"saycid"'`'" enum('yes','no') NOT NULL DEFAULT 'yes',
"'`'"dialout"'`'" varchar(10) DEFAULT NULL,
"'`'"callback"'`'" varchar(10) DEFAULT NULL,
"'`'"review"'`'" enum('yes','no') NOT NULL DEFAULT 'no',
"'`'"operator"'`'" enum('yes','no') NOT NULL DEFAULT 'no',
"'`'"envelope"'`'" enum('yes','no') NOT NULL DEFAULT 'no',
"'`'"sayduration"'`'" enum('yes','no') NOT NULL DEFAULT 'no',
"'`'"saydurationm"'`'" tinyint(4) NOT NULL DEFAULT '1',
"'`'"sendvoicemail"'`'" enum('yes','no') NOT NULL DEFAULT 'no',
"'`'"delete"'`'" enum('yes','no') NULL DEFAULT 'no',
"'`'"nextaftercmd"'`'" enum('yes','no') NOT NULL DEFAULT 'yes',
"'`'"forcename"'`'" enum('yes','no') NOT NULL DEFAULT 'no',
"'`'"forcegreetings"'`'" enum('yes','no') NOT NULL DEFAULT 'no',
"'`'"hidefromdir"'`'" enum('yes','no') NOT NULL DEFAULT 'yes',
"'`'"stamp"'`'" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY  ("'`'"uniqueid"'`'"),
KEY "'`'"mailbox_context"'`'" ("'`'"mailbox"'`'","'`'"context"'`'")
); 

CREATE TABLE "'`'"voicemessages"'`'" (
"'`'"id"'`'" int(11) NOT NULL AUTO_INCREMENT,
"'`'"msgnum"'`'" int(11) NOT NULL DEFAULT '0',
"'`'"dir"'`'" varchar(80) DEFAULT '',
"'`'"context"'`'" varchar(80) DEFAULT '',
"'`'"macrocontext"'`'" varchar(80) DEFAULT '',
"'`'"callerid"'`'" varchar(40) DEFAULT '',
"'`'"origtime"'`'" varchar(40) DEFAULT '',
"'`'"duration"'`'" varchar(20) DEFAULT '',
"'`'"mailboxuser"'`'" varchar(80) DEFAULT '',
"'`'"mailboxcontext"'`'" varchar(80) DEFAULT '',
"'`'"recording"'`'" longblob,
"'`'"flag"'`'" varchar(128) DEFAULT '',
PRIMARY KEY  ("'`'"id"'`'"),
KEY "'`'"dir"'`'" ("'`'"dir"'`'")
);


CREATE TABLE version (
    table_name VARCHAR(32) NOT NULL,
    table_version INT UNSIGNED DEFAULT 0 NOT NULL
);
INSERT INTO version (table_name, table_version) VALUES ('sipusers','6');

GRANT ALL ON asterisk.* TO asterisk@localhost IDENTIFIED BY '"$DB_PASSWORD"';
" > /tmp/asterisk.sql
# "Inject" the above SQL Data...
mysql -u root --password="$DB_PASSWORD" < /tmp/asterisk.sql

# less pager, wget, and vim editor
goodstuff

# Kamailio Installation from-source (Quinn)
cd /usr/local/src
wget -c 'http://www.kamailio.org/pub/kamailio/3.0.1/src/kamailio-3.0.1_src.tar.gz'
tar xvfz kamailio-3.0.1_src.tar.gz
cd kamailio-3.0.1
make include_modules="db_mysql" cfg && make all && make install

# Kamailio DB Installation
echo "DBENGINE=MYSQL
DBROOTUSER=root
DBHOST=localhost
DBNAME=openser" >> /usr/local/etc/kamailio/kamctlrc
rm -f '/usr/local/lib/kamailio/kamctl/kamdbctl.mysql'
wget -O '/usr/local/lib/kamailio/kamctl/kamdbctl.mysql' 'http://quinnebert.net/kamdbctl.mysql'
chown root:staff '/usr/local/lib/kamailio/kamctl/kamdbctl.mysql'
chmod 0644 '/usr/local/lib/kamailio/kamctl/kamdbctl.mysql'
export PW="$DB_PASSWORD"
/usr/local/sbin/kamdbctl create

# Toss in a better Kamailio configuration, which:
#  + Supports bonded registration
#  + Supports smart dial failover
echo '#!KAMAILIO

tcp_connect_timeout=1

#!define WITH_MYSQL
#!define WITH_AUTH
#!define WITH_USRLOCDB
#!define WITH_ASTERISK
#!define WITH_NAT

#
# $Id$
#
# Kamailio (OpenSER) SIP Server v3.0 - basic configuration script
#     - web: http://www.kamailio.org
#     - git: http://sip-router.org
#
# Direct your questions about this file to: <users@lists.kamailio.org>
#
# Refer to the Core CookBook at http://www.kamailio.org/dokuwiki/doku.php
# for an explanation of possible statements, functions and parameters.
#
# Several features can be enabled using '"'"'#!define WITH_FEATURE'"'"' directives:
#
# *** To run in debug mode:
#     - define WITH_DEBUG
#
# *** To enable mysql:
#     - define WITH_MYSQL
#
# *** To enable authentication execute:
#     - enable mysql
#     - define WITH_AUTH
#     - add users using '"'"'kamctl'"'"'
#
# *** To enable persistent user location execute:
#     - enable mysql
#     - define WITH_USRLOCDB
#
# *** To enable presence server execute:
#     - enable mysql
#     - define WITH_PRESENCE
#
# *** To enable nat traversal execute:
#     - define WITH_NAT
#     - install RTPProxy: http://www.rtpproxy.org
#     - start RTPProxy:
#        rtpproxy -l _your_public_ip_ -s udp:localhost:7722
#
# *** To enable PSTN gateway routing execute:
#     - define WITH_PSTN
#     - set the value of pstn.gw_ip
#     - check route[PSTN] for regexp routing condition
#
# *** To enhance accounting execute:
#     - enable mysql
#     - define WITH_ACCDB
#     - add following columns to database
#!ifdef ACCDB_COMMENT
  ALTER TABLE acc ADD COLUMN src_user VARCHAR(64) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE acc ADD COLUMN src_domain VARCHAR(128) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE acc ADD COLUMN dst_ouser VARCHAR(64) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE acc ADD COLUMN dst_user VARCHAR(64) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE acc ADD COLUMN dst_domain VARCHAR(128) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE missed_calls ADD COLUMN src_user VARCHAR(64) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE missed_calls ADD COLUMN src_domain VARCHAR(128) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE missed_calls ADD COLUMN dst_ouser VARCHAR(64) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE missed_calls ADD COLUMN dst_user VARCHAR(64) NOT NULL DEFAULT '"'"''"'"';
  ALTER TABLE missed_calls ADD COLUMN dst_domain VARCHAR(128) NOT NULL DEFAULT '"'"''"'"';
#!endif


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

#!ifdef WITH_DEBUG
fork=no
debug=2
log_stderror=yes
#!else
fork=yes
children=4
debug=2
log_stderror=no
#!endif

memdbg=5
memlog=5

log_facility=LOG_LOCAL0

/* 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 revers DNS on IPs (default on) */
#auto_aliases=no


/* uncomment and configure the following line if you want Kamailio to
   bind on a specific interface/port/proto (default bind on all available) */
listen=udp:'$ETHERNETSIP'
port=5060

####### 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"
#!endif

#!ifdef WITH_ASTERISK
asterisk.bindip = "'$MASTERISKIP'" desc "Asterisk IP Address"
asterisk.bindport = "5060" desc "Asterisk Port"
kamailio.bindip = "'$ETHERNETSIP'" desc "Kamailio IP Address"
kamailio.bindport = "5060" desc "Kamailio Port"
#!endif

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

#set module path
mpath="/usr/local/lib/kamailio/modules_k/:/usr/local/lib/kamailio/modules/"

/* uncomment next line for MySQL DB support */
#!ifdef WITH_MYSQL
loadmodule "db_mysql.so"
#!endif
loadmodule "mi_fifo.so"
loadmodule "kex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "uri_db.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "mi_rpc.so"
loadmodule "acc.so"
#!ifdef WITH_AUTH
loadmodule "auth.so"
loadmodule "auth_db.so"
#!endif
/* uncomment next line for aliases support
   NOTE: a DB (like db_mysql) module must be also loaded */
#loadmodule "alias_db.so"
/* uncomment next line for multi-domain support
   NOTE: a DB (like db_mysql) module must be also loaded
   NOTE: be sure and enable multi-domain support in all used modules
         (see "multi-module params" section ) */
#loadmodule "domain.so"
#!ifdef WITH_PRESENCE
loadmodule "presence.so"
loadmodule "presence_xml.so"
#!endif

#!ifdef WITH_NAT
loadmodule "nathelper.so"
#!endif

#!ifdef WITH_ASTERISK
loadmodule "uac.so"
#!endif

loadmodule "dispatcher.so"

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


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


# ----- rr params -----
# 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)
#!ifdef WITH_ASTERISK
modparam("rr", "append_fromtag", 1)
#!else
modparam("rr", "append_fromtag", 0)
#!endif


# ----- rr 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)


# ----- uri_db params -----
/* by default we disable the DB support in the module as we do not need it
   in this configuration */
modparam("uri_db", "use_uri_table", 0)
modparam("uri_db", "db_url", "")


# ----- acc params -----
/* what sepcial events should be accounted ? */
modparam("acc", "early_media", 1)
modparam("acc", "report_ack", 1)
modparam("acc", "report_cancels", 1)
/* by default ww do not adjust the direct of the sequential requests.
   if you enable this parameter, be sure the enable "append_fromtag"
   in "rr" module */
modparam("acc", "detect_direction", 0)
/* account triggers (flags) */
modparam("acc", "failed_transaction_flag", 3)
modparam("acc", "log_flag", 1)
modparam("acc", "log_missed_flag", 2)
modparam("acc", "log_extra",
        "src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
/* enhanced DB accounting */
#!ifdef WITH_ACCDB
modparam("acc", "db_flag", 1)
modparam("acc", "db_missed_flag", 2)
modparam("acc", "db_url",
        "mysql://openser:openserrw@localhost/openser")
modparam("acc", "db_extra",
        "src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
#!endif

# ----- usrloc params -----
/* enable DB persistency for location entries */
#!ifdef WITH_USRLOCDB
modparam("usrloc", "db_mode",   2)
modparam("usrloc", "db_url",
        "mysql://openser:openserrw@localhost/openser")
#!endif

# ----- auth_db params -----
/* enable the DB based authentication */
#!ifdef WITH_AUTH
modparam("auth_db", "calculate_ha1", yes)
#!ifdef WITH_ASTERISK
modparam("auth_db", "user_column", "username")
modparam("auth_db", "password_column", "sippasswd")
modparam("auth_db", "db_url",
        "mysql://asterisk:'$DB_PASSWORD'@localhost/asterisk")
#!else
modparam("auth_db", "password_column", "password")
modparam("auth_db", "db_url",
        "mysql://openser:openserrw@localhost/openser")
#!endif
modparam("auth_db", "load_credentials", "")
#!endif

# ----- alias_db params -----
/* uncomment the following lines if you want to enable the DB based
   aliases */
#modparam("alias_db", "db_url",
#        "mysql://openser:openserrw@localhost/openser")


# ----- domain params -----
/* uncomment the following lines to enable multi-domain detection
   support */
#modparam("domain", "db_url",
#        "mysql://openser:openserrw@localhost/openser")
#modparam("domain", "db_mode", 1)   # Use caching


# ----- multi-module params -----
/* uncomment the following line if you want to enable multi-domain support
   in the modules (dafault off) */
#modparam("alias_db|auth_db|usrloc|uri_db", "use_domain", 1)


# ----- presence params -----
/* enable presence server support */
#!ifdef WITH_PRESENCE
modparam("presence|presence_xml", "db_url",
        "mysql://openser:openserrw@localhost/openser")
modparam("presence_xml", "force_active", 1)
modparam("presence", "server_address", "sip:10.0.0.10:5060")
#!endif

# ----- nathelper -----
#!ifdef WITH_NAT
modparam("nathelper", "rtpproxy_sock", "udp:127.0.0.1:7722")
modparam("nathelper", "natping_interval", 30)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "sipping_bflag", 7)
modparam("nathelper", "sipping_from", "sip:pinger@kamailio.org")
modparam("registrar|nathelper", "received_avp", "$avp(i:80)")
modparam("usrloc", "nat_bflag", 6)
#!endif

#!ifdef WITH_ASTERISK
####### Routing Logic ########


# main request routing logic

route{

        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;
        }

        # NAT detection
        route(NAT);

        if (has_totag()) {
                # sequential request withing a dialog should
                # take the path determined by record-routing
                if (loose_route()) {
                        if (is_method("BYE")) {
                                setflag(1); # do accounting ...
                                setflag(3); # ... even if the transaction fails
                        }
                        route(RELAY);
                } else {
                        if (is_method("SUBSCRIBE") && uri == myself) {
                                # in-dialog subscribe requests
                                route(PRESENCE);
                                exit;
                        }
                        if ( is_method("ACK") ) {
                                if ( t_check_trans() ) {
                                        # non loose-route, but stateful ACK; must be an ACK after a 487
                                        # or e.g. 404 from upstream server
                                        t_relay();
                                        exit;
                                } else {
                                        # ACK without matching transaction ... ignore and discard.\n");
                                        exit;
                                }
                        }
                        sl_send_reply("404","Not here");
                }
                exit;
        }

        #initial requests

        # CANCEL processing
        if (is_method("CANCEL"))
        {
                if (t_check_trans())
                        t_relay();
                exit;
        }

        t_check_trans();

        # authentication
        route(AUTH);

        # record routing for dialog forming requests (in case they are routed)
        # - remove preloaded route headers
        remove_hf("Route");
        if (is_method("INVITE|SUBSCRIBE"))
                record_route();

        # account only INVITEs
        if (is_method("INVITE")) {
                setflag(1); # do accounting
        }
        if (!uri==myself)
        /* replace with following line if multi-domain support is used */
        ##if (!is_uri_host_local())
        {
                append_hf("P-hint: outbound\r\n");
                route(RELAY);
        }

        # requests for my domain

        if( is_method("PUBLISH|SUBSCRIBE"))
                route(PRESENCE);

        if (is_method("REGISTER"))
        {
                if(isflagset(5))
                {
                        setbflag("6");
                        # uncomment next line to do SIP NAT pinging
                        ## setbflag("7");
                }
                if (!save("location"))
                        sl_reply_error();

#!ifdef WITH_ASTERISK
                route(REGFWD);
#!endif
                exit;
        }

        if ($rU==$null) {
                # request with no Username in RURI
                sl_send_reply("484","Address Incomplete");
                exit;
        }

        route(PSTN);

        # apply DB based aliases (uncomment to enable)
        ##alias_db_lookup("dbaliases");

#!ifdef WITH_ASTERISK
        if(!is_method("INVITE")) {
                # non-INVITE request are routed directly by Kamailio
#!endif
        if (!lookup("location")) {
                switch ($rc) {
                        case -1:
                        case -3:
                                t_newtran();
                                t_reply("404", "Not Found");
                                exit;
                        case -2:
                                sl_send_reply("405", "Method Not Allowed");
                                exit;
                }
        }
#!ifdef WITH_ASTERISK
        } /* end non-INVITE test */
        # only INVITE from now on
        if(route(FROMASTERISK))
        {
                # coming from Asterisk - do location lookup
                if (!lookup("location")) {
                        switch ($rc) {
                                case -1:
                                case -3:
                                        t_newtran();
                                        t_reply("404", "Not Found");
                                        exit;
                                case -2:
                                        sl_send_reply("405", "Method Not Allowed");
                                        exit;
                        }
                }
        } else {
                # new call - send to Asterisk
		ds_select_dst("1","4");
		xlog("Sending call to Asterisk at $rd\n");
                route(TOASTERISK);
        }
#!endif

        # when routing via usrloc, log the missed calls also
        setflag(2);

        route(RELAY);
}


route[RELAY] {
	#!ifdef WITH_NAT
        if (check_route_param("nat=yes")) {
                setbflag("6");
        }
        if (isflagset(5) || isbflagset("6")) {
                route(RTPPROXY);
        }
	#!endif
        /* example how to enable some additional event routes */
        if (is_method("INVITE")) {
		t_on_branch("BRANCH_ONE");
		t_on_reply("REPLY_ONE");
		t_on_failure("FAIL_ONE");
        }
        if (!t_relay()) {
                sl_reply_error();
        }
        exit;
}


# Presence server route
route[PRESENCE]
{
#!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;
}

# Authentication route
route[AUTH] {
#!ifdef WITH_AUTH

#!ifdef WITH_ASTERISK
        # do not auth traffic from Asterisk - trusted!
        if(route(FROMASTERISK))
                return;
#!endif

        if (is_method("REGISTER"))
        {
                # authenticate the REGISTER requests (uncomment to enable auth)
#!ifdef WITH_ASTERISK
                if (!www_authorize("", "sipusers"))
#!else
                if (!www_authorize("", "subscriber"))
#!endif
                {
                        www_challenge("", "0");
                        exit;
                }

                if ($au!=$tU)
                {
                        sl_send_reply("403","Forbidden auth ID");
                        exit;
                }
        } else {
                # authenticate if from local subscriber (uncomment to enable auth)
                if (from_uri==myself)
                {
#!ifdef WITH_ASTERISK
                        if (!proxy_authorize("", "sipusers")) {
#!else
                        if (!proxy_authorize("", "subscriber")) {
#!endif
                                proxy_challenge("", "0");
                                exit;
                        }
                        if (is_method("PUBLISH"))
                        {
                                if ($au!=$tU) {
                                        sl_send_reply("403","Forbidden auth ID");
                                        exit;
                                }
                        } else {
                                if ($au!=$fU) {
                                        sl_send_reply("403","Forbidden auth ID");
                                        exit;
                                }
                        }

                        consume_credentials();
                        # caller authenticated
                }
        }
#!endif
        return;
}

# Caller NAT detection route
route[NAT]{
#!ifdef WITH_NAT
        force_rport();
        if (nat_uac_test("19")) {
                if (method=="REGISTER") {
                        fix_nated_register();
                } else {
                        fix_nated_contact();
                }
                setflag(5);
        }
#!endif
        return;
}

# RTPProxy control
route[RTPPROXY] {
#!ifdef WITH_NAT
        if (is_method("BYE")) {
                unforce_rtp_proxy();
        } else if (is_method("INVITE")){
                force_rtp_proxy();
        }
        if (!has_totag()) add_rr_param(";nat=yes");
#!endif
        return;
}

# PSTN GW routing
route[PSTN] {
#!ifdef WITH_PSTN
        # check if PSTN GW IP is defined
        if (strempty($sel(cfg_get.pstn.gw_ip))) {
                xlog("SCRIPT: PSTN rotuing 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;
        }

        $ru = "sip:" + $rU + "@" + $sel(cfg_get.pstn.gw_ip);

        route(RELAY);
        exit;
#!endif

        return;
}

#!ifdef WITH_ASTERISK
# Test if coming from Asterisk
route[FROMASTERISK] {
        if($si==$sel(cfg_get.asterisk.bindip)
                        && $sp==$sel(cfg_get.asterisk.bindport))
                return 1;
        return -1;
}

failure_route[1] {
	xlog("The $rd Asterisk failed to route us, trying next gateway...\n");
	if (t_check_status("408")) { # if timeout
		ds_mark_dst(); # do not use this destination anymore
		# Failover -- Try next destination...
		ds_next_dst(); # use next
		t_on_failure("1"); # if the next one is dead too
		t_relay();
	} else {
		t_reply("501", "Not Implemented");
	}
}

# Send to Asterisk
route[TOASTERISK] {
        # $du = "sip:" + $sel(cfg_get.asterisk.bindip) + ":"
	#	+ $sel(cfg_get.asterisk.bindport);
	ds_select_dst("1","4"); # 4 = round-robin
	t_on_failure("1"); # If there is no response after 5 sec
	t_relay();
        # route(RELAY);
	exit;
}

# Forward REGISTER to Asterisk
route[REGFWD] {
        if(!is_method("REGISTER"))
        {
                return;
        }
        $var(rip) = $sel(cfg_get.asterisk.bindip);
        $uac_req(method)="REGISTER";
        $uac_req(ruri)="sip:" + $var(rip) + ":" + $sel(cfg_get.asterisk.bindport);
        $uac_req(furi)="sip:" + $au + $var(rip);
        $uac_req(turi)="sip:" + $au + "@" + $var(rip);
        $uac_req(hdrs)="Contact: <sip:" + $au + "@"
                                + $sel(cfg_get.kamailio.bindip)
                                + ":" + $sel(cfg_get.kamailio.bindport) + ">\r\n";
        if($sel(contact.expires) != $null)
                $uac_req(hdrs)= $uac_req(hdrs) + "Expires: " + $sel(contact.expires) + "\r\n";
        else
                $uac_req(hdrs)= $uac_req(hdrs) + "Expires: " + $hdr(Expires) + "\r\n";
        uac_req_send();
}

#!endif

# Sample branch router
branch_route[BRANCH_ONE] {
        xdbg("new branch at $ru\n");
}

# Sample onreply route
onreply_route[REPLY_ONE] {
        xdbg("incoming reply\n");
#!ifdef WITH_NAT
        if ((isflagset(5) || isbflagset("6")) && status=~"(183)|(2[0-9][0-9])") {
                force_rtp_proxy();
        }
        if (isbflagset("6")) {
                fix_nated_contact();
        }
#!endif
}

# Sample failure route
failure_route[FAIL_ONE] {
#!ifdef WITH_NAT
        if (is_method("INVITE")
                        && (isbflagset("6") || isflagset(5))) {
                unforce_rtp_proxy();
        }
#!endif

        if (t_is_canceled()) {
                exit;
        }

        # uncomment the following lines if you want to block client
        # redirect based on 3xx replies.
        ##if (t_check_status("3[0-9][0-9]")) {
        ##t_reply("404","Not found");
        ##        exit;
        ##}

        if (t_check_status("486|408")) {
                sethostport("69.164.207.72:5060");
                append_branch();
                # do not set the missed call flag again
                t_relay();
        }
}' > /usr/local/etc/kamailio/kamailio.cfg
echo '# line format
# setit(integer) destination(sip uri) flags (integer, optional)

# proxies
2 sip:127.0.0.1:5060

# gateways' > /usr/local/etc/kamailio/dispatcher.list
for ASTERISK_IP in $ASTERISKIPS; do \
  echo '1 sip:'"$ASTERISK_IP"':5060' >> /usr/local/etc/kamailio/dispatcher.list; \
done

# cleanup after stackscripts
restartServices

# Finally, Fixup for MySQL Service...
mkdir -p /etc/xinetd.d
echo 'service mysql
{
    only_from      =  localhost '$ETHERNETSIP $ASTERISKIPS'
    flags          =  REUSE
    socket_type    =  stream
    wait           =  no
    user           =  root
    redirect       =  127.0.0.1 3306
    log_on_failure += USERID
    interface      =  '$ETHERNETSIP'
}' > /etc/xinetd.d/mysql
chmod -R 0:0 /etc/xinetd.d
chown 0755 /etc/xinetd.d
chown 0644 /etc/xinetd.d/mysql
apt-get -y install xinetd

# Start Kamailio
/usr/local/sbin/kamailio

#               #
# ALL DONE HERE #
#               #