Limiting concurrent connections per IP

After playing around with ab (apache benchmark) in a test server, I’ve found particulary annoying that with this simple tool I could break this test server.

The problem is that a server have a limitate number of resources (CPU/RAM) and for that reason is not possible to accept too many concurrent requests from the same source. This is the base of DoS attacks: saturating the target machine with many requests, so much so that it cannot respond (or it can do it realy slowly) to legitimate traffic.

What ab does is to open a new TCP connection every time he makes a request and each of them is a new thread of apache which consumes CPU and RAM; after an X number of concurrent connections, the server becomes overloaded with a consequent impossibility to take back it’s control (it needs a forced reboot).

To mitigate this annoying situations there are many tutorials on the net but many of them are simply old, bad documented or simply does not do the work they should do.

Many pages report iptable rules like that:

iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 15 --connlimit-mask 32 -j REJECT --reject-with tcp-reset

but this rule simply won’t work for this case because it’s about packets, not connections.

Other pages which talk about apache’s modules (like mod_security) are really far to be really useful.

At the end, what worked for me is the great article written by Alessio Rocchi on his Mitigate DDoS with iptables and ipt_recent. He describe line by line what happens and after a little bit of trial and error, I’ve also found what works for my test case:

#!/bin/bash
iptables -F
iptables -X
iptables -N ATTACKED
iptables -N ATTK_CHECK
iptables -N SYN_FLOOD
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
iptables -A INPUT -f -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
iptables -A INPUT -p tcp --syn -j SYN_FLOOD
iptables -A SYN_FLOOD -p tcp --syn -m hashlimit --hashlimit 2/sec --hashlimit-burst 3 --hashlimit-htable-expire 3600 --hashlimit-mode srcip  --hashlimit-name synflood -j ACCEPT
iptables -A SYN_FLOOD -j ATTK_CHECK
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 80 -m recent --update --seconds 1800 --name BANNED --rsource -j DROP
iptables -A INPUT -p tcp -m tcp --dport 80 -m state --state NEW -j ATTK_CHECK
iptables -A ATTACKED -m limit --limit 5/min -j LOG --log-prefix "IPTABLES (Rule ATTACKED): " --log-level 7
iptables -A ATTACKED -m recent --set --name BANNED --rsource -j DROP
iptables -A ATTK_CHECK -m recent --set --name ATTK
iptables -A ATTK_CHECK -m recent --update --seconds 120 --hitcount 20 --name ATTK --rsource -j ATTACKED
iptables -A ATTK_CHECK -m recent --update --seconds 60 --hitcount 6 --name ATTK --rsource -j ATTACKED
iptables -A ATTK_CHECK -j ACCEPT

The really important rule is where the hashlimit sets the max number of concurrent connections in each second for each ip (thanks to –hashlimit-mode srcip).
I’ve put it at 2/sec because of the small test server I was using but I think you can adjust it for your needs ;)

In order to use Disqus to comment out you have to accept the use of third-party cookies.