country blocking with iptables and ipset on Debian Wheezy
I've gotten a lot of help from the folks on this board, so I'm posting this to describe my method for blocking incoming traffic from specific countries using iptables and ipset on Debian Wheezy in the hope that it will be useful to someone. The easiest way to describe it is to walk through setting it up.
Support for ipset is now in the kernel in Wheezy, so now it's just an apt-get away. We also need a perl module for aggregating the CIDR zone files:
apt-get install ipset libnet-ip-perl
I use the country zone files published by the kind folks at
mkdir /usr/local/blockip
cd /usr/local/blockip
mkdir allzones
mkdir blockzones
wget http://www.zwitterion.org/software/aggregate-cidr-addresses/aggregate-cidr-addresses
chmod 744 aggregate-cidr-addresses
wget -O /usr/local/blockip/allzones/all-zones.tar.gz http://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz
tar -C /usr/local/blockip/allzones/ -xzf /usr/local/blockip/allzones/all-zones.tar.gz
Now create symlinks in the /blockzones directory for the specific countries you want to block (apologies to our friends in China, Russia, and Ukraine…):
cd blockzones
ln -s ../allzones/cn.zone
ln -s ../allzones/ru.zone
ln -s ../allzones/ua.zone
cd ..
Create the set, then run the selected zones through aggregate-cidr-addresses and add them to the set:
ipset create countryset nethash
for i in $(cat /usr/local/blockip/blockzones/*.zone | /usr/local/blockip/aggregate-cidr-addresses); do ipset add countryset $i; done
check the set with "ipset list -t" if you want to verify your work, then set up an iptables rule to drop traffic from addresses in the set:
iptables -A INPUT -p tcp -m set --match-set countryset src -j DROP
That's it. If you create more sym links and want to update the set in-place, you can create a temporary set, swap it with the active set, and delete the temporary one thusly:
ipset create tempset
for i in $(cat /usr/local/blockip/blockzones/*.zone | /usr/local/blockip/aggregate-cidr-addresses); do ipset add tempset $i; done
ipset swap countryset tempset
ipset destroy tempset
Here's a script that I run from /etc/network/interfaces (" pre-up /usr/local/blockip/countryblock.sh") to enable on startup:
#!/bin/bash
basedir="/usr/local/blockip" ;
/usr/sbin/ipset create countryset nethash ;
for i in $(cat $basedir/blockzones/*.zone | $basedir/aggregate-cidr-addresses); do /usr/sbin/ipset add countryset $i ; done ;
/sbin/iptables -A INPUT -p tcp -m set --match-set countryset src -j DROP ;
And here's a script to update the ipdeny zone files; I run it from cron weekly:
#!/bin/bash
basedir="/usr/local/blockip" ;
[ -e $basedir/allzones/all-zones.tar.gz ] && mv $basedir/allzones/all-zones.tar.gz $basedir/allzones/all-zones.tar.old ;
wget -O $basedir/allzones/all-zones.tar.gz http://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz ;
tar -C /usr/local/blockip/allzones/ -xzf /usr/local/blockip/allzones/all-zones.tar.gz
ipset create tempset nethash ;
for i in $(cat $basedir/blockzones/*.zone | $basedir/aggregate-cidr-addresses); do ipset add tempset $i ; done ;
ipset swap countryset tempset ;
ipset destroy tempset ;
ipset list -terse ;
exit ;
I imagine the same method could be used to block outbound connection attempts too. I will appreciate your comments.
Regards,
-Bart
3 Replies
@bartman:
Hi all,
That's it. If you create more sym links and want to update the set in-place, you can create a temporary set, swap it with the active set, and delete the temporary one thusly:
ipset create tempset for i in $(cat /usr/local/blockip/blockzones/*.zone | /usr/local/blockip/aggregate-cidr-addresses); do ipset add tempset $i; done ipset swap countryset tempset ipset destroy tempset
I imagine the same method could be used to block outbound connection attempts too. I will appreciate your comments.
Regards,
-Bart
Excellent tutorial / how to!
However, you have a mistake in it. I thought it was a typo but seeing you do it 3 times in a row I thought I would comment on it as people using it will just end up in empty sets.
The man says, "ipset swap from-setname to-setname". Now your ipset swap countryset tempest means that:
1. You create your new tempest.
2. You swap and put all your entries from your old countryset to your new tempest. That is you erase all the new entries in your new tempest by replacing them with your old countryset entries.
3. Then you destroy your tempest.
Thus your countryset remains the same all the time and never changes.
The correct swap would be:
ipset swap tempset countryset
Thus all your new entries created in your new tempest would go to your countryset. Then you may safely destroy your tempest.
Good luck!
@klaipedaville:
2. You swap and put all your entries from your old countryset to your new tempest. That is you erase all the new entries in your new tempest by replacing them with your old countryset entries.
3. Then you destroy your tempest.
Thus your countryset remains the same all the time and never changes.
That's not what the manpage says:
w, swap SETNAME-FROM SETNAME-TO
Swap the content of two sets, or in another words, exchange the
name of two sets. The referred sets must exist and identical
type of sets can be swapped only.
So "ipset swap a b" and "ipset swap b a" should do the same thing.
@sweh:
@klaipedaville:2. You swap and put all your entries from your old countryset to your new tempest. That is you erase all the new entries in your new tempest by replacing them with your old countryset entries.
3. Then you destroy your tempest.
Thus your countryset remains the same all the time and never changes.
That's not what the manpage says:w, swap SETNAME-FROM SETNAME-TO Swap the content of two sets, or in another words, exchange the name of two sets. The referred sets must exist and identical type of sets can be swapped only.
So "ipset swap a b" and "ipset swap b a" should do the same thing.
Well, my man says exactly what I said. From a to b only. The other way around does it the other way around yway around does it the