Solved Seeking suggestions for IPv4 Geo-blocking

obsigna

Profile disabled
I would like to restrict access to one of my websites, hosted on FreeBSD 10.3, to clients from two countries only, Brazil and Germany. What is the most effective and effortless way to achieve this objective. I am most comfortable with IPFW.
 
Well, the IPFW stuff is the easy bit. Get your list of CIDR netblocks into a IPFW table, then allow/deny based on matching against the table. One thing to note is that doing it in IPFW is a very user-unfriendly way of doing things, as denied people see a connection failure without any explanation. The user-friendly way of doing it is inside your web application, allowing you to present a friendly failure page.

The hard part is getting a reliable list of the netblocks, and keeping them up to date. Geo-location of IP is not something which is easy to do with certainty, and something which was never intended to be easy to do in terms of the design of IP. It is not at all unusual for you to find things like a netblock which is registered to an organisation with a German contact address (which is where the administrators happen to sit), but actually used by a different part of the same organisation in the UK (and connected to transit ISPs in the UK), for example. Additionally, many geo-location services seem to get the location of my personal netblock quite wrong (to a completely unrelated place in a different country), despite it having accurate whois information. On top of that, the mapping between IP addresses and physical location is in a constant state of flux, either due to dynamic addressing or just the routine churn of customers within an ISP.
 
The hard part is getting a reliable list of the netblocks, and keeping them up to date. Geo-location of IP is not something which is easy to do with certainty, and something which was never intended to be easy to do in terms of the design of IP. It is not at all unusual for you to find things like a netblock which is registered to an organisation with a German contact address (which is where the administrators happen to sit), but actually used by a different part of the same organisation in the UK (and connected to transit ISPs in the UK), for example. Additionally, many geo-location services seem to get the location of my personal netblock quite wrong (to a completely unrelated place in a different country), despite it having accurate whois information. On top of that, the mapping between IP addresses and physical location is in a constant state of flux, either due to dynamic addressing or just the routine churn of customers within an ISP.
It gets even funnier if use an IPv6 broker like HE. My IPv4 address is in the Netherlands, my IPv6 address is in the US :D
 
In the meantime I got it working.

I wrote a shell script for weekly downloading the delegation statistics files from the 5 RIR's (AFRINIC, APNIC, ARIN, LACNIC, RIPENCC). I wrote a tiny C tool for consolidating the IP ranges in said files by combining adjacent ranges having the same country code and preventing any possible overlaps. The result is written out into a binary file containing the sorted address ranges with the respective country codes. This file is read in to a totally balanced binary search tree by a divert(4) type filter daemon that I have written in C, and that responds on a respective ipfw(8) divert rule:

ipfw add 80 divert 8669 tcp from any to me dst-port 80,443 in recv xn0 setup

The search tree contains about 85000 IP ranges, and the mere lookup of a source IP address in the BST takes only apprx. 25 nanoseconds on an AWS EC2 micro instance -- the whole divert cycle takes a bit longer, of course, but should still be way faster than any other geo-blocking solution on the application layer.

I named the daemon geod and it is started in a similar way like natd by an rc script. The countries which are allowed or denied are defined by passing the respective country codes as command line arguments to geod.
 
I just uploaded my IPv4 Geo-blocking solution by the way of a ipfw divert filter daemon as a self contained project to GitHub.

https://github.com/cyclaero/ipdb

The Readme:
Code:
IPv4 Geo-Location database tools and ipfw divert filter daemon for FreeBSD

This project provides all the tools for IPv4 Geo-blocking at the firewall level with ipfw on FreeBSD.

Quick start

1. Download the ipdb project directory from GitHub, and cd into the directory
   $ cd ~/install/ipdb


2. run make
   $ make


3. as user root, install the tools and the ipfw divert filter daemon:
   $ sudo make install clean

or # make install clean

   the following tools and files will be created and/or installed into /usr/local/bin or /usr/local/etc/rc.d
   - ipdb-update.sh    # a shell script file for updateing the geoip database by
                       # downloading the latest delegation statistics files of the 5 RIR's.

   - ipdb              # a tool for consoliting the IPv4 ranges from statistics file into
                       # a sorted binary file suitable for direct reading it into a
                       # completely balanced binary search tree be the lookup tool and
                       # and the ipfw divert filter daemon.

   - geoip             # a tool for manually looking up an IPv4 address on the command line.

   - geod              # the ipfw divert filter daemon.
   - geod.rc           # the rc script of geod, will be copied to /usr/local/etc/rc.d/geod


4. First download the delegation statistic files of the 5 Regional Internet Registries (RIR's), i.e.:
   AFRINIC, APNIC, ARIN, LACNIC, RIPENCC. In theory all the RIR's should mirror the files of each other,
   in practice only the mirrors of the Asia Pacific, the Latin America and the European RIR's are useful.

   Choose one of the three useful mirror sites, depending on where you are located:
   - ftp.apnic.net    # Asia Pacific
   - ftp.lacnic.net   # Latin America
   - ftp.ripencc.net  # Europe and Eurasia

   Start the ipdb-update.sh shell script as user root, passing (n)one of the above mirror ftp domains
   as the commandline parameter. RIPENCC is the default mirror, and that doamin may be omitted.

     # ipdb-update.sh ftp.apnic.net

  This will download teh statistic files together with the MD5 verification hashes into:
  /usr/local/etc/ipdb/IPRanges/. Said directory will becreated if it does not exit. If the
  downloads went smooth, the script will start the ipdb tool in order to generate right in
  the same go the binary file with the consolidated IPv4 ranges.

  Later, you may want to put above command into a weekly cron job.


5. Check whether the database is ready by looking up some IPv4 addresses using the geoip tool.

   $ geoip 62.175.157.33
   62.175.157.33 in 62.174.0.0-62.175.255.255 in ES

   $ geoip 141.33.17.2
   141.33.17.2 in 141.12.0.0-141.80.255.255 in DE

   $ geoip 99.67.80.80
   99.67.80.80 in 98.160.0.0-99.191.255.255 in US

   $ geoip 192.168.1.1
   192.168.1.1 not found


6. If not already done, activate ipfw.


7. In addtion to the ipfw modules, the ipdivert kernel module needs to be loaded.
   WARNING: Do this only after ipfw is setup and running, otherwise it may happen
            that you inadvertently lock out yourself by the following commands.

   # echo 'ipdivert_load="YES"' >> /boot/loader.conf
   # kldload ipdivert.ko


8. Add the lines for starting the geo-blocking ipfw divert filter daemon to /etc/rc.conf

   # echo 'geod_load="YES"'

   Configuration examples (use either the -a or the -d flag into one geod_flags line in /etc/rc.conf):

   - Allow all diverted packets from Germany, Brazil and the US, and deny everything else:
   # echo 'geod_flags="-a DE:BR:US"'

   - Deny all diverted packets from North Korea, Turkey and Great Britain, and allow everything else:
   # echo 'geod_flags="-d KO:TR:GB"'

   - You may add any number of capital letter ISO country codes separated by colons.

   Start geod:
   # service geod start


9. Add the geod divert rule to your ipfw rule set:

Examples:

TCP only filter
   ipfw add 70 divert 8669 tcp from any to any 80,443 in recv WAN_if setup

TCP and UDP filter
   ipfw add 70 divert 8669 ip4 from any to any 53,80,443,500,587,4500 in recv WAN_if


Done.
 
Back
Top