Verizon Interconnection Procedure
André Guimarães, 2012-06-12
Switzernet
1.
Introduction
2.
Requirements
3.
VPN IPSec
4.
How to debug the traffic in the tunnel:
7.
Test results
8.
Resources
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.
To make this procedure you need a server installed with Debian 6.0.
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: 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.
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.
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
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
Donwloadable PCAPs for each test:
[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]
VPN References:
http://arnaud.aucher.net/?page_id=81
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://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