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 🙂
-bash: /root/ipset#: No such file or directory
You must create ipset directory 🙂
tnx for ur code. in bash script codes i found a problem.
in line 7 u need to remove from “if” condition.
No problem, and thank you for notice