The FireHOL project, another firewall and qos project, compiles a set of ip block lists. There are a number of lists that have different focuses - there is some overlap between them. These could be handy to use with IPFW. So let's see what we can do…
We have some constraints:
Tables are going to make this idea possible and down right simple.
IPFW Lookup Tables have some handy features:
When we build our IPFW rules we're going to create a firehol table. We will deny packets that on the WAN interface that are contained in that table. Just to be safe we will also create a table of addresses that we always want to trust. Addresses in that table will skip around the firehol deny rule - so something like like this…
TBL_IP="table(ok)" ipfw table ok create ipfw table ok add $WAN_MASK ipfw table ok add $ISPGW ipfw table ok add mydomain.example ipfw table ok add myotherdomain.example ipfw table ok add $DNS1 ipfw table ok add $DNS2 TBLE_FIREHOL="table(firehol)" ipfw table firehol create missing LIST=/etc/ipfw/firehol/list.combined if [ -e $LIST ]; then echo "load bad guys table" /etc/ipfw/firehol/fireload.pl $LIST > /etc/ipfw/firehol/log.load 2>&1 else echo "WARNING: $LIST not found" fi
The fireload.pl script does what it says on the tin, we will talk a bit more about it in a bit.
Later in the rule set we will have something like…
ipfw add 1036 skipto 1040 ip4 from $TBL_OK to any in recv $WAN ipfw add 1037 skipto 1040 ip4 from any to $TBL_OK out xmit $WAN ipfw add 1038 deny ip4 from $TBL_FIREHOL to any in recv $WAN ipfw add 1039 deny ip4 from any to $TBL_FIREHOL out xmit $WAN ipfw add 1040 count
The lists consist of comment lines, CIDR notation subnet masks, or individual addresses.
We're going to use a fairly naive approach to keep things simple.
I use a set of perl scripts for this but it could be done in any number of ways. There's nothing very fancy here. We're going to grab the lists using something like curl, we then concatenate the lists removing any none CIDR/IP address lines. I prefer, for no great reason, to have all the addresses in CIDR format so I convert the IP addresses into a CIDR netmask by appending /32 to it. The combined list is then sorted removing non-unique lines.
This is where the fireload.pl script comes in that was referenced above. Again, there's nothing really fancy here so you could do it with a shell script just as well. We create a temporary table, add each CIDR address from our combined list to that table and then swap it in. Remember that we're working with lookup tables so we have to add a key and a value. The key would be the CIDR address, the value can always be 0. 0 is assumed if not given. The script would need to execute commands like…
ipfw table fireholload create missing ipfw table fireholload add 0.0.0.0/8 ipfw table fireholload add 10.0.0.0/8 ipfw table fireholload add 192.168.0.0/16 : ipfw table fireholload add 224.0.0.0/3 ipfw table fireholload swap firehol ipfw table fireholload destroy
And we're done. The new combined list is loaded into the firehol table that our rule set is making use of.
Note that the current combination of lists 1, 2, and 3 with duplicates removed contains over 35,000 CIDR/IP addresses so the above is not the best strategy. Fortunately we can add more than a single address to the table at a time so we can chunk things up a bit and do, say, 50 at a time. This speeds things up slightly. The only difference is that we MUST provide a value this way so the above adds would look like
ipfw table fireholload add 0.0.0.0/8 0 10.0.0.0/8 0 192.168.0.0/16 0 224.0.0.0/3 0
Note that while we are removing exact duplicates we're not removing subnets, so if 10.0.0.0/8 is in the combined list, 10.10.0.0/16 or 10.20.20.20 might also be in the list. There are a number of tools and strategies that could be used to overcome this but it's just not worth the effort. The lookup tables are very fast so the reduction in entries would be little or nothing.