Country block/allow with iptables and ipset

Here is a simple way to restrict access to your server from country’s that you don’t want to be able to connect to your services. On website www.ipdeny.com you can find IP lists for specific country’s. With a simple script, you can regularly update those lists so that they are up-to-date with new addresses. In my case, I needed a way to allow some services only available from specific countries. You can also change logic a little bit and blocking only specific county. 

This will work on Linux server with installed iptables and ipset. Ipset will contain all addresses provided from ipdeny.com. 

First, if you don’t already have it, install ipset.

[root@server ~]# dnf install ipset

Then, you’ll need to create ipset array which will contain all addresses. 

ipset create allow_cc hash:net family inet hashsize 1024 maxelem 65536

Inside /root/ipset, create a script named ipset.sh and put code below in it. In variable countries, you must define all country codes that you wish to allow access from. In ROOT_DIR you can change root directory to your needs. Script will create two more directories within ROOT_DIR.

#!/bin/bash
ROOT_DIR=/root/ipset

TMP_DIR=$ROOT_DIR/tmp
IPSET_DIR=$ROOT_DIR/ipset

if [ ! -d "$ROOT_DIR" ]; then
mkdir -p $ROOT_DIR $TMP_DIR $IPSET_DIR;
fi

ALL_ZONES=$ROOT_DIR/all-zones.tar.gz
if [ -f "$ALL_ZONES" ]; then
rm -f $ALL_ZONES
fi

wget -O $ALL_ZONES --no-check-certificate http://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz
tar -xzvf $ALL_ZONES -C $TMP_DIR

countries="si us"

echo -n > $IPSET_DIR/allowed-cc.zone
for cn in $countries; do
cat $TMP_DIR/$cn.zone >> $IPSET_DIR/allowed-cc.zone
done

for range in $(cat $IPSET_DIR/allowed-cc.zone); do
echo "Adding $range to CC...";
ipset add allow_cc $range;
done

Make this script executable and run it, so that it will fill addressees in ipset array.

root@server:~/ipset# chmod +x ipset.sh
root@server:~/ipset# ./ipset.sh 
URL transformed to HTTPS due to an HSTS policy
--2022-05-12 13:22:44--  https://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz
Resolving www.ipdeny.com (www.ipdeny.com)... 149.28.239.174, 2001:19f0:5:40e6:5400:2ff:fe71:c357
Connecting to www.ipdeny.com (www.ipdeny.com)|149.28.239.174|:443... connected.
. . .

You can check this list with command ipset -L. It should be propagated with addressees.

root@server:~/ipset# ipset -L | head -20
Name: allow_cc
Type: hash:net
Revision: 6
Header: family inet hashsize 32768 maxelem 65536
Size in memory: 1900312
References: 10
Number of entries: 63899
Members:
194.169.199.0/24
217.151.96.0/20
185.102.68.0/22
192.109.202.0/24
192.103.32.0/21
45.145.44.0/22
46.244.0.0/19
178.22.200.0/21
156.67.24.0/21
. . .

In your iptables configuration, you must add a rule that will allow access to a specific port only from addresses that are stored in ipset’s allow_cc array. For example, allow SSH only from allowed country’s:
. . .
-A INPUT -i lo -j ACCEPT
-A INPUT -d 127.0.0.0/8 -i lo -j REJECT –reject-with icmp-port-unreachable
-A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEP
-A INPUT -p tcp -m set –match-set allow_cc src -m tcp –dport 22 -j ACCEPT
. . .

Create cron job that will download fresh lists with addressees and update ipset array. For example:

0 1 * * * /bin/bash /root/ipset/ipset.sh > /var/log/country-ipset.log

That should do it. You can change logic according to your needs.

Thank you Dalibor 🙂

4 Comments

Got Something To Say:

Your email address will not be published. Required fields are marked *

*

I accept the Privacy Policy

This site uses Akismet to reduce spam. Learn how your comment data is processed.

-bash: /root/ipset#: No such file or directory

tnx for ur code. in bash script codes i found a problem.

in line 7 u need to remove from “if” condition.

© 2024 geegkytuts.net
Hosted by SIEL


About author