Žilinská univerzita > Fakulta riadenia a informatiky > Katedra informačných sietí

Adding MySQL support into Kamailio 3.1 (debian lenny)

The article describes how to add the MySQL support for the Kamailio 3.1.0 server. Activities described here are following the basic Kamailio server installation, described in the article Installing Kamailio 3.1 on debian lenny.

Installing Mysql server and mysql module for Kamailio

To use such persistant storage as a database we first need to install DB server, the Mysql here, and kamailio modules which the kamailio will use to connect into database, the kamailio-mysql-modules here.

Installation, thanks to adding kamailio repository for debian, is straightforward

pstest:/home/palo# apt-get install mysql-server kamailio-mysql-modules

During the Mysql server installation we are asked to add root password for mysql server.

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.

We will add or uncomment following lines:

SIP_DOMAIN=ps.sip.uniza.sk
DBENGINE=MYSQL
DBHOST=localhost
# I changed DBNAME from default named "openser", cause I've already created opernser for other OpenSER process
DBNAME=kamailio
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
OSER_FIFO="/tmp/kamailio_tmp"
VERBOSE=1
PID_FILE=/var/run/kamailio.pid
 Next we will create DB tables which will be used by the Kamailio as a storage
pstest:/etc/kamailio# kamdbctl create
MySQL password for root:
database engine 'mysql' loaded
INFO: test server charset
INFO: creating database kamailio ...
Creating core table: standard
Creating core table: acc
Creating core table: lcr
Creating core table: domain
Creating core table: group
Creating core table: permissions
Creating core table: registrar
Creating core table: usrloc
Creating core table: msilo
Creating core table: alias_db
Creating core table: uri_db
Creating core table: speeddial
Creating core table: avpops
Creating core table: auth_db
Creating core table: pdt
Creating core table: dialog
Creating core table: dispatcher
Creating core table: dialplan
INFO: Core Kamailio tables succesfully created.

 As a final point we will try add a new user into the database

pstest:/etc/kamailio# kamctl add palo palo_password
database engine 'MYSQL' loaded
Control engine 'FIFO' loaded
is_user: user counter=0
check_db_alias: alias counter=0
new user 'palo' added

Correct, everything works!

Configuration of the Kamailio for using of the MySQL

Loading required modules

We need to check, if required kamailio modules for the Mysql usage are loaded. If not, we will uncomment lines with modules that are required to be loaded. So open the /etc/kamailio/kamailio.cfg file. Looking first time in is for me a little surprise comparing to the old fashioned OpenSER configs. Kamailio 3.1.x comes with a new feature called DEFINE zone blocks, mentioned in http://www.kamailio.org/dokuwiki/doku.php/features:new-in-3.1.x?s[]=define

After a few second of familiarization with this feature we should start. As a first step we define zone blocks for mysql support (WITH_MYSQL), database authentication (WITH_AUTH), database aliasing (WITH_ALIASDB), and persistent location storage (WITH_USRLOCDB) (recommended inside of the config file as notes).

At the end of this article we will see, that using of this define blocks make easier our effort, because everything was prepared for us (of course, the configation of the Mysql support is a very simple example of the kamailio usage).

So as a next step define following zone blocks.

#!define WITH_MYSQL 
#!define WITH_AUTH
#!define WITH_ALIASDB
#!define WITH_USRLOCDB

Go next throught the cfg file and check lines to find inside of the ####### Defined Values ######### config part DB_URL defien block. Check if your DB URL is configured correctly.

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

In my case,  because I've changed table name in /etc/kamailio/kamctlrc file during mysql initiation, my DB_URL is pointing to the "kamailio" DB table, not to the default "openser" DB table.

Next, inside of the module section we find lines:

#!ifdef WITH_MYSQL
loadmodule "db_mysql.so"
#!endif

because we define #!define WITH_MYSQL support, I'm assuming that it is ok, and db_mysql.so module will be loaded.

Following next we also find lines for DB authentication

#!ifdef WITH_AUTH
loadmodule "auth.so"
loadmodule "auth_db.so"
#!endif

and because we also defined #!define WITH_AUTH block zone, I again supposing, that respective modules will be loaded (as we will see).

Next block zone for DB aliasing is in

#!ifdef WITH_ALIASDB
loadmodule "alias_db.so"
#!endif

as a last step check if usrloc module is commented out (by, default is yes)

loadmodule "usrloc.so"

That's all for the module section, all required module should be loaded.

Setting up module parameters

Now we will check and will set up required module parameters to ensure that loaded modules will work properly.

Move to the part of the kamailio.cfg file starting with line

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

The module parameters section is starting here.

Going through the config file we first find modparams regarding usrloc module. Because we define block WITH_USRLOCDB previously, the parameters will be setted up.

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

All parameters meaning looks clear, just  we will check what is db_mode =2. Looking inside of the usrloc module docs for db_mode =2 we will find, that 2 means

2 - Write-Back scheme. This is a combination of previous two schemes. All changes are made to memory and database synchronization is done in the timer. The timer deletes all expired contacts and flushes all modified or new contacts to database. Use this scheme if you encounter high-load peaks and want them to process as fast as possible. The mode will not help at all if the load is high all the time. Also, latency of this mode is much lower than latency of mode 1, but slightly higher than latency of mode 0.

ok, accepted.

Next, check params for auth_db, there are default setting,

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

where it means, that DB table is located at DBURL location, and the server use the password hashed from the DB table column named password.

Ok, accepted.

Next alias_db params

# ----- alias_db params -----
#!ifdef WITH_ALIASDB
modparam("alias_db", "db_url", DBURL)
modparam("alias_db", "use_domain", MULTIDOMAIN)
#!endif

accepted and this is the end of parameters section, next we are going to modify the route logic.

Modifying route logic for using DB

Setting up registrar server

We will use our Kamailio server not only as Proxy but also as Registrar (therefore inside of the config file there is also loaded registrar module "registrar.so" (by default)) to build up a location bindings stored in the DB. The registration process will authenticate users to accept registration. Inside of the main route logic there is a calling into route(AUTH); block zone. Finding this block in cfg file we may see, that this is the part of route logic handling the authentication process. The first part of the route(AUTH) concerns about the handling of the REGISTER message.

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

by default evrything is commented out, so we do not need to change anything.

next part

# 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!=$tU) {
                                        sl_send_reply("403","Forbidden auth ID");
                                        exit;
                                }
                        } else {
                                if ($au!=$fU) {
                                        sl_send_reply("403","Forbidden auth ID");
                                        exit;
                                }
                        }

                        consume_credentials();
                        # caller authenticated
                } 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

and mainly the sub-part

if (from_uri==myself)
                {
                        if (!proxy_authorize("$fd", "subscriber")) {
                                proxy_challenge("$fd", "0");
                                exit;
                        }

is doing the INVITE message proxy authentication, by default is not commented, so it should work!

And we are at the end of configuration, next we will do testing of the configuration.

Testing

First we check if the config is syntactically correct and if we did not do some mistypes. We will use the -c paramerter of the kamailio cmd.

pstest:/etc/kamailio# kamailio -c kamailio.cfg
loading modules under /usr/lib/kamailio/modules_k/:/usr/lib/kamailio/modules/
Listening on
             udp: 158.193.139.51:5060
             tcp: 158.193.139.51:5060
Aliases:
             tcp: pstest:5060
             tcp: pstest.ps.sip.uniza.sk:5060
             udp: pstest:5060
             udp: pstest.ps.sip.uniza.sk:5060
             *: ps.sip.uniza.sk:*

config file ok, exiting..

Next we will restart the kamailio service to accept cfg changes...

pstest:/etc/kamailio# /etc/init.d/kamailio restart
Restarting kamailio: kamailioloading modules under /usr/lib/kamailio/modules_k/:/usr/lib/kamailio/modules/
Listening on
             udp: 158.193.139.51:5060
             tcp: 158.193.139.51:5060
Aliases:
             tcp: pstest:5060
             tcp: pstest.ps.sip.uniza.sk:5060
             udp: pstest:5060
             udp: pstest.ps.sip.uniza.sk:5060
             *: ps.sip.uniza.sk:*

ok...

Next we will add a new user into the DB

pstest:/etc/kamailio# kamctl add jojo jojo's_password
database engine 'MYSQL' loaded
Control engine 'FIFO' loaded
is_user: user counter=0
check_db_alias: alias counter=0
new user 'jojo' added

and we will use our favorite client to make a registration. To obseve the registration process we start the ngrep as the frontend process and will do registration usign the UA.

ngrep -p -q -W byline port 5060
REGISTER sip:ps.sip.uniza.sk SIP/2.0.
Via: SIP/2.0/UDP 192.168.10.108:40468;branch=z9hG4bK-d8754z-f23264153e04534e-1---d8754z-;rport.
Max-Forwards: 70.
Contact: <sip:jojo@192.168.10.108:40468;rinstance=d5b063d544035d5a>.
To: "jojo"<sip:jojo@ps.sip.uniza.sk>.
From: "jojo"<sip:jojo@ps.sip.uniza.sk>;tag=766b1952.
Call-ID: NjA5OGNiZjVhNzdmNmYxODBlNDQ4YTEwMDdmNDAwZWM..
CSeq: 1 REGISTER.
Expires: 3600.
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO.
User-Agent: eyeBeam release 1102q stamp 51814.
Content-Length: 0.
.


U 158.193.139.51:5060 -> 158.193.152.64:28507
SIP/2.0 401 Unauthorized.
Via: SIP/2.0/UDP 192.168.10.108:40468;branch=z9hG4bK-d8754z-f23264153e04534e-1---d8754z-;rport=28507;received=158.193.152.64.
To: "jojo"<sip:jojo@ps.sip.uniza.sk>;tag=f11c829fa10fd0f1cba4621773c131eb.7aac.
From: "jojo"<sip:jojo@ps.sip.uniza.sk>;tag=766b1952.
Call-ID: NjA5OGNiZjVhNzdmNmYxODBlNDQ4YTEwMDdmNDAwZWM..
CSeq: 1 REGISTER.
WWW-Authenticate: Digest realm="ps.sip.uniza.sk", nonce="TOZNH0zmS/PNRBKh6l0jzT2BpN5uANl2".
Server: kamailio (3.1.0 (x86_64/linux)).
Content-Length: 0.


U 158.193.152.64:28507 -> 158.193.139.51:5060
REGISTER sip:ps.sip.uniza.sk SIP/2.0.
Via: SIP/2.0/UDP 192.168.10.108:40468;branch=z9hG4bK-d8754z-371ce327c1613374-1---d8754z-;rport.
Max-Forwards: 70.
Contact: <sip:jojo@192.168.10.108:40468;rinstance=d5b063d544035d5a>.
To: "jojo"<sip:jojo@ps.sip.uniza.sk>.
From: "jojo"<sip:jojo@ps.sip.uniza.sk>;tag=766b1952.
Call-ID: NjA5OGNiZjVhNzdmNmYxODBlNDQ4YTEwMDdmNDAwZWM..
CSeq: 2 REGISTER.
Expires: 3600.
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO.
User-Agent: eyeBeam release 1102q stamp 51814.
Authorization: Digest username="jojo",realm="ps.sip.uniza.sk",nonce="TOZNH0zmS/PNRBKh6l0jzT2BpN5uANl2",uri="sip:ps.sip.uniza.sk",response="6a22108222110e5b4df904c08c5e6879",algorithm=MD5.
Content-Length: 0.
.


U 158.193.139.51:5060 -> 158.193.152.64:28507
SIP/2.0 200 OK.
Via: SIP/2.0/UDP 192.168.10.108:40468;branch=z9hG4bK-d8754z-371ce327c1613374-1---d8754z-;rport=28507;received=158.193.152.64.
To: "jojo"<sip:jojo@ps.sip.uniza.sk>;tag=f11c829fa10fd0f1cba4621773c131eb.00fb.
From: "jojo"<sip:jojo@ps.sip.uniza.sk>;tag=766b1952.
Call-ID: NjA5OGNiZjVhNzdmNmYxODBlNDQ4YTEwMDdmNDAwZWM..
CSeq: 2 REGISTER.
Contact: <sip:jojo@192.168.10.108:40468;rinstance=d5b063d544035d5a>;expires=3600.
Server: kamailio (3.1.0 (x86_64/linux)).
Content-Length: 0.
.

Perfect, it was simplier as look likes when I saw the kamailio.cfg file for the firstime after OpenSER 1.3.2. At the page attachment you can find the working cfg file.

Groups: