You can block traffic from specific countries using iptables by leveraging GeoIP information, which maps IP addresses to geographical locations.
Let’s see it in action. Imagine you’re running a web server and want to block all incoming traffic from Russia.
First, you’ll need to install the necessary tools:
sudo apt update
sudo apt install iptables-persistent geoip-database libtext-csv-perl
Next, you need to populate iptables with GeoIP rules. The xtables-addons package provides modules that can do this. If you don’t have it, install it:
sudo apt install xtables-addons-common
Now, let’s create a rule to block traffic from Russia. We’ll use the geoip match module. The country code for Russia is RU.
sudo iptables -A INPUT -p tcp --dport 80 -m geoip --src-cc RU -j DROP
sudo iptables -A INPUT -p tcp --dport 443 -m geoip --src-cc RU -j DROP
This command adds two rules to the INPUT chain of your iptables firewall.
The first rule targets TCP traffic on port 80 (HTTP), and the second targets TCP traffic on port 443 (HTTPS).
The -m geoip --src-cc RU part tells iptables to only match packets where the source IP address belongs to the country code RU (Russia).
-j DROP instructs iptables to silently discard any matching packets.
To make these rules persistent across reboots, you can use iptables-persistent:
sudo netfilter-persistent save
The geoip module in iptables works by consulting a local database that maps IP address ranges to country codes. When a packet arrives, the module checks the source IP against this database. If a match is found for the specified country code, the specified action (in this case, DROP) is performed. This is significantly more efficient than trying to maintain manual IP blocklists for entire countries.
You can verify your rules are loaded with:
sudo iptables -L INPUT -v -n --line-numbers
You should see lines similar to this:
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
...
0 0 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 geoip:RU
0 0 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 geoip:RU
...
If you wanted to block all traffic, not just HTTP/S, you would omit the port specification:
sudo iptables -A INPUT -m geoip --src-cc RU -j DROP
sudo netfilter-persistent save
The geoip module relies on an up-to-date database. The geoip-database package is usually updated by your system’s package manager, but you can also manually update it using geoupdate if you have a commercial license or if you’re using a different source.
One thing that often trips people up is that the GeoIP database is not perfectly granular. While it’s generally accurate for entire countries, there can be edge cases or specific IP blocks that might be misclassified or not yet updated. For instance, a business with a global IP allocation might appear to be from a different country than its physical location.
The next step after implementing country-level blocking is often to consider blocking specific IP ranges or subnets that are known sources of abuse, which can be achieved with more granular iptables rules or by integrating with threat intelligence feeds.