I am using iptables' rate-limit module to prevent DoS attack (I know it cannot stop a full scale DDoS but at least it can help with smaller attacks).

In my rules I have something like:

/sbin/iptables -A INPUT -p TCP -m state --state NEW -d xx.xxx.xxx.xx --dport 80 -m limit --limit 20/minute --limit-burst 20 -j ACCEPT

It works well until last night when someone was hitting my port 80 non-stop. The connection was being dropped per the rule alright (as shown in the log). However, it also makes the server unavailable to other legitimate users as well.

I don't understand why it happened like that. I thought it would not affect any other users besides the one that is flooding the server.

Is it because iptables was overwhelmed?

Any feedback would be greatly appreciated.

Thank you!


Your rule does not appear to specify any particular origin. After accepting 20 NEW connections in a minute, it stops accepting NEW connections.

You need to use the recent module in order for iptables to remember where the connections are coming from and blocking people that connect too fast from the same address. This takes two rules: one for iptables to "learn" the address, and then one for iptables to see how many times that address has hit the server in the specified time:

/sbin/iptables -A INPUT -p TCP -m state --state NEW -d xx.xxx.xxx.xx --dport 80 -m recent --set
/sbin/iptables -A INPUT -p TCP -m state --state NEW -d xx.xxx.xxx.xx --dport 80 -m recent --update --seconds 60 --hitcount 20 -j DROP

This article goes into more details.

| improve this answer | |
  • I was playing around with the Recent module and wrote a PHP script using cURL to hit my server 10 times in a loop. I was expecting the connection be dropped somewhere in the loop but they always go through all 10 iterations. Only until I re-run the PHP script again is the connection dropped by iptables. I guess it is because we are only tracking NEW connections? I tried to use NEW,ESTABLISHED and the result was the same. How do I block the connections in a loop in this case? Thanks. – TopQ Sep 13 '11 at 18:18
  • @TopQ Both your script and mine are trying to block connections after 20 connections in 60 seconds. Make your script loop past 20 and it should stop accepting connections. Note that you do NOT want to drop ESTABLISHED packets, since this would cut people off while they're downloading or uploading files or data. – DerfK Sep 13 '11 at 19:43
  • I actually use --seconds 20 --hitcount 3 so 10 iterations should exceed it. Thanks. – TopQ Sep 13 '11 at 20:29
  • @TopQ are you using php to execute the curl binary, or are you using the curl_init() etc functions, because the PHP curl module will keep the same connection open between requests unless you curl_close() between them or possibly use the CURLOPT_FORBID_REUSE option. – DerfK Sep 13 '11 at 23:15
  • I am using cURL functions curl_exec() in the loop and only call curl_close() at the end. It is very likely that it is using the same connection and that is the very reason for my original comment: I want to drop those requests on the same connection. Thank you. – TopQ Sep 14 '11 at 0:04

It cuts off traffic for legitimate users as well because you haven't specified a source ip address to apply that rule to. If you changed the rule to have a source address, you would then be RateLimit'ing that specific address. As your rule stands now, that RateLimit is in effect for all addresses.

I have RateLimit setup to limit all IPs except those specified by certain rules. My configuration is as follows:

  • -I INPUT -m tcp -p tcp --dport 80 -d xx.xxx.xx.xx -j ACCEPT

  • -A INPUT -m tcp -p tcp --dport 80 -m hashlimit --hashlimit-upto 400/min --hashlimit-burst 500 --hashlimit-mode srcip --hashlimit-name ratelimit -j ACCEPT

  • -A INPUT -p tcp -m tcp --dport 80 -j RateLimit

I then have a bunch of rules such as

  • -A RateLimit -s xx.xxx.xx.x -j ACCEPT

This will allow communications on port 80, with a connection limit and burst configured, and limit by source ip (the --hashlimit-mode srcip ). IPs will be checked for existence in the RateLimit has ( --hashlimit-name ratelimit ).

Perhaps something like that is more what you are looking for?

| improve this answer | |
  • DerfK's answer is probably a bit more helpful in this situation, as you likely don't know ahead of time which IPs you want (in)(ex)cluded from the RateLimit. However, I know exactly what I need to RateLimit, hence the different between my solution and DerfK's. – Kendall Sep 12 '11 at 18:49
  • Thanks!! Now I kind of understand the differences between limit, hashlimit and recent modules. I thought they served the same purposes. From reading your answer it sounds like both hashlimit and recent keep track of the origin IPs while limit doesn't. I am going to try recent module and hopefully my version of iptables has it... – TopQ Sep 12 '11 at 19:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.