Introduction
What would you do when you want to allow access only to specific countries to access content on your server? Actually there are many ways to do it, like by installing application, using mod_geoip with Apache, etc.But all that isn't global, i.e. if you use Apache to block ips, other ports will be still open to the blocked countries. It might be global in an exceptional case if you installed an application that sits listening to all connections something like a firewall.
But what's the guarantee that it will not be a bloat or extra load on the system? There's no guarantee about it.
So here we have something nice, different, trustable, easy to use and lightweight, IPSets in combination with IPTables.
What is IPSet?
IPSet basically allows you to store multiple IP addresses and/or ports in a table and match across all of them at once. The table seeks are much faster than using individual IPTables rules.IPSet framework is included in 2.4.x and 2.6.x kernels by default, but the utility with which it has to be managed has to be installed separately. I have a no clear idea if an distributions have packages for IPSet.
Some features of IPSets
- Store multiple IP addresses or ports in a table and match against it using iptables at once without much performance overhead.
- Dynamically update the IP addresses or ports in the table, without changing the rules in iptables, again low performance penalty.
- Express multiple IP addresses and ports in one single iptables rule, that is, with one single rule, you can match against a million IPs (just an example, there can be even more).
Installing IPSet
You will need the source code for the current kernel you are running. It is usually available as a kernel-headers package. Varies from distribution to distribution. In most cases the kernel source code is found under /usr/src/linux-<version> which is easier to access as /usr/src/linux-$(uname -r) at the shell, because you don't have to type the version. At the time of writing this, there are two versions available for ipset at http://ipset.netfilter.org/install.html.We will be using ipset 4.5 which is for kernels >= 2.6.16 and >= 2.4.36.
First extract the ipset-4.5.tar.gz and change directory to ipset-4.5:
> tar -xf ipset-4.5.tar.gz
> cd ipset-4.5
Assuming you have the kernel source code available at /usr/src/linux-$(uname -r), issue the following command to compile ipset:
> make KERNEL_DIR=/usr/src/$(uname -r) IP_NF_SET_MAX=256 IP_NF_SET_HASHSIZE=1024
IP_NF_SET_MAX controls the maximum number of IPsets permissible and IP_NF_SET_HASHSIZE sets the default size for hash maps. The default values are used in the above command for illustration, the same values are taken by make even if you don't specify them.Now to install just run sudo make install or su -c 'make install' if you are running as a user or simply make install if you are running as root:
> sudo make install / su -c 'make install' / make install
If you don't get any errors, installation is complete
Using IPSet to block IPs by country
As the title says, our objective is to block IPs belonging to certain countries. In this article I'll consider China (cn) and Russia (ru) to be blocked.
Creating IPsets and Adding IPs to Them
Now that ipset has been installed, let us create the set named `countries'. Please note that all the following commands are to be executed as root, you may use sudo or su -c as applicable.
# ipset -N countries nethash
This creates a new ipset named `country' of type `nethash'. There are different types of ipsets viz. ipmap, macipmap, portmap, iphash, nethash, ipporthash, ipportiphash, ipportnethash, iptree, iptreemap, setlist.Each set has its own purpose and the use of each set can be found in ipset( man page, also available at http://ipset.netfilter.org/ipset.man.html.
Here we are using `nethash' set type because the IP database at ipdeny.com which we will be using to block IPs provides IPs in IP-Address/CIDR-length form which is supported only by `nethash'.
Now that we have created the set named `countries', we can start adding IP Address to the set. As I said earlier, in this article, blocking China and Russia are taken as an example. No offense meant please.
The IPs existing in China and Russia are found at http://www.ipdeny.com/ipblocks/data/countries/cn.zone and http://www.ipdeny.com/ipblocks/data/countries/ru.zone respectively. To add all the IPs from these two zones, we'll be using a simple bash-for loop coupled along with wget to retrieve to the zone files.
# for IP in $(wget -O - http://www.ipdeny.com/ipblocks/data/countries/{cn,ru}.zone)
> do
> ipset -A countries $IP
> done
This will add all the IPs in the CN and RU zones to the IPset. If you are adding more zones to your block list, please note that the nethash set can store up to 65535 addresses. If you exceed the limit, you must add the remaining in another set, and so on. The total number of IPs in China and Russia zones combinedMatching against the IPSet(s) in IPTables
The IPs which we want to block, have been added to the sets. So now let us add rules in IPTables and block those IPs!
We will be applying the filter on INPUT chain, to block all connections from CN and RU.
So here's how you do it-
# iptables -A INPUT -m set --match-set countries src -j DROP
Now connections from all IPs that exist in the set `countries' that is CN & RU as we created the set above will be blocked, unless you have any other rule before this rule to permit connections.In case you exceeded the 65535 address limit and you have multiple sets to match with, for example you named the first set `countries', the second one `countries1' and so on, you can add multiple -m set --match-set options to iptables as illustrated below:
# iptables -A INPUT -m set --match-set countries -m set --match-set countries1 -m set --match-set countries2 -j DROP
So, enjoy, secure your server better Questions/Feedback if any can be posted as comments or mailed to me using the contact form.http://www.itech7.com/Firewall/Blocking-IPs-by-country-using-IPSet-and-IPTables.html