Verizon Interconnection Procedure

André Guimarães, 2012-06-12

Switzernet

1.      Introduction.. 1

2.      Requirements. 1

3.      VPN IPSec.. 1

4.      How to debug the traffic in the tunnel: 5

5.      Kamailio installation: 10

6.      Kamailio configuration: 11

7.      Test results. 39

8.      Resources. 39

 

 

Introduction

This document describes how to install and configure a server to make the interconnection with Verizon VoIP. It describes how to configure Kamailio, the VPN IPSec and DNS.

 

Requirements

To make this procedure you need a server installed with Debian 6.0.

 

VPN IPSec

For the configuration of the VPN IPSec required by Verizon to send the signaling, Racoon was chosen. To install Racoon:

 

# apt-get install racoon ipsec-tools

 

Then the file /etc/racoon/psk.txt should be edited, and a line with the IP of Verizon’s VPN gateway should be added followed by the pre-shared key provided by them:

 

# IPv4/v6 addresses

63.79.179.238 VZXXXXXX

 

Edit the Racoon configuration file to configure a VPN IPSEC with phase1 proposal DH group2-3des-md5 and phase2 proposal PFS group2-esp-3des-md5. In green the IP of the server where we are configuring the VPN. The requirements of Verizon and all data they’ve provided us can be seen in this document [Download]. The Racoon configuration file /etc/racoon/racoon.conf should look like:

 

#

# NOTE: This file will not be used if you use racoon-tool(8) to manage your

# IPsec connections. racoon-tool will process racoon-tool.conf(5) and

# generate a configuration (/var/lib/racoon/racoon.conf) and use it, instead

# of this file.

#

# Simple racoon.conf

#

#

# Please look in /usr/share/doc/racoon/examples for

# examples that come with the source.

#

# Please read racoon.conf(5) for details, and alsoread setkey(8).

#

#

# Also read the Linux IPSEC Howto up at

# http://www.ipsec-howto.org/t1.html

#

 

path pre_shared_key "/etc/racoon/psk.txt";

log notify;

 

 

listen

{

        isakmp 176.31.238.10;

}

 

remote anonymous

{

        exchange_mode aggressive,main;

        doi ipsec_doi;

        situation identity_only;

 

        my_identifier address;

 

        lifetime time 28800 second;   # sec,min,hour

        initial_contact on;

        proposal_check obey;    # obey, strict or claim

 

        proposal {

                encryption_algorithm 3des;

                hash_algorithm md5;

                authentication_method pre_shared_key;

                dh_group 2 ;

        }

}

 

sainfo anonymous

{

        pfs_group 2;

        lifetime time 3600 second;

        encryption_algorithm 3des ;

        authentication_algorithm hmac_md5;

        compression_algorithm deflate ;

}

 

To create the tunnel to the network where the Verizon SIP proxies are we have to configure the following file /etc/ipsec-tools.conf:

 

#!/usr/sbin/setkey -f

 

# NOTE: Do not use this file if you use racoon with racoon-tool

# utility. racoon-tool will setup SAs and SPDs automatically using

# /etc/racoon/racoon-tool.conf configuration.

#

 

flush;

spdflush;

 

#spdadd 176.31.238.10 63.79.179.238 any -P out ipsec

#  esp/transport//require ;

#spdadd 63.79.179.238 176.31.238.10 any -P in ipsec

#  esp/transport//require ;

 

spdadd 176.31.238.10 63.79.178.192/30 any -P out ipsec

  esp/tunnel/176.31.238.10-63.79.179.238/require;

spdadd 63.79.178.192/30 176.31.238.10 any -P in ipsec

  esp/tunnel/63.79.179.238-176.31.238.10/require;

 

 

## Flush the SAD and SPD

#

# flush;

# spdflush;

 

### Some sample SPDs for use racoon

#

# spdadd 10.10.100.1 10.10.100.2 any -P out ipsec

#    esp/transport//require;

#

# spdadd 10.10.100.2 10.10.100.1 any -P in ipsec

#    esp/transport//require;

#

 

Restart the following services:

 

# /etc/init.d/setkey restart

# /etc/init.d/racoon restart

 

At this moment everything is configured and it is possible to open the tunnel. To do this we only have to send traffic to one of the IP addresses in the network behind the VPN, for instance, by doing a ping to one of the IPs.

 

# ping 63.79.178.195

PING 63.79.178.195 (63.79.178.195) 56(84) bytes of data.

ping: sendmsg: Invalid argument

ping: sendmsg: Invalid argument

64 bytes from 63.79.178.195: icmp_req=3 ttl=254 time=114 ms

64 bytes from 63.79.178.195: icmp_req=4 ttl=254 time=114 ms

64 bytes from 63.79.178.195: icmp_req=5 ttl=254 time=114 ms

64 bytes from 63.79.178.195: icmp_req=6 ttl=254 time=114 ms

64 bytes from 63.79.178.195: icmp_req=7 ttl=254 time=114 ms

....

 

The first pings fail due to the time where the VPN is down. The corresponding traffic sent to the VPN was:

 

# tcpdump port 500 -vv

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes

09:56:15.086081 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 292)

    ns228234.ovh.net.isakmp > 63.79.179.238.isakmp: [bad udp cksum 4448!] isakmp 1.0 msgid 00000000 cookie 0fd069f2d17df430->0000000000000000: phase 1 I agg:

    (sa: doi=ipsec situation=identity

        (p: #1 protoid=isakmp transform=1

            (t: #1 id=ike (type=lifetype value=sec)(type=lifeduration value=7080)(type=enc value=3des)(type=auth value=preshared)(type=hash value=md5)(type=group desc value=modp1024))))

    (ke: key len=128)

    (nonce: n len=16  data=(ad58a8a39f577a2c5a2f...00000014afcad71368a1f1c96b8696fc77570100))

    (id: idtype=IPv4 protoid=udp port=500 len=4 ns228234.ovh.net)

    (vid: len=16)

09:56:15.203026 IP (tos 0x0, ttl 52, id 42816, offset 0, flags [none], proto UDP (17), length 372)

    63.79.179.238.isakmp > ns228234.ovh.net.isakmp: [udp sum ok] isakmp 1.0 msgid 00000000 cookie 0fd069f2d17df430->67c7e0f3db109380: phase 1 R agg:

    (sa: doi=ipsec situation=identity

        (p: #1 protoid=isakmp transform=1

            (t: #1 id=ike (type=enc value=3des)(type=hash value=md5)(type=group desc value=modp1024)(type=auth value=preshared)(type=lifetype value=sec)(type=lifeduration value=7080))))

    (vid: len=28)

    (vid: len=16)

    (vid: len=20)

    (ke: key len=128)

    (nonce: n len=20  data=(98d69335749eefee9592...000000149bebd5fec0c776192984b6b5a6fb669f))

    (id: idtype=IPv4 protoid=udp port=500 len=4 63.79.179.238)

    (hash: len=16)

09:56:15.204801 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 76)

    ns228234.ovh.net.isakmp > 63.79.179.238.isakmp: [bad udp cksum 713f!] isakmp 1.0 msgid 00000000 cookie 0fd069f2d17df430->67c7e0f3db109380: phase 1 I agg:

    (hash: len=16)

09:56:15.204906 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 112)

    ns228234.ovh.net.isakmp > 63.79.179.238.isakmp: [bad udp cksum 91b7!] isakmp 1.0 msgid fdfed52e cookie 0fd069f2d17df430->67c7e0f3db109380: phase 2/others I inf[E]: [encrypted hash]

09:56:16.207727 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 312)

    ns228234.ovh.net.isakmp > 63.79.179.238.isakmp: [bad udp cksum 54f2!] isakmp 1.0 msgid a0b69035 cookie 0fd069f2d17df430->67c7e0f3db109380: phase 2/others I oakley-quick[E]: [encrypted hash]

09:56:16.325042 IP (tos 0x0, ttl 52, id 42846, offset 0, flags [none], proto UDP (17), length 320)

    63.79.179.238.isakmp > ns228234.ovh.net.isakmp: [udp sum ok] isakmp 1.0 msgid a0b69035 cookie 0fd069f2d17df430->67c7e0f3db109380: phase 2/others R oakley-quick[E]: [encrypted hash]

09:56:16.325246 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 80)

    ns228234.ovh.net.isakmp > 63.79.179.238.isakmp: [bad udp cksum b698!] isakmp 1.0 msgid a0b69035 cookie 0fd069f2d17df430->67c7e0f3db109380: phase 2/others I oakley-quick[E]: [encrypted hash]

 

After the negotiation there are some transmission errors but they stop afterwards.

 

How to debug the traffic in the tunnel:

 

To dump the SAD and SDP entries:

 

# setkey -DP

(per-socket policy)

        Policy:[Invalid direciton]

        created: May 29 09:50:58 2012  lastused: May 29 09:51:02 2012

        lifetime: 0(s) validtime: 0(s)

        spid=1948 seq=1 pid=30362

        refcnt=1

(per-socket policy)

        Policy:[Invalid direciton]

        created: May 29 09:50:58 2012  lastused: May 29 09:51:02 2012

        lifetime: 0(s) validtime: 0(s)

        spid=1939 seq=2 pid=30362

        refcnt=1

63.79.178.192/30[any] 176.31.238.10[any] any

        fwd prio def ipsec

        esp/tunnel/63.79.179.238-176.31.238.10/require

        created: May 29 09:41:42 2012  lastused:

        lifetime: 0(s) validtime: 0(s)

        spid=1914 seq=3 pid=30362

        refcnt=1

63.79.178.192/30[any] 176.31.238.10[any] any

        in prio def ipsec

        esp/tunnel/63.79.179.238-176.31.238.10/require

        created: May 29 09:41:42 2012  lastused: May 29 09:51:35 2012

        lifetime: 0(s) validtime: 0(s)

        spid=1904 seq=4 pid=30362

        refcnt=2

176.31.238.10[any] 63.79.178.192/30[any] any

        out prio def ipsec

        esp/tunnel/176.31.238.10-63.79.179.238/require

        created: May 29 09:41:42 2012  lastused: May 29 09:51:34 2012

        lifetime: 0(s) validtime: 0(s)

        spid=1897 seq=0 pid=30362

        refcnt=4

 

With either of the following 2 commands we can see the keys needed to decode the traffic in Wireshark:

 

# ip xfrm state

 

or

 

# racoonctl show-sa esp

 176.31.238.10 63.79.179.238

       esp mode=tunnel spi=547518121(0x20a276a9) reqid=0(0x00000000)

       E: 3des-cbc  a63ab288 b5e333f1 e3d50f2d a5007cd1 322d92fe e6a343a4

       A: hmac-md5  8f5f1c2b 438986d7 51322a56 ade37da9

       seq=0x00000000 replay=4 flags=0x00000000 state=mature

       created: May 29 14:08:01 2012   current: May 29 14:34:22 2012

       diff: 1581(s)   hard: 3600(s)   soft: 2880(s)

       last:                           hard: 0(s)      soft: 0(s)

       current: 0(bytes)       hard: 0(bytes)  soft: 0(bytes)

       allocated: 0    hard: 0 soft: 0

       sadb_seq=1 pid=3693 refcnt=0

 63.79.179.238 176.31.238.10

       esp mode=tunnel spi=255501678(0x0f3aa56e) reqid=0(0x00000000)

       E: 3des-cbc  cd4afe68 8757a26a e0a3c60e 00f0b479 66ea2377 3cbf69e5

       A: hmac-md5  1b9c3838 b8494085 fc3c1a6c f24d61a0

       seq=0x00000000 replay=4 flags=0x00000000 state=mature

       created: May 29 14:08:01 2012   current: May 29 14:34:22 2012

       diff: 1581(s)   hard: 3600(s)   soft: 2880(s)

       last: May 29 14:08:02 2012      hard: 0(s)      soft: 0(s)

       current: 6996(bytes)    hard: 0(bytes)  soft: 0(bytes)

       allocated: 159  hard: 0 soft: 0

       sadb_seq=0 pid=3693 refcnt=0

 

A perl script found in one of the links in the resources was modified to print the connexion information needed to decode the traffic in Wireshark:

 

#!/usr/bin/perl

# must be SUID, have root running this, or some permission voodoo

open(RACOON, "racoonctl show-sa esp|") || die "can't execute racoonctl successfully\n";

$sa = 1;

while (<RACOON>) {

  chop();

  if (/^[0-9]/) {

    ($ip1, $ip2) = split(/\s+/, $_);

    # print the SA #1 line for wireshark

    print "SA #$sa:\t\t\tIPv4|$ip1|$ip2|*\n";

    $sa++;

  }

  ($x, $one, $two, $three, $four, $five, $six) = ('','','','','','','');

  if (/^\s*E: aes-cbc/ || /^\s*E: 3des-cbc/) {

    if (!$aes_1) {

            # print "AES-1:\t0x";

            print "Encryption Key #1:\t0x";

            ($x, $x, $x, $one, $two, $three, $four, $five, $six) = split(/\s+/, $_);

            $aes_1 = "$one$two$three$four$five$six";

            # print "AES-1: $aes_1\n";

            print "$aes_1\n";

    } else {

            # print "AES-2:\t0x";

            print "Encryption Key #2:\t0x";

            ($x, $x, $x, $one, $two, $three, $four, $five, $six) = split(/\s+/, $_);

            $aes_2 = "$one$two$three$four$five$six";

            # print "AES-2: $aes_2\n";

            print "$aes_2\n";

    }

  }

  ($x, $one, $two, $three, $four, $five, $six) = ('','','','','','','');

  if (/^\s*A: hmac-sha1/ || /^\s*A: hmac-md5/) {

    if (!$hmac_1) {

      # print "HMAC-1:\t0x";

      print "Authentication Key #1:\t0x";

      ($x, $x, $x, $one, $two, $three, $four, $five) = split(/\s+/, $_);

      $hmac_1 = "$one$two$three$four$five";

      # print "HMAC-1: $hmac_1\n";

      print "$hmac_1\n";

    } else {

      # print "HMAC-2:\t0x";

      print "Authentication Key #2:\t0x";

      ($x, $x, $x, $one, $two, $three, $four, $five) = split(/\s+/, $_);

      $hmac_2 = "$one$two$three$four$five";

      # print "HMAC-2: $hmac_2\n";

      print "$hmac_2\n";

    }

  }

}

 

This returns something like:

 

# perl test.pl

SA #1:                  IPv4|176.31.238.10|63.79.179.238|*

Encryption Key #1:      0x7249193173afee2d2bf4a56fdbf29918b109691231a4cf8f

Authentication Key #1:  0xfc8720e3d9a67425c26a59fa5c7a9dfe

SA #2:                  IPv4|63.79.179.238|176.31.238.10|*

Encryption Key #2:      0x8bb7e3647df2e863303f0951df1dd792daae23eb6260398b

Authentication Key #2:  0x0f6a1e23daa5f82ee8f19e2798f4452c

 

Which can be used then in Wireshark to decode the traffic sent in the tunnel and captured with a:

 

# ngrep -pql host IPGATEWAYVPN -O TC.pcap

 

The following image show the configuration done in Wireshark with the keys above.

 

 

DNS configuration

 

Verizon advises to use a DNS SRV to configure redundant servers or load balancing.

 

To test a SRV domain we can use either of the following two commands:

 

# host -t SRV _sip._udp.sip344.youroute.net

# nslookup -type=SRV _sip._udp.sip344.youroute.net

 

To configure a DNS SRV named vsp for the domain we can add in /var/cache/bind/db.switzernet.com of ns1.switzernet.com the following two lines:

 

_sip._udp.vsp                     SRV      10       1      5060 vspser1.switzernet.com.

_sip._udp.vsp                     SRV      10       1      5060 vspser2.switzernet.com.

 

or

 

_sip._udp.vsp.switzernet.com.     SRV      10       1      5060 vspser1.switzernet.com.

_sip._udp.vsp.switzernet.com.     SRV      10       1      5060 vspser2.switzernet.com.

 

After changing the stamp and restarting bind, we’ll have DNR SRV based load balancing:

 

# host -t SRV _sip._udp.vsp.switzernet.com

_sip._udp.vsp.switzernet.com has SRV record 10 1 5060 vspser2.switzernet.com.

_sip._udp.vsp.switzernet.com has SRV record 10 1 5060 vspser1.switzernet.com.

# host -t SRV _sip._udp.vsp.switzernet.com

_sip._udp.vsp.switzernet.com has SRV record 10 1 5060 vspser1.switzernet.com.

_sip._udp.vsp.switzernet.com has SRV record 10 1 5060 vspser2.switzernet.com.

# host -t SRV _sip._udp.vsp.switzernet.com

_sip._udp.vsp.switzernet.com has SRV record 10 1 5060 vspser2.switzernet.com.

_sip._udp.vsp.switzernet.com has SRV record 10 1 5060 vspser1.switzernet.com.

# host -t SRV _sip._udp.vsp.switzernet.com

_sip._udp.vsp.switzernet.com has SRV record 10 1 5060 vspser1.switzernet.com.

_sip._udp.vsp.switzernet.com has SRV record 10 1 5060 vspser2.switzernet.com.

 

Kamailio installation:

 

Download from the Kamailio repo the latest version of Kamailio:

 

# wget http://deb.kamailio.org/kamailiodebkey.gpg

# apt-key add kamailiodebkey.gpg

# echo -e "\n\ndeb http://deb.kamailio.org/kamailio squeeze main\ndeb-src http://deb.kamailio.org/kamailio squeeze main" >> /etc/apt/sources.list

# apt-get update

 

Install Kamailio and Mysql DB:

 

# apt-get install kamailio kamailio-mysql-modules kamailio-geoip-modules kamailio-nth kamailio-utils-modules

# apt-get install mysql-server-5.1

 

Choose the root password for Mysql when asked.

 

Backup the original configuration files. When working on a configuration file, append a version number to the filename (choose the next number that doesn’t exist).

 

# cp /etc/kamailio/kamailio.cfg /etc/kamailio/kamailio.cfg.original

# cp /etc/kamailio/kamailio.cfg /etc/kamailio/kamailio.cfg.1

# cp /etc/kamailio/kamctlrc /etc/kamailio/kamctlrc.orginal

# cp /etc/default/kamailio /etc/default/kamailio.original

# sed -i -r 's/RUN_KAMAILIO.*/RUN_KAMAILIO=yes/g' /etc/default/kamailio

 

Edit /etc/kamailio/kamctlrc to look like this:

 

# cat /etc/kamailio/kamctlrc|grep -vE "^$|^#"

DBENGINE=MYSQL

DBHOST=localhost

DBNAME=openser

DBRWUSER=openser

DBRWPW="openserrw"

DBROUSER=openserro

DBROPW=openserro

DBROOTUSER="root"

INSTALL_EXTRA_TABLES=ask

INSTALL_PRESENCE_TABLES=ask

CTLENGINE="FIFO"

OSER_FIFO="/tmp/kamailio_fifo"

 

Run the following command to create the DB that will be used by Kamailio:

kamdbctl create

Kamailio configuration:

 

Edit /etc/kamailio/kamailio.cfg.1 to contain the following configuration. Differences and comments in green:

 

#!KAMAILIO

#

# Kamailio (OpenSER) SIP Server v3.2 - default configuration script

#     - web: http://www.kamailio.org

#     - git: http://sip-router.org

#

# Direct your questions about this file to: <sr-users@lists.sip-router.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 IP authentication execute:

#     - enable mysql

#     - enable authentication

#     - define WITH_IPAUTH

#     - add IP addresses with group id '1' to 'address' table

#

# *** 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 enable database aliases lookup execute:

#     - enable mysql

#     - define WITH_ALIASDB

#

# *** To enable speed dial lookup execute:

#     - enable mysql

#     - define WITH_SPEEDDIAL

#

# *** To enable multi-domain support execute:

#     - enable mysql

#     - define WITH_MULTIDOMAIN

#

# *** To enable TLS support execute:

#     - adjust CFGDIR/tls.cfg as needed

#     - define WITH_TLS

#

# *** To enable XMLRPC support execute:

#     - define WITH_XMLRPC

#     - adjust route[XMLRPC] for access policy

#

# *** To enable anti-flood detection execute:

#     - adjust pike and htable=>ipban settings as needed (default is

#       block if more than 16 requests in 2 seconds and ban for 300 seconds)

#     - define WITH_ANTIFLOOD

#

# *** To block 3XX redirect replies execute:

#     - define WITH_BLOCK3XX

#

# *** To enable VoiceMail routing execute:

#     - define WITH_VOICEMAIL

#     - set the value of voicemail.srv_ip

#     - adjust the value of voicemail.srv_port

#

# *** 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 src_ip varchar(64) 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 src_ip varchar(64) 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

 

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

##Modules enabled

###!define WITH_DEBUG

#!define WITH_MYSQL

#!define WITH_AUTH

#!define WITH_IPAUTH

#!define WITH_PSTN

#!define WITH_ANTIFLOOD

 

# *** Value defines - IDs used later in config

#!ifdef WITH_MYSQL

# - database URL - used to connect to database server by modules such

#       as: auth_db, acc, usrloc, a.s.o.

#!define DBURL "mysql://openser:openserrw@localhost/openser"

#!endif

#!ifdef WITH_MULTIDOMAIN

# - the value for 'use_domain' parameters

#!define MULTIDOMAIN 1

#!else

#!define MULTIDOMAIN 0

#!endif

 

# - flags

#   FLT_ - per transaction (message) flags

#       FLB_ - per branch flags

#!define FLT_ACC 1

#!define FLT_ACCMISSED 2

#!define FLT_ACCFAILED 3

#!define FLT_NATS 5

 

#!define FLB_NATB 6

#!define FLB_NATSIPPING 7

 

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

 

#!ifdef WITH_DEBUG

debug=4

log_stderror=yes

#!else

debug=2

log_stderror=no

#!endif

 

memdbg=5

memlog=5

 

log_facility=LOG_LOCAL0

 

fork=yes

children=4

 

/* uncomment the next line to disable TCP (default on) */

## Uncommented to disable TCP

disable_tcp=yes

 

/* uncomment the next line to disable the auto discovery of local aliases

   based on reverse DNS on IPs (default on) */

#auto_aliases=no

 

/* add local domain aliases */

## Created alias with the name of the machine

alias="vspser1.switzernet.com"

#alias="vsp.switzernet.com"

 

/* 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:10.0.0.10:5060

 

/* port to listen to

 * - can be specified more than once if needed to listen on many ports */

port=5060

 

#!ifdef WITH_TLS

enable_tls=yes

#!endif

 

# 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

 

## Enabled the following options required to solve DNS SRV names and do failover and load balancing

use_dns_cache=on

use_dns_failover=on

dns_srv_loadbalancing=on

 

####### 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:

## Variables with the IPs and DNS SRV of the VoIP gateways. Used for outgoing calls

pstn.gw_ip  = "63.79.178.195" desc "Verizon"

pstn.gw_ip2 = "63.79.178.193" desc "Verizon"

pstn.gw_ip3 = "emeanslist.voip4home.com" desc "Verizon SIP SRV"

#

# - by default is empty to avoid misrouting

# pstn.gw_ip = "" desc "PSTN GW Address"

#!endif

 

#!ifdef WITH_VOICEMAIL

# VoiceMail Routing on offline, busy or no answer

#

# - by default Voicemail server IP is empty to avoid misrouting

voicemail.srv_ip = "" desc "VoiceMail IP Address"

voicemail.srv_port = "5060" desc "VoiceMail Port"

#!endif

 

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

 

# set paths to location of modules (to sources or installation folders)

#!ifdef WITH_SRCPATH

mpath="modules_k:modules"

#!else

mpath="/usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/"

#!endif

 

#!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 "siputils.so"

loadmodule "xlog.so"

loadmodule "sanity.so"

loadmodule "ctl.so"

loadmodule "cfg_rpc.so"

loadmodule "mi_rpc.so"

loadmodule "acc.so"

## Additional module required to rewrite packets

loadmodule "uac.so"

loadmodule "cfgutils.so"

 

#!ifdef WITH_AUTH

loadmodule "auth.so"

loadmodule "auth_db.so"

#!ifdef WITH_IPAUTH

loadmodule "permissions.so"

#!endif

#!endif

 

#!ifdef WITH_ALIASDB

loadmodule "alias_db.so"

#!endif

 

#!ifdef WITH_SPEEDDIAL

loadmodule "speeddial.so"

#!endif

 

#!ifdef WITH_MULTIDOMAIN

loadmodule "domain.so"

#!endif

 

#!ifdef WITH_PRESENCE

loadmodule "presence.so"

loadmodule "presence_xml.so"

#!endif

 

#!ifdef WITH_NAT

loadmodule "nathelper.so"

loadmodule "rtpproxy.so"

#!endif

 

#!ifdef WITH_TLS

loadmodule "tls.so"

#!endif

 

#!ifdef WITH_ANTIFLOOD

loadmodule "htable.so"

loadmodule "pike.so"

#!endif

 

#!ifdef WITH_XMLRPC

loadmodule "xmlrpc.so"

#!endif

 

#!ifdef WITH_DEBUG

loadmodule "debugger.so"

#!endif

 

## Module required for incoming calls. Used to configure how the call is delivered to Astrads

loadmodule "dispatcher.so"

#loadmodule "geoip"

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

 

 

# ----- mi_fifo params -----

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

 

 

# ----- tm params -----

# auto-discard branches from previous serial forking leg

modparam("tm", "failure_reply_mode", 3)

# default retransmission timeout: 30sec

modparam("tm", "fr_timer", 30000)

# default invite retransmission timeout after 1xx: 120sec

modparam("tm", "fr_inv_timer", 120000)

 

 

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

## Required to mask fields

modparam("rr", "append_fromtag", 1)

 

 

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

# max value for expires of registrations

modparam("registrar", "max_expires", 3600)

 

 

# ----- acc params -----

/* what special events should be accounted ? */

modparam("acc", "early_media", 0)

modparam("acc", "report_ack", 0)

modparam("acc", "report_cancels", 0)

/* 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", "log_flag", FLT_ACC)

modparam("acc", "log_missed_flag", FLT_ACCMISSED)

modparam("acc", "log_extra",

        "src_user=$fU;src_domain=$fd;src_ip=$si;"

        "dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")

modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)

/* enhanced DB accounting */

#!ifdef WITH_ACCDB

modparam("acc", "db_flag", FLT_ACC)

modparam("acc", "db_missed_flag", FLT_ACCMISSED)

modparam("acc", "db_url", DBURL)

modparam("acc", "db_extra",

        "src_user=$fU;src_domain=$fd;src_ip=$si;"

        "dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")

#!endif

 

 

# ----- usrloc params -----

/* enable DB persistency for location entries */

#!ifdef WITH_USRLOCDB

modparam("usrloc", "db_url", DBURL)

modparam("usrloc", "db_mode", 2)

modparam("usrloc", "use_domain", MULTIDOMAIN)

#!endif

 

 

# ----- auth_db params -----

#!ifdef WITH_AUTH

modparam("auth_db", "db_url", DBURL)

modparam("auth_db", "calculate_ha1", yes)

modparam("auth_db", "password_column", "password")

modparam("auth_db", "load_credentials", "")

modparam("auth_db", "use_domain", MULTIDOMAIN)

 

# ----- permissions params -----

#!ifdef WITH_IPAUTH

modparam("permissions", "db_url", DBURL)

modparam("permissions", "db_mode", 1)

#!endif

 

#!endif

 

 

# ----- alias_db params -----

#!ifdef WITH_ALIASDB

modparam("alias_db", "db_url", DBURL)

modparam("alias_db", "use_domain", MULTIDOMAIN)

#!endif

 

 

# ----- speedial params -----

#!ifdef WITH_SPEEDDIAL

modparam("speeddial", "db_url", DBURL)

modparam("speeddial", "use_domain", MULTIDOMAIN)

#!endif

 

 

# ----- domain params -----

#!ifdef WITH_MULTIDOMAIN

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

# use caching

modparam("domain", "db_mode", 1)

# register callback to match myself condition with domains list

modparam("domain", "register_myself", 1)

#!endif

 

 

#!ifdef WITH_PRESENCE

# ----- presence params -----

modparam("presence", "db_url", DBURL)

 

# ----- presence_xml params -----

modparam("presence_xml", "db_url", DBURL)

modparam("presence_xml", "force_active", 1)

#!endif

 

 

#!ifdef WITH_NAT

# ----- rtpproxy params -----

modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:7722")

 

# ----- nathelper params -----

modparam("nathelper", "natping_interval", 30)

modparam("nathelper", "ping_nated_only", 1)

modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)

modparam("nathelper", "sipping_from", "sip:pinger@kamailio.org")

 

# params needed for NAT traversal in other modules

modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)")

modparam("usrloc", "nat_bflag", FLB_NATB)

#!endif

 

 

#!ifdef WITH_TLS

# ----- tls params -----

modparam("tls", "config", "/etc/kamailio/tls.cfg")

#!endif

 

#!ifdef WITH_ANTIFLOOD

# ----- pike params -----

modparam("pike", "sampling_time_unit", 2)

modparam("pike", "reqs_density_per_unit", 16)

modparam("pike", "remove_latency", 4)

 

# ----- htable params -----

# ip ban htable with autoexpire after 5 minutes

modparam("htable", "htable", "ipban=>size=8;autoexpire=300;")

#!endif

 

#!ifdef WITH_XMLRPC

# ----- xmlrpc params -----

modparam("xmlrpc", "route", "XMLRPC");

modparam("xmlrpc", "url_match", "^/RPC")

#!endif

 

#!ifdef WITH_DEBUG

# ----- debugger params -----

modparam("debugger", "cfgtrace", 1)

#!endif

 

## Module configuration for incoming calls distribution. Used to configure how the call is delivered to Astrads.

# ----- dispatcher params -----

modparam("dispatcher", "db_url",

        "mysql://openserro:openserro@localhost/openser")

modparam("dispatcher", "table_name", "dispatcher")

modparam("dispatcher", "flags", 2)

modparam("dispatcher", "dst_avp", "$avp(AVP_DST)")

modparam("dispatcher", "grp_avp", "$avp(AVP_GRP)")

modparam("dispatcher", "cnt_avp", "$avp(AVP_CNT)")

 

## Module configuration for outgoing calls. Random distribution between two servers with 50% probability for each one

# ------- cfgutils params -------

modparam("cfgutils", "initial_probability", 50)

 

# ------- uak params -------

modparam("uac","from_restore_mode","auto")

 

# ------- geoip params -------

# - Download DB from http://geolite.maxmind.com/download/geoip/database/

# modparam("geoip", "path", "/usr/local/share/GeoLiteCity.dat")

 

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

 

 

# Main SIP request routing logic

# - processing of any incoming SIP request starts with this route

# - note: this is the same as route { ... }

request_route {

 

        # per request initial checks

        route(REQINIT);

 

        # NAT detection

        route(NATDETECT);

 

        # handle requests within SIP dialogs

        route(WITHINDLG);

 

        ### only initial requests (no To tag)

 

        # 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(FLT_ACC); # do accounting

        }

 

        # dispatch requests to foreign domains

        route(SIPOUT);

 

        ### requests for my local domains

 

        # handle presence related requests

        route(PRESENCE);

 

        # handle registrations

        route(REGISTRAR);

 

        if ($rU==$null)

        {

                # request with no Username in RURI

                sl_send_reply("484","Address Incomplete");

                exit;

        }

 

        # dispatch destinations to PSTN

        route(PSTN);

 

        # round-robin calls received from VoIP providers to nodes

        route(DISPATCH);

 

        xlog("SCRIPT: Unauthorized call\n");

        # Unauthorized call

        exit;

 

        # user location service

        # route(LOCATION);

 

        # route(RELAY);

}

 

 

route[RELAY] {

 

        # enable additional event routes for forwarded requests

        # - serial forking, RTP relaying handling, a.s.o.

        if (is_method("INVITE|SUBSCRIBE")) {

                t_on_branch("MANAGE_BRANCH");

                t_on_reply("MANAGE_REPLY");

        }

        if (is_method("INVITE")) {

                t_on_failure("MANAGE_FAILURE");

        }

 

        if (!t_relay()) {

                sl_reply_error();

        }

        exit;

}

 

# Per SIP request initial checks

route[REQINIT] {

#!ifdef WITH_ANTIFLOOD

        # flood dection from same IP and traffic ban for a while

        # be sure you exclude checking trusted peers, such as pstn gateways

        # - local host excluded (e.g., loop to self)

        if(src_ip!=myself)

        {

                if($sht(ipban=>$si)!=$null)

                {

                        # ip is already blocked

                        xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");

                        exit;

                }

                if (!pike_check_req())

                {

                        xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");

                        $sht(ipban=>$si) = 1;

                        exit;

                }

        }

#!endif

        # Some code to block initial attacks of some well known scripts

        if($ua =="friendly-scanner" || $ua=="sundayddr" || $ua=="sip-scan" || $ua=="iWar"){

                # geoip_match("$si", "src");

                xlog("Blocking $rm message from $fu@$si (User agent:$ua)\n");

                if( method=="REGISTER" ) {

                        sl_send_reply("200","OK");

                        exit;

                } else {

                        drop();

                }

        }

 

 

        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;

        }

}

 

# Handle requests within SIP dialogs

route[WITHINDLG] {

        if (has_totag()) {

                # sequential request withing a dialog should

                # take the path determined by record-routing

                if (loose_route()) {

                        if (is_method("BYE")) {

                                setflag(FLT_ACC); # do accounting ...

                                setflag(FLT_ACCFAILED); # ... even if the transaction fails

                        }

                        if ( is_method("ACK") ) {

                                # ACK is forwarded statelessy

                                route(NATMANAGE);

                        }

                        route(RELAY);

                } else {

                        if (is_method("SUBSCRIBE") && uri == myself) {

                                # in-dialog subscribe requests

                                route(PRESENCE);

                                exit;

                        }

                        if ( is_method("ACK") ) {

                                if ( t_check_trans() ) {

                                        # no 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

                                        exit;

                                }

                        }

                        sl_send_reply("404","Not here");

                }

                exit;

        }

}

 

# Handle SIP registrations

route[REGISTRAR] {

        if (is_method("REGISTER"))

        {

                if(isflagset(FLT_NATS))

                {

                        setbflag(FLB_NATB);

                        # uncomment next line to do SIP NAT pinging

                        ## setbflag(FLB_NATSIPPING);

                }

                if (!save("location"))

                        sl_reply_error();

 

                exit;

        }

}

 

# USER location service

route[LOCATION] {

 

#!ifdef WITH_SPEEDIAL

        # search for short dialing - 2-digit extension

        if($rU=~"^[0-9][0-9]$")

                if(sd_lookup("speed_dial"))

                        route(SIPOUT);

#!endif

 

#!ifdef WITH_ALIASDB

        # search in DB-based aliases

        if(alias_db_lookup("dbaliases"))

                route(SIPOUT);

#!endif

 

        $avp(oexten) = $rU;

        if (!lookup("location")) {

                $var(rc) = $rc;

                route(TOVOICEMAIL);

                t_newtran();

                switch ($var(rc)) {

                        case -1:

                        case -3:

                                send_reply("404", "Not Found");

                                exit;

                        case -2:

                                send_reply("405", "Method Not Allowed");

                                exit;

                }

        }

 

        # when routing via usrloc, log the missed calls also

        if (is_method("INVITE"))

        {

                setflag(FLT_ACCMISSED);

        }

}

 

# Presence server route

route[PRESENCE] {

        if(!is_method("PUBLISH|SUBSCRIBE"))

                return;

 

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

        if (is_method("REGISTER"))

        {

                # authenticate the REGISTER requests (uncomment to enable auth)

                if (!www_authorize("$td", "subscriber"))

                {

                        www_challenge("$td", "0");

                        exit;

                }

 

                if ($au!=$tU)

                {

                        sl_send_reply("403","Forbidden auth ID");

                        exit;

                }

        } else {

 

#!ifdef WITH_IPAUTH

                if(allow_source_address())

                {

                        # source IP allowed

                        return;

                }

#!endif

 

                # authenticate if from local subscriber

                if (from_uri==myself)

                {

                        if (!proxy_authorize("$fd", "subscriber")) {

                                proxy_challenge("$fd", "0");

                                exit;

                        }

                        if (is_method("PUBLISH"))

                        {

                                if ($au!=$fU || $au!=$tU) {

                                        sl_send_reply("403","Forbidden auth ID");

                                        exit;

                                }

                                if ($au!=$rU) {

                                        sl_send_reply("403","Forbidden R-URI");

                                        exit;

                                }

#!ifdef WITH_MULTIDOMAIN

                                if ($fd!=$rd) {

                                        sl_send_reply("403","Forbidden R-URI domain");

                                        exit;

                                }

#!endif

                        } else {

                                if ($au!=$fU) {

                                        sl_send_reply("403","Forbidden auth ID");

                                        exit;

                                }

                        }

 

                        consume_credentials();

                        # caller authenticated

                } else {

                        # caller is not local subscriber, then check if it calls

                        # a local destination, otherwise deny, not an open relay here

                        if (!uri==myself)

                        {

                                sl_send_reply("403","Not relaying");

                                exit;

                        }

                }

        }

#!endif

        return;

}

 

# Caller NAT detection route

route[NATDETECT] {

#!ifdef WITH_NAT

        force_rport();

        if (nat_uac_test("19")) {

                if (is_method("REGISTER")) {

                        fix_nated_register();

                } else {

                        fix_nated_contact();

                }

                setflag(FLT_NATS);

        }

#!endif

        return;

}

 

# RTPProxy control

route[NATMANAGE] {

#!ifdef WITH_NAT

        if (is_request()) {

                if(has_totag()) {

                        if(check_route_param("nat=yes")) {

                                setbflag(FLB_NATB);

                        }

                }

        }

        if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB)))

                return;

 

        rtpproxy_manage();

 

        if (is_request()) {

                if (!has_totag()) {

                        add_rr_param(";nat=yes");

                }

        }

        if (is_reply()) {

                if(isbflagset(FLB_NATB)) {

                        fix_nated_contact();

                }

        }

#!endif

        return;

}

 

# Routing to foreign domains

route[SIPOUT] {

        if (!uri==myself)

        {

                append_hf("P-hint: outbound\r\n");

                route(RELAY);

        }

}

 

# 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 routing enabled but pstn.gw_ip not defined\n");

                return;

        }

        if(!allow_source_address(1))

                return;

        # route to PSTN dialed numbers starting with '+' or '00' that don't match owr own

        #     (international format)

        # - update the condition to match your dialing rules for PSTN routing

        # Minimum number length is 6 and maximum is 21

        if(!($rU=~"^(\+|00)?[1-9][0-9]{5,20}$") || $rU=~"^(\+|00)?41[0-9]{2}55[0-9]{5}$")

                return;

        # only local users allowed to call

        if(!allow_source_address(1) && from_uri!=myself) {

                sl_send_reply("403", "Not Allowed");

                exit;

        }

        # For code for generating random call distribution

#        if (rand_event()) {

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

#        } else {

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

#        }

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

        xlog("SCRIPT: CALL FROM $fu@$si TO PSTN $ru\n");

        $td = $sel(cfg_get.pstn.gw_ip);

        uac_replace_from("sip:$fU@$Ri");

        remove_hf("h323-conf-id");

        # Screen=should be yes if we are hiding the CID or not masking the CID. If we mask it with other number should be yes

        # At this moment we dont comply with TC22. Masking CID with another number should have screen=yes

        if ( search("privacy=full;screen=yes") ) {

               # Caller ID hiding. In this case Asterisk sends two headers. This deletes the second and corrects the domain.

               subst('/^Remote-Party-ID:(.*)@[0-9.]*>;party=calling;privacy=off;screen=no/X-RPID:Hide/i');

               remove_hf("X-RPID");

               subst('/^Remote-Party-ID:(.*)@.*privacy=full;screen=yes/Remote-Party-ID:\1@$Ri>;privacy=full;screen=yes/ig');

        } else {

               # Replaces the RPID domain by the interface where we've received the traffic and changes screen to yes

               subst('/^Remote-Party-ID:(.*)@[0-9.]*>;party=calling;privacy=off;screen=no/Remote-Party-ID:\1@$Ri>;privacy=off;screen=yes/i');

        }

        if ( search("X-DH: SIP") ) {

               if (subst('/^X-DH: SIP\/(.*)-NOANSWER./Diversion: <sip:+\1@$Ri>;reason=no-answer/i') == 0) {

                      if (subst('/^X-DH: SIP\/(.*)-BUSY./Diversion: <sip:+\1@$Ri>;reason=user-busy/i') == 0) {

                             subst('/^X-DH: SIP\/(.*)./Diversion: <sip:+\1@$Ri>;reason=user-busy/i');

                      }

               }

        }

        route(RELAY);

        exit;

#!endif

 

        return;

}

 

# XMLRPC routing

#!ifdef WITH_XMLRPC

route[XMLRPC] {

        # allow XMLRPC from localhost

        if ((method=="POST" || method=="GET")

                        && (src_ip==127.0.0.1)) {

                # close connection only for xmlrpclib user agents (there is a bug in

                # xmlrpclib: it waits for EOF before interpreting the response).

                if ($hdr(User-Agent) =~ "xmlrpclib")

                        set_reply_close();

                set_reply_no_connect();

                dispatch_rpc();

                exit;

        }

        send_reply("403", "Forbidden");

        exit;

}

#!endif

 

# route to voicemail server

route[TOVOICEMAIL] {

#!ifdef WITH_VOICEMAIL

        if(!is_method("INVITE"))

                return;

 

        # check if VoiceMail server IP is defined

        if (strempty($sel(cfg_get.voicemail.srv_ip))) {

                xlog("SCRIPT: VoiceMail routing enabled but IP not defined\n");

                return;

        }

        if($avp(oexten)==$null)

                return;

 

        $ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)

                                + ":" + $sel(cfg_get.voicemail.srv_port);

        route(RELAY);

        exit;

#!endif

 

        return;

}

 

route[DISPATCH] {

        if (!allow_source_address(2))

                return;

        # round robin dispatching on gateways group '1'

        if(!ds_select_dst("1", "4"))

        {

                send_reply("404", "No destination");

                exit;

        }

        # ru should be in E164 format?

        # $rU = '41215500331';

        xlog("SCRIPT: going to <$ru> via <$du>\n");

        t_on_failure("RTF_DISPATCH");

        route(RELAY);

        return;

}

 

# Sample failure route

failure_route[RTF_DISPATCH] {

        if (t_is_canceled()) {

                exit;

        }

        # next DST - only for 500 or local timeout

        if (t_check_status("500")

                        or (t_branch_timeout() and !t_branch_replied()))

        {

                if(ds_next_dst())

                {

                        t_on_failure("RTF_DISPATCH");

                        route(RELAY);

                        exit;

                }

        }

}

 

# manage outgoing branches

branch_route[MANAGE_BRANCH] {

        xdbg("new branch [$T_branch_idx] to $ru\n");

        route(NATMANAGE);

}

 

# manage incoming replies

onreply_route[MANAGE_REPLY] {

        xdbg("incoming reply\n");

        if(status=~"[12][0-9][0-9]")

                route(NATMANAGE);

}

 

# manage failure routing cases

failure_route[MANAGE_FAILURE] {

        route(NATMANAGE);

 

        if (t_is_canceled()) {

                exit;

        }

 

#!ifdef WITH_BLOCK3XX

        # block call redirect based on 3xx replies.

        if (t_check_status("3[0-9][0-9]")) {

                t_reply("404","Not found");

                exit;

        }

#!endif

 

#!ifdef WITH_VOICEMAIL

        # serial forking

        # - route to voicemail on busy or no answer (timeout)

        if (t_check_status("486|408")) {

                route(TOVOICEMAIL);

                exit;

        }

#!endif

}

 

The main modifications in the file above were in the route PSTN which is used for calls from nodes to vendors and the addition of a new route DISPATCH which is used for calls from the vendors to our customers.

 

Explaining in depth of the following code:

 

route[DISPATCH] {

        if (!allow_source_address(2))

                return;

        # round robin dispatching on gateways group '1'

        if(!ds_select_dst("1", "4"))

        {

                send_reply("404", "No destination");

                exit;

        }

        # ru should be in E164 format?

        # $rU = '41215500331';

        xlog("SCRIPT: going to <$ru> via <$du>\n");

        t_on_failure("RTF_DISPATCH");

        route(RELAY);

        return;

}

 

allow_source_address(2) - Allows only calls from servers in table address with group id 2 (vendors).

 

ds_select_dst("1", "4") – Send call to servers in table dispatcher with setid 1 using call distribution method number 4. We can choose from the following call distributions:

 

0” - hash over callid

1” - hash over from uri.

2” - hash over to uri.

3” - hash over request-uri.

4” - round-robin (next destination).

5” - hash over authorization-username (Proxy-Authorization or "normal" authorization). If no username is found, round robin is used.

6” - random (using rand()).

7” - hash over the content of PVs string. Note: This works only when the parameter hash_pvar is set.

8” - use first destination (good for failover).

9” - use weight based load distribution. You have to set the attribute 'weight' per each address in destination set.

10” - use call load distribution. You have to set the attribute 'duid' (as an unique string id) per each address in destination set. Also, you must set parameters 'dstid_avp' and 'ds_hash_size'.

The algorithm can be used even with stateless proxy mode, there is no SIP dialog tracking depending on other modules, just an internal lightweight call tracking by Call-Id, thus is fast and suitable even for embedded systems.

The first destination selected by this algorithm is the one that has the least number of calls associated. The rest of the destination list is taken in order of the entries in set - anyhow, until a re-route to next destination happens, the load on each address can change.

This algorithm can be used only for dispatching INVITE requests as it is the only SIP method creating a SIP call.

X” - if the algorithm is not implemented, the first entry in set is chosen.

 

Some code might still be needed to guarantee that the number delivered in each Astrad is in the E164 format. It should be verified if Porta-Billing can do this by itself.

 

The code bellow was used for the tests as the number used for incoming calls didn’t exist in our network. With this we masked the called number:

 

        # ru should be in E164 format?

        # $rU = '41215500331';

 

The route PSTN is more complex as we need to guarantee each of the specifications sent by Verizon:

 

route[PSTN]

        if(!allow_source_address(1))

                return;

        # route to PSTN dialed numbers starting with '+' or '00' that don't match owr own

        #     (international format)

        # - update the condition to match your dialing rules for PSTN routing

        # Minimum number length is 6 and maximum is 21

        if(!($rU=~"^(\+|00)?[1-9][0-9]{5,20}$") || $rU=~"^(\+|00)?41[0-9]{2}55[0-9]{5}$")

                return;

        # only local users allowed to call

        if(!allow_source_address(1) && from_uri!=myself) {

                sl_send_reply("403", "Not Allowed");

                exit;

        }

        # For code for generating random call distribution

#        if (rand_event()) {

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

#        } else {

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

#        }

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

        xlog("SCRIPT: CALL FROM $fu@$si TO PSTN $ru\n");

        $td = $sel(cfg_get.pstn.gw_ip);

        uac_replace_from("sip:$fU@$Ri");

        remove_hf("h323-conf-id");

        # Screen=should be yes if we are hiding the CID or not masking the CID. If we mask it with other number should be yes

        # At this moment we dont comply with TC22. Masking CID with another number should have screen=yes

        if ( search("privacy=full;screen=yes") ) {

               # Caller ID hiding. In this case Asterisk sends two headers. This deletes the second and corrects the domain.

               subst('/^Remote-Party-ID:(.*)@[0-9.]*>;party=calling;privacy=off;screen=no/X-RPID:Hide/i');

               remove_hf("X-RPID");

               subst('/^Remote-Party-ID:(.*)@.*privacy=full;screen=yes/Remote-Party-ID:\1@$Ri>;privacy=full;screen=yes/ig');

        } else {

               # Replaces the RPID domain by the interface where we've received the traffic and changes screen to yes

               subst('/^Remote-Party-ID:(.*)@[0-9.]*>;party=calling;privacy=off;screen=no/Remote-Party-ID:\1@$Ri>;privacy=off;screen=yes/i');

        }

        if ( search("X-DH: SIP") ) {

               if (subst('/^X-DH: SIP\/(.*)-NOANSWER./Diversion: <sip:+\1@$Ri>;reason=no-answer/i') == 0) {

                      if (subst('/^X-DH: SIP\/(.*)-BUSY./Diversion: <sip:+\1@$Ri>;reason=user-busy/i') == 0) {

                             subst('/^X-DH: SIP\/(.*)./Diversion: <sip:+\1@$Ri>;reason=user-busy/i');

                      }

               }

        }

}

 

allow_source_address(1) – Allows only calls from servers in table address with group id 1 (nodes).

$rU=~"^(\+|00)?[1-9][0-9]{5,20}$" – Allows only calls which call a number in this format

$rU=~"^(\+|00)?41[0-9]{2}55[0-9]{5}$" – Don’t call internal numbers

 

To send calls to Verizon we can send the call directly to the desired IP:

 

ru = "sip:" + $rU + "@63.79.178.193";

 

We can also randomly deliver the calls with a set percentage using module cfgutils. This can also be achieved with module dispatcher.

 

        # For code for generating random call distribution

        if (rand_event()) {

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

        } else {

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

        }

 

In alternative to the two previous options we can let the DNS do the failover/load balancing (cfg_get.pstn.gw_ip3 was defined with a DNS SRV domain):

 

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

 

We should use the same domain in variable $td, but in the configuration file above it was not done.

 

        $td = $sel(cfg_get.pstn.gw_ip3);

 

Then the From field is masked with the destination domain/ip of the proxy:

 

uac_replace_from("sip:$fU@$Ri");

 

Asterisk sends an RPID header with the desired CID, or double RPID header when we want to hide the CID. The code bellow removes the additional RPID and corrects the value of screen and privacy when needed. However there are cases where we are unable to comply due to missing information. We cannot distinguish a call where we’ve masked the caller id from another one where the caller id is the original. Due to this we are unable to set the screen value correctly.

 

        # Screen=should be yes if we are hiding the CID or not masking the CID. If we mask it with other number should be yes

        # At this moment we dont comply with TC22. Masking CID with another number should have screen=yes

        if ( search("privacy=full;screen=yes") ) {

               # Caller ID hiding. In this case Asterisk sends two headers. This deletes the second and corrects the domain.

               subst('/^Remote-Party-ID:(.*)@[0-9.]*>;party=calling;privacy=off;screen=no/X-RPID:Hide/i');

               remove_hf("X-RPID");

               subst('/^Remote-Party-ID:(.*)@.*privacy=full;screen=yes/Remote-Party-ID:\1@$Ri>;privacy=full;screen=yes/ig');

        } else {

               # Replaces the RPID domain by the interface where we've received the traffic and changes screen to yes

               subst('/^Remote-Party-ID:(.*)@[0-9.]*>;party=calling;privacy=off;screen=no/Remote-Party-ID:\1@$Ri>;privacy=off;screen=yes/i');

        }

 

If a follow me is set in Porta-Billing we can add a new header in asterisk to mark the call as redirected. In this case we can then add the header diversion required by Verizon in these cases, with the redirection reason.

 

        if ( search("X-DH: SIP") ) {

               if (subst('/^X-DH: SIP\/(.*)-NOANSWER./Diversion: <sip:+\1@$Ri>;reason=no-answer/i') == 0) {

                      if (subst('/^X-DH: SIP\/(.*)-BUSY./Diversion: <sip:+\1@$Ri>;reason=user-busy/i') == 0) {

                             subst('/^X-DH: SIP\/(.*)./Diversion: <sip:+\1@$Ri>;reason=user-busy/i');

                      }

               }

        }

 

After finishing editing this configuration file, replace the Kamailio’s configuration file by it.

 

# cp /etc/kamailio/kamailio.cfg.1 /etc/kamailio/kamailio.cfg

 

Connect to the database Openser.

 

# mysql -p openser

 

Add the IP addresses of all nodes to 'address' table with group id '1' to allow them to make calls through the vendor IP.

 

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.122.64',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.117.76',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.16.79',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.178.108',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.142.9',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.147.45',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.143.56',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.205.108',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.167.75',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.70.119',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.138.5',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.151.75',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.172.156',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.151.58',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.121.115',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'176.31.247.50',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'213.251.169.218',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'91.121.99.16',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'176.31.102.152',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (1,'213.251.170.99',32,5070);

 

Add IP address of provider servers with group id '2' to 'address' table to allow the vendor servers to call our nodes:

 

insert into address (grp,ip_addr,mask,port) VALUES (2,'63.79.178.193',32,5060);

insert into address (grp,ip_addr,mask,port) VALUES (2,'63.79.178.193',32,5060);

 

Add IP addresses of nodes with group id '1' to 'dispatcher' table to add them to the list of servers who will receive calls from the vendor using the distribution method defined:

 

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.117.76:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.16.79:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.178.108:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.142.9:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.147.45:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.143.56:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.205.108:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.167.75:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.70.119:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.138.5:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.151.75:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.172.156:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.151.58:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.121.115:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:176.31.247.50:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:213.251.169.218:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:91.121.99.16:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:176.31.102.152:5060',0);

insert into dispatcher (setid,destination,flags) VALUES (1,'sip:213.251.170.99:5070',0);

 

Restart Kamailio.

 

# /etc/init.d/kamailio restart

Test results

Donwloadable PCAPs for each test:

 

[TCA]  [TCB]  [TCB2]

[TC1]  [TC2]  [TC3]  [TC4]  [TC5]  [TC6]  [TC7]  [TC8]  [TC9]  [TC10]

[TC11] [TC12] [TC13] [TC14] [TC15] [TC16] [TC17] [TC18] [TC19] [TC20]

[TC21] [TC22] [TC23] [TC24] [TC25] [TC26] [TC27] [TC28] [TC29] [TC30]

[TC31] [TC32] [TC33] [TC34] [TC35] [TC36] [TC37] [TC38] [TC39] [TC40]

 

To decode the traces:

 

[Download]

Resources

VPN References:

http://arnaud.aucher.net/?page_id=81

http://blog.guiguiabloc.fr/index.php/2008/10/17/cluster-haute-disponibilite-chez-ovh-avec-ipfailover-heartbeat-et-drbd-via-ipsec/

http://forums.freebsd.org/showthread.php?t=15208

http://lartc.org/howto/lartc.ipsec.automatic.keying.html

http://osr600doc.sco.com/en/NET_ipsec/roadwarrior.html

http://patrickpreuss.wordpress.com/2009/02/14/dmvpn-with-linux/

http://wiki.debian.org/IPsec

http://www.kame.net/newsletter/20001119/

http://www.opennet.ru/openforum/vsluhforumID1/66742.html?n=Vel

http://www.vogelweith.com/debian_server/11_racoon.php

http://www.vps.net/forum/topic/1909-how-to-setup-host-to-host-ipsec-vpn-on-debian-lenny/

ftp://ftp.irisa.fr/local/idsa/doc/livrable/L1/1/html/Evaluation_IPsec_L1.1.html

 

DNS references:

http://www.voip-info.org/wiki/view/DNS+SRV

 

Wireshark references:

http://wiki.wireshark.org/ESP_Preferences

http://www.wireshark.org/lists/wireshark-users/201103/msg00084.html

http://www.gossamer-threads.com/lists/cisco/nsp/114153

 

Kamalio references:

http://www.kamailio.org/wiki/packages:debs

http://kamailio.org/docs/modules/stable/modules_k/dispatcher.html

http://kamailio.org/docs/modules/stable/modules/geoip.html

http://www.kamailio.org/dokuwiki/doku.php/features:new-in-3.1.x