So a few of the servers I manage are being slammed by traffic from China when the sites themselves would have utterly no appeal to anyone in China in any way. To make things worse, lots of unwanted brute force hacking and DDoS attempts are coming from China as well. So while I have Fail2Ban installed to block some of this traffic, I’d really like to just shut off any/all traffic from China—for the time being—to keep these servers running stably and happily.

I have read about how to enable GeoIP support for IPTables and have attempted to follow solutions such as the one presented here, but it doesn’t seem to work on my Ubuntu 12.04.5 (LTS) servers no matter what advice I seem to follow.

One choice I have is to bite the bullet and just upgrade these servers to Ubuntu 14.04, but that opens up a whole can of worms. Past any issues I am having with getting GeoIP filtering up and running, these servers are rock solid and perform quite well. An upgrade to 14.04 would just throw the specter of potential instability into them mix, and I have no time for that; the decision was made to stay on 12.04 since it’s stable and well supported until 2017 so I’m going to cross that bridge when I come to it.

So is there any way I can get IPTables on Ubuntu 12.04 to filter based on geolocation without having to jump through too many system package install hoops?

up vote 2 down vote accepted

Turns out I don’t have to completely reinvent the wheel to get some sort of GeoIP support mixed in with IPTables. Just using IPSet with a copy of MaxMind’s GeoIP Country database in CSV format—in addition to one simple IPTables rule—is all you need to get this up and running in Ubuntu 12.04.5 (LTS).

A side note, but some online tutorials that explain a procedure like this recommend using web-based country zone files like the ones that come from IPDeny’s website:

While this technically works, I don’t like the idea of having to be so reliant on an external website’s data like this. What if I want to create an automated scripting process to manage this and the IPDeny site goes down or is hacked? Whose IPs would I be blocking.

That’s why I am preferring to use the MaxMind GeoIP Country database in CSV format on my servers. I can always fetch a new copy of that database if I need updates and even if their site is down I always have a copy of the database on my servers. And since that database contains all the countries in the world, I can always easily add more countries to the IP set by using the country’s two letter ISO 3166-1 country code.

Anyway, here are the steps I took to get this done with IPSet and the MaxMind GeoIP Country database.

1. Install IPSet.

First, install IPSet like this.

sudo aptitude install ipset

Once that is installed, create a BANNED_RANGES IP set like this:

sudo ipset create BANNED_RANGES hash:net

2. Get a copy of the MaxMind GeoIP Country database in CSV format.

The next key to this is to get a copy of the MaxMind GeoIP Country database in CSV format installed on the server. My steps are as follows:

curl -O -L

Now just UNZip that archive:

unzip -o -q -d .

3. Filter and import a country specific IPSet config like this.

Now we will use Awk to filter out the China specific IP ranges into an IPSet config file:

awk -F "," -v COUNTRY_CODE=CN -v IPSET_TABLE=BANNED_RANGES} '$5 ~ COUNTRY_CODE { gsub(/"/, "", $1); gsub(/"/, "", $2); print "add "IPSET_TABLE" "$1"-"$2; }' /usr/local/share/GeoIP/GeoIPCountryWhois.csv >> ipset.BANNED_RANGES.conf

That will create an IPSet config file named ipset.BANNED_RANGES.conf that can then be imported into IPSet like this:

sudo ipset restore < ipset.BANNED_RANGES.conf

And you can then check the items in that set with this command:

sudo ipset -l BANNED_RANGES | more

4. Make IPTables aware of the IPSet.

Now the final step that brings it all together is to insert a simple rule into IPTables like this:

sudo iptables -I INPUT -p tcp -m set --match-set BANNED_RANGES src -j REJECT

Once that’s done, IPTables now knows that any IP addresses or ranges added to the BANNED_RANGES set will simply be rejected via REJECT.

If you somehow want to get rid of that rule later on you can run this command:

sudo iptables -D INPUT -p tcp -m set --match-set BANNED_RANGES src -j REJECT

But to me that’s a tad messy. A cleaner way to handle a case like this is to just flush all of the IP data out of the BANNED_RANGES set like this:

sudo ipset flush BANNED_RANGES

By doing this you can have that IPTables rule in place and not have to do anything else but flush the data out of BANNED_RANGES. Makes it nicer/easier to update the addresses or ranges if you want to ever add or remove IP addresses or ranges from that set.

  • 1
    wow. this answer would really deserve more upvotes. – Gábor Dani Feb 22 at 21:41

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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