Blocking Access From or to Specific Countries Using FreeBSD and Pf

In recent times, there has been an exponential increase in malicious (or simply rude) traffic from specific countries. Alternatively, sometimes we simply do not need visitors from other parts of the world accessing our server for various reasons.

On FreeBSD, this operation is very simple, and I have been using a reliable and secure system to manage it automatically for a long time. Of course, as with all geolocation blocks, there is never certainty about the result, as sometimes certain IP blocks officially belong to one country but are actually used by another, or users can resort to VPNs to bypass these types of blocks. However, it remains a valid method to filter out unwanted traffic, especially when it comes to rogue bots that do not respect the robots.txt file and bombard our machines with repeated requests, generating real DDoS attacks.

Installation of ipdbtools

First, install the ipdbtools package (http://www.freshports.org/sysutils/ipdbtools):

1
pkg install ipdbtools

Next, download the updated global lists:

1
/usr/local/bin/ipdb-update.sh

Configuring pf

Then, modify the pf configuration. To do this, add the following line at the beginning of the filtering part of your firewall configuration (/etc/pf.conf):

1
block drop log quick from <blocked_countries>

At this point, simply type:

1
service pf reload

to reload the pf configuration and start considering the values in the <blocked_countries> table.

If you do not already have a pf.conf because the only requirement was this, simply insert this line in an empty pf.conf and then run:

1
2
service pf enable
service pf start

Updating the Blocked Countries List

Next, create a file (in my case, I called it /usr/local/sbin/update_blocked_countries.sh) with content similar to the one below. Replace “CC” with the country codes you want to block. For example, to block France, Germany, and Italy, insert “FR:DE:IT”.

1
2
3
4
#!/bin/sh

/usr/local/bin/ipup -p -t CC > /var/db/blocked_countries.txt
/sbin/pfctl -t blocked_countries -T replace -f /var/db/blocked_countries.txt

Make it executable:

1
chmod a+rx /usr/local/sbin/update_blocked_countries.sh

Running the command /usr/local/sbin/update_blocked_countries.sh will show the status of the operation, for example:

314159 addresses added.

This means that the list has been generated for the inserted country codes, and pf has updated the <blocked_countries> table.

It is advisable to update the lists occasionally since IP ranges “move” from one country to another.

Automating with Cron

We can use cron to perform this task. Edit the file /etc/crontab by adding a line like:

1
55 9 * * *    root    /usr/local/bin/ipdb-update.sh > /dev/null 2>&1 && /usr/local/sbin/update_blocked_countries.sh

In this example, at 9:55 every day, the databases will be updated, lists generated, and fed to pf.

This setup will also work correctly on a read-only FreeBSD system on UFS, as described in a previous article. The only precaution in this case is to ensure the crontab runs at every boot since, on every machine restart, the contents of /var will be erased and recreated from scratch. Therefore, also add a line like:

1
@reboot    root    /usr/local/bin/ipdb-update.sh > /dev/null 2>&1 && /usr/local/sbin/update_blocked_countries.sh

Additionally, in a read-only system, you need to add a mount for tmpfs for the /usr/local/etc/ipdb/IPRanges directory in the /etc/fstab file to make it writable:

1
tmpfs /usr/local/etc/ipdb/IPRanges/     tmpfs rw 0 0

Related Content

0%