ipfw divert filter for IPv4 geo-blocking

Dr. Rolf Jansen rj at obsigna.com
Tue Jul 26 19:06:25 UTC 2016


> Am 26.07.2016 um 13:23 schrieb Julian Elischer <julian at freebsd.org>:
> On 26/07/2016 1:41 AM, Dr. Rolf Jansen wrote:
>> Once a week, the IP ranges are compiled from original sources into a binary sorted table, containing as of today 83162 consolidated range/cc pairs. On starting-up, the divert daemon reads the binary file in one block and stores the ranges into a totally balanced binary search tree. Looking-up a country code for a given IPv4 address in the BST takes on average 20 nanoseconds on an AWS-EC2 micro instance. I don't know the overhead of diverting, though. I guess this may be one or two orders of magnitudes higher. Even though, I won't see any performance issues.
> 
> yes the diversion to user space is not a fast operation. When we wrote it, fast was 10Mbits/sec.
> The firewall tables use a radix tree (*) and might be slower than what you have, but possibly it might be made up for by not having to do the divert logic. it's not entorely clear from your description why you look up  a country rather than just a pass/block result, but maybe different sources can access different countries?.

The basic idea was to develop a facility for ipfw for filtering IPv4 packets by country code - see: https://github.com/cyclaero/ipdb

I simply put into /etc/rc.conf:

   geod_enable="YES"
   geod_flags="-a DE:BR:US"

The -a flag tells, that source IP addresses only from these countries are allowed (i.e. passed through the filter). I added also a -d flag, which means deny (i.e. drop packets) from the given list of countries.

With that in place, I need to add a respective divert rule to the ipfw ruleset (the divert port of the geod daemon is 8669, remembering that 8668 is the port of the natd daemon):

    ipfw -q add 70 divert 8669 tcp from any to any 80,443 in recv WAN_if setup

> I did similar once using ipfw tables but couldn't find a reliable source of data.

The IP/CC database is compiled from downloads of the daily published delegation statistics files of the 5 RIR's. I consider the RIR's being the authoritative source. Anyway, on my systems the IP/CC-database is updated only weekly, although, daily updating would be possible. I wrote a shell script for this, that can be executed by a cron job.

    https://github.com/cyclaero/ipdb/blob/master/ipdb-update.sh <https://github.com/cyclaero/ipdb/blob/master/ipdb-update.sh>

There is another tool called geoip , that I uploaded to GitHub, and that I use for looking up country codes by IP addresses on the command line.

    https://github.com/cyclaero/ipdb/blob/master/geoip.c

This one could easily be extended to produce sorted IP ranges per CC that could be fed into tables of ipfw. I am thinking of adding a command line option for specifying CC's for which the IP ranges should be exported, something like:

   geoip -e DE:BR:US:IT:FR:ES 

And this could print sorted IP-Ranges belonging to the listed countries. For this purpose, what would be the ideal format for directly feeding the produced output into ipfw tables?

>> Independent from the actual usage case (geo-blocking), let's talk about divert filtering in general. The original question which is still unanswered can be generalized to, whether "dropping/denying" a package simply means 'forget about it' or whether the divert filter is required to do something more involved, e.g. communicate the situation somehow to ipfw.
> 
> there is no residual information about the packet in the kernel once it has been passed to the  user process.
> so just "forgetting to hand it back" is sufficient to drop it.

OK, many thanks, that just answers my original doubt. At least technically, my daemon handles package dropping correctly, although, more elegant ways can be imagined to do the same thing.

Best regards

Rolf 


More information about the freebsd-ipfw mailing list