Handling SIP Flood Attacks Using Kamailio
Posted . ~3min read.
The Pike module in Kamailio provides detection and alerting of “excessive” SIP traffic to your system. Within the module you can configure the rate limit, time period, and amount of time that the IP (ipv4 or ipv6) should be blocked.
For example, you can configure your system to say that 30 requests from the same IP within 5 seconds should trigger a block of that IP for 5 minutes.
I absolutely love this module and, in my case, Pike more often finds abusive traffic (like dialers) than SIP floods attacks. Some of this comes from the fact that SIP attacks are difficult to “amplify,” and takes more resources than other DDoS attacks (see Sandro Gauci/Enable Security’s discussion on recent DDoS in the VoIP world) .
Of course, handling DDoS is something best approached by design and plan; needing good architecture, software, hardware, and skill.
On the SIP side, even when you trigger a block with Pike, the block is still handled by the software (in this case, Kamailio). Kamailio can handle a tremendous amount of SIP traffic, but software is software and SIP would be handled in the application layer (for you OSI geeks).
Combining Kamailio’s Pike module with, let’s say, IPTABLES would cause a block to occur in the network layer. Due to the beauty of linux’s kernel, blocks via IPTABLES would happen more efficiently.
When looking at the performance improvements of blocking sustained SIP flood attacks (>2000cps), using iptables did cause a significant reduction in CPU. The problem was getting an easy way for Kamailio to manage blocking (and unblocking) ips.
Enter iptables-api
With the http_client module, Kamailio can easily run a curl command from the Kamailio config. Using go(lang), I made a very simple api to manage a local IPTABLES chain (thanks to an IPTABLES module from CoreOS).
In a nutshell, a “block” call to the api will:
- Check if the ip is valid
- Determine if the valid ip is ipv4 or ipv6
- Add the local APIBANLOCAL chain (if needed)
- Add the ip to either iptables or ip6tables
Simple.
When Pike detects a flood, you can run the curl statement, and boom. The ip is blocked via iptables. By default we use a REJECT to help assist DDoS handling, but you can change this to a DROP if it makes you feel more warm and fuzzy.
For even more fun, you can use the HTABLE module to unblock the ip auto-magically when the HTABLE entry expires.
Kamailio Example
In this example, when a Pike check is triggered, the source IP is added to the ipban hash table (with an autoexpire of 10 minutes). A curl statement is then run to add the ip to the local chain.
When the hash table entry expires, a curl statement is run to remove the ip from the local chain.
loadmodule "http_client.so"
loadmodule "htable.so"
loadmodule "pike.so"
...
modparam("htable", "htable", "ipban=>size=8;autoexpire=600;")
...
if (!pike_check_req()) {
xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");
$sht(ipban=>$si) = 1;
http_client_query("http://localhost:8082/addip/$si", "$var(apinfo)");
exit;
}
...
event_route[htable:expired:ipban] {
xlog("mytable record expired $shtrecord(key) => $shtrecord(value)\n");
http_client_query("http://localhost:8082/removeip/$shtrecord(key)", "$var(apinfo)");
}
And with this, I bid you a great day.
For more reading, please check out:
- Kamailio Project
- iptables-api (via github)
- Massive DDoS attacks on VoIP Providers and simulated DDoS testing