This tutorial will, hopefully, guide you on configuration of interconnection between Kamailio and FreeSWITCH. We will use Kamailio as proxy and registrar server and use FreeSWITCH only for services.
All of the configuration files that have been changed are part of attachment of this tutorial. In Original.zip you will find the original files and in Modified.zip the modified version. So you can actually compare them side by side. This could be really useful and I hope it will help you in every way possible.
Note:
I will use mcedit as editor throughout this tutorial, but feel free to use anything you like (nano, joe, vim, whatever…)
1. Basic installation of Kamailio 3.3
First download and add GPG key to your apt key list:
root@server:/# wget http://deb.kamailio.org/kamailiodebkey.gpg root@server:/# apt-key add kamailiodebkey.gpg
Then add the repository lines to your /etc/apt/sources.list file depending on the Kamailio version of your choice. As we have chosen the latest stable release (3.3) for Debian Squeeze we can either use:
root@server:/# mcedit /etc/apt/sources.list deb http://deb.kamailio.org/kamailio33 squeeze main deb-src http://deb.kamailio.org/kamailio33 squeeze main
Then just execute the following command from shell
root@server:/# apt-get update root@server:/# apt-get install kamailio
Now we need to edit file /etc/default/kamailio in following manner. Find the line RUN_KAMAILIO=no and replace no with yes:
root@server:/# mcedit /etc/default/kamailio RUN_KAMAILIO=yes
This change will make sure that Kamailio will automatically start also after reboot.
Then edit the file /etc/kamailio/kamailio.cfg and find the line #alias="sip.mydomain.com" in the
####### Global Parameters #########
section and change it accordingly to your domain. Delete the # character from the beginning as this character identifies comment.
root@server:/# mcedit /etc/kamailio/kamailio.cfg alias="sitea.local"
Save the file.
You can now run Kamailio:
root@server:/# kamctl start
or
root@server:/# /etc/init.d/kamailio start
/etc/init.d/kamailio start is better when you want to see the IPs and ports that Kamailio listens to, use abbreviated form kamctl start when you don't need to verify this.
Note:
After every change in configuration (after edit of file /etc/kamailio/kamailio.cfg) you must restart Kamailio process. You can do this by this command:
root@server:/# kamctl restart
or
root@server:/# /etc/init.d/kamailio restart
The second command is better in the same way as /etc/init.d/kamailio start, because it gives an output of IP and ports which Kamailio listens to.
If you need to stop Kamailio entirely, just issue following command:
root@server:/# kamctl stop
or
(root@server:/# /etc/init.d/kamailio stop)
In this case it really doesn't matter which one you use.
To make sure that Kamailio listens on the right IP and port we will run it issuing the first mentioned way.
root@server:/# /etc/init.d/kamailio start Starting Kamailio: loading modules under /usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/ Listening on udp: 127.0.0.1:5060 udp: 158.193.139.52:5060 tcp: 127.0.0.1:5060 tcp: 158.193.139.52:5060 Aliases: tcp: server:5060 tcp: server.sitea.local:5060 tcp: localhost:5060 udp: server:5060 udp: server.sitea.local:5060 udp: localhost:5060 *: sitea.local:* kamailio started.
2. Installation of MySQL and adding MySQL support into Kamailio
During MySQL server installation we have to add password for root user of database. That user have the rights to administrate all databases.
root@server:/# apt-get install mysql-server kamailio-mysql-modules
Next, we have to specify parameters, which the kamailio server will use for database connection. Therefore we need to edit the /etc/kamailio/kamctlrc file and we need to set up required parameters, which the kamailio server and kamctl cmd will use.
root@server:/# mcedit /etc/kamailio/kamctlrc
We will uncomment and ,if necessary, change following lines:
SIP_DOMAIN=sitea.local DBENGINE=MYSQL DBHOST=localhost DBNAME=openser DBRWUSER=openser DBRWPW="openserrw" DBROUSER=openserro DBROPW=openserro DBROOTUSER="root" ALIASES_TYPE="DB" CTLENGINE="FIFO" # rewrite OSER_FIFO="FIFO", # because it is causing the fifo error #!!! change from previous version of such a tutorial where OSER_FIFO="/tmp/kamailio_tmp" !!! #https://nil-test.kis.fri.uniza.sk/sip/kamailio/adding-mysql-support-kamailio-31-debian-lenny OSER_FIFO="/tmp/kamailio_fifo" VERBOSE=1 PID_FILE=/var/run/kamailio.pid
Then we have to create Kamailio database by issuing command:
root@server:/# kamdbctl create
Then type in the mysql root password. If you want to, you can install also presence and some extra tables, if you plan to go beyond the basic configuration or to improve it later with some extra features such as presence, messaging and so on.
Then edit the file /etc/kamailio/kamailio.cfg
root@server:/# mcedit /etc/kamailio/kamailio.cfg
Find lines like # – define WITH_MYSQL
(only the following 4, not all)
and change them like this:
#!define WITH_MYSQL #!define WITH_AUTH #!define WITH_USRLOCDB #!define WITH_ALIASDB
Then restart Kamailio
root@server:# /etc/init.d/kamailio restart
Note:
Some useful commands for Kamailio DB are:
kamdbctl reinit -drops the database then recreate it
kamdbctl create -create new database for Kamailio
kamdbctl drop -drops Kamailio database
So we can now add users which can then register with Kamailio and make calls. I strongly advice to test this before moving further – so if there are any errors you can find it easily, later on they will be much harder to spot!
To do this, we can use opensource client Jitsi (also good for testing presence and messaging), or free version of X-lite (just calls and messaging).
root@server:/# kamctl add pepe pass123 root@server:/# kamctl add jojo pass321
This will add 2 users (pepe with password pass123 and jojo with password pass321) into database, which can then register and make call with one another.
3. Basic installation of FreeSWITCH
First we need to meet some prerequisites. You can check them here: http://wiki.freeswitch.org/wiki/Installation_Guide#Common_Prerequisites
root@server:/# apt-get install autoconf automake gawk g++ libjpeg62-dev libncurses5-dev libtool make python-dev pkg-config libtiff4-dev libperl-dev libgdbm-dev libdb-dev
I recommend to install FreeSWITCH from GIT rather than download it as an archive and compiling.
Git provides access to the latest features and bug fixes added throughout the day. Most often you will only use the "clone" and "pull" commands. There is an excellent Online Git Book available in multiple languages. http://progit.org/book
Installing GIT is rather simple:
root@server:# apt-get install git-core
Selecting version:
There are 2 branches in Git – Master and v1.2.stable
v1.2.stable is the branch for the 1.2 series. It will be the most recent 1.2.x release (currently 1.2.2), plus any patches made since that release.
Master is where the development for the future 1.4 release is being done. New features are added to this branch, but it may be less stable than 1.2.stable at times.
So we will choose the stable 1.2 version.
root@server:/# cd /usr/local/src root@server:/usr/local/src# git clone -b v1.2.stable git://git.freeswitch.org/freeswitch.git
Note:
If you want to later switch branches on already cloned Git tree you can use:
root@server:/usr/local/src# git checkout master
(or git checkout v1.2.stable if you were using the Master branch)
To find out more check this site: http://wiki.freeswitch.org/wiki/Installation_Guide#Installed_from_Git
We will now proceed to the next step.
All of the following commands are run from freeswitch directory, therefore we issue the command:
root@server:/usr/local/src# cd /usr/local/src/freeswitch
The configuration files must be built before the first compile. ./bootstrap.sh creates many files including modules.conf. Once this is performed it's not normally required to be performed again:
root@server:/usr/local/src/freeswitch# ./bootstrap.sh
Note:
You can use multiple cores for your bootstrap/config/build, by specifying it at the start, e.g.: (note this may make build errors harder to spot)
cd /usr/local/src/freeswitch
./bootstrap.sh -j
Now to configure FreeSWITCH for compilation
./configure sets compilation options. Invoke the following command to configure for compilation:
root@server:/usr/local/src/freeswitch# ./configure
You can have the checks cached for each module, by using:
root@server:/usr/local/src/freeswitch# ./configure -C
If you want to install FreeSWITCH to a non-standard location you can simply append the –prefix option to the configure script as shown in this example:
root@server:/usr/local/src/freeswitch# ./configure --prefix=<example of non standard location>
Edit modules.conf
The modules.conf file contains the list of modules to be compiled, some are commented as they are not required. As your FreeSWITCH٠configuration becomes more complex additional modules may be required. If you plan to test the sample IVR after installation, FLITE must be added to the compile as follows:
Use an editor to navigate to and edit /usr/local/src/freeswitch/modules.conf (or whatever directory it was placed into)
root@server:/usr/local/src/freeswitch# mcedit modules.conf
Search for "flite" and remove the # to uncomment asr_tts/mod_flite
asr_tts/mod_flite
Save the file.
If this is your first experience with FreeSWITCH don't add more than FLITE. Adding functions may result in additional prerequisites that must be installed.
Building FLITE requires about 450 megabytes of addressable memory, so if you are building on a device with limited RAM, you'll need to create a swap file (a.k.a. Virtual Memory or paging file) of sufficient size to allow the build to proceed, or simply do not include mod_flite in the build. All other modules in the default configuration will build successfully on devices with less than 100MB of available RAM.
Note:
I have also installed module for HTML5 just for my testing purposes. Everything worked fine.
In the FreeSWITCH Wiki they forgot to mention that you need to have some unzipper for the modules because they are downloaded during the compilation and installation in .tar.bz2 format. Unzip worked for me just fine.
root@server:/usr/local/src/freeswitch# apt-get install unzip
Note:
This is the error you get if you don't install unzip
making all mod_flite
–2012-09-13 15:56:41– http://files.freeswitch.org/downloads/libs/flite-1.5.4-current.tar.bz2
Resolving files.freeswitch.org… 108.161.188.3
Connecting to files.freeswitch.org|108.161.188.3|:80… connected.
HTTP request sent, awaiting response… 200 OK
Length: 14740774 (14M) [application/x-bzip2]
Saving to: 㧬ite-1.5.4-current.tar.bz2⍊
100%[===================================================================================================================>] 14,740,774 11.6M/s in 1.2s
2012-09-13 15:56:42 (11.6 MB/s) – 㧬ite-1.5.4-current.tar.bz2⍊
/usr/local/src/freeswitch/build/getlib.sh: line 43: -c: command not found
/bin/tar: This does not look like a tar archive
/bin/tar: Exiting with failure status due to previous errors
/bin/bash: /usr/local/src/freeswitch/libs/flite-1.5.4-current/configure: No such file or directory
make[5]: *** [/usr/local/src/freeswitch/libs/flite-1.5.4-current/Makefile] Error 127
make[4]: *** [all] Error 1
make[3]: *** [mod_flite-all] Error 1
make[2]: *** [all-recursive] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2
List and description of the modules can be found here: http://wiki.freeswitch.org/wiki/Modules
Invoke the following commands to compile and create the binaries:
root@server:/usr/local/src/freeswitch# make && make install
Note:
"make install" does not overwrite existing configuration files in freeswitch/conf if a freeswitch.xml file already exists in conf.
Now for compilation and installation of sounds. There are IVR sound prompts and music on hold files that are optional but must be compiled and installed to run the sample IVR. There are four versions available:
sounds-install moh-install (8 kHz)
hd-sounds-install hd-moh-install (16 kHz)
uhd-sounds-install uhd-moh-install (32 kHz)
cd-sounds-install cd-moh-install (48 kHz)
The cd sounds are recommended since all the sampling rates are provided resulting in fewer problems. Invoke the following command:
root@server:/usr/local/src/freeswitch# make all cd-sounds-install cd-moh-install
Note:
If you want to know how to install FreeSWITCH on Debian with packages, take a look here:
http://codeghar.wordpress.com/2010/03/10/install-freeswitch-on-debian/
(after the packages are created, it is easier to install FreeSWITCH on more machines)
At last we create a symlink
root@server:/# ln -s /usr/local/freeswitch/bin/fs_cli /usr/local/bin/fs_cli
which will allow us connect to FreeSWITCH CLI (fs_cli) just by typing the command
root@server:/# fs_cli
If you want to leave CLI type in:
/bye
or
/exit
or
/quit
Finally we can run FreeSWITCH.
root@server:/usr/local/src/freeswitch# cd /usr/local/freeswitch/bin root@server:/usr/local/freeswitch/bin# ./freeswitch
If you want to run FreeSWITCH on background, run it with option -nc
root@server:/usr/local/freeswitch/bin# ./freeswitch -nc
If we want to stop or restart FreeSWITCH here is how to do it from CLI:
fsctl shutdown [cancel|elegant|asap|restart|now]
cancel discontinue a previous shutdown request.
elegant wait for all traffic to stop; do not prevent new traffic.
asap wait for all traffic to stop; do not allow new traffic.
restart restart FreeSWITCH immediately following the shutdown.
now shutdown FreeSWITCH immediately.
When giving "elegant", "asap" or "now" it's also possible to give the restart command:
fsctl shutdown [elegant|asap|now] restart
4. Kamailio configuration for interconnection
As there already is an WITH_VOICEMAIL directive and routing block present in Kamailio 3.3 default configuration file, we will keep it and use it to route calls that either not answered or busy or not answered in a specific time.
But we will need another block for routing to and from FreeSWITCH and conference (and anything else you would like to have, for example IVR, direct calling to VoiceMail or listening to VoiceMails from VoiceMail menu). Therefore we will name the second block simply as WITH_FREESWITCH. This block will accomodate all the other functions that will FreeSWITCH provide to us.
All of the following changes in part 4 (4.1,4.2 as well) are done in kamailio.cfg file located in /etc/kamailio/kamailio.cfg
Note:
Since there will be things added throughout this tutorial I will mark them with
for the beginning of the modified part
##<----MODIFIED---->##
and for the end of the added or somehow modified part
##<////MODIFIED////>##
just for better recognition
We will use two separate directives:
WITH_VOICEMAIL //which is already defined, just uncomment it
WITCH_FREESWITCH //we will need to add this for example after the WITH_VOICEMAIL directive
Example:
root@server:/# mcedit /etc/kamailio/kamailio.cfg ... # *** 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 # ##<----MODIFIED---->## # *** To enable other FreeSwitch routing like conferences and IVR execute: #!define WITH_FREESWITCH # - set the value of freeswitch.srv_ip # - adjust the value of freeswitch.srv_port ##<////MODIFIED////>## # ...
Then we will set the value of port and IP. In our case it will be the same IP and port of our FreeSWITCH. This is done in the
####### Custom Parameters #########
section.
As we will run the Kamailio and FreeSWITCH on the SAME machine, IP address will be the same as for Kamailio but port MUST be different. I have chosen port 5090.
Example
#!ifdef WITH_VOICEMAIL # VoiceMail Routing on offline, busy or no answer # # - by default Voicemail server IP is empty to avoid misrouting voicemail.srv_ip = "158.193.139.52" desc "VoiceMail IP Address" voicemail.srv_port = "5090" desc "VoiceMail Port" #!endif #!ifdef WITH_FREESWITCH # FreeSWITCH conference and IVR, everything except redirection to VoiceMail # freeswitch.srv_ip = "158.193.139.52" desc "Freeswitch IP Address" freeswitch.srv_port = "5090" desc "Freeswitch Port" #
We need to tell Kamailio to NOT authenticate any traffic coming from FreeSWITCH. This traffic is TRUSTED. We will make such a change in FreeSWITCH respectively later on in this tutorial.
So change the routing block AUTH:
Original routing block AUTH
# Authentication route route[AUTH] { #!ifdef WITH_AUTH #!ifdef WITH_IPAUTH if((!is_method("REGISTER")) && allow_source_address()) { # source IP allowed return; } #!endif if (is_method("REGISTER") || from_uri==myself) { # authenticate requests if (!auth_check("$fd", "subscriber", "1")) { auth_challenge("$fd", "0"); exit; } # user authenticated - remove auth header if(!is_method("REGISTER|PUBLISH")) consume_credentials(); } # if caller is not local subscriber, then check if it calls # a local destination, otherwise deny, not an open relay here if (from_uri!=myself && uri!=myself) { sl_send_reply("403","Not relaying"); exit; } #!endif return; }
Modified
# Authentication route route[AUTH] { #!ifdef WITH_AUTH ##<----MODIFIED---->## #!ifdef WITH_FREESWITCH if(route(FROMFREESWITCH)) return; #!endif ##<////MODIFIED////>## #!ifdef WITH_IPAUTH if((!is_method("REGISTER")) && allow_source_address()) { # source IP allowed return; } #!endif if (is_method("REGISTER") || from_uri==myself) { # authenticate requests if (!auth_check("$fd", "subscriber", "1")) { auth_challenge("$fd", "0"); exit; } # user authenticated - remove auth header if(!is_method("REGISTER|PUBLISH")) consume_credentials(); } # if caller is not local subscriber, then check if it calls # a local destination, otherwise deny, not an open relay here if (from_uri!=myself && uri!=myself) { sl_send_reply("403","Not relaying"); exit; } #!endif return; }
Note that we have added a route block FROMFREESWITCH which is not defined yet. Now is the time to add it.
In addition we will also add block TOFREESWITCH for relaying all the calls to conferences, voicemails, ivr and so on to FreeSWITCH.
Just put this under the end of route[TOVOICEMAIL] section:
##<----MODIFIED---->## # FreeSWITCH routing blocks #!ifdef WITH_FREESWITCH route[FROMFREESWITCH] { if($si== $sel(cfg_get.freeswitch.srv_ip) && $sp==$sel(cfg_get.freeswitch.srv_port)) return 1; return -1; } route[TOFREESWITCH] { $du = "sip:" + $sel(cfg_get.freeswitch.srv_ip) + ":" + $sel(cfg_get.freeswitch.srv_port); route(RELAY); } #!endif ##<////MODIFIED////>##
Ok. This is pretty much it. With these configured we can move on to configuring VoiceMail and then some additional services.
4.1 Kamailio voicemail configuration
The nice thing about Kamailio 3.3 is that most of the work has been done for you in this version if you want to use only VoiceMail.
Original
# 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 rotuing 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
We must slightly change (add a string "vmbox-" into variable $ru) TOVOICEMAIL routing block to this:
Modified
# 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 rotuing enabled but IP not defined\n"); return; } if($avp(oexten)==$null) return; ##<----MODIFIED---->## $ru = "sip:" + "vmbox-" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip) + ":" + $sel(cfg_get.voicemail.srv_port); ##<////MODIFIED////>## route(RELAY); exit; #!endif return; }
The string vmbox- is not necessary if you make a different dialplan in FreeSWITCH. But it is not such a big thing and it really helps to differentiate traffic and ease debugging.
Everything should work just fine but we can make another small change. When calling an user which is not defined in Kamailio database, call is still forwarded to FreeSWITCH which responds with 404 Not Found. I don't like this concept as it is Kamailio which should reject such call. It is unnecessary to forward traffic, which we know would be rejected, to FreeSWITCH and we should stop it as soon as possible.
We will accomplish this by using one of the functions of uri_db module. The module is included in default installation of Kamailio but not loaded. So we need to load uri_db module first.
loadmodule "uri_db.so"
to the ####### Modules Section ########
This will allow us to use functions from this module.
Then we must slightly change routing block of LOCATION.
Just put route(TOVOICEMAIL) inside condition if (does_uri_exist()).
Original
# 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); } }
Modified
# 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; ##<----MODIFIED---->## if (does_uri_exist()) { route(TOVOICEMAIL); } ##<////MODIFIED////>## 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); } }
Finished! This is all it takes for basic VoiceMail to function (after configuring FreeSWITCH of course). That means – if a user is busy, doesn't answer in 30s or reject the call it will be redirected to the voicemail.
But we also need to somehow listen to our voicemails…
This is how we do it. Find the route[SIPOUT] and modify it in following manner:
Original
# Routing to foreign domains route[SIPOUT] { if (!uri==myself) { append_hf("P-hint: outbound\r\n"); route(RELAY); } }
Modified
# Routing to foreign domains route[SIPOUT] { if (!uri==myself) { append_hf("P-hint: outbound\r\n"); route(RELAY); } ##<----MODIFIED---->## #!ifdef WITH_FREESWITCH else { #Routing inside my domain #Routing to voicemail menu if ($tU=~"^9999$") { #voicemail menu xlog("L_NOTICE", " VoiceMail Menu Call"); $rU = "vmmenu-" + $au; route(TOFREESWITCH); } } #!endif ##<////MODIFIED////>## }
Additional configuration can be made to receive notifications that you have voicemail and even how many of them. Some of the clients support this (Jitsi for example). Since this operation is closely related to presence, we will add it there.
Note:
It is NOT needed to have the presence enabled for this function!
Original
# 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; }
Modified
# Presence server route route[PRESENCE] { if(!is_method("PUBLISH|SUBSCRIBE")) return; ##<----MODIFIED---->## #!ifdef WITH_FREESWITCH if (is_method("SUBSCRIBE") && $(hdr(Event))=="message-summary") { route(TOFREESWITCH); } #!endif ##<////MODIFIED////>## #!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; }
4.2 Kamailio Conference
Because we have already done all the hard work interconnecting with FreeSWITCH in the previous chapter, things are going to be really simple here.
So once again open the kamailio config file:
root@server:/# mcedit /etc/kamailio/kamailio.cfg
We will modify the route[SIPOUT] once more and change it just slightly. Just add the else if after the VoiceMail condition. We will put our conference routing there.
Original
# Routing to foreign domains route[SIPOUT] { if (!uri==myself) { append_hf("P-hint: outbound\r\n"); route(RELAY); } ##<----MODIFIED---->## #!ifdef WITH_FREESWITCH else { #Routing inside my domain #Routing to voicemail menu if ($tU=~"^9999$") { #voicemail menu xlog("L_NOTICE", " VoiceMail Menu Call"); $rU = "vmmenu-" + $au; route(TOFREESWITCH); } } #!endif ##<////MODIFIED////>## }
Modified
# Routing to foreign domains route[SIPOUT] { if (!uri==myself) { append_hf("P-hint: outbound\r\n"); route(RELAY); } ##<----MODIFIED---->## else { #!ifdef WITH_FREESWITCH #Routing inside my domain #Routing to voicemail menu if ($tU=~"^9999$") { #voicemail menu xlog("L_NOTICE", " VoiceMail Menu Call"); $rU = "vmmenu-" + $au; route(TOFREESWITCH); } #Routing to conferences else if($rU=~"^3001$") { #conference xlog("L_NOTICE", " Conference Call"); route(TOFREESWITCH); } } #!endif ##<////MODIFIED////>## }
Okay that should do the trick! Now for the FreeSWITCH part.
And don't forget to restart Kamailio! If you made any typo, you will be warned during the restart. So go to the line that Kamailio complains about and repair it – then try to restart it again. Good luck!!!
root@server:/# /etc/init.d/kamailio restart
Congratulations, you have just add additional 90 lines to kamailio configuration file! 🙂
Note:
When debugging, messages from Kamailio logging (Kamailio logs) are stored in /var/log/syslog
This file is default logging file so there are other processes as well, don't be surprised when you see them.
This is very useful and try to use it whenever there is a problem. It really helps a lot. If you want to read just few rows from the end of the file (which are the most recent ones), try to use tail
root@server:/# tail /var/log/syslog
otherwise use some editor
root@server:/# mcedit /var/log/syslog
For more info about logging see this article:
https://nil-test.kis.fri.uniza.sk/sip/kamailio/kamailio-logging-how-debian-lenny
5. FreeSWITCH common config for interconnection
Be aware that there are many thing you can do with FreeSWITCH. These few explained here are merely a scratch of its possibilities. But once you learn to handle these and understand them, you can configure almost anything. This is the nice thing about FreeSWITCH as its configuration files are written completely in XML language rather than "custom made" such as those found in Asterisk.
Furthermore, FreeSWITCH is now well documented on its Wiki pages
http://wiki.freeswitch.org/wiki/
and in addition to that, you can visit their IRC channel which is always full of poeple, some of them even willing to help :).
We will try to leave intact as much of the original configuration as we can. There are a lot of demos and examples in each of them so keep your eyes and mind open – you might learn something ;-).
Note!!!:
There are lots of regular expressions. You should really get used to them. One big warning: when you will be adjusting configration to your need, don't forget that expression in brackets () are assigned to variables $1,$2… etc.
Example for some voicemail block:
<extension name="example">
<condition field="destination_number" expression="^vm-(1234)$">
<action application="voicemail" data="default ${domain_name} $1"/>
</condition>
</extension>
the content in the brackets, in this case 1234, will be then stored into variable $1 for further use in such block.
Note:
We will use marking of the modified parts similar to Kamailio version. But since this is XML, we will use typical XML syntax to comment.
beginning of modified part:
<!-- **MODIFIED** -->
the end of the added or somehow modified part
<!-- //MODIFIED// -->
Look at the conf directory:
root@server:/# ls -all /usr/local/freeswitch/conf/
Here are stored all the configuration files. Take a look at the directory strucutre. Most of the configuration files are stored in autoload_configs. Main dialplan is stored in dialplan directory. Inside directory called "directory" there are user profiles files.
Remember earlier in this tutorial when we have said that traffic from FreeSWITCH will be trusted by Kamailio and vice versa? This is where we tell FreeSWITCH to trust Kamailio.
So turn off the authentication of calls – we will make sure in the next step by configuring ACL that nobody other will get in.
Now configuration of ACL. As we have installed both proucts on one machine, the IP will be the same, just ports will differ.
root@server:/# mcedit /usr/local/freeswitch/conf/autoload_configs/acl.conf.xml
Original
<list name="domains" default="deny"> <!-- domain= is special it scans the domain from the directory to build the ACL --> <node type="allow" domain="$${domain}"/> <!-- use cidr= if you wish to allow ip ranges to this domains acl. --> <!-- <node type="allow" cidr="192.168.0.0/24"/> --> </list>
Modified
<list name="domains" default="deny"> <!-- domain= is special it scans the domain from the directory to build the ACL --> <node type="allow" domain="$${domain}"/> <!-- **MODIFIED** --> <node type="allow" cidr="158.193.139.52/32"/> <!-- //MODIFIED// --> <!-- use cidr= if you wish to allow ip ranges to this domains acl. --> <!-- <node type="allow" cidr="192.168.0.0/24"/> --> </list>
Then we need to direct the SIP traffic sent by Kamailio from public dialpan to default dialpan.
Edit usr/local/freeswitch/conf/dialplan/public.xml
root@server:/# mcedit usr/local/freeswitch/conf/dialplan/public.xml
and add following lines just behind the public_extensions section:
<!-- **MODIFIED** --> <extension name="from_kamailio"> <condition field="network_addr" expression="^158\.193\.139\.52$" /> <condition field="destination_number" expression="^(.+)$"> <action application="transfer" data="$1 XML default"/> </condition> </extension> <!-- //MODIFIED// -->
Since SIP in general uses the port 5060, we have configured Kamailio to bind that port, and since we are running both machines on the same machine with the same IP, FreeSWITCH will have listen on another port (5090, for TLS 5091).
Open the vars.xml file
root@server:/# mcedit /usr/local/freeswitch/conf/vars.xml
and find the section <!– Internal SIP Profile –>
Then change it in following manner (change the ports to 5090 and 5091 and disable authentication of calls – internal_auth_calls=false)
Original
<!-- Internal SIP Profile --> <X-PRE-PROCESS cmd="set" data="internal_auth_calls=true"/> <X-PRE-PROCESS cmd="set" data="internal_sip_port=5060"/> <X-PRE-PROCESS cmd="set" data="internal_tls_port=5061"/> <X-PRE-PROCESS cmd="set" data="internal_ssl_enable=false"/> <X-PRE-PROCESS cmd="set" data="internal_ssl_dir=$${base_dir}/conf/ssl"/>
Modified
<!-- Internal SIP Profile --> <!-- **MODIFIED** --> <X-PRE-PROCESS cmd="set" data="internal_auth_calls=false"/> <X-PRE-PROCESS cmd="set" data="internal_sip_port=5090"/> <X-PRE-PROCESS cmd="set" data="internal_tls_port=5091"/> <!-- //MODIFIED// --> <X-PRE-PROCESS cmd="set" data="internal_ssl_enable=false"/> <X-PRE-PROCESS cmd="set" data="internal_ssl_dir=$${base_dir}/conf/ssl"/>
Note:
We have changed the port for TLS to 5091, but TLS is not enabled by default. But it is not necessary as we can configure TLS in Kamailio. The traffic between Kamailio and FreeSWITCH doesn't have to be encrypted.
5.1 FreeSwitch Voicemail
Now we are going to edit the main dialplan section. This is where all the important stuff happens – such as redirecting calls to VoiceMail application or Conference app.
root@server:/# mcedit /usr/local/freeswitch/conf/dialplan/default.xml
Add the following after the "laugh break" section.
<!-- **MODIFIED** --> <extension name="voicemail"> <condition field="destination_number" expression="^vmbox-(.+)$"> <action application="answer"/> <action application="voicemail" data="default ${domain_name} $1"/> </condition> </extension> <extension name="voicemailmenu"> <condition field="destination_number" expression="^vmmenu-(.+)$"> <action application="voicemail" data="check default ${domain_name} $1"/> </condition> </extension> <!-- //MODIFIED// -->
Ok, VoiceMail configuration is done! But we can't use it since we don't have user profiles defined. I will explain this after the conference part of tutorial.
5.2 FreeSWITCH Conference
Once again open the default dialplan but we won't change anything since it is all there. Just to know what is what – if you would like to change it later.
root@server:/# mcedit /usr/local/freeswitch/conf/dialplan/default.xml
Take a look at this section:
<!-- start a dynamic conference with the settings of the "default" conference profile in conference.conf.xml --> <extension name="nb_conferences"> <condition field="destination_number" expression="^(30\d{2})$"> <action application="answer"/> <action application="conference" data="$1-${domain_name}@default"/> </condition> </extension> <extension name="wb_conferences"> <condition field="destination_number" expression="^(31\d{2})$"> <action application="answer"/> <action application="conference" data="$1-${domain_name}@wideband"/> </condition> </extension> <extension name="uwb_conferences"> <condition field="destination_number" expression="^(32\d{2})$"> <action application="answer"/> <action application="conference" data="$1-${domain_name}@ultrawideband"/> </condition> </extension> <!-- MONO 48kHz conferences --> <extension name="cdquality_conferences"> <condition field="destination_number" expression="^(33\d{2})$"> <action application="answer"/> <action application="conference" data="$1-${domain_name}@cdquality"/> </condition> </extension>
There are more types of conference defined, each in different quality of voice. The great thing about FreeSWITCH is that conferences are created dynamically when first user calls in, therefore NOT wasting memory on conferences that are currently empty.
Look at
/usr/local/freeswitch/conf/autoload_configs/conference.conf.xml
There is a lot of possibilities, for example using pin code when you want to enter conference. This can be very handy. Just add pin parameter to conference profile and there you go – your own private conference room with password.
<profiles> <!--If no profile is specified it will default to "default"--> <profile name="default"> <param name="pin" value="123"/> ... </profile> ... </profiles>
Pin is transmitted via DTMF signals in RTP stream as shown on callflow diagram. Therefore, only numeric pin is allowed.
Important!!! You have to reload the configuration files in order to make changes to running configuration of FreeSWITCH. But another nice thing about FreeSWITHC is that you don't have to actually restart whole FreeSWITCH after configuration change like you had to in Kamailio. Just connect to fs_cli and reload xml files:
root@server:/#fs_cli freeswitch_internal> reloadxml freeswitch_internal> /exit
5.3 FreeSWTICH – user profiles
One drawback of this interconnection is the need of defining the same users from Kamailio also in FreeSWITCH. I have read that you can overcome this by calling an application written in Lua (for example) that connects to Kamailio database and return the user profiles. But I have not tried it as I don't know LUA. Another way could be writing an application in php that will connect to the database and create profiles for FreeSWITCH dynamically. This is not so hard to do and I will try to write an article on that in future as manual creation of user profiles is not very effective, especially when dealing with many users.
User profiles are stored in:
/usr/local/freeswitch/conf/directory/default/
So here is the manual way. You must create an file in that directory. I will create profiles for pepe and jojo.
root@server:/# mcedit /usr/local/freeswitch/conf/directory/default/pepe.xml
<include> <user id="pepe" mailbox="2000"> <!--if id is numeric mailbox param is not necessary--> <!-- ATTENTION PLEASE READ THIS... (I know you won't but you've been warrned) Let it be known that this user can register without a password but since we do not assign this user a user_context and we don't authenticate this user they will be put in context 'public'. This isn't a security issue as the endpoint would be put into the same context 'public' as the sofia profile that starts on 5080 by default. If you're paranoid just remove this file and remove the external profile also. If you're this paranoid you might wanna go buy some more tinfoil and disconnect from the internets. Cuz we all know the internets is for pr0n anyway. --> <params> <param name="vm-password" value="123"/> </params> <variables> <!--all variables here will be set on all inbound calls that originate from this user --> <!-- set these to take advantage of a dialplan localized to this user --> <variable name="accountcode" value="2000"/> <variable name="user_context" value="default"/> <variable name="effective_caller_id_name" value="pepe"/> <variable name="effective_caller_id_number" value="2000"/> </variables> </user> </include>
Save the file and do another for jojo (with another vm-password for VoiceMail checking, and another mailbox value):
root@server:/# mcedit /usr/local/freeswitch/conf/directory/default/jojo.xml
<include> <user id="jojo" mailbox="2001"> <!--if id is numeric mailbox param is not necessary--> <!-- ATTENTION PLEASE READ THIS... (I know you won't but you've been warrned) Let it be known that this user can register without a password but since we do not assign this user a user_context and we don't authenticate this user they will be put in context 'public'. This isn't a security issue as the endpoint would be put into the same context 'public' as the sofia profile that starts on 5080 by default. If you're paranoid just remove this file and remove the external profile also. If you're this paranoid you might wanna go buy some more tinfoil and disconnect from the internets. Cuz we all know the internets is for pr0n anyway. --> <params> <param name="vm-password" value="321"/> </params> <variables> <!--all variables here will be set on all inbound calls that originate from this user --> <!-- set these to take advantage of a dialplan localized to this user --> <variable name="accountcode" value="2001"/> <variable name="user_context" value="default"/> <variable name="effective_caller_id_name" value="jojo"/> <variable name="effective_caller_id_number" value="2001"/> </variables> </user> </include>
Note:
Maybe you have spotted this line <user id="jojo" mailbox="2001"> <!–if id is numeric mailbox param is not necessary–>
When you open another file like 1001.xml there is not an mailbox parameter. That is because number defined users (without alphabetical characters) have mailbox of the same number as their ID. Therefore it is not necessary to define this parameter.
The number is also used to represent user in another (not alphanumerical) way.
Note:
VoiceMail passwords MUST be defined as an numbers for the very same reason as for the conferences. Pin is transmitted in form of DTMF inside RTP.
Don't forget to reloadxml!
Congratulations, that's it!!!
6. Additional notes
Some great ways to debug SIP is to use nestat and ngrep. You can use netstat to find out which ports are open. Ngrep is a packet analyzer which is very useful.
Some hints how to use netstat:
root@server:/# netstat -tulpn
-t tcp
-u udp
-l listening
-p program name
-n use addresses rather than DNS names
For the ngrep part.
You must first install ngrep:
root@server:/# apt-get install ngrep
Usage example:
root@server:/# ngrep -d eth0 -p -q -W byline port 5060 > outputfile.txt
-d which interface will be used to capture data, usable if server has more than one interface
-p does not put an interface into promiscuite mode (capture only our frames/packets)
-q quiet mode, does not print other information, only application headers
-W byline display output by lines
– port listen on port (either source or destination)
> will save the output of the ngrep into file outputfile.txt
Note:
If you want to capture traffic between Kamailio and FreeSWITCH you ned to capture in on loopback interface, not ethernet!!!
Good luck with configuration and take care! If you have any questions, comments or you found some error feel free to post in as a comment.
Hi,
Thanks for the great work done. I need some guidance regarding Jitsi Conference. How We can use Kamailio as a SIP Server and forward SIP call from a SIP Device to the Jitsi Meeting room.
Thanks,
Santanu
Hello Santana,
appologize, due to my worklaod as university teacher and the shift of interests I no more testing Kamailio, therefore I can not help you right now.
pavel
In my search on how to integrate Kamailio + Freeswitch, i came across this site. I tried to follow it, but it seems to fail. I am running Debian 10, Kamailio 5.5, freeswitch 1.10. One system has kamailio with IP:192.168.0.100, the other system has freeswitch with IP:192.168.0.101. Users will be created in Kamailio and in Freeswitch, correct?