#!/usr/bin/perl use strict; ## these may need to be fully qualified unless they are on the path my $rndc = "/usr/sbin/rndc"; ## location and name of the generated zone my $spewsbase = "spews.org"; my $spewszone = "blackholes"; my $spews = "$spewszone.$spewsbase"; my $zone = "/var/named/named.$spews"; ## which level do we want my $level = 'spews_list_level1.txt.bz2'; # Do we bounce or not? 75 = TEMPFAIL my $error = 75; my $time = time(); my $logfile = "/var/log/spews.log"; my $filename = "/tmp/spews.data"; my $heading = "\$TTL 86400 ;1 day \$ORIGIN $spewsbase. $spewszone IN SOA ns.$spews. root.$spews. ( $time ;serial number 14400 ;refresh every 4 hours 3600 ;retry after 1 hour 864000 ;expire after 10 days 3600 ) ;negative cache ttl IN NS ns.$spews. \$ORIGIN $spews. ns IN A 127.0.0.1 "; open LOGFILE, ">>$logfile"; print LOGFILE "[" . localtime($time) . "] Start processing, fetch the spews list\n"; # # fetch spews list, bunzip2 # system("curl http://spews.org/$level 2>/dev/null | bzcat >$filename"); # # reformat for the sort # print LOGFILE "[" . localtime($time) . "] Reformat for sort\n"; open OUTFILE, ">$filename.sort"; open STREAM, "<$filename"; while () { if (/(.*?)\/(.*?) .*\] (.*)/) { my $ip = $1; my $cidr = $2; my $who = $3; print OUTFILE "$cidr $ip $who\n"; } } close STREAM; close OUTFILE; # # sort based on cidr block size and create zone file # print LOGFILE "[" . localtime($time) . "] Sort and create zone file\n"; system("mv -f $zone $zone.save"); open OUTFILE, ">$zone"; open STREAM, "sort <$filename.sort|"; $error = 0; print OUTFILE "$heading"; my $cidr = '(.*?) '; ## match the cidr block size my $ip = '(.*?)\.(.*?)\.(.*?)\.(.*?) '; ## match the ip address my $who = '(.*)'; ## match the txt part my %snum2txt; my %net162obj; my $count = 0; while () { chomp; if (/$cidr$ip$who/oi) { $count = $count + 1; my $cidrv = $1; my $ipa = $2; my $ipb = $3; my $ipc = $4; my $ipd = $5; my $n16 = $ipa * 256 + $ipb; my $whov = $6; my $lo; my $hi; my $pat; my $snum; if ($whov =~ /.*S(.*)/) { $snum = "S$1"; } $snum2txt{$snum} = $whov; SWITCH: { $lo = 0; $pat = "\*.$ipb.$ipa"; if ($cidrv == 16) { $hi = $lo + 0; last SWITCH; } $lo = $ipc; $pat = "\*.\$.$ipb.$ipa"; if ($cidrv == 17) { $hi = $lo + 127; last SWITCH; } if ($cidrv == 18) { $hi = $lo + 63; last SWITCH; } if ($cidrv == 19) { $hi = $lo + 31; last SWITCH; } if ($cidrv == 20) { $hi = $lo + 15; last SWITCH; } if ($cidrv == 21) { $hi = $lo + 7; last SWITCH; } if ($cidrv == 22) { $hi = $lo + 3; last SWITCH; } if ($cidrv == 23) { $hi = $lo + 1; last SWITCH; } $lo = 0; $pat = "\*.$ipc.$ipb.$ipa"; if ($cidrv == 24) { $hi = $lo + 0; last SWITCH; } $lo = $ipd; $pat = "\$.$ipc.$ipb.$ipa"; if ($cidrv == 25) { $hi = $lo + 127; last SWITCH; } if ($cidrv == 26) { $hi = $lo + 63; last SWITCH; } if ($cidrv == 27) { $hi = $lo + 31; last SWITCH; } if ($cidrv == 28) { $hi = $lo + 15; last SWITCH; } if ($cidrv == 29) { $hi = $lo + 7; last SWITCH; } if ($cidrv == 30) { $hi = $lo + 3; last SWITCH; } if ($cidrv == 31) { $hi = $lo + 1; last SWITCH; } $lo = 0; $pat = "$ipd.$ipc.$ipb.$ipa"; if ($cidrv == 32) { $hi = $lo + 0; last SWITCH; } } if (!($net162obj{$n16})) { $net162obj{$n16} = netblock->new(); } my $obj = $net162obj{$n16}; ($lo, $hi) = $obj->validate($lo, $hi, $pat); if ($lo <= $hi) { print OUTFILE "\$GENERATE $lo-$hi $pat CNAME $snum\n"; } } } my $item; foreach $item (keys %snum2txt) { print OUTFILE "$item IN A 127.0.0.2\n"; print OUTFILE " TXT \"$snum2txt{$item}\"\n"; } close STREAM; close OUTFILE; if ($count < 12000) { print LOGFILE "[" . localtime($time) . "] Short file. Aborting!\n"; close LOGFILE; system("mv -f $zone.save $zone"); exit($error); } #system("rm -f $filename"); #system("rm -f $filename.sort"); print LOGFILE "[" . localtime($time) . "] New zone file written: $zone\n"; # # reload the new zone # system("$rndc reload $spews"); print LOGFILE "[" . localtime($time) . "] New zone file loaded: $spews\n"; close LOGFILE; exit(0); # # a helper package to detect # package netblock; sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; return bless [], $class; } sub validate { my $self = shift; my $lo = shift; my $hi = shift; my $pat = shift; if ($pat =~ /(.*?)\.(.*?)\.(.*?)\.(.*?)/) { my $ipa = $4; my $ipb = $3; my $ipc = $2; my $ipd = $1; my $loo; my $hii; if ($ipd eq "*") { if ($pat =~ /\$/) { $loo = $lo * 256 + 0; $hii = $hi * 256 + 255; } else { $loo = $ipc * 256 + 0; $hii = $ipc * 256 + 255; } } else { if ($pat =~ /\$/) { $loo = $ipc * 256 + $lo; $hii = $ipc * 256 + $hi; } else { $loo = $ipc * 256 + $ipd; $hii = $loo; } } my $n = scalar(@{$self}); my $l; my $h; for (my $i = 0; $i < $n; $i++) { $l = $self->[$i][0]; $h = $self->[$i][1]; if (($l <= $loo) && ($hii <= $h)) { # don't need this one, it is covered by a duplicate or larger block return (1,0); } if (($loo <= $l) && ($h <= $hii)) { # we will skip this, a smaller block got here first # should never happen, since we sort by cidr block size return (1,0); } } push @{$self}, [$loo, $hii]; return ($lo, $hi); } return (1,0); }