Geoip Blocking Made Simple

Geoip Blocking Made Simple

September 21, 2021

While no solution can be 100% reliable because of the way IP addresses move around, below is a simple and efficient option to blocking access to a server from specific geographic areas of the world.

After several months of watching port scans and web probing of my VPS servers it became apparent that 90% of of this type of traffic comes from 2 specific countries, Russia and China. While Fail2ban is a great tool for stopping both types of activity it became apparent that there needed to be a complimenting security implementation to simply block all IP traffic from these locations since I am not expecting or wanting any access from them anyway.

A good firewall implementation using iptables is essential to rounding out VPS security. Iptables can also block IP ranges represented in CIDR notation, for example, 192.168.0.0/16. However, even when using this format to identify blocks of IP addresses it will still require approximately 20,000 rules to be created. That number of rules to evaluate for every packet entering a server would certainly be a performance concern. While other posts show how to generate thousands of rules from a text file with IP addresses I do not really consider that to be practical solution. Hence the approach here uses a technology Linux calls ipset. With ipset the administrator basically creates an in memory hash of IP addresses and with 2 rules can block all IP’s found within the in-memory list.

First we need a list of IP’s in CIDR format for each location we want to block. A useful free source can be found here:

https://www.ip2location.com/free/visitor-blocker

Be sure and select the country and CIDR as the format. You may have to download locally and upload the list to your server.

If you haven’t already installed ipset you will need to do that now for your operating system. For example, in Debian it is a matter of running:

apt install ipset

To create a new empty list for our IP addresses in a list we will call ‘blacklist’ simple run:

ipset create blacklist nethash

Assuming our IP list we downloaded from ip2location.com is called firewall-china.txt we can now load the IP’s into the newly created list by running:

cat firewall-china.txt | awk '/^[^#]/ { print $1 }' | sudo xargs -I {} ipset add blacklist {}

The command above might take a few seconds but it will create a memory efficient hash that can be used to query incoming IP addresses and to look for matches. You can repeat the above command for other geographic locations and continue to add more IP addresses to the ‘blacklist’. Once done, all we need are a couple of firewall rules to utilize the list.

iptables -I INPUT -m set --match-set blacklist src -j DROP
iptables -I FORWARD -m set --match-set blacklist src -j DROP

At this point we have a working firewall with geoip blocking. However, this is a temporary setup. Once the server is rebooted the list and the rule will be gone. That might be good if you accidentally block yourself out of your server but once you know everything is working as you want then a way to restore the process would be good. There are posts with startup scripts for systemd that might be useful but for now I have elected to run a simple bash script after a reboot to restore the geoip blocks. ipset can also save and restore it’s database to a file but since it can load the initial input lists fast enough for my purposes I elected to rebuild the database from the lists at each startup. That way I can easily update the lists say once a month or so to pick up any changes. Here is a sample bash script that can be adapted to your needs. The file names may need tweaking or you can follow the convention I use when downloading the input files.

#!/bin/bash

# Update lists from: https://www.ip2location.com/free/visitor-blocker

echo "Creating blacklist..."
ipset -q destroy blacklist
ipset create blacklist nethash

echo "Loading Russia CIDR.."
cat firewall-russia.txt | awk '/^[^#]/ { print $1 }' | sudo xargs -I {} ipset add blacklist {}

echo "Loading China CIDR..."
cat firewall-china.txt | awk '/^[^#]/ { print $1 }' | sudo xargs -I {} ipset add blacklist {}

echo "Creating firewall rules"
iptables -I INPUT -m set --match-set blacklist src -j DROP
iptables -I FORWARD -m set --match-set blacklist src -j DROP

A call this script ipset.start. Likewise I have another script called ipset.stop as follows which disables what the start script does.

#!/bin/bash

echo "Removing firewall rules"
iptables -D INPUT -m set --match-set blacklist src -j DROP
iptables -D FORWARD -m set --match-set blacklist src -j DROP

echo "Destroying blacklist..."
ipset destroy blacklist

I have Fail2ban email me whenever an IP was blocked for suspicious activity. And I got quite a few emails on a daily basis. But since implementing the above the number of banned IP’s dropped significantly since they were already being blocked. Certainly some other hosting providers even in the US need to do a better job of watching what there customers are doing on their servers (i.e. Digital Ocean) and of course it doesn’t stop someone from using a VPN or proxy to access your server but it does cut down on some of the nonsense that system administrators have to be mindful of.