#!/usr/bin/perl # THIS IS A HACK! # Copyright (c) 2005 Nick Johnson # All rights reserved. # # The Spatula Public License: # # Redistribution and use in source and binary forms, with or without # modification, are permitted for non-commercial purposes, # provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # For (3) and (4) below, "incorporated" means used in whole or part # in a derived work or used as a dependency of a separate work. # # 3. Neither source code or binary form may be incorporated into any # work falling under a license which requires the work or any derived # work to use a particular license. # 4. Neither source code or binary form may be incorporated into any # work which requires for its operation the installation of other works # which may fall under the restrictions given in (3) above. # 5. If this work is included or integrated, modified or unmodified, # with a derived or separate work with a more restrictive license than # this one, this work must be included as a separate whole in either # source or binary form, according to the provisions in (1) and (2) # above. # # 6. This license is subject to periodic updates. For the latest version # of this license, visit http://spatula.net/license.txt # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. for ($bits = 24; $bits >= 8; $bits--) { $size = int(2 ** (32 - $bits)); $sizes{$size} = $bits; $bitsize{$bits} = $size; } if ($> != 0) { die "This script must be run as root"; } # fetch the latest RIPE NCC data $allocations = `fetch -o - ftp://ftp.ripe.net/ripe/stats/delegated-ripencc-latest 2>/dev/null`; # for testing, comment out the above line and uncomment the next line, which should be something # you fetched as above #$allocations = `cat vodka`; @blocks = split(/[\r\n]+/, $allocations); @interestingBlocks = grep(/\|(UA|PL|RU|RO)\|/, @blocks); # Greedy algorithm for merging ajacent blocks. # It does not guarantee the optimal merge, but it does a reasonably good job in O(n) time # except for the following sort, which is n-log-n or something like that. @interestingBlocks = sort ipsort @interestingBlocks; # we are guaranteed by the NIC that blocks won't overlap # so this range-finding is OK kinds foreach (@interestingBlocks) { ($nic, $cc, $type, $base, $addrs, $date, $status) = split(/\|/, $_); next if $status ne 'allocated'; next if $type ne 'ipv4'; $mask = $sizes{$addrs}; $rangeStart = ipToInt($base); $rangeEnd = ipToInt($base) + $addrs; push (@ranges, [ $rangeStart, $rangeEnd]); } # try to merge the current block with the next block, and # keep merging in blocks as long as they're adjacent. Keep # track of the last block to have a valid size and only merge # as many adjacent blocks as can be to meet that valid size. # Whatever's left over will have to stand on its own. for ($i = 0; $i <= $#ranges; $i++ ) { $lastValid = -1; $lastStart = $ranges[$i][0]; $lastEnd = $ranges[$i][1]; if ($i <= $#ranges - 1) { for ($j = $i+1; $j <= $#ranges; $j++) { $thisStart = $ranges[$j][0]; if ($thisStart == $lastEnd) { $lastEnd = $ranges[$j][1]; $size = $lastEnd - $lastStart; $lastValid = $j if ($sizes{$size}) > 0; } else { last; } } } if ($lastValid > 0) { $lastEnd = $ranges[$lastValid][1]; $i = $lastValid; # i will be incremented next time thru the loop } else { $lastEnd = $ranges[$i][1]; } push(@merged, [ $lastStart, $lastEnd]); } # apply the firewall rules print scalar(@ranges) . " ranges in, " . scalar(@merged) . " ranges out\n"; #exit; `/sbin/ipfw del 11`; foreach (@merged) { $base = $_->[0]; $size = $_->[1] - $_->[0]; $bits = $sizes{$size}; `/sbin/ipfw add 11 deny ip from $base/$bits to me` } sub ipsort { $a =~ /\|(\d+\.\d+\.\d+\.\d+)\|/; my $aip = $1; $b =~ /\|(\d+\.\d+\.\d+\.\d+)\|/; my $bip = $1; return ipToInt($aip) <=> ipToInt($bip); } sub ipToInt { my ($ip) = @_; @parts = split(/\./, $ip); $sum = $parts[0] * 16777216 + $parts[1] * 65536 + $parts[2] * 256 + $parts[3]; return $sum; } sub intToIp { my ($int) = @_; $part1 = int($int / 16777216); $int -= $part1 * 16777216; $part2 = int($int / 65536); $int -= $part2 * 65536; $part3 = int($int / 256); $int -= $part3 * 256; return "$part1.$part2.$part3.$int"; }