Kamailio SIP server evolved from SER and OpenSER. Written in ANSI C , primarily it is an open source proxy SIP server. RFC 3261 compliant and has support for various Operating system to install and run on as alpine , centos , deb , fedora , freebsd , netbsd , obs , openbsd , opensuse , oracle , rhel , solaris so on .
With modular design it already has 150 + modules and can have third party addons like Databases , RTP engines etc. Anyone can contribute to extensions and modules read here. Also contains cmd line tool kamcmd , kamcli and Web management interface SIREMIS .
It has provisions for complex routing logic development through scripts and programming languages interpreter support.
Over the years kamailio as proven a key component of a “carrier-grade” SIP service delivery platform. Either as SBC interfacing internal softswitch with public internet and handling complex operation as NAT, auth , flood control, topology hiding etc or even as the core SIP Server handling RTP relay as well.
Kamailio’s call routing log can be divided into:
- Core functions
- Core modules needed for almost any useful configuration like transaction module , Record route module etc ( read more https://telecom.altanai.com/2014/11/18/kamailio-modules/)
- Ancillary modules to provide specific functionality (e.g. JANSSON , PIKE)
- Pseudo-variables , which hold read/writeable attributes and
- Transformations and custom logic definition.
Kamailio config
kamailio confguration file should be composed of
Core configuration directives as
!ifdef WITH_MULTIDOMAIN
!define MULTIDOMAIN 1
!else
!define MULTIDOMAIN 0
!endif
Global Parameters like
memdbg=5
memlog=5
log_facility=LOG_LOCAL0
fork=yes
children=4
Loading Modules
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
Module parameters
For example considering for tm auto-discard branches from previous serial forking leg as failure_reply_mode ,30 sec as default retransmission timeout with 120 sec as invite retransmission timeout after 1xx
modparam("tm", "failure_reply_mode", 3)
modparam("tm", "fr_timer", 30000)
modparam("tm", "fr_inv_timer", 120000)
Subroutines (in essence, SIP event callbacks):
Request routes (request_route)
Reply routes (onreply_route)
Failure routes (failure_route)
Branch routes
For example consider main sip routing block
request_route {
route(REQINIT);
route(NATDETECT);
if (is_method("CANCEL"))
{
if (t_check_trans()) {
route(RELAY);
}
exit;
}
route(WITHINDLG);
t_check_trans();
route(AUTH);
if (is_method("INVITE|SUBSCRIBE"))
record_route();
route(SIPOUT);
route(PRESENCE);
route(REGISTRAR);
...
}
Custom event routes (callbacks/event handlers exposed by modules).
Code for programming languages and runtimes:
String transformations
Variables
Ephemeral/scratch-pad variables ($var(…))
Transaction-persistent variables ($avp(…)/$xavp(…)) , extended AVP like AVP ar attached to transactions and not messages .
Dialog-persistent variables ($dlg_var(…))
$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;
}
This article describes call routing config for Kamailio under following roles
- SIP Proxy
- Registrar
- Accountant
- Session border Controller
Kamailio as Proxy Server
Simple Kamailio configuration with basic features like alias , accounting , record routing , handling SIP requests like INVITE and its replies . Also failure and NAT handling . More samples of Kamailio config and call routing are at https://github.com/altanai/kamailioexamples
#!KAMAILIO
#Defined Values
!substdef "!MY_IP_ADDR!!g"
!substdef "!MY_EXTERNAL_IP!!g"
!substdef "!MY_UDP_PORT!!g"
!substdef "!MY_TCP_PORT!!g"
!substdef "!MY_UDP_ADDR!udp:MY_IP_ADDR:MY_UDP_PORT!g"
!substdef "!MY_TCP_ADDR!tcp:MY_IP_ADDR:MY_TCP_PORT!g"
!define MULTIDOMAIN 0
; - 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
; LOG Levels:3 = DBG, 2 = INFO, 1 = NOTICE, 0 = WARN, -1 = ERR
debug = 2
log_stderror = no
memdbg = 5
memlog = 5
log_facility = LOG_LOCAL0
log_prefix = "{$mt $hdr(CSeq) $ci} "
/* number of SIP routing processes */
children = 2
/* uncomment the next line to disable TCP (default on) */
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 */
alias = "sip.mydomain.com"
/* listen addresses */
listen = udp:127.0.0.1:5060
listen = MY_UDP_ADDR advertise MY_EXTERNAL_IP:MY_UDP_PORT
listen = MY_TCP_ADDR advertise MY_EXTERNAL_IP:MY_TCP_PORT
# Modules Section
loadmodule "jsonrpcs.so"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"
loadmodule "acc.so"
loadmodule "counters.so"
----------------- setting module-specific parameters --------------
----- jsonrpcs params -----
modparam("jsonrpcs", "pretty_format", 1)
/* set the path to RPC fifo control file */
modparam("jsonrpcs", "fifo_name", "/var/run/kamailio/kamailio_rpc.fifo")
/* set the path to RPC unix socket control file */
modparam("jsonrpcs", "dgram_socket", "/var/run/kamailio/kamailio_rpc.sock")
; ----- ctl params -----
/* set the path to RPC unix socket control file */
modparam("ctl", "binrpc", "unix:/var/run/kamailio/kamailio_ctl")
; ----- 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 -----
# set next param to 1 to add value to;lr param (helps with some UAs)
modparam("rr", "enable_full_lr", 0)
; do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)
----- 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)
# Routing Logic
/* Main SIP request routing logic*/
request_route {
; per request initial checks
route(REQINIT);
; CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans()) {
route(RELAY);
}
exit;
}
; handle retransmissions
if (!is_method("ACK")) {
if (t_precheck_trans()) {
t_check_trans();
exit;
}
t_check_trans();
}
; handle requests within SIP dialogs
route(WITHINDLG);
; only initial requests (no To tag)
; 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
}
if ($rU==$null) {
# request with no Username in RURI
sl_send_reply("484", "Address Incomplete");
exit;
}
# update $du to set the destination address for proxying
$du = "sip:" + $rd + ":9";
route(RELAY);
exit;
}
# Wrapper for relaying requests
route[RELAY] {
if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
if (!t_is_set("branch_route"))
t_on_branch("MANAGE_BRANCH");
}
if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
if (!t_is_set("onreply_route"))
t_on_reply("MANAGE_REPLY");
}
if (is_method("INVITE")) {
if (!t_is_set("failure_route"))
t_on_failure("MANAGE_FAILURE");
}
if (!t_relay()) {
sl_reply_error();
}
exit;
}
#P er SIP request initial checks
route[REQINIT] {
if ($ua = ~ "friendly-scanner|sipcli|VaxSIPUserAgent") {
# sl_send_reply("200", "OK");
exit;
}
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483", "Too Many Hops");
exit;
}
if (is_method("OPTIONS") && uri==myself && $rU==$null) {
sl_send_reply("200", "Keepalive");
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())
return ;
if (loose_route()) {
if (is_method("BYE")) {
setflag(FLT_ACC); # do accounting ...
setflag(FLT_ACCFAILED); # ... even if the transaction fails
} else{
if (is_method("NOTIFY")) {
# Add Record-Route for in -dialog NOTIFY as per RFC 6665.
record_route();
}
route(RELAY);
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
route(RELAY);
exit;
} else {
# ACK without matching transaction, ignore and discard
exit;
}
}
sl_send_reply("404", "Not here"); exit;
#Manage outgoing branches
branch_route[MANAGE_BRANCH] {
xdbg("new branch [$T_branch_idx] to $ru\n");
}
--# Manage incoming replies
onreply_route[MANAGE_REPLY] {
xdbg("incoming reply\n");
}
--# Manage failure routing cases
failure_route[MANAGE_FAILURE] {
if (t_is_canceled()) exit;
}
Controlling Call Routing from command Line
To find the loaded flags while starting kamailio
kamailio -v
version: kamailio 5.1.8 (x86_64/linux) d8e930
flags: STATS: Off, USE_TCP, USE_TLS, USE_SCTP, TLS_HOOKS, USE_RAW_SOCKS, DISABLE_NAGLE, USE_MCAST, DNS_IP_HACK, SHM_MEM, SHM_MMAP, PKG_MALLOC, Q_MALLOC, F_MALLOC, TLSF_MALLOC, DBG_SR_MEMORY, USE_FUTEX, FAST_LOCK-ADAPTIVE_WAIT, USE_DNS_CACHE, USE_DNS_FAILOVER, USE_NAPTR, USE_DST_BLACKLIST, HAVE_RESOLV_RES
ADAPTIVE_WAIT_LOOPS=1024, MAX_RECV_BUFFER_SIZE 262144 MAX_URI_SIZE 1024, BUF_SIZE 65535, DEFAULT PKG_SIZE 8MB
poll method support: poll, epoll_lt, epoll_et, sigio_rt, select.
id: d8e930
compiled on 09:47:09 May 3 2019 with gcc 4.8.4
kamdbctl
creates the database support for many kamailio modules such as auth , location , dispatcher , permission etc
make sure you load a DB engine , during kamailio installation and configuration . It can be either done though make command or though modules.lst file
make include_modules="db_mysql" cfg
make all
make install
since json replaced all fifo command, ensure you do not get "json.h: No such file or directory
” in server by install json either via libjson-c-dev or libjson-cpp-dev
apt-get install libjson-c-dev
For uuid/uuid.h: No such file or directory
install
apt-get install uuid-dev
For libpq-fe.h: No such file or directory
install
apt-get install libpq-dev
kamdbctl command list
kamdbctl create <db name or db_path, optional> ...(creates a new database)
kamdbctl drop <db name or db_path, optional> .....(!entirely deletes tables!)
kamdbctl reinit <db name or db_path, optional> ...(!entirely deletes and than re-creates tables!)
kamdbctl backup <file> ...........................(dumps current database to file)
kamdbctl restore <file> ..........................(restores tables from a file)
kamdbctl copy <new_db> ...........................(creates a new db from an existing one)
kamdbctl presence ................................(adds the presence related tables)
kamdbctl extra ...................................(adds the extra tables)
kamdbctl dbuid ...................................(adds the uid tables)
kamdbctl dbonly ..................................(creates empty database)
kamdbctl grant ...................................(grant privileges to database)
kamdbctl revoke ..................................(revoke privileges to database)
kamdbctl add-tables <gid> ........................(creates only tables groupped in gid)
if you want to manipulate database as other database user than
root, want to change database name from default value "kamailio",
or want to use other values for users and password, edit the
"config vars" section of the command kamdbctl.
kamdbctl pframework create .......................(creates a sample provisioning framework file)
For psql: received invalid response to SSL negotiation: [
errors . Remember for mysql the defaul port is 3306, but for psql it is 5432 . Hence make the change in /etc/kamailio/kamctlrc
ERROR: Creating database failed!
database port DBPORT=3306 DBPORT=5432
Kamctl
If kamctl isnt accessible from the machine installed with kamailio , just goto kamctl folder and compile it yourself . For example for me , I took the git pull of kamailio source code v 5.1.0 and went to util folder
cd /kamailio_source_code/utils/kamctl make && make install
some commands
‘start|stop|restart|trap’
‘acl’ – manage access control lists (acl)
‘lcr’ – manage least cost routes (lcr)
‘cr’ – manage carrierroute tables show|reload|dump
‘rpid’ – manage Remote-Party-ID (RPID)
‘add|passwd|rm’ – manage subscribers
‘add|dump|reload|rm|show’ – manage trusted
‘add|dump|reload|rm|show’ – manage address
‘add|dump|reload|rm|show’ – manage address
‘dispatcher’ – manage dispatcher
dispatcher add 1 sip:1.2.3.1:5050 1 5 'prefix=proxycall' 'gatewaye33'
‘dialog’ – manage dialog records
‘srv’ – server management commands
‘cisco_restart’ – restart CISCO phone (NOTIFY)
‘online’ – dump online users from memory
‘monitor’ – show internal status
[cycle #: 3; if constant make sure server lives]
Kamailio Runtime Details:
kamailio 5.1.8 (x86_64/linux) d8e930
now: Fri May 24 13:39:19 2019
up_since: Fri May 24 13:31:37 2019
uptime: 462
Transaction Statistics:
tmx:UAS_transactions = 0 tmx:UAC_transactions = 0 tmx:active_transactions = 0 tmx:inuse_transactions = 0
Stateless Server Statistics:
sl:sent_replies = 0 sl:sent_err_replies = 0
UsrLoc Statistics:
usrloc:location-contacts = 0 usrloc:location-expires = 0 usrloc:location-users = 0 usrloc:registered_users = 0
Core Statistics:
core:rcv_requests = 0 core:fwd_requests = 0 core:rcv_replies = 0 core:fwd_replies = 0
Shared Memory Statistics:
shmem:fragments = 1 shmem:max_used_size = 2807640 shmem:total_size = 67108864
shmem:free_size = 64301224 shmem:real_used_size = 2807640 shmem:used_size = 2566040
‘ping’ – ping a SIP URI (OPTIONS)
‘ul|alias’ – manage user location or aliases
‘ps’ – print details about running processes
‘ps’ – print details about running processes
‘stats’ – print internal statistics
{
"jsonrpc": "2.0",
"result": [
"core:bad_URIs_rcvd = 0",
"core:bad_msg_hdr = 0",
"core:drop_replies = 0",
"core:drop_requests = 0",
"core:err_replies = 0",
"core:err_requests = 0",
"core:fwd_replies = 0",
"core:fwd_requests = 0",
"core:rcv_replies = 0",
"core:rcv_replies_18x = 0",
"core:rcv_replies_1xx = 0",
"core:rcv_replies_2xx = 0",
"core:rcv_replies_3xx = 0",
"core:rcv_replies_401 = 0",
"core:rcv_replies_404 = 0",
"core:rcv_replies_407 = 0",
"core:rcv_replies_480 = 0",
"core:rcv_replies_486 = 0",
"core:rcv_replies_4xx = 0",
"core:rcv_replies_5xx = 0",
"core:rcv_replies_6xx = 0",
"core:rcv_requests = 0",
"core:rcv_requests_ack = 0",
...
}
‘rpc’ – send raw RPC commands
Kamcmd
unix tool for interfacing with Kamailio using exported RPCs. It uses binrpc (a proprietary protocol, designed for minimal packet size and fast parsing) over a variety of transports (unix stream sockets, unix datagram sockets, udp or tcp).
cfg.add_group_inst cfg.commit cfg.del cfg.del_delayed cfg.del_group_inst cfg.diff cfg.get cfg.help cfg.list cfg.reset cfg.rollback cfg.set cfg.set_delayed cfg.set_delayed_int cfg.set_delayed_string cfg.set_now_int cfg.set_now_string cfg.seti cfg.sets cnt.get cnt.get_raw cnt.get_vars cnt.grp_get_all cnt.grps_list cnt.help cnt.list_groups cnt.list_vars cnt.reset cnt.var_list core.aliases_list core.arg core.echo core.flags core.info core.kill core.modules core.ppdefines core.printi core.prints core.ps core.psx core.pwd core.shmmem core.sockets_list core.tcp_info core.tcp_list core.tcp_options core.udp4_raw_info core.uptime core.version corex.debug corex.list_aliases corex.list_sockets corex.pkg_summary corex.shm_status corex.shm_summary ctl.connections ctl.listen ctl.who dns.add_a dns.add_aaaa dns.add_srv dns.debug dns.debug_all dns.delete_a dns.delete_aaaa dns.delete_all dns.delete_all_force dns.delete_cname dns.delete_ebl dns.delete_naptr dns.delete_ptr dns.delete_srv dns.delete_txt dns.lookup dns.mem_info dns.view dst_blacklist.add dst_blacklist.debug dst_blacklist.delete_all dst_blacklist.mem_info dst_blacklist.view jsonrpc.echo mod.stats pkg.stats pv.shvGet pv.shvSet sl.stats stats.clear_statistics stats.fetch stats.get_statistics stats.reset_statistics system.listMethods system.methodHelp system.methodSignature tm.cancel tm.clean tm.hash_stats tm.list tm.reply tm.reply_callid tm.stats tm.t_uac_start tm.t_uac_wait ul.add ul.db_contacts ul.db_expired_contacts ul.db_users ul.dump ul.flush ul.lookup ul.rm ul.rm_contact alias: ps alias: psx alias: list alias: ls alias: ver alias: version alias: who alias: listen alias: dns_mem_info alias: dns_debug alias: dns_debug_all alias: dst_blacklist_mem_info alias: dst_blacklist_debug builtin: ? builtin: help builtin: version builtin: quit builtin: exit builtin: warranty builtin: license
some examples of the kamcmd commands
stats
> kamctl kamcmd tm.stats { current: 0 waiting: 0 total: 0 total_local: 0 rpl_received: 0 rpl_generated: 0 rpl_sent: 0 6xx: 0 5xx: 0 4xx: 0 3xx: 0 2xx: 0 created: 0 freed: 0 delayed_free: 0 }
Get info about TLS
kamcmd> tls.info
{
max_connections: 2048
opened_connections: 1
clear_text_write_queued_bytes: 0
}
Get info about open sockets
kamcmd> core.sockets_list
{
socket: {
proto: udp
address: 1.2.3.4
port: 5060
mcast: no
mhomed: no
}
socket: {
proto: tcp
address: 1.2.3.4
port: 5060
mcast: no
mhomed: no
}
socket: {
proto: tcp
address: 1.2.3.4
port: 80
mcast: no
mhomed: no
}
socket: {
proto: tls
address: 1.2.3.4
port: 5061
mcast: no
mhomed: no
}
socket: {
proto: tls
address: 1.2.3.4
port: 443
mcast: no
mhomed: no
}
}
get core info
kamcmd > core.info
{
version: kamailio 5.2.3
id: 4a4588
compiler: gcc 5.4.0
compiled: 15:54:50 Jun 27 2019
flags: STATS: Off, USE_TCP, USE_TLS, USE_SCTP, TLS_HOOKS, USE_RAW_SOCKS, DISABLE_NAGLE, USE_MCAST, DNS_IP_HACK, SHM_MEM, SHM_MMAP, PKG_MALLOC, Q_MALLOC, F_MALLOC, TLSF_MALLOC, DBG_SR_MEMORY, USE_FUTEX, FAST_LOCK-ADAPTIVE_WAIT, USE_DNS_CACHE, USE_DNS_FAILOVER, USE_NAPTR, USE_DST_BLACKLIST, HAVE_RESOLV_RES
}