Wednesday, August 21, 2013

RTPproxy Revisited [Kamailio 4.0]

Time and again I see people getting stuck on RTPproxy integration with Kamailio. I recently got another opportunity to put RTPproxy in between the User Phones and Kamailio setup as depicted in the following diagram.



That is similar to what I've posted earlier on this topic. In this post I will try be more verbose and write each and every step I did to have RTPs flowing.

I assume you've a Kamailio installed and working and configurations file from Asipto Knowledge Base by Daniel and that there are TWO NICs configured with Public IP and Private IP as shown in the diagram above.

The important thing which I'm looking for from the configuration is the WITH_NAT tag. follow the code and see how the NAT is handled. route[NATMANAGE] is called at almost all important routes.

The overall idea is;

1- Install RTPproxy
2- Start RTPproxy in Bridged mode
3- Make Kamailio aware of multiple NICs
4- Add Private IP asterisks in dispatcher
5- Create a new route RTPPROXY to engage RTP-proxy whenever needed
6- Call in the RTPPROXY route in the NATMANAGE route.
7- Important Things to take care of.

So lets start following the steps.

1- Installing RTPproxy

root@Kamailio:~# cd /usr/src/
root@Kamailio:~# wget http://b2bua.org/chrome/site/rtpproxy-1.2.1.tar.gz
root@Kamailio:~# tar zxvf rtpproxy-1.2.1.tar.gz
root@Kamailio:~# cd rtpproxy-1.2.1/
root@Kamailio:~# ./configure
root@Kamailio:~# make
root@Kamailio:~# make install

Setup LSB script for RTP-proxy
root@Kamailio:~# cp debian/rtpproxy-default.ex /etc/default/rtpproxy
edit the default file and put in the parameters.
root@Kamailio:~# vim /etc/default/rtpproxy

2- Start RTPproxy in Bridged mode


DAEMON_OPTS="-F -s udp:127.0.0.1:7722 -l 77.66.55.44/192.168.1.244 -d DBUG:LOG_LOCAL0 -u root"

Save and Exit

root@Kamailio:~# cp debian/rtpproxy.init /etc/init.d/rtpproxy
root@Kamailio:~# chmod a+x /etc/init.d/rtpproxy

Open up the file

root@Kamailio:~# vim /etc/init.d/rtpproxy

see that the DAEMON field points to the file in /usr/bin/rtpproxy

DAEMON=/usr/bin/rtpproxy

Lets copy the RTPproxy binary to that location.

root@Kamailio:~# cp rtpproxy /usr/bin/rtpproxy

Start up RTPproxy

root@Kamailio:~# /etc/init.d/rtpproxy start

verify that rtpproxy is running and listening on the specified 7722 

root@Kamailio:~# netstat -pln | grep rtpp
udp        0      0 127.0.0.1:7722          0.0.0.0:*                           6554/rtpproxy
Thats all.

3- Making Kamailio aware of multiple NICs


Lets move on to step 3 involving Kamailio configurations.

root@Kamailio:~# vim /usr/local/etc/kamailio/kamailio.cfg

Insert the following line in global parameters section, just under where we define "listen=" or "port=" 

mhomed=1

That will ensure that Kamailio uses its Private IP to communicate with Asterisks on Private subnet. Don't forget this.

We also need to put this line on the top definitions of kamailio.cfg file so kamailio use the NAT functions.

#!define WITH_NAT

4- Adding Asterisks to dispatcher


Now Add Private IP asterisks in dispatcher: Follow my post on adding dispatcher to the plain configurations from here: http://saevolgo.blogspot.com/2011/11/how-to-increasing-voip-services.html

5- Writing some Kamailio routing logic for RTPPROXY

That was easy, now the real thing the addition of RTPPROXY route which I modified a little bit from the last link mentioned.

To have the code working I have used the SQLOPS module configured to query kamailio.dispatcher table as the AVPOPS module was already busy.

NOTE: Using the DB query is a costly operation BUT it allows me to detect if Kamailio is sending call to Dispatcher listed IPs or not. I have a mix of Asterisks on Private Subnet and on Public Subnet and if the Asterisk dispatcher has chosen or the call is coming from is a Private IP then engage RTPproxy. This detection is handled by IPOPS module and its function is_ip_rfc1918()

loadmodule "ipops.so"
loadmodule "sqlops.so"
modparam("sqlops","sqlcon","ca=>mysql://openser:openserrw@localhost/kamailio")

Then declare the route:

# RTPProxy control
route[RTPPROXY] {
        if (is_method("INVITE")){
                sql_query("ca", "select destination from dispatcher where destination like '%$dd%'","ra");
                if($dbr(ra=>rows)>0){
                        $avp(duip)=$(du{s.select,-2,:});
                        if (is_ip_rfc1918("$avp(duip)")) {
                                xlog("L_INFO", "Call is going to private IPv4 Media Server Engage RTPProxy Now\n");
                                #rtpproxy_manage("crwie","192.168.1.244");
                                rtpproxy_manage("rwie");
                        }

                }
                else if(ds_is_from_list()){
                        if (is_ip_rfc1918("$si")) {
                                xlog("L_INFO", " Call is coming from a private IPv4 Media Server Engage RTPProxy Now\n");
                                #rtpproxy_manage("crwei","77.66.55.44");
                                rtpproxy_manage("rwei");

                        }
                }else if(!ds_is_from_list()){
                          rtpproxy_manage("rwie");

                }
      }
}

6- Using RTPPROXY route

Add the RTPPROXY route just where the FLT_NATS and FLB_NATB flags are tested.

        if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))){
                return;
        }
                route(RTPPROXY);


Now Save and Exit the kamailio.cfg file.

Restart Kamailio.

root@Kamailio:~# /etc/init.d/kamailio stop
root@Kamailio:~# /etc/init.d/kamailio start

7- Helpful Things to know

Asterisk needs to have the peer declared for kamailio using its Private IP.

[Kamailio]
type=friend
host=192.168.1.244
port=5060
disallow=all
allow=gsm
allow=g729
allow=alaw
allow=ulaw
context=SBC-Incoming
canreinvite=no
insecure=port,invite
nat=force_rport,comedia
qualify=yes
directrtpsetup=no

See that I've used "directrtpsetup=no" so that Asterisk don't decide to go direct with the End caller.

Use xlog lines in kamailio.cfg file to follow the call.

The way I always setup my whole environment is that Kamailio handles the REGISTRATIONs and only INVITES are load-balanced to Asterisks or FreeSWITCHes where they receive the call from Kamailio peer and execute dialplan applications and IF call needs to dial out they dial the destination back to kamailio.
Kamailio needs to detect the call coming FROM the Media-Servers (ds_is_from_list() function)

So I know when a user calls in and when the call comes in from the media-servers.

Always try to first have an echo test working for calls. I use Asterisk application Echo() and when I dial in from user I get my own audio echoed back and I know that atleast my audio path is complete. This never tells you that your setup is 100% perfect but it is a good way to know if you're headed right direction.


Wireshark is a great Friend. Use it to examine everything in depth. No matter what I do I always need Wireshark to visually see what is going on with the SIP packets, that gives me everything I need to know to make things right.

root@Kamailio200:~# tcpdump -i any -s 0 -w rtp-calls.pcap -vvv
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
1666 packets captured
Download this "rtp-calls.pcap" file and open it up in Wireshark. Click "Telephony"  from the menu bar and select "VoIP Calls"


Hit the Flow button and you'll see beautiful arrows showing the direction of SIP and RTP packets.


On the very Left Hand side is my Soft Phone's Public IP address, then 77.66.55.44 is kamailio's WAN side, and suddenly we see 192.168.1.244 which is Private IP of Kamailio communicating with an Asterisk on 192.168.1.36
The Bold arrows labeled RTP are flowing in both direction means all Perfect.

Thats all for one day. Hope to have some comments and questions on this soon.

Sunday, July 28, 2013

Linux IPSec VPN-2: Amazon Cloud Sever & Linksys Router

This is a post in response to a comment made earlier on my previous blog post on Linux IPSec Setup asking for assistance. So here's what I could possibly do to help the needy.

This is a setup which I assisted one of my friend in creating a VPN between a Static IP Linksys Router and an Amazon cloud based server. Since we all know that Amazon cloud servers don't actually have a static public IP assigned to them instead they've a One-to-One NAT mechanism at the best so this becomes a bit trickier for anyone new to the OpenSWAN or IPSec in Linuxes.

Regardless of the Operating System the openswan package needs to be installed on the server properly. Please refer to other blogs or Google in order to install ipsec service. See this references in this link:

The topology we'll be working on is defined in the diagram below.


Now get to the configurations.

The ipsec.conf file contains these:

config setup
        interfaces=%defaultroute
        klipsdebug=all
        plutodebug=all
        protostack=netkey
        nat_traversal=yes
conn Linksys
        type=tunnel
        left=10.2.147.164
        leftnexthop=%defaultroute
        leftsubnet=10.2.147.164/26
        right=120.121.122.123
        rightnexthop=%defaultroute
        rightsubnet=192.168.4.0/24
        auth=esp
        keyexchange=ike
        authby=secret
        pfs=yes
        auto=start

And ipsec.secrets contains this:

10.2.147.164 120.121.122.123 : PSK  "y0ur_S3cret_PSK_k3y"

Lets quickly get to the Linksys router and adjust the router according to the following settings.

Move to the VPN tab after logging in to the Linksys router.




Save the settings and restart vpn on both ends. Your VPN should start rocking by now. Ping from the 192.168.4.0/24 LAN to the Amazon IPSec Server's Private IP and it should be replying.

Please always read logs on both the router and the linux server very carefully and figure out what they are trying to communicate. Without any logs I probably would never had created this VPN.

I hope it be of some help to someone. Have a great day.

Wednesday, July 24, 2013

NIC Bonding in CentOS 6.4,Ubuntu 12.04, and Vyatta 6.6

Its late night here and unexpectedly I'm high on motivation to do something except working hence just shifting my procrastination energy into writing this blog.

I've previously blogged a post on setting up an Active/Passive HA setup for Linux servers, so this on is one step further into one server. By one step further into the server I mean to have some form of High Availability on Network Interfaces.

Link Aggregation, NIC Bonding, NIC teaming, Interface Bonding are various names it is known as. Read some basics on it visit this wikipedia link.

My basic motivation for creating NIC Bonding on my servers was to create a self healing topology in which a single cable or interface failure do not impact any service at all. Since I've redundant powers, servers, switches, and routers setup from my very own hands so I know how this will add up in my setup. Removing one cable from the server keeps the server accessible and hence all services working perfectly fine.

The additional benefit which I can benefit from NIC bonding is link "Aggregation". The two 1Gbps interface will and can combine to give me an aggregated speed of 2Gbps. That is something I still need to test and probably post my findings on its reality sometime by transferring huge chunks of data.

WARNING: I had to reboot one of my server as I had an interface already configured so a service restart didn't work properly and the same IP remained configured on eth0 and bond0 and hence caused temporary access issue. Just to be sure have a KVM/ILOM remote access ready while doing this setup.

Lets move forward.

Creating NIC Bond interface on CentOS 6.4

[root@ASTERISK-A ~]# vim /etc/sysconfig/network-scripts/ifcfg-bond0

and insert the following fairly simple to understand lines.

DEVICE=bond0
IPADDR=192.168.15.10
NETMASK=255.255.255.0
GATEWAY=192.168.15.45
USERCTL=no
BOOTPROTO=none
ONBOOT=yes
DNS1=192.168.15.45

Now remember, we need to have atleast two NIC present on the server to be part of the bond. This could be three Gig Interfaces if you've them available in order to achieve a 3Gbps link.

Edit the Interfaces going to be part of this bond.

[root@ASTERISK-A ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth0

DEVICE=eth0
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
MASTER=bond0
SLAVE=yes

[root@ASTERISK-A ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth1

DEVICE=eth1
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
USERCTL=no
MASTER=bond0
SLAVE=yes

Now its time to setup some parameters for the 007-Bond Interface.

[root@ASTERISK-A ~]# vim /etc/modprobe.d/bonding.conf

Write the lines below in the file,save and exit.
alias bond0 bonding
options bond0 mode=1 miimon=100 arp_interval=100 arp_ip_target=192.168.15.45,192.168.15.5,192.168.15.20


The above configuration is used by the "bonding" Linux kernel module. The options are important here:

mode=1 : Set the bonding method to Active backup
miimon=100 : Set the MII link monitoring frequency to 100 milliseconds. This determines how often the link state of each slave is inspected for link failures.
arp_interval=100 : Set the ARP link monitoring frequency to 100 milliseconds (You can setup any keeping your network equipment in mind). This is important to be there.
arp_ip_target=192.168.15.45, 192.168.15.5 : Use the 192.168.15.5 (router ip) and 192.168.15.45 IP addresses to use as ARP monitoring peers when arp_interval is > 0. This is used determine the health of the link to the targets. Multiple IP addresses must be separated by a comma. At least one IP address must be given (usually I set it to router IP) for ARP monitoring to function. The maximum number of targets that can be specified is 16.

Thats all. Just restart the networking service and if you've any ethernet interface configured then you might need to shutdown that interface and start the network service again.

[root@ASTERISK-A ~]# /etc/init.d/network restart

Creating NIC Bond interface on Ubuntu 12.04

On Ubuntu Server the steps for configuring are 90% the same except that we need to install the package which gets the bonding kernel module.

root@OpenSIPS-A:~# apt-get install ifenslave

We just need to edit one file here.

root@OpenSIPS-A:~# vim /etc/network/interfaces

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual
        bond-master bond0

auto eth1
iface eth1 inet manual
        bond-master bond0

auto bond0
iface bond0 inet static
mtu 9000
        address 192.168.15.30
        netmask 255.255.255.0
        network 192.168.15.0
        broadcast 192.168.15.255
        gateway 192.168.15.45
        dns-nameservers 192.168.15.45
        bond-miimon 100
        bond-downdelay 200
        bond-updelay 200
        bond-mode active-backup
        bond-slaves none

To make sure that the bonding kernel module is loaded on reboots edit the file /etc/modules
add the word "bonding" at the end save, and exit. To Load bonding module right away execute the following command:

root@OpenSIPS-A:~# modprobe bonding

Now restart the networking service and bond0 interface should be up and ready. 

root@OpenSIPS-A:~# /etc/init.d/networking restart

             Creating NIC Bond interface on Vyatta 6.6

Vyatta is one of my favorite subject, huge thanks to Mr. Asim Ansari who introduced me to it back in 2010 and I've been using it and loving it ever since. There are other cool stuff Vyatta is doing for me which I'll cover later on. Lets see how to create a Bond Interface on Vyatta.

vyatta@FW-A:~$ configure
vyatta@FW-A# set interfaces bonding bond0 address 192.168.15.45/24
vyatta@FW-A# set interfaces bonding bond0 arp-monitor interval 100
vyatta@FW-A# set interfaces bonding bond0 mode adaptive-load-balance
vyatta@FW-A# set interfaces bonding bond0 mtu 9000
vyatta@FW-A# set interfaces ethernet eth0 bond-group bond0
vyatta@FW-A# set interfaces ethernet eth1 bond-group bond0
vyatta@FW-A# commit
vyatta@FW-A# save


WARNING: Once again ensure that the eth0 and eth1 are not assigned with IP address already, if so please delete them before assigning that ethX interface to bond-group. 

Thats all for tonight, I'm sleepy now and should take rest while you guys enjoy having good time with your servers and setups.

Recommended Articles:

Sunday, June 23, 2013

My Book: Implementing Citrix XenServer Quickstarter

Implementing Citrix XenServer Quickstarter
Last week was a happy week for me since my book got published by Packt Publish, its really a big achievement for me to have a book published internationally on some technical topic. It feels awesome to be an author.

It all started from my blog post on Vyatta+OpenSIPS on Citrix XEN-Server when it caught attention of an Author Relation Executive from Packt Publishing, a well known publisher for technical books. I was contacted and was subsequently asked to write a 100 page book on the Citrix XenServer.

So my work with this book started around Oct,2012  A lot of things changed around me while writing this book; I changed my job, got married, got busy in personal startup as a vendor of a star product for a big Telecom here. And meanwhile all these, this book got a little bit delayed. I personally thank Yogesh Dalvi the Editor, and Sneha Modi the Project Coordinator of this book who tolerated with me throughout this book happily.

Summary of the Book:
As the title suggests this book is a Quick Starter guide for Citrix XenServer, anyone who knows about clouds and virtualization and wants to get involved with this wide spreading technologies should take this book as a beginner to interim level guide. Citrix is a giant leader in providing cloud based solutions, there are other great products as well see this link.

I've tried to keep things as simple as possible to understand and not use the really techy jargon. Like usual approach the starting chapters introduce the history of XenServer, and my personal introduction with virtualization. Since this is a quick starter book so the immediate goals are to setup a Citrix XenServer host and then find out what can be done to create virtual machines; where to place those virtual machines; storage concepts and their usage in our Virtual machines setup.
Daily maintenance like, creating and deploying snapshots, templates and importing virtual machines are covered besides topic like cloning, network connectivity,  and importance of XenServer tools.

This book explains the management of a VM resources like CPU, Memory, storage. Specialized networking concepts are also explained like Network pools, VLANs, NIC Bonding, and introduction to Virtual Switches and Routers. Advanced topics related to Citrix XenServer such as High Availability, Role Based Admin Control, and conversion of Physical machine to Virtual machine are briefly introduced in the last chapter.

Acknowledgements:
Besides being thankful to God, and my loving Parents, I'd like to say my heartiest thanks to my dear Wife who really helped me completing the last few lingering chapters, I love you my sweet Wife. Then I want to thank my colleagues and friends at Vopium who not only appreciated this book-writing but also helped me in multiple ways to dedicate my time on this book. I'm thankful to Mr. Husnain from HR team; Mr. Imran Iqbal   Head of Operations who appreciated, allowed, and applauded this activity; Mr. Haroon Scrum Master who provisioned me with only enough projects to be able to give time to writing this; Mr. Shahzad Senior Manager VoIP team as being my Mentor; then Mr. Abdul Basit, my Manager VoIP who gave me permissions and assisted me in starting up with this book. My friend Salman, Faheem, Rizwan, and Qasim who made fun of me and made me feel 'encouraged' to continue writing(:P).

Thank you all. I am really grateful and very much appreciate the help to avail this opportunity.

Saturday, June 8, 2013

Book Review: FreeSWITCH 1.2

FreeSWITCH 1.2 Second Edition
Build robust, high-performance telephony systems 
using FreeSWITCH

I raised my hand when the reviewers for the new FreeSWITCH book  were wanted and hence this is my very first effort in writing a book review on FreeSWITCH which I really like and love to work with.

Anthony Minessale The Father of FreeSWITCH , Michael S Collins from Barracuda Networks, Darren Schreiber CEO & Co-founder 2600Hz, and Raymond Chandler also from Barracuda Networks are the authors of this book.

What is FreeSWITCH:
Quoting from the book,
FreeSWITCH 1.2
"FreeSWITCH is a scalable softswitch. In practical terms, this means that it can do anything a traditional PBX can do and much more. It can (and does) act as the core switching software for commercial carriers. It can scale up to handle thousands of simultaneous calls. It can also scale down to act as a simple softphone for your laptop or personal computer. It can also work in a cluster of servers. FreeSWITCH is the telephony engine that powers the CudaTel Communication Server from Barracuda Networks. "

What FreeSWITCH is NOT:
Again quoting the authors here,
"FreeSWITCH is not a proxy server. If you need proxy server functionality, then consider OpenSIPS, Kamailio, Repro, or other similar software. FreeSWITCH is a back-to-back user agent or B2BUA. In this regard, it is similar to Asterisk and other IP PBX software."

Compared to the previous book, FreeSWITCH 1.0.6, which was released three years ago, this one contains updates which happened all these years. FreeSWITCH is getting more feature rich, scalable, and reliable as the opensource community grows and hence this book is essentially an updated revision of the previous book. There are new chapters covering more details like mod_xml_curl is now a separate chapter explaining its usage for creating dynamic configurations. Similarly the mod_httapi is detailed in chapter 11 this module is developed last year.

I really appreciate the addition of chapter 12,13 on Handling NAT and VoIP Security respectively. I believe these two chapters are more important for beginners on FreeSWITCH as they face NAT issues right when they start using FreeSWITCH, and once they do get through this stage the insecure nature of their deployment becomes their top most priority. A very good detailed explanation on how to secure the Server at Network layer, and Application layer with separate methods to secure the Signalling and Media.

As expected and naturally the first chapter deals with the introduction of the application's architecture and how different module types are connected to the central core and there are further loadable modules which enable their respective functionality into the system.
The image on the right is self explanatory on how different modules are independent of each other and this modular approach enables FreeSWITCH to be a scalable system where the core handles the switching part only. In next chapter Installation, and starting up of FS is detailed on different operating systems including Windows.

If you're a beginner and want to understand the working of FS then you need to attend to Chapter 3 very carefully. I personally refreshed some very basic but important concepts related to XML dialplan and use of channel variables from this chapter. This chapter teaches us exactly how to interact with FreeSWITCH using it Command Line Interface plus Sort of Hello-world configuration handling in the form of:
•  Configuring different phones to work with FreeSWITCH
•  Calling various default extensions in the system

I really like the way the chapters are written progressing step by step, I enjoyed adding up a new SIP user in the User Directory. Defining user groups, routing to newly created dialplan in XML, testing the voicemail really made me smile. Looking at the gateway configurations, integrating my test FreeSWITCH with my CISCO gateway and making calls IN/OUT was fun. Chapter 4 was indeed addition to my knowledge and skills related to FS.
[Tip: execute 'sofia profile external restart reloadxml' to add the gateway.]

I was impressed to know that FreeSWITCH has more than 140 Dialplan applications.

LUA is one of my favorite language and honestly I got introduced to LUA from FreeSWITCH. Since then I enjoy writing complex FreeSWITCH application using LUA. We do however need some XML in our deployments but most of the time I find myself working in LUA. I was happy to see full chapters on both LUA and XML advance concepts. Click on the book thumbnail to Preview the chapter on Dialplan scripting with LUA.

I really appreciate the effort put in by the authors and reviewers, a very big help for anyone who wish to get closer to the FreeSWITCH VoIP Servers. A very well written book focusing every step required to start using the FS without hurdles.

Looking forward to read books like these from OpenSource VoIP community. I hope to implement the given examples myself in upcoming weekends and post my experiences.

Thursday, June 6, 2013

Asterisk Dialplan and Redis Integration

I came across this very strange task that I need to have the asterisk get/set data from Redis. My initial thought was this is easy, just going to plug in a perl AGI, use redis connector and everything will be super cool. BUT the condition was I've to stay within the extensions.conf. Yes, I did try convince everyone around but to no avail. NO AGIs, use anything else however I want.

So what I did was create a small shell script which behaves as an API for Redis, and use the Asterisk System() application to GET/SET my desired memcached values.

root@asterisk1:~# vim /etc/asterisk/redis.pl

Insert the following lines in there, add more commands to it see this link: http://search.cpan.org/dist/Redis/lib/Redis.pm

#!/usr/bin/perl

my $redis_db = $ARGV[0];
my $command = $ARGV[1];
my $keyname = $ARGV[2];
my $value = $ARGV[3];

# PERL MODULE
require Redis;
my $redis = Redis->new(server => '127.0.0.1:6379');

if($redis_db > 0 && $redis_db < 16){
        $redis->select("$redis_db");
} else {
        print "using Default Redis DB\n";
}
if($command eq "GET"){
        $val=$redis->get("$keyname");
        print "$val";
}
if($command eq "SET" && $value != ""){
        $redis->set("$keyname" => "$value");
}
if($command eq "INCR"){
 $redis->incr("$keyname");
}

if($command eq "DECR"){
 $redis->decr("$keyname");
}

if($command eq "DECRBY"){
 $redis->decrby("$keyname",$value);
}
if($command eq "DEL"){
$redis->del("$keyname" ) || warn "key doesn't exist";
}
$redis->quit;

Save and Exit;

give permissions to this script.

root@asterisk1:~# chmod 755 /etc/asterisk/redis.pl

Now in Dialplan I call System() Application like this.

exten => _XXX,1,SET(CALLS=${SHELL(/etc/asterisk/redis.pl 1 GET ${CALLERID(num)})})
same => n,NOOP(The Caller:${CALLERID(num)} has ${CALLS} calls in the system)
same => n,Answer()
same => n,System(/etc/asterisk/redis.pl 1 INCR ${CALLERID(num)})
same => n,NOOP(Do some dialplan actions as you want)
...
...
exten => h,1,System(/etc/asterisk/redis.pl 1 DECR ${CALLERID(num)})
exten => h,n,Hangup()

Thats all. Now I can keep realtime track of the active calls for any user/trunk/carrier etc etc from my dialplan. The real beauty of using this shared Redis Memcache store is that I've like 8 asterisk servers, all of them using the same Redis store and all of them are aware of the current number of calls from/to a particular user.

I've also used it to share the Statuses of Queues and Conference rooms residing on special servers with normal IVR servers. Without using this shared store I can only think of using a Database used by all and I believe that doesn't perform well when multiple users are accessing and modifying the same field concurrently especially when the usage is heavy.

Tuesday, May 14, 2013

OpenSIPS/Kamailio High Availability Clustering - 2


High Availability Setup

This post was due for a very very long time since I posted about the general design of a HA-SIP-Proxy in one of my old blogpost.

Now lets start working on this. Using this setup we can cluster two or more machine by using one single Public IP on their WAN interface one-at-a-time. To ensure service availability in case primary (current master) server crashes the application heartbeat resource is configured to monitor the service's status every after 30 seconds. If the Service is found to be stopped it tries start it on the same server for couple of times and then migrate the group of services to the other node. 

This tutorial is equally good for OpenSIPS or Kamailio or any other services.


Active/Passive design diagram

Pre-Requisites:

- Atleast two servers with WAN interfaces empty but cable connected, such that if Public IP is assigned it readily gets accessible from Internet.

- LAN interfaces on both servers should be on the same subnet and should have static Private IP configured.

- The WAN and LAN interfaces on both servers should have similar names i,e eth0=WAN, eth1=LAN

- There should be NO default route inserted to these servers.

Installing Packages:

- Insert a default g/w for LAN interface on both machines temporarily

- Install OpenSIPS or Kamailio or any other tools as per requirement.
- Install heartbeat and sipsak 

Linux-console:~# apt-get install heartbeat sipsak

SIPSAK can be used in the opensips LSB init.d script to send an SIP OPTIONS packet to OpenSIPS port and on the server's reply it'll announce the service is running. This is optional and I suggest users to try this on their own. I recommend looking into the sample asterisk lsb-script provided by heartbeat, there they use sipsak to monitor asterisk's sip port and decided if service is up or not.

Configuring Files for Heartbeat


NOTE: All the files we are going to edit here should be copied to the second server as well.

1- Edit the /etc/hosts file to add hostname for the two servers

192.168.100.148 SIP-SERVER_HA1
192.168.100.62 SIP-SERVER_HA2
2- Edit the /etc/heartbeat/ha.cf file and insert the following.

# enable pacemaker, without stonith
crm             yes
# log where ?
logfacility     local0
# warning of soon be dead
warntime        10
# declare a host (the other node) dead after:
deadtime        20
# dead time on boot (could take some time until net is up)
initdead        120
# time between heartbeats
keepalive       2
# the nodes
node            SIP-SERVER_HA2
node            SIP-SERVER_HA1
# heartbeats, over dedicated replication interface!
ucast           eth1 192.168.100.148
# ignored by node1 (owner of ip)
ucast           eth1 192.168.100.62 # ignored by node2 (owner of ip)
# ping the switch to assure we are online
ping            192.168.100.100


3- Edit the /etc/heartbeat/authkeys file and insert the following:

auth 1
1 sha1 S3cr3tP@ssw0rd

- Assign permissions to the above mentioned file:


Linux-console:~# chmod 0600 /etc/heartbeat/authkeys

Files editing is done here. Copy the files to other server(s).

- Start the heartbeat service on both servers:
Linux-console:~# /etc/init.d/heartbeat start


- Wait for at least 30 seconds and then check the status of the cluster by issuing the following command on both servers.

At the end there will be displayed the cluster online nodes.
Linux-console:~# crm status
============
Last updated: Tue Jan 22 08:02:17 2013
Stack: Heartbeat
Current DC: SIP-SERVER_ha2 (8b5cf63e-4f77-448c-9a75-6a91d4a00cb7) - partition with quorum
Version: 1.0.9-74392a28b7f31d7ddc86689598bd23114f58978b
2 Nodes configured, unknown expected votes
0 Resources configured.
============
Node SIP-SERVER_ha1 (fe3e635f-0d4e-4d8c-99e1-195d1952ac53): UNCLEAN (offline)
Online: [ SIP-SERVER_ha2 SIP-SERVER_ha1]



Note that in the very last line above we've a list of nodes which have joined this Heartbeat group.

Configuring Heartbeat

Goto one of the active nodes in the cluster and on that server’s console issue the following commands sequentially. Once these commands are executed on one server they will be replicated to other serves in the cluster automatically so don't need to copy these commands to other servers.


Linux-console:~# crm configure property stonith-enabled=false
Linux-console:~# crm configure primitive FAILOVER-IP ocf:heartbeat:IPaddr2 params ip="11.22.33.44" nic="eth0" cidr_netmask="255.255.255.240" op monitor interval="10s"
Linux-console:~# crm configure primitive OSIPS lsb:opensips op monitor interval="30s"
Linux-console:~# crm configure primitive SETRoute ocf:heartbeat:Route params destination="default" device="eth0" gateway="11.22.33.1" op monitor interval="10s"
Linux-console:~# crm configure group PIP-OSIP-ROUTE FAILOVER-IP SETRoute OSIPS
Linux-console:~# crm configure colocation OSIPS-WITH-PIP-ROUTE inf: FAILOVER-IP SETRoute OSIPS
Linux-console:~# crm configure order IP-ROUTE-OSIPS inf: FAILOVER-IP SETRoute OSIPS



The very first line is important to disable the Shoot The Other Nood In The Head

In second line we're configuring a resource for the Public IP that will be assigned to the Interface eth1 and named it FAILOVER-IP.

In third line we configure the resource for OpenSIPS LSB (/etc/init.d/opensips start/stop/status) script and named it OSIPS

In fourth line we configured the resource for the Linux default route to access to Internet and named it SETRoute.

So now  in fifth line we created a group of these above mentioned resources.
In next line we bound them to move together whenever they're shifted from one machine to another.

In the very last line we arranged the services to be started in such an order that FAILOVER-IP is assigned to Interface first, then the SETRoute resource is executed to put in the default route to reach to Internet, and then OSIP resource is called to start OpenSIPS.


References and Useful Links: