1

I run a public UDP based service on AWS. A few weeks ago, alarms starting going off that revealed a UDP flood attack was in effect.

A few years back, as result of a previous DDOS attack, I updated the socket code to detect these types of attacks and to ignore incoming packets from any IP attempting to flood the port with bogus requests.

Fast forward to today. The new attack was an order of magnitude than anything seen previously. So I spun up a few new instances for load balancing and tweaked the code to more aggressively throttle. Crisis averted.

I also got the idea to also try collecting all the IPs of all the flooders and just block each IP via an iptables call below.

sudo iptables -A INPUT -s 1.2.3.4 -j DROP

Where 1.2.3.4 was replaced with an actual IP address. And then I had a script that would ban that would invoke this command for the 2000+ IP addresses that were involved with the flood attack based on other scripts I had run. I did this on one particular AWS instance while leaving the other instances alone. The idea being that it would be more effective to block the offending IP addresses at the firewall level rather than letting the server code itself deal with it.

The result was that CPU usage spiked way up (above 50%) on the instance with all the iptables rules. The other machines were relying on their own software code to drop flooding IPs and were at normal CPU levels. I wound up deleting the rules from this specific instance.

I would think that looking up an IP address in a table would be a cheap operation on the order of O(1) with a reasonably sized hash table. Perhaps it's linear or just the fact that iptables needs to log and do bookkeeping on each blocked packet. r perhaps there's a better way to mass block this many IPs.

What's the best way to block out 2000+ IP addresses without incurring additional CPU overhead?

2

The rules, as you wrote it, will be looked up one by one and will take time to process. What you are looking for is likely ipset.

ipset create banned-hosts hash:ip
ipset add banned-hosts 1.2.3.4
:
ipset add banned-hosts 2.4.6.8

and match on it:

iptables -A INPUT -m set --match-set banned-hosts src -j DROP
2

You are adding the IP addresses as separate rules in the chain, which means that the kernel has to go through all the rules for all the packets.

A couple of optimisations might help:

  1. Add the DROP rule to the IPTables raw table instead of the normal filter table. This means that no connection tracking entries are created for those packets, which saves resources. Use iptables -t raw -A input -s 192.168.100.100 -j DROP to add to raw table.
  2. Use the IPSet feature to match a set of IP addresses in one rule, thereby avoiding the traversal of the complete chain. Look at http://ipset.netfilter.org/ for more information.
1

there is a single solution for large lists of ips

this is

ipset

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.