Programing in SIP servers enables the IP telephony provider to add complex control that is difficult to realise with simple dialplan XML and IVR menus. These are best handled by using a program that is compiled with the telecom application server and invoked by SIP requests or responses in the session. This may include
using policy control or dynamic input to control call routing or blacklisting
transcription for voicemail
media file playback with dynamic text to speech ….so on.
Common Freeswitch , opensips , Kamailio and Astersik suppored programing engines may include python, java, c++, javascript. Opensips and kamailio also include XML_RPC, HTTP API and Websockets as additional means of adding call control login in telephony sever.
Kamailo modules
Opensips modulesFreeswitch modules
Lua (https://www.lua.org) is a small, powerful and lightweight scripting language, mostly used for embedded and gaming use cases. Among many programming engines supported by FreeSWITCH and Kamailio, Lua is very handy to add business logic to call control by integrating with the telecom server.
Form the a multiple choice, Lua is the prefered language for scripting in SIP server which is due to
Does not requie recompilation
Saves on the effort to resatrt the freeswitch server while loading updated script
this in turn saves service disruption for the time server woulve taken to shutdown and restart
Can ve sync or asyn
lua : runs in current thread and waits for script completion
luarun : runs in seprate thread and returns immediately
Freeswitch Lua Integration
To load the program
<action aplication="lua" data="mainprog.lua">
1. In the program, we could get status and print to console log
local api = freeswitch.API()
local status = api:execute("status")
freeswitch.consoleLog(status)
2. we could also check is session is active and play a file inot the call
if session:ready() then
session:streamFile("silence_stream://100000")
end
3.Program to answer call , play file and hangup using session class methods
-- Answer call, play a prompt, hang up
session:answer()
-- Create a string with path and filename of a sound file
pathsep = '/'
-- Windows users do this instead pathsep = ''
prompt ="ivr" ..pathsep .."ivr-welcome_to_freeswitch.wav"
-- Play the prompt
freeswitch.consoleLog("WARNING","About to play '" .. prompt .."'n")
session:streamFile(prompt)
-- Hangup
session:hangup()
freeswitch.consoleLog("WARNING","After hangup")
output
[INFO] mod_dialplan_xml.c:637 Processing altanai <altanai>->5000 in context public
EXECUTE sofia/internal/altanai@x.x.x.x lua(/etc/freeswitch/dialplan/lua_session_answer_prompt_hangup.lua)
...
[DEBUG] switch_channel.c:3781 (sofia/internal/altanai@x.x.x.x) Callstate Change EARLY -> ACTIVE
[WARNING] switch_cpp.cpp:1376 About to play 'ivr/ivr-welcome_to_freeswitch.wav
...
[DEBUG] switch_ivr_play_say.c:1942 done playing file /usr/share/freeswitch/sounds/en/us/callie/ivr/ivr-welcome_to_freeswitch.wav
...
[DEBUG] switch_cpp.cpp:731 CoreSession::hangup
[NOTICE] switch_cpp.cpp:733 Hangup sofia/internal/altanai@x.x.x.x [CS_EXECUTE] [NORMAL_CLEARING]
[WARNING] switch_cpp.cpp:1376 After hangup
other methods :
Initiate new session session:originate()
Record Audio session:recordFile()
5. Fire and consume Events
freeswitch.Event() and freeswitch.eventConsume() can be used to fire new events and consume events respectively. For instance to fire callback function on hangup session:setHangupHook()
In this article, we discuss Nating in a SIP Server like Kamailio. Types of NAT pings, their behaviour and types. Also some implementation of some of the Kamailios modules like
To resolve hostname into IPs Kamailio can do either of below
use libresolv and a combination of the locally configured DNS server /etc/hosts and the local Network Information Service (NIS/YP a.s.o) or
cache the query results and first look into internal cache
DNS failover – if destination resolves to multiple addresses tm can try all of them until it finds one to which it can successfully send the packet or it exhausts all of them, with internal DNS cache. Also used when the destination host doesn’t send any reply to a forwarded invite within the SIP timeout interval (tm fr_timer parameter).
DNS load balancing – SRV based load balancing with weight value in the DNS SRV record.
(-) Only the locally configured DNS server (usually in /etc/resolv.conf) is used for the requests (/etc/hosts and the local Network Information Service are ignored).
optional: disable the DNS cache (use_dns_cache=off or compile without -DUSE_DNS_CACHE).
(-) DNS cache uses extra memory
optional: disable the DNS cache.
(-) DNS failover introduces a very small performance penalty
optional: disable the DNS failover (use_dns_failover=off).
(-) DNS failover increases the memory usage (the internal structures used to represent the transaction are bigger when the DNS failover support is compiled).
optional: compile without DNS failover support (DUSE_DNS_FAILOVER).Turning it off from the config file is not enough in this case (the extra memory will still be used).
Network address translation replaces the IP address within packets with a different IP address which internet endpoints can relate with. This enables multiple hosts in a private subnet with their pwn private address ( 10.x.x.x or 192.x.x.x etc ) to share single public IP address interface, to access the Internet.
NAT is bidirectional- If the private ip:port got translated to public ip:port on the inside interface while entering outside internet, on arriving from outside interface it will get translated from public ip:port to private ip:port.
For a SBC ( Session border controller ) or where the kamailio server is directly customer facing, where you dont have a private line or VPN to clients, then it is often encountered with NATed endpoints. Read more about NAT traversal using STUN and TURN here
These characteristics of SIP design and operation flows demonstrate why NAT solutions are so important
RFC 3261 for SIP presumed end-to-end reachability and does not specify much around ANT issues .
No NLRI (Network Layer Reachability Information) translation layer exists, such as DNS or ARP
SIP is designed to used RTP which uses dynamically allocated ports to stream media. It is comparable to FTP which creates ephemeral connections on unpredictable dynamic ports to send multiplexed data and “metadata”, instead of protocol like HTTP where all data is sent on same connection.
UDP (default transport for SIP) is connection less and session tracking requires these be mapped onto a statelful flow, rigorous keepalives and other such techniques like using TCP instead have their own tradeoffs
since sip packets put network and transport information right on sip header they are limited by the rateability and awareness of their network interface thereby prevent other endpoint from reaching its ip or port
Types of NAT solutions
Client-side NAT traversal – clients are responsible for identifying their WAN NLRI and adding ip and port to navigate them in outside world
Server-side NAT traversal – SIP server should discover the client’s WAN addressing while clients continue to work transparently behind NAT. Requires that DIP server look at the source and destination ip and port of actual packets instead of relying on the encapsulated sip headers and SDP body.
ALG (Application Layer Gateways) – mostly applied at router itself. wodk by susbtitung public IP/port information inplace of provate and vice versa for return packets. Limitataions – they dont provide a fullproof fix example they may fix Via but not the Contact address or SDP body or RTP ports
Open network leading to smooth p2p media stream
Far-end NAT traversal solution ( TURN server)
public private ip mapping , firewalls and private network obstruct p2p media flow. TURN is useful to relay media pckets
NAT behaviours
Cone NAT
Symmetric NAT
Local client performs an outbound connection to a remote UA and a dynamic rule is created for the destination IP tuple, allowing the remote machine to connect back.
Local client allows inbound connections from a specific source IP address and port, also NAT assigns a new random source port for each destination IP tuple
Further subdivied into: 1. Full Cone NAT 2. Restricted Cone NAT – all requests from the same internal IP address and port are mapped to the same external IP address and port. -3. Port-Restricted Cone NAT
RTP NAT
NAT not only applies to sip signalling packets but also to RTP. Even RTP packets are not able to transverse accross private -public network interfaces to the right place across a NAT’d connection.
To solve two-way media RTP performs RTP latching, where client listens for at least one RTP frame arriving at the destination port it advertised, and harvests the source IP and port from that packet and uses that for the return RTP path. RTP latching works out of the box for public RTP endpoints but not for ones behind NAT.
It is thus recommended to use an intermediate RTP relay such as RTPengine on kamailio. It is controlled via a UDP control socket by kamailio as an external process. More on installation and descrition of RTP engine on kamailio is covered here. When RTPengine control module receives RTP offer /answer from Kamailio, it opens a pair of RTP/RTCP ports to receive traffic and substitues in SDP. Doing so for both ends makes RTP engine come in the path of media stream packets for both directions.
A first INVITE has no no corresponding on NAT ( as no port has been allocated yet ) so the c= contact and m = media lines would look like
c=IN IP4 192.0.2.13. m=audio 23767 RTP/AVP 0 101.
We can force RTP to go through a proxy by changing c line and m line to
A separate daemon called an RTP proxy (with a public IP address) that both user agents can send their audio to, can be setup by calling force_rtp_proxy().
Fixing NAT
When the client is behind NAT, following needs to be taken careof to provide smooth operation
Ensuring Tranactional replies are sent to correct source address ( maybe using ;rport param and forcerport() method ) instead of just relying on via header transport protocol and port.
example:
Any far-end NAT traversal solution ( TURN server) if employed should stay in path of entire Dialog not just for initial INVITE transaction which many times results in ACK being dropped. This can be achived by adding Record-Route header of rr module to the initial INVITE request itself
Set the advertised address of the public-facing inetrface to the Public NAT IP using “listen” parameter
Ensure contact URI is NAT processed by using NATHelper modules which rewrites the domain portion of the Contact URI to contain the source IP and port of the request or reply. add_contact_alias([ip_addr, port, proto]) in NAThelper module which adds “;alias=ip~port~transport” parameter to the contact URI containing either received ip, port, and transport protocol or those given as parameters
Implement RTP proxy which performs NAT for streams such as rtpengine module
Provides far-end NAT traversal to kamailio’s SIP signalling. Its role is
detect user agents behind NAT
manipulate SIP headers so that user agents can continue working behind NAT transparently
keepalives to UA behind NAT to preserve their visibility in network
Some pros and cons of NATTravsersal module
(+) detect even UAs behind multiple cascaded NAT boxes, complex distributed env with multiple proxies
(+) handle env where incoming and outgoing paths are diff for SIP messages
(+) handle cases when routing path may even change between consecutive dialogs
(+) can work for other than registered UA’s also
(-) built for IPv4 NAT handling not adapted to support IPv6 session keepalives.
Why use keepalive when Registrations are already there for NATing ?
NAT binding works for registered users who want incoming calls. However for cases like outgoing calls or for presence subscription notifications, failings registration implies inability to receive further in-dialog messages after the NAT binding expires. This artificial binding for registrations makes system unreliable and volatile as it doesnot guarantee the delivery of in-dialog messages for outgoing calls without registration renewal. Therefore keepalive are adopted which also works for unregistered users.
Minimizes the traffic as only border proxies send keepalives which send keepalives statelessly, instead of having to relay messages generated by the registrars.
Also for situations when DNS resolves diff proxies for outgoing or incoming path traditional register based keepalives fail to associate or dissociate correct routes.
How keepalives work for NATing ?
This mechanism works by sending a SIP request to a user agent behind NAT to make that user agent send back a reply. The purpose is to have packets sent from inside the NAT to the proxy often enough to prevent the NAT box from timing out the connection.
Module sends Keeplaives to preserve their visibility only in :
Registration – for user agent that have registered to for incoming calls, triggering keepalive for a REGISTER request.
Subscription – for presence agents that have subscribed to some events for receiving back notifications with SUBSCRIBE request.
Dialogs – for user agents that have initiated an outgoing call for receiving further in-dialog messages. When all the conditions to keepalive a NAT endpoint will disappear, that endpoint will be removed from the list with the NAT endpoints that need to be kept alive.
function nat_keepalive()
the function needs to be called on proxy directly interacting with UA behind NAT.
call only once for the requests (REGISTER, SUBSCRIBE or outgoing INVITEs) that triggers the need for network visibility.
call before the request gets either a stateless reply or it is relayed with t_relay()
for outgoing INVITE , it triggers dialog tracing for that dialog and will use the dialog callbacks to detect changes in the dialog state.
Dependencies – sl , tm and dialog module
Params
keepalive_interval – time interval between sending a keepalive message to all the endpoints that need being kept alive. A negative value or zero will disable the keepalive functionality.
keepalive_extra_headers – extra headers that should be added to the keepalive messages. Header must also include the CRLF (\r\n) line separator. Multiple headers can be specified by concatenating with \r\n separator.
keepalive_state_file – filename where information about the NAT endpoints and the conditions for which they are being kept alive is saved . It is used when Kamailio starts to restore its internal state and continue to send keepalive messages to the NAT endpoints that have not expired in the meantime. Also used at kamailio restart as it avoids losing keepalive state information about the NAT endpoints.
client_nat_test ()– Check if the client is behind NAT. Tests to be performed gievn by int can be : 1 – tests if client has a private IP address or one from shared address space in the Contact field of the SIP message. 2 – tests if client has contacted Kamailio from an address that is different from the one in the Via field. 4 – tests if client has a private IP address or one from shared address space in the top Via field of the SIP message.
For example calling client_nat_test(“3”) will perform test 1 and test 2 and return true if at least one succeeds, otherwise false.
fix_contact() – replace the IP and port in the Contact header with the IP and port the SIP message was received from. Usually called after a succesfull call to client_nat_test(type)
if (client_nat_test("3")) {
fix_contact();
}
nat_keepalive() – Triggers keepalive functionality for the source address of the request. When called it only sets some internal flags, which will trigger later the addition of the endpoint to the keepalive list if a positive reply is generated/received (for REGISTER and SUBSCRIBE) or when the dialog is started/replied (for INVITEs). For this reason, it can be called early or late in the script. The only condition is to call it before replying to the request or before sending it to another proxy. If the request needs to be sent to another proxy, t_relay() must be used to be able to intercept replies via TM or dialog callbacks.
If stateless forwarding is used, the keepalive functionality will not work. Also for outgoing INVITEs, record_route() should also be used to make sure the proxy that keeps the caller endpoint alive stays in the path.
NAT traversal and reuse of TCP connections. Helps symmetric UAs who are not able to determine their public address.
NAT pinging types
UDP packet 4 bytes (zero filled) UDP packets are sent to the contact address.
SIP request a stateless SIP request is sent to the UDP contact address.
(+) low bandwitdh traffic, (+) easy to generate by Kamailio;
(+) bidirectional traffic through NAT (+) since each PING request from Kamailio (inbound traffic) will force the SIP client to generate a SIP reply (outbound traffic) – the NAT bind will be surely kept open.
(-) unidirectional traffic through NAT (inbound – from outside to inside); if many NATs do update the bind timeout only on outbound traffic, the bind may expire and closed.
(-) higher bandwitdh traffic (-) more expensive (as time) to generate by Kamailio;
Dependencies – usrloc
Params
force_socket – Socket to be used when sending NAT pings for UDP communication.
Asterisk is a framework or toolkit designed for VOIP systems . It can support Enterprise communication systems like PBXs, call distributors, VoIP gateways , conference bridges etc . It is open source and free to use . It is developed in C and runs in linux .
Technically , Asterisk has protocol support for many telephony technologies and protocols such as SIP , H323 . It can connect old PSTN or copper line and VOIP .
Asterisk is a framework for building multi-protocol, real-time communications applications and solutions. Asterisk is to realtime voice and video applications as what Apache is to web applications
– asterisk.org
Combine the SIP channel, the PSTN interface channel and some Dialplan script and you have a gateway.
Change the Dialplan to drop calls into a ConfBridge session and you have a conference server.
Alter it once more to route calls into voice mailboxes and you have a voicemail server.
Tie it all together and you have an amazingly powerful phone system.
Asterisk as a Central signalling SIP application Server in VoIP Platform
Due to the wide array of call flow processing and media, channel, bridge management module support of asterisk, it is ideal to sit at the core of a VoIP of Communication platform solution. A WebRTC capable CPaaS overall architecture with inbound and outbound Kamailio proxy and central asterisk signaller and integration to telecom service providers over SIP trunks can be described as below
I am using the latest release candidate at the time writing this article asterisk-16.2.0-rc1-patch.tar.gz
Some external Dependencies apt-get install subversion
Then install the source dependencies
sudo su contrib/scripts/get_mp3_source.sh
This will install mp3 related programs such as
A addons/mp3 A addons/mp3/decode_ntom.c A addons/mp3/interface.c A addons/mp3/MPGLIB_README A addons/mp3/common.c A addons/mp3/huffman.h A addons/mp3/tabinit.c A addons/mp3/Makefile A addons/mp3/README A addons/mp3/decode_i386.c A addons/mp3/dct64_i386.c A addons/mp3/MPGLIB_TODO A addons/mp3/mpg123.h A addons/mp3/layer3.c A addons/mp3/mpglib.h Exported revision 202.
Actual dependencies will be installed via install_prereq script
contrib/scripts/install_prereq install
Output snippet
Run configure which will create scripts for next processes
Asterisk 16.2.0-rc1, Copyright (C) 1999 - 2018, Digium, Inc. and others. Created by Mark Spencer markster@digium.com
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public License version 2 and other licenses; you are welcome to redistribute it under certain conditions. Type 'core show license' for details.
Connected to Asterisk 16.2.0-rc1 currently running on ip-172-31-45-26 (pid = 13388)
ip-172-31-45-26*CLI>
Register sip phones with asterisk PBX and make / receive calls
To make calls among users, we need to configure channel driver with sip support . Using the sip protcol the phones within the enterprise will be able to send call signals out to one another. Open pjsip.conf
and set the values in sip softphone like zoiper , register with provided creds
registering sip phone zoiper with newly created asterisk PBX
If the registration creds used are not matching with the ones defines in pjsip.conf then REGISTER request failed message is displayed
Request 'REGISTER' from '' failed for 'x.x.x.x:18475' (callid: hp8iN6oWLRdER4zvEBdiUg..) - No matching endpoint found
On correct creds used the server prints traces such as
-- Added contact 'sip:1113@x.x.x.x:44312;transport=UDP;rinstance=b8aceff08623b51e' to AOR '1113' with expiration of 60 seconds
== Endpoint 1113 is now Reachable
-- Removed contact 'sip:1113@x.x.x.x:44312;transport=UDP;rinstance=b8aceff08623b51e' from AOR '1113' due to request
== Contact 1113/sip:1113@x.x.x.x:44312;transport=UDP;rinstance=b8aceff08623b51e has been deleted
== Endpoint 1113 is now Unreachable
-- Added contact 'sip:1113@x.x.x.x:18475;transport=UDP;rinstance=5af431512ae0af3a' to AOR '1113' with expiration of 60 seconds
== Endpoint 1113 is now Reachable
Alternatively one can also create new sip endpoints
exten=>6124,1,Verbose(2,The channel name is ${CHANNEL})
same => n,Verbose(2,The unique id is ${UNIQUEID})
same => n,Verbose(2,The caller id is ${CALLERID(all)})
same => n,Verbose(2,The datetime is ${DATETIME})
same => n,Verbose(2,The timestamp is ${TIMESTAMP})
same => n,Verbose(2,The context is ${CONTEXT})
same => n,Verbose(2,The SYSTEMNAME is ${SYSTEMNAME})
same => n,Verbose(2,The PRIORITY is ${PRIORITY})
same => n,Verbose(2,The CHANNEL is ${CHANNEL})
settings varaibles and Say
exten=>6009,1,Verbose("------------ Set variable -------")
same => n,Set(COUNT=3)
same => n,SayNumber(${COUNT})
same => n,Set(${COUNT}=10)
same => n,SayNumber(${COUNT})
Simple Voicemail ( also need configuration on voicemail.conf)
exten => 1235,1,VoiceMail(1235,u)
PBX and applications
PBX cores settings
Version: 16.2.0-rc1
Build Options: BUILD_NATIVE, OPTIONAL_API
Maximum calls: Not set
Maximum open file handles: 1024
Root console verbosity: 5
Current console verbosity: 5
Debug level: 0
Maximum load average: 0.000000
Minimum free memory: 0 MB
Startup time: 10:27:35
Last reload time: 10:27:35
System: Linux/4.15.0-1021-aws built by root on x86_64 2019-02-11 11:48:29 UTC
System name:
Entity ID: 0e:28:c0:44:39:5e
PBX UUID: a2df96bb-6d1a-4f64-a953-cf02030e9851
Default language: en
Language prefix: Enabled
User name and group: /
Executable includes: Disabled
Transcode via SLIN: Enabled
Transmit silence during rec: Disabled
Generic PLC: Disabled
Generic PLC on equal codecs: Disabled
Min DTMF duration:: 80
Cache media frames: Enabled
RTP use dynamic payloads: 1
RTP dynamic payload types: 35-63,96-127
Subsystems
Manager (AMI): Disabled
Web Manager (AMI/HTTP): Disabled
Call data records: Enabled
Realtime Architecture (ARA): Disabled
Directories
Configuration file: /etc/asterisk/asterisk.conf
Configuration directory: /etc/asterisk
Module directory: /usr/lib/asterisk/modules
Spool directory: /var/spool/asterisk
Log directory: /var/log/asterisk
Run/Sockets directory: /var/run/asterisk
PID file: /var/run/asterisk/asterisk.pid
VarLib directory: /var/lib/asterisk
Data directory: /var/lib/asterisk
ASTDB: /var/lib/asterisk/astdb
IAX2 Keys directory: /var/lib/asterisk/keys
AGI Scripts directory: /var/lib/asterisk/agi-bin
Asterisk Applications
Some of the application are listed below . Note that this is not an extensive list as more application are added and old ones are removed every minor release .
AddQueueMember: Dynamically adds queue members. AlarmReceiver: Provide support for receiving alarm reports from a burglar or fire alarm panel. AMD: Attempt to detect answering machines. Answer: Answer a channel if ringing. AttendedTransfer: Attended transfer to the extension provided and TRANSFER_CONTEXT BackGround: Play an audio file while waiting for digits of an extension to go to. BackgroundDetect: Background a file with talk detect. BlindTransfer: Blind transfer channel(s) to the extension and context provided Bridge: Bridge two channels. BridgeAdd: Join a bridge that contains the specified channel. BridgeWait: Put a call into the holding bridge. Busy: Indicate the Busy condition. ChanSpy: Listen to a channel, and optionally whisper into it. ConfBridge: Conference bridge application. Dial: Attempt to connect to another device or endpoint and bridge the call. Dictate: Virtual Dictation Machine. Echo: Echo media, DTMF back to the calling party ExtenSpy: Listen to a channel, and optionally whisper into it. ExternalIVR: Interfaces with an external IVR application. FollowMe: Find-Me/Follow-Me application. ForkCDR: Forks the current Call Data Record for this channel. Hangup: Hang up the calling channel. Log: Send arbitrary text to a selected log level. MailboxExists: Check to see if Voicemail mailbox exists. Milliwatt: Generate a Constant 1004Hz tone at 0dbm (mu-law). MixMonitor: Record a call and mix the audio during the recording. Use of StopMixMonitor is required to guarantee the audio file is available for processing during dialplan execution. Monitor: Monitor a channel. Morsecode: Plays morse code. MusicOnHold: Play Music On Hold indefinitely. NoCDR: Tell Asterisk to not maintain a CDR for this channel. NoOp: Do Nothing (No Operation). Originate: Originate a call. Park: Park yourself. PauseMonitor: Pause monitoring of a channel. PauseQueueMember: Pauses a queue member. Pickup: Directed extension call pickup. Playback: Play a file. PlayTones: Play a tone list. PrivacyManager: Require phone number to be entered, if no CallerID sent Proceeding: Indicate proceeding. Progress: Indicate progress. Queue: Queue a call for a call queue. Read: Read a variable. SendImage: Sends an image file. SendText: Send a Text Message on a channel. SendURL: Send a URL. Set: Set channel variable or function value. SetAMAFlags: Set the AMA Flags. SMS: Communicates with SMS service centres and SMS capable analogue phones. SoftHangup: Hangs up the requested channel. SpeechActivateGrammar: Activate a grammar. SpeechBackground: Play a sound file and wait for speech to be recognized. SpeechCreate: Create a Speech Structure. SpeechDeactivateGrammar: Deactivate a grammar. SpeechDestroy: End speech recognition. SpeechLoadGrammar: Load a grammar. SpeechProcessingSound: Change background processing sound. SpeechStart: Start recognizing voice in the audio stream. SpeechUnloadGrammar: Unload a grammar. StackPop: Remove one address from gosub stack. StartMusicOnHold: Play Music On Hold. Stasis: Invoke an external Stasis application. StopMixMonitor: Stop recording a call through MixMonitor, and free the recording’s file handle. StopMonitor: Stop monitoring a channel. StopMusicOnHold: Stop playing Music On Hold. StopPlayTones: Stop playing a tone list. StreamEcho: Echo media, up to ‘N’ streams of a type, and DTMF back to the calling party VMSayName: Play the name of a voicemail user VoiceMail: Leave a Voicemail message. Record: Record to a file. RemoveQueueMember: Dynamically removes queue members. ResetCDR: Resets the Call Data Record. RetryDial: Place a call, retrying on failure allowing an optional exit extension. Return: Return from gosub routine. Ringing: Indicate ringing tone. SayNumber: Say Number. SMS: Communicates with SMS service centres and SMS capable analogue phones. SoftHangup: Hangs up the requested channel. SpeechActivateGrammar: Activate a grammar. SpeechBackground: Play a sound file and wait for speech to be recognized. SpeechCreate: Create a Speech Structure. SpeechDeactivateGrammar: Deactivate a grammar. SpeechDestroy: End speech recognition. SpeechLoadGrammar: Load a grammar. SpeechProcessingSound: Change background processing sound. SpeechStart: Start recognizing voice in the audio stream. StartMusicOnHold: Play Music On Hold. Stasis: Invoke an external Stasis application. StopMixMonitor: Stop recording a call through MixMonitor, and free the recording’s file handle. StopMonitor: Stop monitoring a channel. StopMusicOnHold: Stop playing Music On Hold. StopPlayTones: Stop playing a tone list. StreamEcho: Echo media, up to ‘N’ streams of a type, and DTMF back to the calling party System: Execute a system command. VoiceMail: Leave a Voicemail message. VoiceMailMain: Check Voicemail messages. VoiceMailPlayMsg: Play a single voice mail msg from a mailbox by msg id. Wait: Waits for some time. Zapateller: Block telemarketers with SIT.
To connect video based webrtc endpoints ensure you load the codecs and also libsrtp . Overwrite the selective conf in this folders with the existing conf of asterisk to run a basic webrtc video call . These were tested with jssip on asterisk v17 with res_pjsip.
confirm using pjsip – since chan_sip is depriciate. Confirm that yo are not using chan_sip and instead ensure using re_pjsip
module unload chan_sip
module show like res_pjsip
If pjssip is not found load it wither form menuselect or by using cli load module command .
use the “ast_tls_cert” script in the “contrib/scripts” Asterisk source directory to make a self-signed certificate authority and an Asterisk certificate.
sh ast_tls_cert.sh -C localhost -O "altanai" -d .
after creating the self signed keys start the server
asterisk -vvvvvvc
channels
Peer User/ANR Call ID Format Hold Last Message Expiry Peer
10.10.10.10 1060 e8ae107f-ce90-2 (ulaw) No Rx: ACK 1060
Codecs – check for the webrtc supported audio and video codesc in the list , if not found install the modules and reload.
31 image png png (PNG Image)
6 audio g726 g726 (G.726 RFC3551)
4 audio alaw alaw (G.711 a-law)
2 audio g723 g723 (G.723.1)
20 audio speex speex (SpeeX)
21 audio speex speex16 (SpeeX 16khz)
22 audio speex speex32 (SpeeX 32khz)
24 audio g722 g722 (G722)
25 audio siren7 siren7 (ITU G.722.1 (Siren7, licensed from Polycom))
32 video h261 h261 (H.261 video)
33 video h263 h263 (H.263 video)
8 audio adpcm adpcm (Dialogic ADPCM)
36 video h265 h265 (H.265 video)
44 audio silk silk8 (SILK Codec (8 KHz))
45 audio silk silk12 (SILK Codec (12 KHz))
46 audio silk silk16 (SILK Codec (16 KHz))
47 audio silk silk24 (SILK Codec (24 KHz))
28 audio g719 g719 (ITU G.719)
34 video h263p h263p (H.263+ video)
35 video h264 h264 (H.264 video)
19 audio g729 g729 (G.729A)
9 audio slin slin (16 bit Signed Linear PCM)
10 audio slin slin12 (16 bit Signed Linear PCM (12kHz))
11 audio slin slin16 (16 bit Signed Linear PCM (16kHz))
12 audio slin slin24 (16 bit Signed Linear PCM (24kHz))
13 audio slin slin32 (16 bit Signed Linear PCM (32kHz))
14 audio slin slin44 (16 bit Signed Linear PCM (44kHz))
15 audio slin slin48 (16 bit Signed Linear PCM (48kHz))
16 audio slin slin96 (16 bit Signed Linear PCM (96kHz))
17 audio slin slin192 (16 bit Signed Linear PCM (192kHz))
3 audio ulaw ulaw (G.711 u-law)
18 audio lpc10 lpc10 (LPC10)
27 audio testlaw testlaw (G.711 test-law)
43 audio none none (<Null> codec)
42 image t38 t38 (T.38 UDPTL Fax)
39 video vp9 vp9 (VP9 video)
38 video vp8 vp8 (VP8 video)
5 audio gsm gsm (GSM)
37 video mpeg4 mpeg4 (MPEG4 video)
23 audio ilbc ilbc (iLBC)
40 text red red (T.140 Realtime Text with redundancy)
41 text t140 t140 (Passthrough T.140 Realtime Text)
29 audio opus opus (Opus Codec)
30 image jpeg jpeg (JPEG image)
7 audio g726aal2 g726aal2 (G.726 AAL2)
1 audio codec2 codec2 (Codec 2)
26 audio siren14 siren14 (ITU G.722.1 Annex C, (Siren14, licensed from Polycom))
Webrtc clients
Here is a succesful run using PJSIP as the webrtc client to communicated to another pjsip client via Asterisk server .
Note that all signalling and media isi getting proxied via the Asterisk server signalling and media plane which is in contrast to the peer to peer nature of WebRTC
Register with SIP Registrar on AsteriskSpecify the contact URI as the Asterisk server tooIncoming CallWebRTC Call in progress via asterisk SIP and Media ServerSignalling and Media Proxy Via Asterisk
The purpose of this article is to demo the process of using Kamailio + RTP Engine to enable SIP-based WebRTC call to a traditional SIP UA like Xlite. Kamailio Will thus provide not only call routing but also NATing, TLS and WebSocket support for webrtc endpoints. For this bridging of SRTP from WebRTC endpoint like JSSIP to RTP for SIP UA like Xlite, we will use the RTP engine.
Output should be like … Certificate is to be certified until Jun 25 11:02:41 2020 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
and files genrated shoudl look like
/home/ubuntu# ls
certs kamailio1_cert.pem kamailio1_cert_req.pem privkey.pem
Copy the newly created certs to their respective paths
Websocket is considered a transport option just as TCP or UDP in kamailio config , hence just as one defines IP addr and ports for TCP, UDP protocol , we need to define the same for WS or WSS
check if port in R-URI meant for ws or wss, did not receive websocket or secure websocket
if (($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT) && !(proto == WS || proto == WSS)) {
xlog("L_WARN", "SIP request received on $Rp\n");
sl_send_reply("403", "Forbidden");
exit;
}
request_route for websocket , included checking is client is behind NAT using nat_uac_test methods from NAThelper. If it is then for REGISTER methods do fix_nated_register and for other add_contact_alias
Like most other WebRTC libraries , JSSIP is event driven and provides provide core WEBRTC API like getUserMedia and RTP PeerConnection providing STUN,ICE,DTLS, SRTP features. It also integrated with rtcninja to provide cross browser accessibility. The differentiators with JSSIP lies in the fact that it supports SIP stack over websockets
Instantiate JSSIP websocket interface with kamailio IP
var socket = new JsSIP.WebSocketInterface('wss://<kamailio_ip>:443');
Add configuration for registeration . Note if not using kamailio as proxy to SBC, it is recommended to add regiseteration features to provide user reachability for incoming calls and NAT pings
var configuration = {
sockets : socket,
uri : 'sip:username@example.com',
password : 'password'
};
INVITE from user1 altanai to john, notice that “To” header doesnt have tag. This will be handy for recognizing whether it is first message of dialog offer and in-dialog message such as ACK , RE-INVITE , BYE etc
100trying from callee, note the to and from headers remain same for request or responses. This is send automatically by kamailio for INVITE.
SIP/2.0 100 trying -- your call is important to us
Via: SIP/2.0/WSS ipoct61ao12v.invalid;branch=z9hG4bK4220209;rport=17502;received=x.x.x.x
To: sip:john@voiptelco.com
From: sip:altanai@voiptelco.com;tag=2q0lecmbsn
Call-ID: s8bnv5869fp68d1ju8c1
CSeq: 1799 INVITE
Server: kamailio (5.2.3 (x86_64/linux))
Content-Length: 0
180 ringing from Callee, note the addition of contact header
since ACK is a Within dialog message and sequential request withing a dialog should take the path determined by record-routing, we first check if it has to tag. Having a to tag validates that it is a in-dialog request .
After this validate if is loose_route() and has no destination URI $du , then try to add rui alias using handle_ruri_alias( ), if that fails, reject the request.
If it is not loose_route() and method is ACK then check if the ACK matches a transaction t_check_trans() ie is stateful. If it is then relay otherwise reject.
route(WITHINDLG);
...
route[WITHINDLG] {
if (has_totag()) {
if (loose_route()) {
if ($du == "") {
if (!handle_ruri_alias()) {
xlog("L_ERR", "Bad alias <$ru>\n");
sl_send_reply("400", "Bad Request");
exit;
}
}
route(RELAY);
} else {
if ( is_method("ACK") ) {
if ( t_check_trans() ) {
t_relay();
exit;
} else {
exit;
}
}
sl_send_reply("404", "Not Found");
}
exit;
}
}
Also required to convert ICE packet fromWebRTC to non ICE for Xlite.
Due to its very flexible and customisable routing engine it can be used in number of scenarios such as an SIP proxy or a router and due to its high throughput it is widely recommended as an enterprise grade inbound/outbound proxy server.
This article talks about modules and subparts of Opensips and their role in defining the purpose and application of Opensips which can be as an lighweight proxy to loadbalancer or even as AAA server.
Dispatcher Module
This modules implements a dispatcher for destination addresses. It computes hashes over parts of the request and selects an address from a destination set. The selected address is used then as outbound proxy. The module can be used as a stateless load balancer, having no guarantee of fair distribution.
Path to the file with destination sets by default is “/etc/opensips/dispatcher.list” or “/usr/local/etc/opensips/dispatcher.list”.
setid_col (string) – storing the gateway’s group id. Default value is “setid”.
modparam("dispatcher", "setid_col", "groupid")
destination_col (string) – destination’s sip uri.
modparam("dispatcher", "destination_col", "uri")
flags_col (string) – The column’s name in the database storing the flags for destination uri.
modparam("dispatcher", "flags_col", "dstflags")
force_dst (int) – If set to 1, force overwriting of destination address when that is already set. Default value is “0”.
modparam("dispatcher", "force_dst", 1)
flags (int) – affect dispatcher’s behaviour. Default value is “0”.
If flag 1 is set only the username part of the uri will be used when computing an uri based hash.
If no flags are set the username, hostname and port will be used The port is used only if different from 5060 (normal sip uri) or 5061 (in the sips case).
If flag 2 is set, then the failover support is enabled. The functions exported by the module will store the rest of addresses from the destination set in AVP, and use these AVPs to contact next address when the current-tried fails.
modparam("dispatcher", "flags", 3)
use_default (int) – If the parameter is set to 1, the last address in destination set is used as last option to send the message. For example, it is good when wanting to send the call to an anouncement server saying: “the gateways are full, try later”. Default value is “0”.
modparam("dispatcher", "use_default", 1)
dst_avp (str) – The name of the avp which will hold the list with addresses, in the order they have been selected by the chosen algorithm.
modparam("dispatcher", "dst_avp", "$avp(i:271)")
If use_default is 1, the value of last dst_avp_id is the last address in destination set. The first dst_avp_id is the selected destinations. All the other addresses from the destination set will be added in the avp list to be able to implement serial forking.
grp_avp (str) – The name of the avp storing the group id of the destination set. Good to have it for later usage or checks. Default is null.
modparam("dispatcher", "grp_avp", "$avp(i:272)")
cnt_avp (str) – The name of the avp storing the number of destination addresses kept in dst_avp avps.
modparam("dispatcher", "cnt_avp", "$avp(i:273)")
hash_pvar (str) – String with PVs used for the hashing algorithm like to do hashing over custom message parts.Default value is “null” – disabled.
ds_ping_method (string) – With this Method you can define, with which method you want to probe the failed gateways. This method is only available, if compiled with the probing of failed gateways enabled. Default value is “OPTIONS”.
modparam("dispatcher", "ds_ping_method", "INFO")
ds_ping_from (string) – With this Method you can define the “From:”-Line for the request, sent to the failed gateways. This method is only available, if compiled with the probing of failed gateways enabled. Default value is “sip:dispatcher@localhost”.
ds_ping_interval (int – With this Method you can define the interval for sending a request to a failed gateway. This parameter is only used, when the TM-Module is loaded. If set to “0”, the pinging of failed requests is disabled.Default value is “10”.
modparam("dispatcher", "ds_ping_interval", 30)
ds_probing_threshhold (int) – If you want to set a gateway into probing mode, you will need a specific number of requests until it will change from “active” to probing. The number of attempts can be set with this parameter. Default value is “3”.
ds_probing_mode (int) – Controls what gateways are tested to see if they are reachable.
If set to 0, only the gateways with state PROBING are tested,
if set to 1, all gateways are tested. If set to 1 and the response is 407 (timeout), an active gateway is set to PROBING state. Default value is “0”.
modparam("dispatcher", "ds_probing_mode", 1)
options_reply_codes (str) – The codes defined here will be considered as valid reply codes for OPTIONS messages used for pinging, apart for 200. Default value is “NULL”.
ds_select_dst(set, alg) – The method selects a destination from addresses set. Algorithm used to select the destination address can be :
“0” – hash over callid
“1” – hash over from uri.
“2” – hash over to uri.
“3” – hash over request-uri.
“4” – round-robin (next destination).
“5” – hash over authorization-username (Proxy-Authorization or “normal” authorization). If no username is found, round robin is used.
“6” – random (using rand()).
“7” – hash over the content of PVs string. Note: This works only when the parameter hash_pvar is set.
“X” – if the algorithm is not implemented, the first entry in set is chosen.
ds_select_dst("1", "0");
You can use ‘ds_next_dst()’ to use next address to achieve serial forking to all possible destinations. This function can be used from REQUEST_ROUTE.
ds_select_domain(set, alg) – selects a destination from addresses set and rewrites the host and port from R-URI. This function can be used from REQUEST_ROUTE.
ds_next_dst() – Takes the next destination address from the AVPs with id ‘dst_avp_id’ and sets the dst_uri (outbound proxy address). This function can be used from FAILURE_ROUTE.
ds_next_domain() – Takes the next destination address from the AVPs with id ‘dst_avp_id’ and sets the domain part of the request uri. This function can be used from FAILURE_ROUTE.
ds_mark_dst() – Mark the last used address from destination set as inactive, in order to be ingnored in the future. In this way it can be implemented an automatic detection of failed gateways. When an address is marked as inactive, it will be ignored by ‘ds_select_dst’ and ‘ds_select_domain’. This function can be used from FAILURE_ROUTE.
ds_mark_dst(“s”) – Mark the last used address from destination set as :
inactive (“i”/”I”/”0”),
active (“a”/”A”/”1”) or
probing (“p”/”P”/”2”).
With this function, an automatic detection of failed gateways can be implemented. When an address is marked as inactive or probing, it will be ignored by ‘ds_select_dst’ and ‘ds_select_domain’.
ds_is_from_list() – This function returns true, if the current request comes from a host from the dispatcher-list; otherwise false. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE and ONREPLY_ROUTE.
ds_is_from_list(“group”) – This function returns true, if the current request comes from a host in the given group of the dispatcher-list; otherwise false.
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE and ONREPLY_ROUTE.
Exported MI Functions
ds_set_state – Sets the status for a destination address (can be use to mark the destination as active or inactive).
Parameters: state : state of the destination address
“a”: active
“i”: inactive
“p”: probing group: destination group id address: address of the destination in the group
MI FIFO Command Format:
:ds_set_state:reply_fifo_file state group address empty_line
ds_list – It lists the groups and included destinations.
MI FIFO Command Format:
:ds_list:reply_fifo_file empty_line
ds_reload – reloads the groups and included destinations.
MI DATAGRAM Command Format:
":ds_reload:\n."
Installation and Running
Destination List File – Each destination point must be on one line. First token is the set id, followed by destination address. Optionally, the third field can be flags value (1 – destination inactive, 2 – destination in probing mod — you can do bitwise OR to set both flags). The set id must be an integer value. Destination address must be a valid SIP URI. Empty lines or lines starting with “#” are ignored.
Exmaple of a dispatcher list file
line format
setit(integer) destination(sip uri) flags (integer, optional)
Implementation for a simplified database engine based on text files. It can be used by OpenSIPS DB interface instead of other database module (like MySQL). It keeps everything in memory.
The db_text database system architecture contains
a database is represented by a directory in the local file system. NOTE: when you use db_text in OpenSIPS, the database URL for modules must be the path to the directory where the table-files are located, prefixed by “text://”,
e.g., “text:///var/dbtext/opensips”.
a table is represented by a text file inside database directory.
Internal format of a db_text table
column definition name(type,attr) where types can be int , double , str and attributes be auto , null ,
* each other line is a row with data. The line ends with “\n”.
* the fields are separated by “:”.
* no value between two ‘:’ (or between ‘:’ and start/end of a row) means “null” value.
* next characters must be escaped in strings: “\n”, “\r”, “\t”, “:”.
* 0 — the zero value must be escaped too.
This database interface don’t support the data insertion with default values. All such values specified in the database
template are ignored.
db_mode (integer) – Set caching mode (0 – default) or non-caching mode (1). In caching mode, data is loaded at startup. In non-caching mode, the module check every time a table is requested whether the correspondingfile on disk has changed, and if yes, will re-load table from file.
modparam("db_text", "db_mode", 1)
Exported MI Functions
dbt_dump – Write back to hard drive modified tables.
opensipsctl fifo dbt_dump
dbt_reload – Causes db_text module to reload cached tables from disk. Parameters:
1 db_name (optional) – database name to reload.
2 table_name (optional, but cannot be present without the
db_name parameter) – specific table to reload.
setting module-specific parameters and making initial sanity checks — messages with max_forwards==0, or excessively long requests
-- mi_fifo params --
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
-- usrloc params --
modparam("usrloc", "db_mode", 2)
modparam("usrloc|auth_db", "db_url", "text:///tmp/opensipsdb")
modparam("auth_db", "calculate_ha1", 1)
modparam("auth_db", "password_column", "password")
modparam("auth_db", "user_column", "username")
modparam("auth_db", "domain_column", "domain")
route{
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops");
exit;
};
if ($ml >= 65535 ) {
sl_send_reply("513", "Message too big");
exit;
};
if (!$rm=="REGISTER") record_route();
//if the request is for other domain use UsrLoc
if (is_myself("$rd")) {
if ($rm=="REGISTER") {
# digest authentication
if (!www_authorize("", "subscriber")) {
www_challenge("", "0");
exit;
};
save("location");
exit;
};
lookup("aliases");
if (!is_myself("$rd")) {
append_hf("P-hint: outbound alias\r\n");
route(1);
exit;
};
# native SIP destinations are handled using our USRLOC DB
if (!lookup("location")) {
sl_send_reply("404", "Not Found");
exit;
};
};
append_hf("P-hint: usrloc applied\r\n");
route(1);
}
route[1]
{
if (!t_relay()) {
sl_reply_error();
};
}
After the starting of a transaction such as REGISTER or INVITE we ensure that subsequent messages withing a dialog should take the path determined by record-routing using “record_route” function.
It is an multi-functional, multi-purpose SIP server especially used in VoIP landscape as standalone SIP server or SBC ( Session Border Controller ) for inbound and outbound traffic by carriers, telecoms backend layers or ITSPs for call routing and trunking solutions. It can be deployed with Class4/5 Platforms, SIP Trunking , hosted or IP PBX setup , existing gateways/ Session Border Controllers, Application Servers, proxy server, Front-End Load Balancers, IMS Platforms, Call Center etc.
Due to its very flexible and customisable routing engine it can be used in number of scenarios such as an SIP proxy or a router and due to its high throughput it is widely recommended as an enterprise grade inbound/outbound proxy server.
SIP to XMPP gateway for presence and IM (bidirectional)
Load-balancer or dispatcher
Inbound/front end for gateways/asterisk
SIP NAT traversal unit
Application server with custom logic
Since Opensips has emerged as a resilent SIP server , it is also used in specific usecases such as – DID ( Direct Inward dialling ) for SIP trunking solutions , – Local Number Portability (LNP) providers, – Canonical Name (CNAME) providers etc
It can act as Registrar with NAT traversal abilities (STUN, TURN, SIP pinging)
UDP , TCP , TLS , SCTP and WS transports over both IPv4 and IPv6 Additionally it can be connected to multiple networks ( Multihomed ) and do IP authentication or IP blacklisting
Class 4 routing capabilities in opensips include SIP aliases, Direct Inward Dialing , Speed dial, CPL,vDialplan , dispatcher with various algorithms, prefix-based routing to multiple carriers , failover support, Load balancing , ENUM-based or Geolocation-based routing etc. Some of the Class 5 capabilities in opensips are B2B , call queuing UAC registration , authentication, mangling, White/Black list
SIP SIMPLE features as messaging , Presence , Busy Lamp Field (BLF), Shared Call/Line Appearance (SCA) , Bridged Line Appearance (BLA) , Message Waiting notifications (MWI), XCAP , Resource List Server ( RLS ) , XMPP , SMS gateway (AT and SMPP)
Although opensips has no built-in media capabilities, but it modules for external media engines for Media relaying (RTPProxy, MediaProxy, RTPEngine), Media transcoding (Sangoma D1 cards) , Codec manipulation.
Opensips has majorly 2 parts core and addon-modules.
Opensips Core part is only a proxy stateless SIP server . It contains
SIP transport layer which supports UDP, TCP, TLS and WS for SIP. As per the listener in routing script transport protocols is selected .
SIP factory — the message parser and builder which can be used to add new headers or remove existing ones.
Routing script parser and interpreter for the routing script which loads it to the memory at the startup time. To load a new script server restart is required.
Memory and locking manager for the memory allocation and locking to prevent deadlocks and starvation. Although these arn’t accesible by route scripting, it can be configured at compile time.
Core script functions and variables which can be used in routing scripts in addition to the functions exported by add-on modules.
Interfaces
Events Interface
Used to notify external applications about events triggered internal to OpenSIPS such as
core events – E_CORE_THRESHOLD ,E_CORE_PKG_THRESHOLD , E_CORE_SHM_THRESHOLD , modules events , or even a custom event using raise_event() command
Statistics Interface
Provide insights to statistics of opensips in numerical results which could be used for services like monitoring, load evaluation, realtime integration etc. The statictsics can be of two kinds :
1. counter like – variables that keep counting things that happened in OpenSIPS, like received requests, processed dialogs, failed DB queries, etc
2. computed values – variables that are calculated in realtime, like how much memory is used, the current load, active dialogs, active transactions, etc
These variable would reset form 0 at start sometimes even during runtime.
Binary Internal Interface
Provider communication between individual OpenSIPS instances. Used in cases such as failovers where dialogs needs to persist for service continuity. Hence with this interface one can replicate all the events related to the runtime data (creation / updating / deletion) to a backup OpenSIPS instance.
SQL interface and NoSQL interface
SQL interfaces provides interaction with Sql DB drivers and services such as MySQL, Postgres, Oracle, Berkeley, unixODBC etc , while NoSQL interface provides access to Redis, CouchBase, Cassandra, MongoDB, Memcached, and other databases which are more frequently implemented as external caches.
AAA interface definition
Currently, OpenSIPS supports the RADIUS driver for the AAA interface with upcoming support for DIAMETER.
Management interface
Allows the external applications to trigger predefined commands
Push data like setting a debug level, registering a contact etc
Fetch data like registered users, ongoing calls, get statistics etc
Trigger an internal action as reloading the data, sending a message so on
1. Functional SIP modules
SIP signalling modules such as B2B_ENTITIES , B2B_LOGIC , CALL CENTER ( for Inbound call center system ) , DIALOG , NAT_TRAVERSAL , NATHELPER
OPTIONS , REGISTRAR ,SIGNALING , UAC_REGISTRANT
TM (Transaction/stateful module) , SL (Stateless replier ) , SMS (SIP-to-SMS IM gateway)
A config file opensips.config has 3 main logical parts :
1.global parameters – network listeners, available transport protocols, forking (and number of processes), the logging
2.modules section – the modules that are to be loaded with path to their .so file
3.routing logic – logic for routing sip traffic
Routes
OpenSIPS routing logic uses several types of routes. Each type of route is triggered by a certain event and allows you to process a certain type of message (request or reply).
route SIP requests routing. The main ‘route’ block identified by ‘route{…}’ or ‘route[0]{…}’ is executed for each SIP request. To send a reply or forward the request, explicit actions must be called inside the route block. in example below which sends 200 ok reply for each options request.
branch_route Handles different branches of a SIP request. if the branch is not dropped the branch will be automatically sent out. It is executed only by TM module after it was armed via t_on_branch(“branch_route_index”).
if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
}
branch_route[MANAGE_BRANCH] {
xdbg("new branch [$T_branch_idx] to $ru\n");
route(NATMANAGE);
}
or lookup location and discard branches where uri matches ip 1.2.3.4 by using drop()
failure_route Failed transaction routing block. It contains a set of actions to be taken each transaction that received only negative replies (>=300) for all branches which completes the transaction. The ‘failure_route’ is executed only by TM module after it was armed via t_on_failure(“failure_route_index”).
if (is_method("INVITE")) {
if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
}
failure_route[MANAGE_FAILURE] {
route(NATMANAGE);
if (t_is_canceled()) {
exit;
}
}
onreply_route Reply routing block. It can be stateful (if bound to a transaction) or stateless (if global reply route). If the reply is not dropped (only provisional replies can be), it will be injected and processed by the transaction engine. There are three types of onreply routes:
global – catches all replies and uses simple definition ‘onreply_route {…}’ or ‘onreply_route[0] {…}’.
Exmaple for “global” reply route set the whole transaction
route {
seturi("sip:bob@opensips.org"); first branch
append_branch("sip:alice@opensips.org"); second branch
t_on_reply("global");
t_on_branch("1");
t_relay();
}
onreply_route {
xlog("OpenSIPS received a reply from $si\n");
}
onreply_route[global] {
if (t_check_status("1[0-9][0-9]")) {
setflag(1);
log("provisional reply received\n");
if (t_check_status("183"))
drop;
}
}
per request/transaction – it catches all received replies belonging to a certain transaction and uses “t_on_reply()” at request time, in REQUEST ROUTE – named ‘onreply_route[N] {…}’.
per branch – it catches only the replies that belong to a certain branch from a transaction via “t_on_reply()” ) at request time, but in BRANCH ROUTE, when a certain outgoing branch is processed – named ‘onreply_route[N] {…}’.
Certain ‘onreply_route’ blocks can be executed by TM module for special replies. For this, the ‘onreply_route’ must be armed for the SIP requests whose replies should be processed within it, via t_on_reply(“onreply_route_index”).
Exmaple of reply route set for this branch only
branch_route[1] {
if ($rU=="alice")
t_on_reply("alice");
}
onreply_route[alice] {
xlog("received reply on the branch from alice\n");
}
error_route
executed automatically on meeting and error such as parsing error in SIP request processing, script assert failure. Performs error handling . The Default action is to discard request. In error_route, the following pseudo-variables are available to get access to error details:
$(err.class) - the class of error (now is '1' for parsing errors)
$(err.level) - severity level for the error
$(err.info) - text describing the error
$(err.rcode) - recommended reply code
$(err.rreason) - recommended reply reason phrase
error_route {
xlog("--- error route class=$(err.class) level=$(err.level)
info=$(err.info) rcode=$(err.rcode) rreason=$(err.rreason) ---\n");
xlog("--- error from [$si:$sp]\n+++++\n$mb\n++++\n");
sl_send_reply("$err.rcode", "$err.rreason");
exit;
}
local_route
executed automatically as TM created a new request, internally (no UAC side). This is a route intended to be used for message inspection, accounting and for applying last changes on the message headers. Routing and signaling functions are not allowed.
startup_route Executed only once when OpenSIPS is started and before the processing of SIP messages begins. Used in initilization cases cases such as loading some data in the cache.
startup_route {
avp_db_query("select gwlist where ruleid==1",$avp(i:100));
cache_store("local", "rule1", "$avp(i:100)");
}
timer_route Route executed periodically at a configured interval of time specified next to the name(in seconds).
timer_route[gw_update, 300] {
avp_db_query("select gwlist where ruleid==1",$avp(i:100));
$shv(i:100) =$avp(i:100);
}
event_route execute script code when an event is triggered. If no way to handle the event specified, default will be synchronously. Triggered by the event_route module when an event is raised by the OpenSIPS Event Interface such as event raised by the pike module when it decides an ip should be blocked called E_PIKE_BLOCKED or E_SCRIPT_EVENT etc ( checke events interface for more events)
event_route[E_PIKE_BLOCKED] {
xlog("The E_PIKE_BLOCKED event was raised\n");
}
event_route[E_PIKE_BLOCKED, async] {
xlog("The E_PIKE_BLOCKED event was raised\n");
}
Scripting Language
Opensips scripting provided more advanced controls
1. Core Keywords
Keywords specific to SIP messages which can be used mainly in ‘if’ expressions. af – address family of the received SIP message. It is INET if the message was received over IPv4 or INET6 if the message was received over IPv6.
if(af==INET6) {
log("Message received over IPv6 link\n");
};
dst_ip – IP of the local interface where the SIP message was received.
if(dst_ip==127.0.0.1) {
log("message received on loopback interface\n");
};
dst_port – local port where the SIP packet was received
if(dst_port==5061)
{
log("message was received on port 5061\n");
};
from_uri – reference to the URI of ‘From’ header.
if(is_method("INVITE") &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; from_uri=~".*@opensips.org")
{
log("the caller is from opensips.org\n");
};
method – SIP method of the message.
if(method=="REGISTER")
{
log("this SIP request is a REGISTER message\n");
};
msg:len – the size of the message
if(msg:len&amp;amp;amp;amp;gt;2048)
{
sl_send_reply("413", "message too large");
exit;
};
$retcode – value returned by last function executed like $?. If tested after a call of a route, it is the value retuned by that route.
route {
route(1);
if($retcode==1)
{
log("The request is an INVITE\n");
};
}
route[1] {
if(is_method("INVITE"))
return(1);
return(2);
}
proto – transport protocol of the SIP message.
if(proto==UDP)
{
log("SIP message received over UDP\n");
};
status – status code of the reply.
if(status=="200")
{
log("this is a 200 OK reply\n");
};
1.10 src_ip – source IP address
if(src_ip==127.0.0.1)
{
log("the message was sent from localhost!\n");
};
1.11 src_port – source port of the SIP message (from which port the message was sent by previous hop).
if(src_port==5061)
{
log("message sent from port 5061\n");
}
1.12 to_uri – URI from To header.
if(to_uri=~"sip:.+@opensips.org")
{
log("this is a request for opensips.org users\n");
};
1.13 uri – request URI.
if(uri=~"sip:.+@opensips.org")
{
log("this is a request for opensips.org users\n");
};
2. Core Values
Values that can be used in ‘if’ expressions to check against Core Keywords
if(msg:len&amp;amp;amp;amp;gt;max_len)
{
sl_send_reply("413", "message too large to be forwarded over UDP without fragmentation");
exit;
}
myself – reference to the list of local IP addresses, hostnames and aliases that has been set in OpenSIPS configuration file. This lists contain the domains served by OpenSIPS.
if(uri==myself) {
log("the request is for local processing\n");
};
null – reset the value of a per-script variable or to delete an avp.
$avp(i:12) = null;
$var(x) = null;
3. Core parameters
abort_on_assert – Set to true in order to make OpenSIPS shut down immediately in case a script assert fails.
abort_on_assert = true // default is false
advertised_address – address advertised in Via header and other destination lumps (e.g RR header).
advertised_port – port advertised in Via header and other destination lumps (e.g. RR).
db_max_async_connections – Maximum number of TCP connections opened from a single OpenSIPS worker to each individual SQL backend. Default value is 10. Individual backends are determined from DB URLs as follows: [ scheme, user, pass, host, port, database ]
disable_503_translation – If ‘yes’, OpenSIPS will not translate the received 503 replies into 500 replies . disable_core_dump – By default core dump limits are set to unlimited or a high enough value. Set this config variable to ‘yes’ to disable core dump-ing (will set core limits to 0).
disable_core_dump=yes //Default value is 'no'.
disable_dns_blacklist– DNS resolver, when configured with failover, can automatically store in a temporary blacklist the failed destinations. This will prevent (for a limited period of time) OpenSIPS to send requests to destination known as failed. So, the blacklist can be used as a memory for the DNS resolver.
The temporary blacklist created by DNS resolver is named “dns” and it is by default selected for usage (no need use the use_blacklist()) function. The rules from this list have a life time of 4 minutes – you can change it at compile time, from resolve.c . Can be ‘yes’ or ‘no’. By default the blacklist is disabled (Default value is ‘yes’).
disable_dns_failover – By default DNS-based failover is enabled. Set this config variable to ‘yes’ to disable the DNS-based failover. This is a global option, affecting the core and the modules also.
disable_stateless_fwd – controls the handling of stateless replies:
yes – drop stateless replies if stateless fwd functions (like forward) are not used in script
no – forward stateless replies
dns – controls if the SIP server should attempt to lookup its own domain name in DNS. Default is no.
dns_retr_time – Time in seconds before retrying a dns request. Default value is system specific, depends also on the ‘/etc/resolv.conf’ content (usually 5s).
dns_retr_no – Number of dns retransmissions before giving up.
dns_servers_no – How many dns servers from the ones defined in ‘/etc/resolv.conf’ will be used. Default value is to use all of them.
dns_try_ipv6 – If it is set to ‘yes’ and a DNS lookup fails, it will retry it for ipv6 (AAAA record). Default value is ‘no’.
dns_try_naptr – Disables the NAPTR lookups when doing DNS based routing for SIP requests – if disabled, the DNS lookup will start with SRV lookups. By default it is enabled, value ‘yes’.
dns_use_search_list
dst_blacklist – static (read-only) IP/destination blacklist. These lists can be selected from script (at runtime) to filter the outgoing requests, based on IP, protocol, port, etc.
test patter – is a filename like matching (see “man 3 fnmatch”) applied on the outgoing request buffer (first_line+hdrs+body)
enable_asserts – Set to true in order to enable the assert script statement.
event_pkg_threshold – A number representing the percentage threshold above which the E_CORE_PKG_THRESHOLD event is raised, warning about low amount of free private memory. It accepts integer values between 0 and 100. Default value is 0 ( event disabled ).
event_pkg_threshold = 90
event_shm_threshold A number representing the percentage threshold above which the E_CORE_SHM_THRESHOLD event is raised, warning about low amount of free shared memory. It accepts integer values between 0 and 100. Default value is 0 ( event disabled ).
event_shm_threshold = 90
exec_dns_threshold – A number representing the maximum number of microseconds a DNS query is expected to last. Anything above the set number will trigger a warning message to the logging facility. Default value is 0 ( logging disabled ).
exec_dns_threshold = 60000
exec_msg_threshold – A number representing the maximum number of microseconds the processing of a SIP msg is expected to last. Anything above the set number will trigger a warning message to the logging facility. Aside from the message and the processing time, the most time consuming function calls from the script will also be logged. Default value is 0 ( logging disabled ).
exec_msg_threshold = 60000
include_file – load additional routes/blocks with file path
include_file "proxy_regs.cfg"
import_file – Same as include_file but will not throw an error if file is not found.
import_file "proxy_regs.cfg"
listen – Set the network addresses the SIP server should listen to. syntax is protocol:address[:port]
The listen definition may accept several optional parameters for:
configuring an advertised IP and port only for an interface. Syntax “AS 11.22.33.44:5060”
setting a different number of children for this interface only (for UDP, SCTP and HEP_UDP interfaces only). This will override the global “children” parameter. Syntax “use_children 5”
Remember that the above parameters only affect the interface they are configured for; if they are not defined for a given interface, the global values will be used instead.
listen = udp:* listen = udp:eth1 listen = tcp:eth1:5062 listen = tls:localhost:5061 listen = hep_udp:10.10.10.10:5064 listen = ws:127.0.0.1:5060 use_children 5 listen = sctp:127.0.0.1:5060 as 99.88.44.33:5060 use_children 3 On startup, OpenSIPS reports all the interfaces that it is listening on. The TCP engine processes will be created regardless if you specify only UDP interfaces here. 3.41 log_facility – control the facility for logging in syslog. Default value is LOG_DAEMON.
log_facility=LOG_LOCAL0
3.42 log_level – logging level (how verbose OpenSIPS should be). Higher values make OpenSIPS to print more messages.
log_level=1 — print only important messages (like errors or more critical situations) recommended for running proxy as daemon
log_level=4 — print a lot of debug messages use it only when doing debugging sessions
Actual values are:
-3 – Alert level
-2 – Critical level
-1 – Error level
1 – Warning level
2 – Notice level
3 – Info level
4 – Debug level
The ‘log_level’ parameter is usually used in concordance with ‘log_stderror’ parameter.
Value of ‘log_level’ parameter can also be get and set dynamically using log_level Core MI function or $log_level script variable.
3.43 log_name – Set the id to be printed in syslog. The value must be a string and has effect only when OpenSIPS runs in daemon mode (fork=yes), after daemonize. Default value is argv[0].
log_name=”osips-5070″
3.44 log_stderror – write log messages to standard error. Possible values are: – “yes” – write the messages to standard error – “no” – write the messages to syslog , also the default
max_while_loops – maximum loops that can be done within a “while”. Comes as a protection to avoid infinite loops in config file execution. Default is 100.
max_while_loops=200
maxbuffer – size in bytes not to be exceeded during the auto-probing procedure of discovering the maximum buffer size for receiving UDP messages. Default value is 262144.
maxbuffer=65536
mem-group – Defines a group of modules (by name) to get separate memory statistics.In order for the feature to work you have to run “make generate-mem-stats” and complile with the variable SHM_EXTRA_STATS defined and complile with the variable SHM_SHOW_DEFAULT_GROUP definedwill generate the statistics for the default group
mem_warming – Only relevant when the HP_MALLOC compile flag is enabled. If set to “on”, on each startup, OpenSIPS will attempt to restore the memory fragmentation pattern it had before the stop/restart. Memory warming is useful when dealing with high volumes of traffic (thousands of cps on multi-core machines – the more cores, the more useful), because processes must mutually exclude themselves when chopping up the initial big memory chunk. By performing fragmentation on startup, OpenSIPS will also behave optimally in the first minute(s) after a restart. Fragmentation usually lasts a few seconds (e.g. ~5 seconds on an 8GB shm pool and 2.4Ghz CPU) – traffic will not be processed at all during this period.
mem_warming = on
mem_warming_percentage – How much of OpenSIPS’s memory should be fragmented with the pattern of the previous run, upon a restart.
mem_warming_percentage = 50 //Default value: 75
mem_warming_pattern_file – Default value: “CFG_DIR/mem_warming_pattern”.The memory fragmentation pattern of a previous OpenSIPS run. Used at startup, if mem_warming is enabled.
memdump | mem_dump – Log level to print memory status information (runtime and shutdown). Default: memdump=L_DBG (4)
memlog | mem_lo – Log level to print memory debug info. It has to be less than the value of ‘log_level’ parameter if you want memory info to be logged. Default: memlog=L_DBG (4)
mcast_loopback – If set to ‘yes’, multicast datagram are sent over loopback. Default value is ‘no’.
mcast_loopback=yes
mcast_ttl – Set the value for multicast ttl. Default value is OS specific (usually 1).
mhomed – Set the server to try to locate outbound interface on multihomed host. By default is not (0) – it is rather time consuming.
mhomed=1
mpath – Set the module search path. This can be used to simplify the loadmodule parameter
open_files_limit – If set and bigger than the current open file limit, OpenSIPS will try to increase its open file limit to this number. Note: OpenSIPS must be started as root to be able to increase a limit past the hard limit (which, for open files, is 1024 on most systems).
open_files_limit=2048
poll_method – (deprecated post 2.2) poll method to be used by the I/O internal reactor – by default the best one for the current OS is selected. The available types are: poll, epoll_lt, sigio_rt, select, kqueue, /dev/poll.
Starting with version 2.2, epoll_et is deprecated and if it is used in the script, it will be automatically replaced by epoll_lt.
poll_method=select
port – port the SIP server listens to. The default value for it is 5060.
reply_to_via – If it is set to 1, any local reply is sent to the address advertised in top most Via of the request. Default value is 0 (off).
reply_to_via=0
query_buffer_size -If set to a value greater than 1, inserts to DB will not be flushed one by one. Rows to be inserted will be kept in memory until until they gather up to query_buffer_size rows, and only then they will be flushed to the database.
query_buffer_size=5
query_flush_time – If query_buffer_size is set to a value greater than 1, a timer will trigger once every query_flush_time seconds, ensuring that no row will be kept for too long in memory.
query_flush_time=10
rev_dns – should the SIP server attempt to lookup its own IP address in DNS. If this parameter is set to yes and the IP address is not in DNS a warning is printed on syslog and a “received=” field is added to the via header. Default is no.
server_header – The body of Server header field generated by OpenSIPS when it sends a request as UAS. It defaults to “OpenSIPS (<version> (<arch>/<os>))”.
server_header="Server: My Company SIP Proxy"
server_signature – control “Server” header in any locally generated message. If it is enabled (default=yes) a header is generated as Server: OpenSIPS (0.9.5 (i386/linux))
shm_hash_split_percentage – Only relevant when the HP_MALLOC compile flag is enabled. It controls how many memory buckets will be optimized. (e.g. setting it to 2% will optimize the first 81 most used buckets as frequency). The default value is 1.
shm_secondary_hash_size – Only relevant when the HP_MALLOC compile flag is enabled. It represents the optimization factor of a single bucket (e.g. setting it to 4 will cause the optimized buckets to be further split into 4). The default value is 8.
sip_warning – Can be 0 or 1. If set to 1 (default value is 0) a ‘Warning’ header is added to each reply generated by OpenSIPS. The header contains several details that help troubleshooting using the network traffic dumps.
sip_warning=0
tcp_children – Number of children processes to be created for reading from TCP connections. If no value is explicitly set, the same number of TCP children as UDP children (see “children” parameter) will be used.
tcp_accept_aliases – If enabled, OpenSIPS will enforce RFC 5923 behaviour when detecting an “;alias” Via header field parameter and will reuse any TCP (or TLS, WS, WSS) connection opened for such SIP requests (source IP + Via port + proto) when sending other SIP requests backwards, towards the same (source IP + Via port + proto) pair. Default value 0 (disabled).
tcp_listen_backlog – maximum length for the queue of pending connections for the TCP listeners. Default configured value is 10.
tcp_connect_timeout – Time in milliseconds before an ongoing blocking attempt to connect will be aborted. Default value is 100ms.
tcp_connection_lifetime – Lifetime in seconds for TCP sessions. Default value is defined in tcp_conn.h: define DEFAULT_TCP_CONNECTION_LIFETIME 120.
tcp_connection_lifetime = 3600
tcp_max_connections – maximum number of tcp connections. Default is defined in tcp_conn.h: define DEFAULT_TCP_MAX_CONNECTIONS 2048
tcp_max_connections = 4096
tcp_max_msg_time – maximum number of seconds that a SIP message is expected to arrive via TCP. Default value is 4
tcp_max_msg_time = 8
tcp_no_new_conn_bflag -A branch flag to be used as marker to instruct OpenSIPS not to attempt to open a new TCP connection when delivering a request, but only to reuse an existing one (if available). If no existing conn, a generic send error will be returned.
This is intended to be used in NAT scenarios, where makes no sense to open a TCP connection towards a destination behind a NAT (like TCP connection created during registration was lost, so there is no way to contact the device until it re-REGISTER). Also this can be used to detect when a NATed registered user lost his TCP connection, so that opensips can disable his registration as useless.
tcp_no_new_conn_bflag = TCP_NO_CONNECT<br> ...<br> route {<br> ...<br> if (isflagset(DST_NATED) && $proto == "TCP")<br> setbflag(TCP_NO_CONNECT);<br> ...<br> t_relay("0x02"); // no auto error reply<br> $var(retcode) = $rc;<br> if ($var(retcode) == -6) {<br> xlog("unable to send request to destination");<br> send_reply("404", "Not Found");<br> exit;<br> } else if ($var(retcode) < 0) {<br> sl_reply_error();<br> exit;<br> }<br> }
3.77 tcp_threshold – A number representing the maximum number of microseconds sending of a TCP request is expected to last. Anything above the set number will trigger a warning message to the logging facility. Default value is 0 ( logging disabled ).
tcp_threshold = 60000
tcp_keepalive – Enable or disable TCP keepalive (OS level). Enabled by default.
tcp_keepcount -Number of keepalives to send before closing the connection (Linux only). Default value: 0 (not set). Setting tcp_keepcount to any value will enable tcp_keepalive.
tcp_keepidle – Amount of time before OpenSIPS will start to send keepalives if the connection is idle (Linux only). Default value: 0 (not set)
tcp_keepidle = 30
tcp_keepinterval – Interval between keepalive probes, if the previous one failed (Linux only).Default value: 0 (not set). Setting tcp_keepinterval to any value will enable tcp_keepalive.
tcp_keepinterval = 10
tls_ca_list
tls_certificate
tls_ciphers_list
tls_domain
tls_handshake_timeout
tls_log
tls_method
tls_port_no
tls_private_key
tls_require_certificate
tls_send_timeout
tls_verify
tos – TOS (Type Of Service) to be used for the sent IP packages (both TCP and UDP).
user_agent_header – The body of User-Agent header field generated by OpenSIPS when it sends a request as UAC. It defaults to “OpenSIPS (<version> (<arch>/<os>))”.
user_agent_header=”User-Agent: My Company SIP Proxy”
wdir – working directory used by OpenSIPS at runtime.
wdir="/usr/local/opensips"
xlog_buf_size – Default value: 4096
Size of the buffer used to print a single line on the chosen logging facility of OpenSIPS. If the buffer is too small, an overflow error will be printed, and the concerned line will be skipped.
xlog_buf_size = 8388608 #given in bytes
xlog_force_color
xlog_default_level -Default value for the logging level of the xlog core function, when the log_level parameter is omitted.
OpenSIPS routing logic uses several types of routes. Each type of route is triggered by a certain event and allows you to process a certain type of message (request or reply).
route SIP requests routing. The main ‘route’ block identified by ‘route{…}’ or ‘route[0]{…}’ is executed for each SIP request. To send a reply or forward the request, explicit actions must be called inside the route block. in example below which sends 200 ok reply for each options request.
branch_route Handles different branches of a SIP request. if the branch is not dropped the branch will be automatically sent out. It is executed only by TM module after it was armed via t_on_branch(“branch_route_index”).
if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
}
branch_route[MANAGE_BRANCH] {
xdbg("new branch [$T_branch_idx] to $ru\n");
route(NATMANAGE);
}
or lookup location and discard branches where uri matches ip 1.2.3.4 by using drop()
failure_route Failed transaction routing block. It contains a set of actions to be taken each transaction that received only negative replies (>=300) for all branches which completes the transaction. The ‘failure_route’ is executed only by TM module after it was armed via t_on_failure(“failure_route_index”).
if (is_method("INVITE")) {
if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
}
failure_route[MANAGE_FAILURE] {
route(NATMANAGE);
if (t_is_canceled()) {
exit;
}
}
onreply_route Reply routing block. It can be stateful (if bound to a transaction) or stateless (if global reply route). If the reply is not dropped (only provisional replies can be), it will be injected and processed by the transaction engine. There are three types of onreply routes:
global – catches all replies and uses simple definition ‘onreply_route {…}’ or ‘onreply_route[0] {…}’.
Exmaple for “global” reply route set the whole transaction
route {
seturi("sip:bob@opensips.org"); first branch
append_branch("sip:alice@opensips.org"); second branch
t_on_reply("global");
t_on_branch("1");
t_relay();
}
onreply_route {
xlog("OpenSIPS received a reply from $si\n");
}
onreply_route[global] {
if (t_check_status("1[0-9][0-9]")) {
setflag(1);
log("provisional reply received\n");
if (t_check_status("183"))
drop;
}
}
per request/transaction – it catches all received replies belonging to a certain transaction and uses “t_on_reply()” at request time, in REQUEST ROUTE – named ‘onreply_route[N] {…}’.
per branch – it catches only the replies that belong to a certain branch from a transaction via “t_on_reply()” ) at request time, but in BRANCH ROUTE, when a certain outgoing branch is processed – named ‘onreply_route[N] {…}’.
Certain ‘onreply_route’ blocks can be executed by TM module for special replies. For this, the ‘onreply_route’ must be armed for the SIP requests whose replies should be processed within it, via t_on_reply(“onreply_route_index”).
Exmaple of reply route set for this branch only
branch_route[1] {
if ($rU=="alice")
t_on_reply("alice");
}
onreply_route[alice] {
xlog("received reply on the branch from alice\n");
}
error_route
executed automatically on meeting and error such as parsing error in SIP request processing, script assert failure. Performs error handling . The Default action is to discard request. In error_route, the following pseudo-variables are available to get access to error details:
$(err.class) - the class of error (now is '1' for parsing errors)
$(err.level) - severity level for the error
$(err.info) - text describing the error
$(err.rcode) - recommended reply code
$(err.rreason) - recommended reply reason phrase
error_route {
xlog("--- error route class=$(err.class) level=$(err.level)
info=$(err.info) rcode=$(err.rcode) rreason=$(err.rreason) ---\n");
xlog("--- error from [$si:$sp]\n+++++\n$mb\n++++\n");
sl_send_reply("$err.rcode", "$err.rreason");
exit;
}
local_route
executed automatically as TM created a new request, internally (no UAC side). This is a route intended to be used for message inspection, accounting and for applying last changes on the message headers. Routing and signaling functions are not allowed.
startup_route Executed only once when OpenSIPS is started and before the processing of SIP messages begins. Used in initilization cases cases such as loading some data in the cache.
startup_route {
avp_db_query("select gwlist where ruleid==1",$avp(i:100));
cache_store("local", "rule1", "$avp(i:100)");
}
timer_route Route executed periodically at a configured interval of time specified next to the name(in seconds).
timer_route[gw_update, 300] {
avp_db_query("select gwlist where ruleid==1",$avp(i:100));
$shv(i:100) =$avp(i:100);
}
event_route execute script code when an event is triggered. If no way to handle the event specified, default will be synchronously. Triggered by the event_route module when an event is raised by the OpenSIPS Event Interface such as event raised by the pike module when it decides an ip should be blocked called E_PIKE_BLOCKED or E_SCRIPT_EVENT etc ( checke events interface for more events)
event_route[E_PIKE_BLOCKED] {
xlog("The E_PIKE_BLOCKED event was raised\n");
}
event_route[E_PIKE_BLOCKED, async] {
xlog("The E_PIKE_BLOCKED event was raised\n");
}
opensipsctlrc
opensipsctlrc file controls the opensipsctl and osipsconsole utilities. It is a shell script utility to manage opensips from command line
opensipsctl can manage
Start, stop, and restart
Show, grant, and revoke ACLs Add, remove, and list aliases
Add, remove, and configure an AVP
Low Cost Route (LCR)
Remote Party Identity (RPID)
Add, remove, and list subscribers
Add, remove, and show the usrloc table in-Random Access Memory (RAM)
Kamailio uses a native scripting laguage for its configuration file kamailio.cfg . This components of this file are :
global parameters
loading modules
module parameters
routing blocks like request_route {…}, reply_route {…}, branch_route {…} etc
These parameters including initialization event routes , are interpeted and loaded at kamailio startup.
We know that restart of sip server hinder all ongoing traffic and slows development of routing logic.
Due to limitation of customizatiosn with native language and mostly due to the fact that interpreter precompiles kamailio.cfg at startup preventing routing script to reload without restart , other programming languages were used such as Kamailio Embedded Interface (KEMI) framework.
Post v5 of kamailio , the interpreters of these languages were integrated with kamailio and feature rich SIP routing logic could be written with them for runtime execution. The routing blocks are in form of functions written in a KEMI ( Kamaialio EMbedded Interface) supported scripting language such as Lua as discussed in this article. Other components are still initialised by kamailio.cfg at starup. Apart from above mentioned advantages of programming languages , another plus point is that it enables test-cases , debug functionality without having to restart the server for code update.
KEMI supported programming languages:
JavaScript (app_jsdt)
Lua (app_lua)
Python (app_python)
Python3 (app_python3)
Squirrel (app_sqlang)
Kamailio has other modules that allow inline execution of scripts written in other programming languages, but don’t implement the KEMI yet. Such as Perl (app_perl) .Net (C#, etc.) (app_mono), Java (app_java)
As Kamailio becomes the interpreter for these languages , it executes logic faster at runtime . KEMI also extends the modules with extension to kamailio c functions
Lua KEMI Interpreter
Lua interpreter is linked from liblua library in app_lua module.
ksr_request_route() : executed by Kamailio core every time a SIP request is received, equivalent of request_route {} from kamailio.cfg
ksr_reply_route() : executed by Kamailio core every time a SIP Response (reply) is received, equivalent of reply_route {} from kamailio.cfg
ksr_onsend_route() : executed when a SIP request (and optionally for a response) is sent out, equivalent of onsend_route {}
branch route callback : name of the Lua function to be executed instead of a branch route has to be provided as parameter to KSR.tm.t_on_branch(…)
onreply route callback : name of the Lua function to be executed instead of an onreply route has to be provided as parameter to KSR.tm.t_on_reply(…)
failure route callback : name of the Lua function to be executed instead of a failure route has to be provided as parameter to KSR.tm.t_on_failure(…)
branch failure route callback : name of the Lua function to be executed instead of an event route for branch failure has to be provided as parameter to KSR.tm.t_on_branch_failure(…)
event route callback : name of the Lua function to be exectued instead of module specific event_route blocks is provided via event_callback parameter of that module
KSR is the new dynamic object exporting Kamailio functions. sr is the old static object exporting Kamailio functions
route.lua for routing logic
function ksr_request_route()
KSR.info("===== request - from kamailio lua script\n");
if KSR.maxfwd.process_maxfwd(10) < 0 then
KSR.sl.send_reply(483, "Too Many Hops");
return;
end
//KSR.sl.sreply(200, "OK Lua");
KSR.pv.sets("$du", "sip:127.0.0.1:5080")
KSR.tm.t_on_branch("ksr_branch_route_one");
KSR.tm.t_on_reply("ksr_onreply_route_one");
KSR.tm.t_on_failure("ksr_failure_route_one");
if KSR.tm.t_relay() < 0 then
KSR.sl.send_reply(500, "Server error")
end
end
function ksr_reply_route()
KSR.info("===== response - from kamailio lua script\n");
end
function ksr_branch_route_one()
KSR.info("===== branch route - from kamailio lua script\n");
end
function ksr_onreply_route_one()
KSR.info("===== onreply route - from kamailio lua script\n");
end
function ksr_failure_route_one()
KSR.info("===== failure route - from kamailio lua script\n");
end
Core Kemi functions
KSR.add_local_rport() : Set the internal flag to add rport parameter to local generated Via header.
KSR.add_tcp_alias() : Adds a tcp port alias for the current connection (if tcp). Can help in firewall or nat traversal
KSR.add_tcp_alias_via() : Adds the port from the message via as an alias to TCP connection.
void KSR.dbg(…) : debug log
KSR.dbg("debug log message from embedded interpreter\n");
void KSR.err(…) : error logging
KSR.err("error log message from embedded interpreter\n");
void KSR.info(…) : info log
KSR.info("info log message from embedded interpreter\n");
KSR.force_rport() : Add rport parameter to the top Via of the incoming request and sent the SIP response to source port.
KSR.is_method() : Return true if the value of the parameter matches the method type of the SIP message.
if(KSR.is_method("INVITE")) {
...
}
KSR.is_method_in() ; Return true if SIP method of the currently processed message is matching one of the corresponding characters given as parameter. Matching the method is done based on corresponding characters:
I – INVITE
A – ACK
B – BYE
C – CANCEL
R – REGISTER
M – MESSAGE
O – OPTIONS
S – SUBSCRIBE
P – PUBLISH
N – NOTIFY
U – UPDATE
K – KDMQ
G – GET
T – POST
V – PUT
D – DELETE
if KSR.is_method_in("IABC") then
-- the method is INVITE, ACK, BYE or CANCEL
...
end
KSR.is_INVITE() : Return true if the method type of the SIP message is INVITE.
KSR.is_ACK() : true if the method type is ACK.
KSR.is_BYE() : true if the method type is BYE.
KSR.is_CANCEL() : true if CANCEL.
KSR.is_REGISTER() : true if REGISTER.
KSR.is_MESSAGE() : true if SIP message is MESSAGE.
KSR.is_SUBSCRIBE() : true if SIP message is SUBSCRIBE.
KSR.is_PUBLISH() : true if PUBLISH.
KSR.is_NOTIFY() : true if NOTIFY.
KSR.is_OPTIONS() : true if OPTIONS.
KSR.is_INFO() : true if INFO.
KSR.is_UPDATE() : true if UPDATE.
KSR.is_PRACK() : true if PRACK.
KSR.is_myself(…) : Return true of the URI address provided as parameter matches a local socket (IP) or local domain.
if KSR.is_myself("sip:127.0.0.1:5060") then
...
end
KSR.is_myself_furi() : Return true if the URI in From header matches a local socket (IP) or local domain.
KSR.is_myself_ruri() : Return true if the R-URI matches a local socket (IP) or local domain.
KSR.is_myself_turi() : Return true if the URI in To header matches a local socket (IP) or local domain.
KSR.is_myself_suri() : true if the URI built from source IP, source port and protocol matches a local socket (IP).
KSR.is_myself_suri() : true if the source IP matches a local socket (IP).
void KSR.log(…) : Write a log message specifying the level value. The level parameter can be: “dbg” , “info” , “warn” , “crit” , “err”
KSR.setflag(…) : Set the SIP message/transaction flag ( int from 0 to 31 ) at the index provided by the parameter.
KSR.resetflag(…) : Reset the SIP message/transaction flag ( int from 0 to 31 ) at the index provided by the parameter.
KSR.isflagset(…) :Return true if the message/transaction flag at the index provided by the parameter is set (the bit has value 1).
KSR.setbflag(…) : Set the branch flag(0-31) at the index provided by the parameter.
KSR.resetbflag(…) : Reset the branch flag(0-31) at the index provided by the parameter.
KSR.isbflagset(…) : Return true if the branch flag at the index provided by the parameter is set (the bit has value 1).
KSR.setbiflag(…) : Set the flag at the index provided by the first parameter to the branch number specified by the second parameter. The flag parameter has to be a number from 0 to 31. The branch parameter should be between 0 and 12 (a matter of max_branches global parameter).
KSR.resetbiflag(…) : Reset a branch flag by position and branch index.
KSR.isbiflagset(…) : Test if a branch flag is set by position and branch index.
KSR.setsflag(…) : Set a script flag.
KSR.resetsflag(…) : Reset a script flag.
KSR.issflagset(…) : Test if a script flag is set.
KSR.seturi(…) : Set the request URI (R-URI).
KSR.seturi("sip:alice@voip.com");
KSR.setuser(…)
KSR.setuser("alice");
KSR.sethost(…)
KSR.sethost("voip.com");
KSR.setdsturi(…)
KSR.setdsturi("sip:voip.com:5061;transport=tls");
KSR.resetdsturi(…) : Reset the destination URI (aka: outbound proxy address, dst_uri, $du).
KSR.isdsturiset(…) : Test if destination URI is set.
KSR.force_rport(…) : Set the flag for “rport” handling (send the reply based on source address instead of Via header).
KSR.set_drop(…) : Set the DROP flag, so at the end of KEMI script execution, the SIP request branch or the SIP response is not forwarded.
KSR.set_advertised_address() : Set the address (host or ip) to be advertised in Via header.
KSR.set_advertised_port() : Set the port (in string format) to be advertised in Via header.
KSR.set_forward_close(…) : Set the flag to close the connection after forwarding the message.
KSR.set_forward_no_connect(…) : Set the flag to not open a connection if the connection to the target does not exist when attempting to forward a message.
KSR.set_reply_close(…) : Set the flag to close the connection after sending a response.
KSR.set_reply_no_connect(…) : Set the flag to not open a connection if the connection for sending the response does not exist.
KSR.forward(…) : Forward the SIP request in stateless mode to the address set in destination URI ($du), or, if this is not set, to the address in request URI ($ru).
KSR.forward_uri(…) : Forward the SIP request in stateless mode to the address provided in the SIP URI parameter.
KSR.pv submodule provides the functions to get, set and test the values of pseduo-variables.
The pvname that appears in the next sections in the function prototypes has to be a valid pseudo-variable name for Kamailio native configuration file (for example $ru, $var(x), $shv(z), …).
KSR.pv.get(…) : Return the value of pseudo-variable pvname. The returned value can be string or integer.
KSR.dbg("ruri is: " + KSR.pv.get("$ru") + "\n");
KSR.pv.gete(…) : Return the value of pseudo-variable pvname if it is different than $null or the empty string (“”) if the variable is having the $null value.
KSR.dbg("avp is: " + KSR.pv.gete("$avp(x)") + "\n");
KSR.pv.getvn(…) : Return the value of pseudo-variable pvname if it is different than $null or the parameter vn if the variable is having the $null value.
KSR.dbg("avp is: " + KSR.pv.getvn("$avp(x)", 0) + "\n");
KSR.pv.getvs(…) : Return the value of pseudo-variable pvname if it is different than $null or the parameter vs if the variable is having the $null value.
KSR.dbg("avp is: " + KSR.pv.getvs("$avp(x)", "foo") + "\n");
KSR.pv.getw(…) : Return the value of pseudo-variable pvname if it is different than $null or the string <> if the variable is having the $null value. This should be used instead of KSR.pv.get(…) in the scripting languages that throw and error when attempting to print a NULL (or NIL) value.
KSR.dbg("avp is: " + KSR.pv.getw("$avp(x)") + "\n");
KSR.pv.seti(…) : set the value of pseudo-variable pvname to integer value provided by parameter val.
KSR.pv.seti("$var(x)", 10);
KSR.pv.sets(…) : set the value of pseudo-variable pvname to string value provided by parameter val.
KSR.pv.sets("$var(x)", "kamailio");
KSR.pv.unset(…) : Set the value of pseudo-variable pvname to $null.
KSR.pv.unset("$avp(x)");
KSR.pv.is_null(…) : Return true if pseudo-variable pvname is $null.
if(KSR.pv.is_null("$avp(x)")) {
...
}
KSR.x.modf(…) : Execute a function (specified by fname) exported by a Kamailio module.
KSR.x.modf("sl_send_reply", "200", "OK");
KSR.x.exit(…) : stop the execution of the SIP routing script.
KSR.x.drop(…) : stop the execution of the SIP routing script and drop routing further the SIP request branch or response.
RTPengine is a proxy for RTP traffic and other UDP based media traffic over either IPv4 or IPv6. It can even bridge between diff IP networks and interfaces. It can do TOS/QoS field setting. It is Multi-threaded, can advertise different addresses for operation behind NAT.
This article focuses on setting up sipwise rtpegine to proxy RTP traffic from the Kamailio app server. This is an updated version of the old article on RTPEngine, since then there have many many updates on the software. I also wrote an article covering all relevant and important Kamailio modules earlier including RTPProxy and RTP engine https://telecom.altanai.com/2014/11/18/kamailio-modules/
It bears in-kernel packet forwarding for low-latency and low-CPU performance. When used with the Kamailio, the RTP engine module adds more features to media stream routing and management, especially around RTP proxy and Mos scores.
There are 3 parts of the source structure in sipwise NGCP ( Next Generation communication Platform) rtpengine :
1.daemon
The userspace daemon and workhorse, minimum requirement for anything to work. Running make will compile the binary, which will be called rtpengine.
Required packages including their development headers are required to compile the daemon:
pkg-config
GLib including GThread and GLib-JSON version 2.x
zlib
OpenSSL
PCRE library
XMLRPC-C version 1.16.08 or higher
hiredis library
gperf
libcurl version 3.x or 4.x
libevent version 2.x
libpcap
libsystemd
MySQL or MariaDB client library (optional for media playback and call recording daemon)
libiptc library for iptables management (optional)
ffmpeg codec libraries for transcoding (optional) such as libavcodec, libavfilter, libswresample
bcg729 for full G.729 transcoding support (optional)
options for make – with_iptables_option , with_transcoding
with_transcoding=no make
2.iptables-extension
Required for in-kernel packet forwarding. With the iptables development headers installed, issuing make will compile the plugin for iptables and ip6tables. The file will be called libxt_RTPENGINE.so and needs to be copied into the xtables module directory. The location of this directory can be determined through pkg-config xtables –variable=xtlibdir on newer systems, and/or is usually either /lib/xtables/ or /usr/lib/x86_64-linux-gnu/xtables/.
3.kernel-module
Required for in-kernel packet forwarding. Compilation of the kernel module requires the kernel development headers to be installed in/lib/modules/$VERSION/build/, where $VERSION is the output of the command uname -r.
Successful compilation of the module will produce the file xt_RTPENGINE.ko. The module can be inserted into the running kernel manually through insmod xt_RTPENGINE.ko
It is recommended to copy the module into /lib/modules/$VERSION/updates/, followed by running depmod -a.
After this, the module can be loaded by issuing modprobe xt_RTPENGINE.
vi debian/control
change from default-libmysqlclient-dev to libmysqlclient-dev, change from libiptcdata-dev to libiptc-dev and install the alternatives such as
apt install libmysqlclient-dev libiptcdata-dev
Generated deb files should be outside the rtpegine home folder
To avoid the overhead involved in processing each individual RTP packet in userspace-only operation, especially as RTP traffic consists of many small packets at high rates, rtpengine provides a kernel module to offload the bulk of the packet forwarding duties from user space to kernel space. This also results in increasing the number of concurrent calls as CPU usage decreases.In-kernel packet forwarding is implemented as an iptables module (x_tables) and has 2 parts – xt_RTPENGINE and plugin to the iptables and ip6tables command-line utilities
Sequence of events for a newly established media stream is then:
Kamailio as SIP proxy controls rtpengine and signals it about a newly established call.
Rtpengine daemon allocates local UDP ports and sets up preliminary forward rules based on the info received from the SIP proxy.
An RTP packet is received on the local port.
It traverses the iptables chains and gets passed to the xt_RTPENGINE module.
The module doesn’t recognize it as belonging to an established stream and thus ignores it.
The packet continues normal processing and eventually ends up in the daemon’s receive queue.
The daemon reads it, processes it and forwards it. It also updates some internal data.
This userspace-only processing and forwarding continues for a little while, during which time information about additional streams and/or endpoints may be obtained from the SIP proxy.
After a few seconds, when the daemon is satisfied with what it has learned about the media endpoints, it pushes the forwarding rules to the kernel.
From this moment on, the kernel module will recognize incoming packets belonging to those streams and will forward them on its own. It will stop those packets from traversing the network stacks any further, so the daemon will not see them any more on its receive queues.
In-kernel forwarding is allowed to cease to work at any given time, either accidentally (e.g. by removal of the iptablesrule) or deliberatly (the daemon will do so in case of a re-invite), in which case forwarding falls back to userspace-only operation.
Kernel Module
The kernel module supports multiple forwarding tables, identified through their ID number, bydefault 0 to 63. Each running instance of the rtpengine daemon controls one such table.
To load use modprobe xt_RTPENGINE and to unload rmmod xt_RTPENGINE. With the module loaded, a new directory will appear in /proc/, namely /proc/rtpengine/, containing pseudo-files, control ( to create and delete forwarding tables) and list ( list of currently active forwarding tables)
To manually create a forwarding table with ID 33, the following command can be used:
echo 'add 43' > /proc/rtpengine/control
iptables module
In order for the kernel module to be able to actually forward packets, an iptables rule must be set up to send packets into the module. Each such rule is associated with one forwarding table. In the simplest case, for forwarding table 33, this can be done through:
iptables -I INPUT -p udp -j RTPENGINE --id 33
To restrict the rules to the UDP port range used by rtpengine, e.g. by supplying a parameter like –dport 30000:40000. If the kernel module receives a packet that it doesn’t recognize as belonging to an active media stream, it will simply ignore it and hand it back to the network stack for normal processing.
A typical start-up sequence including in-kernel forwarding might look like this:
To run multiple instances of rtpengine on the same machine run multiple instances of the daemon using different command-line options ( local addresses and listening ports), together with multiple different kernel forwarding tables.
For example, if one local network interface has address 10.64.73.31 and another has address 192.168.65.73, then the start-up sequence might look like this:
With this setup, the SIP proxy can choose which instance of rtpengine to talk to and thus which local interface to use by sending its control messages to either port 2223 or port 2224.
Currently transcoding is supported for audio streams. Can be turned off with with_transcoding=no option in makeFile.
Normally rtpengine leaves codec negotiation up to the clients involved in the call and does not interfere. In this case, if the clients fail to agree on a codec, the call will fail.
Transcoding options in the ng control protocol, transcode or ptime. If a codec is requested via the transcode option that was not originally offered, transcoding will be engaged for that call. With transcoding active for a call, all unsupported codecs will be removed from the SDP.
Transcoding happens in userspace only, so in-kernel packet forwarding will not be available for transcoded codecs. Codecs that are supported by both sides will simply be passed through transparently (unless repacketization is active). In-kernel packet forwarding will still be available for these codecs.
Codecs supported by rtpengine can be shown with –codecs options
rtpengine –codecs
PCMA: fully supported
PCMU: fully supported
G723: fully supported
G722: fully supported
QCELP: supported for decoding only
G729: supported for decoding only
speex: fully supported
GSM: fully supported
iLBC: not supported
opus: fully supported
vorbis: codec supported but lacks RTP definition
ac3: codec supported but lacks RTP definition
eac3: codec supported but lacks RTP definition
ATRAC3: supported for decoding only
ATRAC-X: supported for decoding only
AMR: supported for decoding only
AMR-WB: supported for decoding only
PCM-S16LE: codec supported but lacks RTP definition
PCM-U8: codec supported but lacks RTP definition
MP3: codec supported but lacks RTP definition
ng Control Protocol
Advanced control protocol to pass SDP body from the SIP proxy to the rtpengine daemon, has the body rewritten in the daemon, and then pas back to the SIP proxy to embed into the SIP message. It is based on the bencode standard and runs over UDP transport.
Each message passed between the SIP proxy and the media proxy contains of two parts:
message cookie ( to match requests to responses, and retransmission detection) and
bencoded dictionary
The dictionary of each request must contain at least one key called command and corresponding value must be a string and determines the type of message. Currently the following commands are defined:
ping
offer
answer
delete
query
start recording
stop recording
block DTMF
unblock DTMF
block media
unblock media
start forwarding
stop forwarding
play media
stop media
The response dictionary must contain at least one key called result. The value can be either ok (optional key warning) or error( to be accompanied by error-reason). For the ping command, the additional value pong is allowed.
Security is Critical for a VoIP platform as it is susceptible to hacks , misuse , eavesdropping or just sheer misuse of the system by making robotic flood calls . Kamailio SIP Server provides some key features to meet these challenges which will be discussed in this blog .
Sanity checks for incoming SIP requests
Being a gateway on the VOIP system permiter is a challenging task due to the security threast it posses. It is must to configure per request initial checks for all incoming SIP request. This ideally should be the first step in routing clock before any other processing.
request_route {
route(REQINIT);
...
// proceed with routing
}
Pointers for functionality
For replies coming from local users , usually behind NAT , do not open a new TCP connection on each reply
set_reply_no_connect();
For indialog requests also close connection after forwarding the request.
if(has_totag()) {
set_forward_no_connect();
}
Check if any IP is flooding the server with messages and block for some time ( ANTI-FLOOD and pike decsribed later in the article ).
Ofcourse exclude self IP . sample to do blocking using hastable’s psedi variable ipban
Friendly-scanners are type of botnets probing and scanning known IP ranges(5060,5061..) for SIP server, softswitches, cloud PBX. Once they detect a suitably open server they use brute force tactic to send all commonly/default username/passwords accounts. The prime purpose is to extract all vulenrable accounts for creating fradulent calls such as crating DOS attacks using high tarffic and consuming all bandwidth from good calls, free internation calls or imposter/scam calls.
Among some obvious ways to block the flood of packets by these scanner are
imply strict firewalls rules for allowing only known client IP’s
changing default SIP port from 5060 to some other non standard port in network
checking User agent for known attackes such as (sipcli , sipvicious , sip-scan , sipsak , sundayddr , friendly-scanner , iWar , CSipSimple , SIVuS , Gulp , sipv , smap , friendly-request , VaxIPUserAgent , VaxSIPUserAgent , siparmyknife , Test Agent)
track unsuccesfull quick/consecutive attempts from an IP and block its access temporatliy or permamntly. Such as failing to REGISTER / autehticate for 3 consecutive time should block it .
Track if the message is hopping too many times within the server server , intra or inter networks not reaching the destination . mf_process_maxfwd_header(maxvalue). Note maxvalue is added is no Max-Forward header is found in the message.
mf_process_maxfwd_header(10)
Sanity is a complete module by itself to perform various checks and validation such as
ruri sip version – (1) – checks if the SIP version in the request URI is supported, currently only 2.0
ruri scheme – (2) – checks if the URI scheme of the request URI is supported (sip[s]|tel[s])
required headers – (4) -checks if the minimum set of required headers to, from, cseq, callid and via is present in the request
via sip version – (8) – disabled
via protocol – (16) – disabled
Cseq method – (32) – checks if the method from the Cseq header is equal to the request method
Cseq value – (64) – checks if the number in the Cseq header is a valid unsigned integer
content length – (128) – checks if the size of the body matches with the value from the content length header
expires value – (256) – checks if the value of the expires header is a valid unsigned integer
proxy require – (512) – checks if all items of the proxy require header are present in the list of the extensions from the module parameter proxy_require.
parse uri’s – (1024) – checks if the specified URIs are present and parseable by the Kamailio parsers
digest credentials (2048) – Check all instances of digest credentials in a message
duplicated To/From tags (4096) – checks for the presence of duplicated tags in To/From headers.
authorization header (8192) – checks if the Authorization is valid if the scheme in “digest” always returns success for other schemes.
sample for URI checks for list of parsed URIs: Request URI (1), From URI (2) and To URI (4).
if (allow_routing("rules.allow", "rules.deny")) {
t_relay();
};
Registration permissions
if (method=="REGISTER") {
if (allow_register("register")) {
save("location");
exit;
} else {
sl_send_reply("403", "Forbidden");
};
};
URI permissions
if (allow_uri("basename", "$rt")) { // Check Refer-To URI
t_relay();
};
Address permissions
// check if sourec ip/port is in group 1
if (!allow_address("1", "$si", "$sp")) {
sl_send_reply("403", "Forbidden");
};
Trusted Requests
if (allow_trusted("$si", "$proto")) {
t_relay();
};
checks protocols which could be one of the “any”, “udp, “tcp”, “tls”, “ws”, “wss” and “sctp”.
Hiding Topology Details
Stripping the SIP routing headers that show topology details involves steps such as hiding the local IP address of user agent , hiding path taken to reach the server , obscuring the core SIP server’s ip and details etc . Some headers which giave away information are
top most Via header
contact address
Record-Route headers
sometimes the Call-ID header
This goes a long way in helping to keep the inner network topology secure from malacious exploiters, expecially to protect IP of the PSTN gateways which could let to an costly mess or gensrally from attackers and reverse engineering.
Topoh module hides the network topology by removing the internal IP addresa and instead add ing them in encrypted form the same sip packet. Diff server using the same shared secret key can encode decode the encrypted addresses.
This way it doesnt not even have to store the state of the call and is transpoarent to all call routing logic
Primarily it does these things hide the addresses of PSTN gateways protect your internal network topology interconnection provider – to keep the details of connected parties secret to the other, to prevent a bypass of its service in the future
Primarily tis module uses mask key to code the trimmed via header information and insert them into pre specified param names with prefixes. Hence it can work with stageful or stateless proxy and can also work if server is restarted in between
topos module
Offers topology hiding by stripping the SIP routing headers that show topology details.
It requires 2 modules rr module since server must perform record routing to ensure in-dialog requests are encoded/decoded and database module to store the data for topology stripping and restoring.
Params : storage (str) – could be redis or database backend
mask_callid (int) – Whether to replace or not the Call-ID with another unique id generated by Kamailio. ( present with topoh) sanity_checks (int) – with sanity module to perform checks before encoding /decoding branch_expire (int) dialog_expire (int) clean_interval (int) event_callback (str) – callback event
modparam("topos", "event_callback", "ksr_topos_event")
..
function ksr_topos_event(evname)
KSR.info("===== topos module triggered event: " .. evname .. "\n");
return 1;
end
event route : event_route[topos:msg-outgoing]
loadmodule "topos.so"
loadmodule "topos_redis.so"
//topos params
modparam("topos", "storage", "redis")
//branch_expire is 10 min
modparam("topos", "branch_expire", 10800)
// dialog_expire is 1 day
modparam("topos", "dialog_expire", 10800)
modparam("topos", "sanity_checks", 1)
FireWall
To save from the automatic port scans that attackers carry out to hack into the system use the script below
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
:CHECK_TCP - [0:0]
:ICMP - [0:0]
:PRIVATE - [0:0]
:PSD - [0:0]
:SERVICES - [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth0 -p ipv6 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j SERVICES
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A CHECK_TCP -p tcp -m tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags FIN,ACK FIN -m state --state INVALID,NEW,RELATED -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags FIN,RST FIN,RST -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags PSH,ACK PSH -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags ACK,URG URG -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-option 64 -j DROP
-A CHECK_TCP -p tcp -m tcp --tcp-option 128 -j DROP
-A ICMP -p icmp -m icmp --icmp-type 11/1 -m limit --limit 5/sec -m state --state NEW -j ACCEPT
-A ICMP -p icmp -m icmp --icmp-type 11/0 -m limit --limit 5/sec -m state --state NEW -j ACCEPT
-A ICMP -p icmp -m icmp --icmp-type 3 -m limit --limit 10/sec -m state --state NEW -j ACCEPT
-A ICMP -p icmp -m icmp --icmp-type 8 -m limit --limit 10/sec --limit-burst 10 -m state --state NEW -j ACCEPT
-A ICMP -p icmp -j DROP
-A PRIVATE -d 192.168.0.0/16 -j DROP
-A PRIVATE -d 172.16.0.0/12 -j DROP
-A PRIVATE -d 10.0.0.0/8 -j DROP
-A PRIVATE -j RETURN
-A PSD -p tcp -m statistic --mode random --probability 0.050000 -j REJECT --reject-with icmp-port-unreachable
-A PSD -p tcp -m statistic --mode random --probability 0.050000 -j TARPIT --reset
-A PSD -p tcp -m statistic --mode random --probability 0.500000 -j TARPIT --tarpit
-A PSD -p udp -m statistic --mode random --probability 0.050000 -j REJECT --reject-with icmp-port-unreachable
-A PSD -m statistic --mode random --probability 0.050000 -j REJECT --reject-with icmp-host-unreachable
-A SERVICES -p icmp -m state --state INVALID -j DROP
-A SERVICES -p icmp -j ICMP
-A SERVICES -p tcp -j CHECK_TCP
-A SERVICES -p udp -m udp --dport 123 -m state --state NEW -j ACCEPT
-A SERVICES -p udp -m udp --dport 53 -m state --state NEW -j ACCEPT
-A SERVICES -p tcp -m tcp --dport 53 -m state --state NEW -j ACCEPT
-A SERVICES -p tcp -m udp -m multiport --dports 5060 -m state --state NEW -j ACCEPT
-A SERVICES -p tcp -m udp -m multiport --dports 5061 -m state --state NEW -j ACCEPT
-A SERVICES -i eth0 -j PSD
COMMIT
Update/Remove Server and User Agent Headers
Rewrite server header to save the exact version of server from hackers
server_header="Server: Simple Server"
or completely rmemove it from traces
server_signature=no
and
user_agent_header="User-Agent: My SIP Server"
Remove Server warnings from traces and log file
Warnings expose the vulnerabilities of system and it is best to remove them in production enviornment
user_agent_header="User-Agent: My SIP Server"
Anti Flood
During Auth or logging there is a fair chance of leaking credentials or the fact that users opt for weak password themselves compromising the system via bruteforcing username/password . Or attacker may be bruteforcing prefixes to understand config and routing logic Random unnecessary flood of SIP requests can consume CPU and make it slow or unavailable for others as Denial of Service . These situations can be made less daunting via pike module
pike modules
tracks the number of SIP messages per source IP address, per period.
SIPp UAC / UAS on TLS to generate traffic to check secruity of Kamailio SIP server
sipp is a powerful traffic generate for SIP applications and is widely used to test call flow routing applications in white box envrionmenet as well as stress or load testing. Read more about sipp https://telecom.altanai.com/2018/02/01/sipp/
OpenSIP provided dispatcher modules which computes hashes over parts of the request and selects an address from a destination set which is then as outbound proxy.
Tthe algorithm used to select the destination address. “0” – hash over callid “1” – hash over from uri. “2” – hash over to uri. “3” – hash over request-uri. “4” – round-robin (next destination). “5” – hash over authorization-username (Proxy-Authorization or “normal” authorization). If no username is found, round robin is used. “6” – random (using rand()). “7” – hash over the content of PVs string. Note: This works only when the parameter hash_pvar is set. “X” – if the algorithm is not implemented, the first entry in set is chosen.
and the state of the destination address can be
“a”: active “i”: inactive “p”: probing
Load Balancer
Opensip can function as load balancer , distributing the load between different SIP Application servers .
example of gateway sets file in dbtext/diapatcher.list
id(int,auto) setid(int) destination(string) socket(string,null) state(int) weight(int) priority(int) attrs(string) description(string)
1:1:sip\:10.20.30.40\:5060:null:0:1:1:'carrier':'load balancer for OB'
2:2:sip\:10.50.60.70\:5060:null:0:1:1:'carrier':'Load balancer for IB'
Health Monitoring
Probing and pinging features in Opensips can detect whether gateways are responding or not . Threshold and probing mode can fine tune the behaviour.
dbtext is an implementation for a simplified database engine based on text files. It can be used by OpenSIPS DB interface instead of other database module (like MySQL). It keeps everything in memory.
The db_text database system architecture contains
a database is represented by a directory in the local file system. NOTE: when you use db_text in OpenSIPS, the database URL for modules must be the path to the directory where the table-files are located, prefixed by “text://”,
e.g., “text:///var/dbtext/opensips”.
a table is represented by a text file inside database directory.
This database interface don’t support the data insertion with default values. All such values specified in the database
template are ignored.
db_mode (integer)
Set caching mode (0 – default) or non-caching mode (1). In caching mode, data is loaded at startup. In non-caching mode, the module check every time a table is requested whether the correspondingfile on disk has changed, and if yes, will re-load table from file.
Set db_mode parameter
…
modparam(“db_text”, “db_mode”, 1)
…
A typical voice core network consists of a B2BUA SIP server with media proxy and media processing units/servers along with components for billing, user profile management, shared memory/ cache, transcoders, call routing logic etc. However, a VOIP provider would not want to interface these critical servers to the outside world directly. An SBC ( Session Border Controller ) helps to abstract the core VoIP platform from public access and traffic.
The role of an SBC is to shield the core network from external entities such as user agent’s, carrier networks (topology hiding) while also providing security, auth and accounting services. In many cases, SBC also provides NAT traversal and policy control features ( such as rate-limiting, ACL etc ). In advanced cases, transcoding, topology concealment and load balancing are also achievable via an SBC such as Kamailio.
Block user based on excessive REGISTER request till an expiry time
For instance to block DDOS attacks, kamailio can check for the number of register requests a user sends and block above a threshold number subsequently .
To be on edge of a voip pltform, a SIP server must keep track of all incoming request and their sources. Blocking the ones which exceed the limit or appear like a dos attack. Pike module reports high traffic from an IP if detected.
A sample script to detect high traffic from an IP and add it to ban list for a while . But exclude the known IP sources such as PSTN gateways etc
#!ifdef WITH_ANTIFLOOD
loadmodule "htable.so"
loadmodule "pike.so"
#!endif
...
# ----- pike params -----
modparam("pike", "sampling_time_unit", 2)
modparam("pike", "reqs_density_per_unit", 16)
modparam("pike", "remove_latency", 4)
...
route[REQINIT] {
...
if(src_ip!=myself) {
if($sht(ipban=>$si)!=$null) {
# ip is already blocked
xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");
exit;
}
if (!pike_check_req()) {
xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");
$sht(ipban=>$si) = 1;
exit;
}
}
Load balancing is critical to a production ready system to provide High availability and load sharing among available servers. This could be either stateless or stateful where they use call state tracking
Dispatcher module in Kamailio lends capabilities of SIP traffic dispatcher to it. It can load routes to gateways or destination sets from any storage source such as mysql , psql database or even plain text file (modparam("dispatcher", "db_url", <datasource_name>).
It can also assign priority for routing sip traffic to it ( modparam("dispatcher", "priority_col", "dstpriority"))
To discover active of inactive gateways it uses TM module. One can choose one among many algorithms to share the load , like
0 – hash over callid
1 – hash over from URI
2 – hash over to URI
3 – hash over request-URI
4 – round-robin (next destination)
5 – hash over authorization-username
6 – random destination (using rand())
7 – hash over the content of PVs string
8 – select destination sorted by priority attribute value (serial forking ordered by priority).
9 – use weight based load distribution . Needs attribute ‘weight’ per each address
10 – call load distribution ie route to one that has the least number of calls associated
11 – relative weight based load distribution(rweight)
12 – dispatch to all destination in setid at once (parallel forking).
x – if the algorithm is not implemented, the first entry in set is chosen.
Some attributes passed with each destination set
duid – identify a destination (gateway address). Practically the load within the group is associated with this value.
maxload – upper limit of active calls per destination
weight – percent of calls to be sent to that gateways
rweight – relative weight based load distribution.
socket – sending socket for the gateway including keepalives
ping_from – from URI in OPTIONS keepalives
Active host usage probability is, rweight/(SUM of all active host rweights in destination group). recalculation is fired as host enables or disables.
Every destination has congestion threshold(weight) and after enabling c (congestion control), rweight is also used to control congestion tolerance lowering the weight by 1 as congestion is detected.
EWMA ( exponential weighted moving average ) is speed at which the older samples are dampened.
name
type
size
default
null
key
extra
id
unsigned int
10
no
primary
auto increment
setid
int
not specified
0
no
destination
string
192
“”
no
flag
int
not specified
“”
no
priority
int
not specified
0
no
attrs
string
198
0
no
description
string
64
“”
no
To insert into dispatcher
INSERT INTO "dispatcher" VALUES(1,1,'sip:192.168.0.1:5060',0,12,'rweight=50;weight=50;cc=1;','');
I have added a detailed description of how kamalio based SIP servers can function as proxy / SBC for SIP Application server which could be an enterprise PBX or a full fledged Telecom Application Server such as Asterix , Freeswitch , Oracle Weblogic, telestax sip server etc
A PBX acts as the central switching system for phone calls within a business.
Cloud Hosted IP PBX Systems
On-premise IP PBX
An IP PBX is a PBX system with IP connectivity and may provide additional audio, video, or instant messaging communication utilizing the TCP/IP protocol stack.
Essentially an IP PBX is a telecommunication device( on IP Interface) that provides voice connectivity to IP phones within an organization/internal office network.
Enterprise applications, media servers, presence servers, and the VoIP/SIP PBX are interconnected through a company intranet.SIP clients can be SIP hard-phones or soft-phones on PCs, PDAs etc. A PSTN gateway links the enterprise SIP PBX to the public PSTN.
A soft switch (SIP PBX) can be a combination of several SIP entities, such as SIP registrar, proxy server, redirect server, forking server, Back-To-Back User Agent (B2BUA) etc.
FreeSWITCH is free and open source communications software licensed under Mozilla Public License. It if often the core of voice core to provider call routing and media control . Its core library, libfreeswitch, is capable of being embedded into other projects, as well as being used as a stand-alone application. Read more about FreeSwitch SIP and Media Server.
Just a network-switch is hardware that controls network traffic by receiving and forwarding data to the destination device, a soft-switch is a software that controls traffic and call routing in a voIP communication network.
Class 4 switch
Class 5 switch
Class 4 switches route calls between communication providers such as – between telco and enterprise PBX
Class 5 switches connect communication provider with real clients (or end users) caller and callee. – can provide platform + user agent such as diallers
-nf -- no forking
-reincarnate -- restart the switch on an uncontrolled exit
-reincarnate-reexec -- run execv on a restart (helpful for upgrades)
-u [user] -- specify user to switch to
-g [group] -- specify group to switch to
-core -- dump cores
-help -- this message
-version -- print the version and exit
-rp -- enable high(realtime) priority settings
-lp -- enable low priority settings
-np -- enable normal priority settings
-vg -- run under valgrind
-nosql -- disable internal sql scoreboard
-heavy-timer -- Heavy Timer, possibly more accurate but at a cost
-nonat -- disable auto nat detection
-nonatmap -- disable auto nat port mapping
-nocal -- disable clock calibration
-nort -- disable clock clock_realtime
-stop -- stop freeswitch
-nc -- do not output to a console and background
-ncwait -- do not output to a console and background but wait until the system is ready before exiting (implies -nc)
-c -- output to a console and stay in the foreground
Options to control locations of files:
-base [basedir] -- alternate prefix directory
-cfgname [filename] -- alternate filename for FreeSWITCH main configuration file
-conf [confdir] -- alternate directory for FreeSWITCH configuration files
-log [logdir] -- alternate directory for logfiles
-run [rundir] -- alternate directory for runtime files
-db [dbdir] -- alternate directory for the internal database
-mod [moddir] -- alternate directory for modules
-htdocs [htdocsdir] -- alternate directory for htdocs
-scripts [scriptsdir] -- alternate directory for scripts
-temp [directory] -- alternate directory for temporary files
-grammar [directory] -- alternate directory for grammar files
-certs [directory] -- alternate directory for certificates
-recordings [directory] -- alternate directory for recordings
-storage [directory] -- alternate directory for voicemail storage
-cache [directory] -- alternate directory for cache files
-sounds [directory] -- alternate directory for sound files
checks with ACL for permission and set NAT. Isolate SDP for processing.
New Channel sofia/internal/from_number@sometelco.com:5060 [a8a2003f-5755-40fe-ab63-aab2f5264886]
Running State Change CS_NEW (Cur 1 Tot 274)
receiving invite from caller_ip:35365 version: 1.9.0 -742-8f1b7e0 64bit
IP caller_ip Approved by acl "domains[]". Access Granted.
Setting NAT mode based on nat.auto
Channel sofia/internal/from_number@sometelco.com:5060 entering state [received][100]
Remote SDP:
v=0
o=- 1553248503383592 1 IN IP4 192.168.1.23
s=X-Lite release 5.4.0 stamp 94385
c=IN IP4 192.168.1.23
t=0 0
m=audio 49874 RTP/AVP 8 101
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
mainatin and Updates call-state (switch_core_state_machine ) CS_NEW -> CS_INIT -> CS_ROUTING -> RINGING and send 100 trying to caller
State Change CS_NEW -> CS_INIT
State NEW
Running State Change CS_INIT (Cur 1 Tot 274)
State INIT
SOFIA INIT
Standard INIT
State Change CS_INIT -> CS_ROUTING
State INIT going to sleep
Running State Change CS_ROUTING (Cur 1 Tot 274)
Change DOWN -> RINGING
State ROUTING
send 413 bytes to tcp/[caller_ip]:35365 at 09:55:07.937474:
------------------------------------------------------------------------
SIP/2.0 100 Trying
Via: SIP/2.0/TCP 192.168.1.23:55934;branch=z9hG4bK-524287-1---cc11593581af6519;rport=35365;received=caller_ip
From: "from_number"<sip:from_number@sometelco.com:5060>;tag=47a61272
To: <sip:to_number@sometelco.com:5060>
Call-ID: 94385YTY3ODNlNzE1YjE5MmY4NmQ3ZWUyZDAzM2E0YzBkM2I
CSeq: 1 INVITE
User-Agent: FreeSWITCH-mod_sofia/1.9.0-742-8f1b7e0~64bit
Content-Length: 0
------------------------------------------------------------------------
Checks dialplan to route incoming call. In this case action is to bridge the incoming call to internal user
mod_sofia.c:154 sofia/internal/from_number@sometelco.com:5060 SOFIA ROUTING
switch_core_state_machine.c:236 sofia/internal/from_number@sometelco.com:5060 Standard ROUTING
mod_dialplan_xml.c:637 Processing from_number <from_number>->to_number in context public
Dialplan: sofia/internal/from_number@sometelco.com:5060 parsing [public->dialplan_cutsom] continue=false
Dialplan: sofia/internal/from_number@sometelco.com:5060 Regex (PASS) [dialplan_cutsom] destination_number(to_number) =~ /^(\d+)$/ break=on-false
Dialplan: sofia/internal/from_number@sometelco.com:5060 Action log(INFO ***** Forwarding calls to gateway ****** )
Dialplan: sofia/internal/from_number@sometelco.com:5060 Action bridge({sip_auth_username=user,sip_auth_password=pass,sip_route_uri=sip:to_number@ip_addr;transport=tls,sip_invite_req_uri=sip:to_number@sometelco.com;transport=tls}sofia/external/to_number@ip_addr)
update call state CS_ROUTING -> CS_EXECUTE
State Change CS_ROUTING -> CS_EXECUTE
State ROUTING going to sleep
Running State Change CS_EXECUTE (Cur 1 Tot 274)
State EXECUTE
SOFIA EXECUTE
set the crypto and codecs for the new call
switch_ivr_originate.c:2159 Parsing global variables
switch_channel.c:1104 New Channel sofia/external/to_number@ip_addr [cc1ae238-9efd-4f51-93e9-05abd48bea4d]
mod_sofia.c:5026 (sofia/external/to_number@ip_addr) State Change CS_NEW -> CS_INIT
switch_core_state_machine.c:584 (sofia/external/to_number@ip_addr) Running State Change CS_INIT (Cur 2 Tot 275)
switch_core_state_machine.c:627 (sofia/external/to_number@ip_addr) State INIT
mod_sofia.c:93 sofia/external/to_number@ip_addr SOFIA INIT
Set Local audio crypto Key [1 AEAD_AES_256_GCM_8 inline:ZbEHd76sP6FZSO9AYcqryybaA4HY3O5p2Uo+e1gmmfVaZCEic6cvKyArhMU]
Set Local video crypto Key [1 AEAD_AES_256_GCM_8 inline:Ehr3LoDR8Ur+wtNAMqoqIDn3S7V2inE2/n++awxS6/1P2ijcqfk12+LM/Pc]
Set Local text crypto Key [1 AEAD_AES_256_GCM_8 inline:NVSfjOmSS5BaP/5yqg+SOXcqvEFTHHrC8R5AYkkClXLuNOXYoaUYlrIWeW0]
Set Local audio crypto Key [2 AEAD_AES_128_GCM_8 inline:ePH/F2Qw5+zi8c7tkBb6Y2AQE5uevp+jWUkjgQ]
Set Local video crypto Key [2 AEAD_AES_128_GCM_8 inline:YWdfNLSx6MqG9WQ3TmsV/cSBDqjRUAbHE0rRCg]
Set Local text crypto Key [2 AEAD_AES_128_GCM_8 inline:DFXOP2V2Ep6FoHNz5HIMrm0cu6Za8I5wOI/hUw]
Set Local audio crypto Key [3 AES_CM_256_HMAC_SHA1_80 inline:SG5rYx3GSR2imutYQ+LzqHufG9UkG3n/SfmFHFOG/r75v2pwf2lG7Qpup+J0mw]
Set Local video crypto Key [3 AES_CM_256_HMAC_SHA1_80 inline:LkU3i9MD25k2wtTfSXUvhlxo66GtMWnXkKoxSdgRZyANoeOhufYnXzbXDo+7+w]
Set Local text crypto Key [3 AES_CM_256_HMAC_SHA1_80 inline:AUgUOVmFunzotvwZ6KuMDnBRR2XKk1DsX2qg465MsT6OAxHc2qKBFpeQEpxrqA]
Set Local audio crypto Key [4 AES_CM_192_HMAC_SHA1_80 inline:2PVBBJEp4QcTzTf4Th8Ag/7KiVPmrYb/FCowiRb6yAuTO/kxQLc]
Set Local video crypto Key [4 AES_CM_192_HMAC_SHA1_80 inline:OiFbZQ6mWuf5sHJT1pFPU6EWxEvQAO/0rcp8uGMf79k7RSR3IQA]
Set Local text crypto Key [4 AES_CM_192_HMAC_SHA1_80 inline:XyednWJmzRfsWQOgdhKaMeOeE/OLmnwo6hVEZWl4OJdKdgK6TVc]
Set Local audio crypto Key [5 AES_CM_128_HMAC_SHA1_80 inline:Yd4L5Qi7A/8xay5ZHWR1jKk9j5Kvy9s2Zo3NOES2]
Set Local video crypto Key [5 AES_CM_128_HMAC_SHA1_80 inline:ImgbbD6cnhnH19O1knP5SSIUULsZTaNJJIUepxt0]
Set Local text crypto Key [5 AES_CM_128_HMAC_SHA1_80 inline:V7+IbSZmTdQNjh/upUZ5TFDSlgarhDTVfV+AcUA+]
Set Local audio crypto Key [6 AES_CM_256_HMAC_SHA1_32 inline:JI+s9uFdZ3JfZmRRfwHr0OrpyZdtUXmMC0WRIZow1EuXRB9xKFRBk6KmSWomqQ]
Set Local video crypto Key [6 AES_CM_256_HMAC_SHA1_32 inline:MX6CGCrMEioUCJsIOCxRqlHOx4mUYRw4DslpY25njZQAkH6MgG/9hp7G8xr44A]
Set Local text crypto Key [6 AES_CM_256_HMAC_SHA1_32 inline:ikCz2sYLGoMO+dlrZj+znlQ3djAkGSYzSLLu6Az8u2THWPgnkFJXVgXSxHOaHw]
Set Local audio crypto Key [7 AES_CM_192_HMAC_SHA1_32 inline:5JzlrMywFZhHuNLWPG/HBrUi/Zcg414Q7ZfSaJQnUF5N9APy+GQ]
Set Local video crypto Key [7 AES_CM_192_HMAC_SHA1_32 inline:K0dZtwH1Q7AuSMBPPUesy047c4nAF+QuFsVvGdf3fYJDOD0Uwxo]
Set Local text crypto Key [7 AES_CM_192_HMAC_SHA1_32 inline:96SwyWAdV1a+BU3UbiX1PHdkRlSS4RtmwPWNPbCR3NDm1MyBh58]
Set Local audio crypto Key [8 AES_CM_128_HMAC_SHA1_32 inline:/RLYPhZs07WCCBRY8tWNTJemT/IFq1VPHGHmGvnG]
Set Local video crypto Key [8 AES_CM_128_HMAC_SHA1_32 inline:mQlgScFq1iMKEW8vobzwhmN9TWSmVblAv9u7c1/c]
Set Local text crypto Key [8 AES_CM_128_HMAC_SHA1_32 inline:WAQveMfrQkPBcfqH2qLmuzY63VLfT+N30/YLyuqE]
Set Local audio crypto Key [9 AES_CM_128_NULL_AUTH inline:f2fx2ekxPG3GTwTYARtquNJ87qO0Q5ei47KYlo9K]
Set Local video crypto Key [9 AES_CM_128_NULL_AUTH inline:qpAkfc1bWnZ0Y/1ql+dNvhIGgxxWZoVltnRD5kqn]
Set Local text crypto Key [9 AES_CM_128_NULL_AUTH inline:LyhSlzI3X38WKPwZ83035Ddvse4J/2KnKoydo2FD]
set proxy route and create SDP for sending invite to bridged client
manage and update call state for this call leg too CS_INIT -> CS_ROUTING -> CS_CONSUME_MEDIA
Standard INIT
State Change CS_INIT -> CS_ROUTING
State INIT going to sleep
Running State Change CS_ROUTING (Cur 2 Tot 275)
Channel sofia/external/to_number@ip_addr entering state [calling][0]
State ROUTING
SOFIA ROUTING
State Change CS_ROUTING -> CS_CONSUME_MEDIA
State ROUTING going to sleep
Running State Change CS_CONSUME_MEDIA (Cur 2 Tot 275)
State CONSUME_MEDIA
State CONSUME_MEDIA going to sleep
recv 365 bytes from tls/[ip_addr]:5061 at 09:55:07.940977:
------------------------------------------------------------------------
SIP/2.0 100 trying -- your call is important to us
Via: SIP/2.0/TLS via_addr:5080;rport=59774;branch=z9hG4bK21Qm9U3eHX0Nc;received=via_addr
From: "from_number" <sip:from_number@via_addr>;tag=8jByBXa2pF1Fj
To: <sip:to_number@ip_addr>
Call-ID: 6a827514-c72b-1237-8aab-02a933b32da0
CSeq: 2070461 INVITE
Server: XYZ
Content-Length: 0
------------------------------------------------------------------------
set audio codecs, update call state CS_CONSUME_MEDIA -> CS_EXCHANGE_MEDIA
entering state [ready][200]
looking for crypto suite [AEAD_AES_256_GCM_8] in [3 AES_CM_256_HMAC_SHA1_80 inline:/itE1k5BLMoTNzo7YEv6hCyM6R6wyHem3Coc5jjYVlKR2L3tEzBG5zx1QHgVSg==]
looking for crypto suite [AEAD_AES_128_GCM_8] in [3 AES_CM_256_HMAC_SHA1_80 inline:/itE1k5BLMoTNzo7YEv6hCyM6R6wyHem3Coc5jjYVlKR2L3tEzBG5zx1QHgVSg==]
looking for crypto suite [AES_CM_256_HMAC_SHA1_80] in [3 AES_CM_256_HMAC_SHA1_80 inline:/itE1k5BLMoTNzo7YEv6hCyM6R6wyHem3Coc5jjYVlKR2L3tEzBG5zx1QHgVSg==]
Found suite AES_CM_256_HMAC_SHA1_80
Set Remote Key [3 AES_CM_256_HMAC_SHA1_80 inline:/itE1k5BLMoTNzo7YEv6hCyM6R6wyHem3Coc5jjYVlKR2L3tEzBG5zx1QHgVSg==]
Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMA:8:8000:20:64000:1]
Audio Codec Compare [PCMA:8:8000:20:64000:1] ++++ is saved as a match
Set telephone-event payload to 101@8000
Set Codec sofia/external/to_number@ip_addr PCMA/8000 20 ms 160 samples 64000 bits 1 channels
sofia/external/to_number@ip_addr Original read codec set to PCMA:8
Set telephone-event payload to 101@8000
sofia/external/to_number@ip_addr Set 2833 dtmf send payload to 101 recv payload to 101
AUDIO RTP [sofia/external/to_number@ip_addr] 10.130.74.15 port 20072 -> <FS_IPADDR> port 33516 codec: 8 ms: 20
Starting timer [soft] 160 bytes per 20ms
Set 2833 dtmf send payload to 101
Set 2833 dtmf receive payload to 101
Set rtp dtmf delay to 40
Activating audio Secure RTP SEND
srtp:sdes:AES_CM_256_HMAC_SHA1_80
Activating audio Secure RTP RECV
srtp:sdes:AES_CM_256_HMAC_SHA1_80
has been answered
Callstate Change DOWN -> ACTIVE
Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMU:0:8000:20:64000:1]
Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMA:8:8000:20:64000:1]
Audio Codec Compare [PCMA:8:8000:20:64000:1] ++++ is saved as a match
Set telephone-event payload to 101@8000
Set Codec sofia/internal/from_number@sometelco.com:5060 PCMA/8000 20 ms 160 samples 64000 bits 1 channels
sofia/internal/from_number@sometelco.com:5060 Original read codec set to PCMA:8
Set telephone-event payload to 101@8000
sofia/internal/from_number@sometelco.com:5060 Set 2833 dtmf send payload to 101 recv payload to 101
Goto folder /usr/local/freeswitch/conf/directory/ and vim default.xml
<include>
<!--the domain or ip (the right hand side of the @ in the addr-->
<domain name="$${domain}">
...
<users>
<user id="altanai">
<params>
<param name="password" value="$${default_password}"/>
<param name="vm-password" value="1000"/>
</params>
<variables>
<variable name="toll_allow" value="domestic,international,local"/>
<variable name="accountcode" value="987"/>
<variable name="user_context" value="video-mcu-stereo"/>
<variable name="effective_caller_id_name" value="altanai"/>
<variable name="outbound_caller_id_name" value="altanai_outbound"/>
</variables>
</user>
</users>
..
</domain>
</include>
2. Blind Registeration
Allow users to register with any username and password
Goto /usr/local/freeswitch/conf/sip_profiles/internal.xml and uncomment below snippet
<!-- this lets anything register -->
<!-- comment the next line and uncomment one or both of the other 2 lines for call authentication -->
<param name="accept-blind-reg" value="true"/>
<!-- accept any authentication without actually checking (not a good feature for most people) -->
<param name="accept-blind-auth" value="true"/>
3. Set a profile
Goto folder for freeswitch conf such as /usr/local/freeswitch/conf/directory/default
Back in 2010 , there was a very resilient SIP server called BEA weblogic , essentially used to write B2BUA ( back to back user agent application ) using SIP servlets for SIP based call flows . It was later acquired by Oracle and termed as Oracle Weblogic , then OCAS – Oracle Communication application Server and now Oracle Communications Evolved Application Server (v7.1) .
This article describes what is OCAS and some applications that can be build over it . OCAS is Java EE-SIP-IMS application server. It uses SIP Servlet 2.0 built on Java EE 7 containing concurrent session management, web sockets, CDI interface , POJO and
standard JSON, XML, JAX, JMS interfaces. Also 3GPP ISC (SIP), and Sh/Ro/Rf (Diameter).
Converged Web and JEE SIP Servlets
OCAS is a Converged Web-telecom application container based on SIP Servlet, IMS, Java EE, Diameter, JSR 309 Media Server Control and Web Services . It can host IP-based, communication-enabled applications.
It is said to be a converged application server as it can host both web and sip project and even a hybrid project of both such as web page with click to dial options ( customer care ) , IPTV based web telecom , VoIP, locations/ Registrar , UCC Unified Communicator an Collaborator , Rich CommunicationServices (RCS) including Voice over LTE (VoLTE), SIP OPTIONS, Presence, Instant Messaging (SIMPLE) , MSRP, XDMS, and media servers , multimedia conferencing, SIP/IMS-based call control etc.
Converged container-developer platform supporting modern tools such as Eclipse and programming techniques based on Java 8 (POJOs, Annotations, CDI).
API support includes – SIP Servlet API (JSR 289) , Service Foundation Toolkit API , Media server API , Diameter API , Converged Load Balancer API , JEE API
Scaling
Application can be build once and run anywhere since build on open source tools and components . Additionally OCAS supports Function virtualization ( VNF) can be integrated with NFV ( network function virtualization ) for automatic scaling and being hardware agnostic in terms of computer , storage and network . This makes it suited for large scale deployment such as CSP ( communication Service Providers ) or Enterprise Comm Agents .
Operating systems – Oracle Solaris 11 , Linux , Windows 7(64 bit) , HP-UX
Oracle 6+, Redhat
Virtual Machines – M Java Virtual Machine , Oracle Java VM, HP JVP, Oracle Virtual Machine
Service Creation Environment on Eclipse for SIP servlets and Debugging
SCE provides tools for building a Converged Application Project which may includes the following facets:
Dynamic Web Module
Java
JavaScript
Oracle Communication Converged Application Extensions, including:
– SIP Servlet
– SFT Communication Bean
Oracle WebLogic Web Application Extensions
It can also have standard JRE resources, system library files, such as sft-communication-api.jar and sipservlet.jar, as well as sft.xml, sip.xml, and web.xml deployment descriptor files. With this we can create SFT Communication Beans and SIP Servlets along with standard HTTP Servlets, JPSs, static files, and EJB-based classes. For Diameter applications enable the facet.
Register Sip Servlet Handler
import javax.servlet.ServletException ;
import javax.servlet.sip.SipApplicationSessionEvent;
import javax.servlet.sip.SipApplicationSessionListener;
import javax.servlet.sip.SipServlet ;
import javax.servlet.sip.SipServletContextEvent;
import javax.servlet.sip.SipServletListener;
import javax.servlet.sip.SipServletRequest ;
public class SipRegistrarServlet extends SipServlet {
public void init() throws ServletException {
super.init();
logger.debug("SIP Registrar Servlet..");
}
// Override SipServlet's default implementation.
@Override
public void doRegister(SipServletRequest request)
throws ServletException
{
// create instance of auitheticator class
SipAuthenticator authenticator = SipAutheticatorFactory.getInstance();
try{
autheticate(authenticator, request);
// Call the registration service
SipRegistrarService.processRegister(request);
}
catch (Exception e){
// Perform Logging
}
}
}
In most cases, converged applications are deployed as SAR or WAR files. However, you can choose to output to an EAR file if your project contains both SIP and enterprise JavaBean components. Target environment can be Oracle WebLogic Server 11gR1 (10.3.6). Environment variables like JAVA_HOME and BEA_HOME need to be set .
SIP Deployment Descriptor file is sip.xml . It can contain filter for sip request types that this application will handle . for example only to handle register
Sample Servlet for handling message requests and responding 200 ok
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.sip.*;
public class MessageServletApp extends SipServlet {
protected void doMessage(SipServletRequest req)
throws ServletException, IOException
{
SipServletResponse res = req.createResponse(200);
res.send();
}
}
Templates
SCE provides wizards ( SIP Servlet , SIP Listener , CommunicationBean )and templates for creating a variety of SIP and converged application types.
SIP servlets templates
Parent class to be extended is javax.servlet.sip.SipServlet
SIP Proxy – providing routing capabilities and performing user authentication, accounting, registration, and security.
B2BUA / back-to-back user agent – can act as both a user agent client and server. Uses the helper class, javax.servlet.sip.B2buaHelper
Subscribe UAS – subscribes to a User Agent Server (UAS).
Invite UAS – initiates communication sessions between UA peers.
After template selection , the wizard populates the new class with the stub methods appropriate for the type of SIP servlet . Therafter programmer can put their custom routing logic / business logic inside the functions .
Generic SIP servlet acting as adapter for all request types
import javax.servlet.ServletException;
import javax.servlet.sip.Address;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipApplicationSessionEvent;
import javax.servlet.sip.SipApplicationSessionListener;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.SipServlet;
import javax.servlet.sip.SipServletContextEvent;
import javax.servlet.sip.SipServletListener;
import javax.servlet.sip.SipServletMessage;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.SipSessionsUtil;
import javax.servlet.sip.TimerService;
public class SipCustomServlet extends SipServlet implements SipServletListener,
SipApplicationSessionListener
{
public void init() throws ServletException
{
super.init();
SipFactory sipFactory = (SipFactory) getServletContext().getAttribute( "javax.servlet.sip.SipFactory");
SipSessionsUtil sipSessionsUtil = (SipSessionsUtil)getServletContext().getAttribute( "javax.servlet.sip.SipSessionsUtil");
SessionTimerHandler.initializeSessionTimers((TimerService) getServletContext().getAttribute("javax.servlet.sip.TimerService"));
}
/** This is the entry point for all SIP Requests received by the servlet
* @see javax.servlet.sip.SipServlet#doRequest(javax.servlet.sip.SipServletRequest)
*/
protected void doRequest(SipServletRequest req) throws ServletException, IOException
{
if( ! serverStatus.isActive()){
SipServletResponse resp = req.createResponse(503, "Server Not Active");
sendResponse(resp);
return;
}
if (req.getMethod().equals("SUBSCRIBE"))
{
eventService.doSubscribe(req);
return;
}
else if (req.getMethod().equals("NOTIFY"))
{
String eventHeader = req.getHeader("Event");
// perform business logic
eventService.doNotify(req);
return;
}
if (req.getMethod().equals("OPTIONS"))
{
SipServletResponse resp = null;
if(check some cond){
// send forbidden
resp = req.createResponse(403);
}
else
{
// send success
resp = req.createResponse(200);
}
sendResponse(resp);
return;
}
if (req.getMethod().equalsIgnoreCase("PUBLISH"))
{
PublishHandler handler = PublishHandler.getInstance();
handler.processPublish(req);
return;
}
doRequestInvite(req);
}
SIP Listener Wizard
listens for certain types of SIP-specific events, and typically performs some processing action in response to the event. For this select at least one application event to listen for. The available events are standard SIP-specified events, and include application events, session events, errors, timer events, and initialization events.
SFT Communication Bean Wizard
performs the functions of a SIP or HTTPservlet while hiding the complexities of SIP and communication protocol programming. CommunicationBeans use annotations to encapsulate common functions or roles fulfilled by communication applications. Instead of specifying the code that performs the function, you simply add the annotation to the source file. The SFT framework expands the annotation to the appropriate code.
Add methods to your communication bean that listen for specific events as
follows:
Step1 : From the Event Type list, choose the event category from these options:
CommunicationEvent, ParticipantEvent, or ProtocolEvent.
Step 2 : From the Event menu, choose the specific event on which you want the method to listen. The options vary depending on the event type. For instance, for ProtocolEvent, you can choose from these specific events: REQUESTRECEIVED, REQUESTSENT, RESPONSERECEIVED, or RESPONSESENT.
Step 3 : Optionally, modify the default priority for the method, 100.
Automatic Processes
Converged Application Server automatically execute the following response and retransmission processes:
Sending “100 Trying”: When Converged Application Server receives an INVITE request, it automatically creates and sends “100 Trying.”
Response to CANCEL: When WebLogic Communications Server receives a CANCEL request, it executes the following processes if the request is valid.
1. Sends a 200 response to the CANCEL request.
2. Sends a 487 response to the INVITE request to be cancelled.
3. Invokes a doCancel method on the SIP servlet.
Sends ACK to an error response to INVITE
Retransmission process when using UDP
System Headers
These cannot be changed by sip servlets applications and they are used for holding critical info about message delivery
Call-ID – ID information to associate multiple SIP messages as Call.
From, To – Information on the sender and receiver of the SIP request (SIP, URI, etc.). tag parameters are given by the servlet container.
CSeq – Sequence numbers and method names.
Via – Contains a list of servers the SIP message passed through , to keep track of the path to send a response to the request.
Record-Route – Route Used when the proxy server mediates subsequent requests.
Contact – Network information (such as IP address and port number) that is used for direct communication between terminals.
Note : For a REGISTER message, 3xx, or 485 response, this is not considered as the system header and SIP servlets can directly edit the information.
SIP factory
Factory class to create SIP Servlet-specific objects for application execution. Class objects as URI, SipURI, Address , SipServletRequest , SipApplicationSession
Recursive routing (recursive): When the destination of proxying returns a 3xx response, the request is proxied to the specified target.
Record-Route setting: Sets a Record-Route header in the specified request.
Parallel/Sequential (parallel): Determines whether forking is executed in parallel or sequentially.
stateful: Determines whether proxying is transaction stateful. This parameter is not relevant because stateless proxy mode is deprecated in JSR289.
Supervising mode: In the event of the state change of proxying (response receipts),an application reports this.
Changing SIP application session
Synchronous : Applications that need to read and update a session attribute in a transactional and synchronous manner must use the WlssAction API
Asynchronous : Applications that need to update a different SipApplicationSession while in the context of a locked SipApplicationSession can perform asynchronous updates using the WlssAsynchronousAction API.
Join header, defined in RFC 3911
Logically joins an existing SIP dialog with a new SIP dialog. Used in SIP Call Control and Multi-Party applications for enabling features such as Call Forwarding, Message Screening, and Call Center Monitoring.
Replaces header, defined in RFC 3891
Logically replaces an existing SIP dialog with a new SIP dialog. Used to enable features such as Attended Call Transfer and Call Pickup.
Note : To enable support for Join and Replaces headers, edit the entry for the –Dwlss.dialog.index.enabled=false command in the startWebLogic.sh script, and
set its value to true.
Testing , Debugging and Simulation
network components for simulation integration include – XDMS server , Diameter Ro server , Diameter Rf server , Diameter HSS server , Media server
Sipp plug-in for testing sip call routing logic
Media Server simulation for applications as conferencing, audio prompting, and speech detection
Production Environment
For production scenarios, SIP applications are deployed to a cluster of Converged Application Server instances that form the engine tier cluster. A separate cluster of servers in the SIP data tier provides a replicated, in-memory database of the call states for active calls.
For production grade apps :
Use setAttribute() to Modify Session Data in “No-Call” Scope.
Send() Calls Are Buffered and transmitted in order after the SIP method returns
Mark SIP servlets as distributable in sip.xml also in the web.xml for a WAR file for depliying to cluster of enginer tier servers . Can be omitted for single non replicated deployment .
Non blocking , no threaded Applications
Converged Application Server architecture is a multi-threaded application server that manages resource allocation, concurrency, and thread synchronization for the modules it hosts. Since SIP servlet container automatically locks call state before calling doXXX methods. We shouldnt create new threads to avoid deadlock scenarios in doXXX methods ourselves.
String application data in session in a seriallizable way
Make use of Session attributes to store all application data of session .To serialize an object means to convert its state to a byte stream so that the byte stream can be reverted back into a copy of the object. Therefore to support in-memory replication of SIP application call states, all objects stored in the SIP Servlet session should be serializable. Also in a replicated configuration, engine tier servers maintains no cached information; all application data must be de-serialized from the session attribute available in SIP data tier servers.
We used Brekeke SIP server to run our SIP applications . Although there are newer versions of Brekeke SIP server out now . More awesome than before , we prefer using the old one for the sake of not messing with legacy SIP applications . The official site for brekeke is – http://www.brekeke.com/sip/ .
A general architecture of Brekeke SIP server is .
Here are the steps of installing and configuring a Brekeke SIP server .
Step 5 : Once the license is activates , we can goto the console screen after loggin with default username and password sa .
Step 6 : Once we are at console , we could add/ delete / modify parameters like port , start/shutdown status etc . Step 7 : Once the server is all setup , just add the IP and port of SIP server to SIP clients server filed . Now all the SIP request and response will be catered by this SIP Server
The post has been edited after publishing with updated content and Kamailio modules.
Kamailio® (successor of former OpenSER and SER) is an Open Source SIP Server released under GPLv2+, able to handle thousands of call setups per second. Kamailio can be used to build large platforms for VoIP and realtime communications – presence, WebRTC, Instant messaging and other applications. Moreover, it can be easily used for scaling up SIP-to-PSTN gateways, PBX systems or media servers like Asterisk™, FreeSWITCH™ or SEMS.
Kamailio follows RFC 3261 for SIP and can act as Registrar, Location server, Proxy, Redirect or event Application Server based on its configuration. The modular architecture of Kamailio enables extending the core functionality in various directions using modules.
There are over 150 modules in Kamailio dealing with add-on features that can be categorised into various functional areas such as
registrar and user location management
accounting, authorization and authentication
text and regular expression operations
stateless replying
stateful processing – SIP transaction management
Stateful
Stateless
stateful processing is per SIP transaction
Each SIP transaction will be kept in memory so that any replies, failures, or retransmissions can be recognized
Forwarding each msg in the dialog without any context.
Application understands the transactions , for example – recognize if a new INVITE message is a resend – know that 200 OK reponse belongs to the initial INVITE which it will be able to handle in an onreply_route[x] block.
it doesnt know that the call is on-going. However it can use callId to match INVITE and BYE.
Uses : manage call state , routing , call control like forward on busy, voicemail
Uses : Load distribution , proxying
SIP dialogs tracking – active calls management
instant messaging and presence extensions
RADIUS and LDAP support
SQL and no-SQL database connectors
MI and RPC transports
Enum, GeoIP API and CPL interpreter
topology hiding and NAT traversal
load balancing and least cost routing
asynchronous SIP request processing
interactive configuration file debugger
Lua, Perl, Python and Java SIP Servlet extensions
Routing a Call
A SIP server can either
direct the call and let the UA contact with each other directly or
force itself in the path by inserting a Route header in the SIP message (e record_route())
Kamailio provides a custom locking system its root element is a mutex semaphore, that can be set (locked) or unset (unlocked). The locking.h lib provides the functionality in C code.
A problem however with locks is that processes can eat a lot of CPU. Locking issues also occur when locks are set but not unset resulting in no more SIP messages being processed. Hence Kamailio uses gdb with PID and get backtraces to the lock that wasnt released .
Multliple processes run simultenously within kamailio server, hence it bears private and shared memeories to facailitate their working. One can increase shared memory using -m and private memory using -M command line option.
Private Memory
Shared Memory
Memeory is specific per process. No synchronization is needed to access structures allocated in it, such as varaibles not needed by other process or ones for temporary operations.
Private memory manager is accessed via mem/mem.h
The data stored in shared memeory is visible in all Kamailio modules such as, user location, TM structures for stateful processing, routing rules for the dispatcher etc.
Here locks are used to prvent race conditions.
Shared memeory can be acceses via mem/shm_mem.h.
pkg_malloc(…) pkg_free(…) pkg_realloc(…)
shm_malloc(…) shm_free(…) shm_realloc(…)
Problems in memory management can occur due to :
(-) Out of memory by allocating memory at runtime and not freeing it afterwards , called memory leaks
(-) writing more than allocated for that structure, called segmentation fault.
Since kamailio has a modular architecture with core components and modules to extend the functionality, this article will be discussing few of the essential modules in Kamailio. Specific modules Discussed in this Article :
UserLoc
Registrar
Dialog
UAC
XHTTP
Websocket
Few categories of modules discoverable via apt-cache search kamailio
kamailio – very fast and configurable SIP proxy
kamailio-autheph-modules – authentication using ephemeral credentials module for Kamailio
kamailio-berkeley-bin – Berkeley database module for Kamailio – helper program
kamailio-berkeley-modules – Berkeley database module for Kamailio
kamailio-carrierroute-modules – carrierroute module for Kamailio
kamailio-cnxcc-modules – cnxcc modules for Kamailio
kamailio-cpl-modules – CPL module (CPL interpreter engine) for Kamailio
kamailio-dbg – very fast and configurable SIP proxy [debug symbols]
kamailio-dnssec-modules – contains the dnssec module
kamailio-erlang-modules – earlang modules for Kamailio
kamailio-extra-modules – extra modules for Kamailio
kamailio-geoip-modules – contains the geoip module
kamailio-ims-modules – IMS module for Kamailio
kamailio-java-modules – contains the app_java module
kamailio-json-modules – Json parser and jsonrpc modules for Kamailio
kamailio-kazoo-modules – kazoo modules for Kamailio
kamailio-ldap-modules – LDAP modules for Kamailio
kamailio-lua-modules – contains the app_lua module
kamailio-memcached-modules – interface to memcached server
kamailio-mono-modules – contains the app_mono module
kamailio-mysql-modules – MySQL database connectivity module for Kamailio
kamailio-outbound-modules – Outbound module for Kamailio
kamailio-perl-modules – Perl extensions and database driver for Kamailio
kamailio-postgres-modules – PostgreSQL database connectivity module for Kamailio
kamailio-presence-modules – SIMPLE presence modules for Kamailio
kamailio-purple-modules – Provides the purple module, a multi-protocol IM gateway
kamailio-python-modules – contains the app_python module
kamailio-radius-modules – RADIUS modules for Kamailio
kamailio-redis-modules – Redis database connectivity module for Kamailio
kamailio-sctp-modules – sctp module for Kamailio
kamailio-snmpstats-modules – SNMP AgentX subagent module for Kamailio
kamailio-sqlite-modules – SQLite database connectivity module for Kamailio
kamailio-tls-modules – contains the TLS kamailio transport module
kamailio-unixodbc-modules – unixODBC database connectivity module for Kamailio
kamailio-utils-modules – Provides a set utility functions for Kamailio
kamailio-websocket-modules – Websocket module for kamailio
kamailio-xml-modules – XML based extensions for Kamailio’s Management Interface
kamailio-xmpp-modules – XMPP gateway module for Kamailio
The first set under explanation is Usrloc and Register module which take care of user persistance in Database and handling an incoming register request with authentication and validation.
The first set under explanation is Usrloc and Register module which take care of user persistance in Database and handling an incoming register request with authentication and validation.
We know that dialog represent the p2p relationship between 2 sip clients and contains sequence of transactions along with routing information and facilitate sequencing of more messages. Dialog module keeps track of current dialogs also provides API support. It can be loaded and used as
event_callback (str) – name of the function in the kemi configuration file (embedded scripting language such as Lua, Python, …) to be executed instead of event_route[…] blocks.
The callback function receives a string parameter with the name of the event, the values are: ‘dialog:start’, ‘dialog:end’, ‘dialog:failed’. It is also executed if ‘$dlg_ctx(timeout_route)’ is set
function ksr_dialog_event(evname)
KSR.info("===== dialog module triggered event: " .. evname .. "\n");
if (evname == "dialog:end") or (evname == "dialog:failed") then
logger.log("info", "in dialog event callback with event-name - " .. evname .. " start CDR process ")
if not cdrProcess.post() then
logger.log("err", "Failed")
else
logger.log("info", "successfully posted")
core.exit()
end
end
end
Provides basic HTTP/1.0 server functionality. SIP requires a Content-Length header for TCP transport. But most HTTP clients do not set the content length for normal GET requests. Therefore, the core must be configured to allow incoming requests without content length header:
tcp_accept_no_cl=yes
Parameters :
url_skip : if there is a match , event route is not executed modparam(“xhttp”, “url_skip”, “^/RPC2”)
url_match : if there is no match , event route is not executed modparam(“xhttp”, “url_match”, “^/sip/”)
event_Callback : function in the kemi configuration file (embedded scripting language such as Lua, Python) to be executed instead of event_route[xhttp:request] block
modparam("xhttp", "event_callback", "ksr_xhttp_event")
// and the event callback function implemented in Lua
function ksr_xhttp_event(evname)
KSR.info("===== xhttp module triggered event: " .. evname .. "\n");
return 1;
end
Function
xhttp_reply(code, reason, ctype, body) – Send back a reply with content-type and body.
This module provides websocket ( ws and wss) support to kamailio ( RFC 6455). Handles handshaking, management (including connection keep-alive), and framing for the SIP and MSRP WebSocket sub-protocols (RFC 7118 and RFC 7977).