#!/usr/bin/perl # $Header: /u/cvsroot/env/b/nic-to-tcprules,v 1.4 2003/07/23 19:30:58 mayoff Exp $ use strict; use vars qw( %ranges ); foreach my $cc (@ARGV) { $cc =~ y/A-Z/a-z/; $ranges{$cc} = []; } @ARGV = (); while (<>) { my ($nic, $cc, $type, $n, $size, $date, $status) = split(/\|/); $cc =~ y/A-Z/a-z/; if ($type eq 'ipv4' && exists($ranges{$cc}) && $size > 0) { if ($size == 1) { push(@{$ranges{$cc}}, $n); } else { push(@{$ranges{$cc}}, get_ranges($n, $size)); } } } foreach my $cc (sort keys %ranges) { next if (length(@{$ranges{$cc}}) == 0); print "# $cc\n"; foreach my $range (@{$ranges{$cc}}) { print "$range:deny\n"; } print "\n"; } exit(0); sub get_ranges { my ($dotted_start, $length) = @_; my $start = undot($dotted_start); my $end = $start + $length - 1; my @start_octets = get_octets($start); my @end_octets = get_octets($end); my $i; for ($i = 0; $i < 4; $i++) { last if ($start_octets[$i] != $end_octets[$i]); } my $matchlength = $i; $i++; for ( ; $i < 4; $i++) { if ($start_octets[$i] != 0 || $end_octets[$i] != 255) { warn "cannot handle range $dotted_start, $length"; return; } } my $range; for ($i = 0; $i < $matchlength; $i++) { $range .= $start_octets[$i]; $range .= '.'; } $range .= $start_octets[$i]; $range .= '-'; $range .= $end_octets[$i]; $range .= '.' if ($i < 3); return ($range); } sub undot { my ($dotted) = @_; my @octets = split(/\./, $dotted); my $n = 0; foreach my $octet (@octets) { $n = ($n << 8) + $octet; } return $n; } sub get_octets { my ($ip) = @_; return ( ($ip >> 24) & 0xff, ($ip >> 16) & 0xff, ($ip >> 8) & 0xff, $ip & 0xff ); } __END__ =head1 NAME nic-to-tcprules =head1 SYNOPSIS I I [I ...] I> I =head1 DESCRIPTION I takes a list of two-letter country codes as command-line arguments, and reads a series of address assignments on standard input. For each IPv4 address block assignment, if the block is assigned to one of the country codes given on the command line, the program prints a I-style "deny" line for that address block. The output lines are grouped by country. Address assignments for various regions, in the format needed by this program, can be found at these URLs: =over 4 =item Ehttp://ftp.apnic.net/stats/apnic/E =item Eftp://ftp.arin.net/pub/stats/arin/E =item Eftp://ftp.ripe.net/ripe/stats/E =back =head1 MOTIVATION I get a lot of unwanted e-mail from IP addresses assigned to countries like Korea and China. Since I don't know anyone in those countries, I'm willing to risk blocking all e-mail from those countries. My incoming SMTP server runs under I (Ehttp://cr.yp.to/ucspi-tcp/tcpserver.htmlE), so I need to convert the APNIC data to the format used by I (Ehttp://cr.yp.to/ucspi-tcp/tcprules.htmlE). =head1 BUGS This version of I does not support arbitrary address ranges. An input range that can be expressed as a single I range will be converted; any other range will produce a warning on standard error and nothing on standard output. As of 2002/06/16, all RIPE and APNIC blocks are convertable, but some ARIN blocks are not. This doesn't bother me because the only countries I currently want to block are handled by APNIC. =head1 AUTHOR Rob Mayoff =head1 VERSION $Id: nic-to-tcprules,v 1.4 2003/07/23 19:30:58 mayoff Exp $ =cut