Kamailio as Inbound/Outbound proxy or Session Border Controller

A typical voice core network consists of 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 outside world directly , there for a SBC ( Session Border Controller ) comes into picture .

The role of an SBC is to shield the core network from external entities such as user agent’s , carrier network 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 is also achievable via a SBC such as Kamailio .

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

Anti Flood with Pike Module

To be on edge of a voip pltform , a SIP server must keep trac 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

Functions

Call Routing

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

Mask inner IPS with topology hiding

-tbd

PSTN gateway routing

-tbd

Kamailio basic setup as proxy for FreeSWITCH

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s