Kamailio as Inbound/Outbound proxy or Session Border Controller (SBC)


SBC ( Session Border Controller )

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.

SBC interfaces

Following sections are usecases / features kamailio can extend to. Routing scripts at https://github.com/altanai/kamailioexamples

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 .

if($sht(auth_block_list=>$au::auth_count)==30){
    $var(block) = $Ts - 900;
    $var(expire) = $Ts - 300;

    if($sht(auth_block_list=>$au::last_block) > $var(block)){
        xlog("L_INFO", "$fU@$fd - REGISTER - $au User Already Blocked for Exceeded Register Requests.\n");
        sl_send_reply("403", "Already Blocked Forbidden");
        exit;
    } else if($sht(auth_block_list=>$au::last_auth) > $var(expire)) {
        $sht(auth_block_list=>$au::last_block) = $Ts;
        xlog("L_INFO", "$fU@$fd - REGISTER - $au User Blocked for Exceeded Register Requests.\n");
        sl_send_reply("403", "Blocked Forbidden");
        exit;
    } else {
        $sht(auth_block_list=>$au::auth_count) = 0;
    } 
}

More information on kamailio security can be found on https://telecom.altanai.com/2018/02/17/kamailio-security/. It includes Sanity checks for incoming SIP requests ,Access Control Lists and Permissions, Hiding Topology Details, Anti Flood and Traffic Monitoring and Detection.

Anti Flood with Pike Module

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;
	}
}

Access Control List with Permission Module

permission module handles ACL by storing permission rules in plaintext configuration files , hosts.allow and hosts.deby by tcpd.

#!ifdef WITH_IPAUTH
loadmodule "permissions.so"
#!endif
...
# ----- permissions params -----
#!ifdef WITH_IPAUTH
modparam("permissions", "db_url", DBURL)
modparam("permissions", "db_mode", 1)
#!endif
..
#!ifdef WITH_IPAUTH
    if((!is_method("REGISTER")) && allow_source_address()) {
        # source IP allowed
        return;
    }
#!endif

Call Routing Functions

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”.

Perform Load Balancing with Dispatcher Module

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.

nametypesizedefaultnullkeyextra
idunsigned int10noprimaryauto
increment
setidintnot specified0no
destinationstring192“”no
flagintnot specified“”no
priorityintnot specified0no
attrsstring1980no
descriptionstring64“”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;','');

set ping gateway once per second

modparam("dispatcher", "ds_ping_interval", 1)

enabling congestion metrics

modparam("dispatcher", "ds_ping_latency_stats", 1)

latency estimator

modparam("dispatcher", "ds_latency_estimator_alpha", 900)
loadmodule "dispatcher.so"
...
# ----- dispatcher params ----- 
modparam("dispatcher", "db_url", DBURL) 
modparam("dispatcher", "table_name", "dispatcher") modparam("dispatcher", "flags", 2) 
modparam("dispatcher", "dst_avp", "$avp(AVP_DST)") modparam("dispatcher", "grp_avp", "$avp(AVP_GRP)") modparam("dispatcher", "cnt_avp", "$avp(AVP_CNT)") modparam("dispatcher", "sock_avp", "$avp(AVP_SOCK)")
...

request_route {
# do checks , indialog etc ...
# dispatch destinations 
route(DISPATCH); 
}

# Dispatch requests
route[DISPATCH] {
     # round robin dispatching on gateways group '1'
     if(!ds_select_dst("1", "4")) {
         send_reply("404", "No destination");
         exit;
     }
     xlog("L_DBG", "--- SCRIPT: going to <$ru> via <$du>\n");
     t_on_failure("RTF_DISPATCH");
     route(RELAY);
     exit;
 }


# Try next destinations in failure route, except if session gets cancelled 
failure_route[RTF_DISPATCH] {
     if (t_is_canceled()) {
         exit;
     }
     # next DST - only for 500 or local timeout
     if (t_check_status("500") or (t_branch_timeout() and !t_branch_replied())) {
         if(ds_next_dst()) {
             t_on_failure("RTF_DISPATCH");
             route(RELAY);
             exit;
         }
     }
 }

More on Kamailio Call routing and Control

Kamailio basic setup as proxy for FreeSWITCH

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

Kamailio basic setup as proxy for FreeSWITCH

References

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.