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