OpenWRT Geofencing
Geofencing refers to allowing or blocking a connection based on country of origin. Unfortunately, OpenWRT / LEDE does not support geofencing out of the box.
The way I’ve worked around this is described below.
Shell script
I created a shell script /root/bin/ipset-update.sh
to pull Maxmind Geolite2 database periodically, and use that to populate an ipset set which I can then reference from iptables.
The shell script is based on this one with a few tweaks for Openwrt: change bash
to ash
and change the paths of some of the utilities ipset
, curl
etc
The shell script takes 2 arguments: the ipset name to create/update, and the country name to pull out of the Geolite database.
If I call it like this: /root/bin/ipset-update.sh australia Australia
then the resulting ipsets are australia4
and australia6
(ipv4 + ipv6 respectively)
Cronjob
The Maxmind database changes over time as, so it’s important to update it on a periodic basis. I installed a cronjob as root
user to run the script once per week:
0 0 * * sun /root/bin/ipset-update.sh australia Australia
Iptables
From the command line, you can use the new ipset like so:
iptables -A INPUT -p tcp -m tcp --dport 22 -m set --match-set australia4 src -j ACCEPT
ip6tables -A INPUT -p tcp -m tcp --dport 22 -m set --match-set australia6 src -j ACCEPT
I prefer to use the Luci interface for configuring the firewall. While it doesn’t support setting an ipset target directly it does allow you to specify arbitrary iptables switches. When creating a port forwarding or traffic rule that requires geofencing, I put the following in the Extra arguments:
section: -m set --match-set australia4 src
.
As the interface only allows one ipset to be specified per rule, you can either create multiple rules for multiple countries, or create one ipset that combines multiple countries into a group.
Survive reboot
At boot time rules that use ipsets will fail to load as the ipsets will not exist at that point. To work around that I put the following lines into the /etc/rc.local
:
/root/bin/ipset-update.sh australia Australia
/etc/init.d/firewall restart