Developers Documentation

×

Warning

301 error for file:https://clearos.com/dokuwiki2/lib/exe/css.php?t=dokuwiki&tseed=82873f9c9a1f5784b951644363f20ef8

User Tools

Site Tools


Country Blocking with iptables and ipset

The purpose of this howto is to outline a a script which can be used to create a list of country-associated IP's which can be used to either block or allow access to your system. There are 4 part elements to this:

  1. Create the country list
  2. Set up a boot mechanism
  3. Create the firewall rules

Create the country list

The following script will create an ipset list of selected countries' IP addresses. Create a file, /etc/cron.monthly/country_list in in it put:

#!/bin/bash

# A list of the ISO country codes can be found at http://en.wikipedia.org/wiki/ISO_3166-1
# Countries are case insensitive for this script

ISO="at be ch cy cz de dk es fr gb gr ie it lu mt nl pt eu va sm mc je gg im"
MAXELEM=131072
#MAXELEM=524288

if [ "`lsmod | grep ip_set`" = "" ]; then
	modprobe ip_set
fi

# Destroy country-list-temp in case it exists and is populated
ipset destroy -q country-list-temp

# Make sure the new lists exist
ipset create country-list nethash maxelem $MAXELEM -exist
ipset create country-list-temp nethash maxelem $MAXELEM -exist

# Load the country list
curl -s -d country=1 --data-urlencode "country_list=$ISO" -d format_template=prefix https://ip.ludost.net/cgi/process | grep -v ^# | while read -r line
do
    ipset -A -exist country-list-temp $line
done

if [ $(ipset list country-list-temp | wc -l) -le 7 ]; then
    logger -t country-list "Update failed"
    echo 'Country List Update failed' | mail -s 'Country List Update failed' somewhere@example.com
    ipset destroy -q country-list-temp
    exit
fi

# Make the temp list current
ipset swap country-list country-list-temp

# Destroy the (now old) temp list
ipset destroy -q country-list-temp

# add some exceptions
#ipset add -exist country-list 209.90.117.194
#ipset add -exist country-list 209.90.117.196
#ipset add -exist country-list 159.203.19.178

# Create save list for loading on boot
ipset save country-list > /usr/src/ipset_country-list.save
sed -i 's/create/create -exist/g' /usr/src/ipset_country-list.save
sed -i 's/add/add -exist/g' /usr/src/ipset_country-list.save

logger -t country-list "Updated"

Notes:

  • you could put it in cron.weekly if you wanted but the list should be fairly stable so monthly updates are probably OK.
  • change the list of countries to suit your needs. A full list of country codes can be found here .
  • change the e-mail address to suit where you want the error message sent to if the update fails.

Then make the script executable and execute the script for the first time:

chmod 0755 /etc/cron.monthly/country_list
/etc/cron.monthly/country_list

It takes a couple of minutes to run. If it errors, you may need to increase the list size (MAXELEM). China and the US both produce very big lists. Oddly, increasing the number of countries blocked can reduce the list size. This can happen as it can become possible for lots of smaller IP blocks to be consolidated into fewer bigger IP blocks. ludost.net does this consolidation for you.

Boot up

In order for this to work from start up, we need to restore the last created list that the script backs up, otherwise you have to wait until the next cron.monthly run. Add the following to /etc/rc.d/rc.local:

# Load in all previously saved ipset sets
if [ "`lsmod | grep ip_set`" = "" ]; then
	modprobe ip_set
fi

for file in /usr/src/ipset_*.save ; do
	ipset restore <  $file
done

And make it executable:

chmod 0744 /etc/rc.d/rc.local

Add the firewall rules

Note the firewall rules need to be personalised to your environment. Add them to a file /etc/clearos/firewall.d/20-ipset-blocks. The could be something like:

# IPv4 only for now
#------------------

if [ "$FW_PROTO" != "ipv4" ]; then
    return 0
fi

if [ "`lsmod | grep ip_set`" = "" ]; then
	modprobe ip_set
fi

# Block country addresses (exempt permitted countries)
#
# note the  > /dev/null 2>&1 is needed for some odd reason
ipset create country-list nethash -exist  > /dev/null 2>&1
$IPTABLES -I INPUT -m conntrack --ctstate NEW -m set ! --match-set country-list src -p tcp -m multiport --dports 587,993 -j DROP
$IPTABLES -I INPUT -m conntrack --ctstate NEW -m set ! --match-set country-list src -p udp -m multiport --dports 1194 -j DROP

This example would restrict me to only be able to pick up e-mails and connect to OpenVPN from my chosen countries as these ports are open further down the INPUT chain.

An alternative rule to block anything but TCP would be:

$IPTABLES -I INPUT -m conntrack --ctstate NEW -m set ! --match-set country-list src ! -p tcp -j DROP

As an alternative to allowing OpenVPN in the normal incoming firewall then dripping OpenVPN from outside the chosen list, you could not open OpenVPN in the incoming firewall ans just use:

$IPTABLES -I INPUT -m conntrack --ctstate NEW -m set ! --match-set country-list src -p udp -m multiport --dports 1194 -j ACCEPT

Once you have created your firewall rules, restart the firewall with a:

systemctl restart firewall
content/en_us/kb_howtos_country_blocking.txt · Last modified: 2020/01/06 04:48 by nickh

https://clearos.com/dokuwiki2/lib/exe/indexer.php?id=content%3Aen_us%3Akb_howtos_country_blocking&1710849051