#!/usr/bin/perl -w # ###################################################################### # Copyright 2004-2005 Alex de Kruijff # ###################################################################### $rulesRangeInStart = 2300; $rulesRangeOutStart = $rulesRangeInStart + 100; $rulesRangeInClose = 2400; $rulesRangeOutClose = $rulesRangeInClose + 100; $location_lists = "/root/etc/blocklist/"; alarm(900); $st = time(); $et = 0; sub showtime() { my $t = time()-$st; if ($t-$et >= 1) { warn "\b\b\b\b\b".$t."s\n"; $et = $t; } } sub ip_devider_cmp { my ($posA1, $posA2, $posB1, $posB2) = (0, -1, 0, -1); showtime(); while($posA1 != -1 && $posB1 != -1) { $tmp1 = index($a, ".", $posA1); $tmp2 = index($a, "-", $posA1); $posA2 = ($tmp1 < $tmp2 || $tmp2 == -1) ? $tmp1 : $tmp2; $tmp1 = index($b, ".", $posB1); $tmp2 = index($b, "-", $posB1); $posB2 = ($tmp1 < $tmp2 || $tmp2 == -1) ? $tmp1 : $tmp2; my $subA = ($posA2 != -1) ? substr($a, $posA1, $posA2-$posA1) : substr($a, $posA1); my $subB = ($posB2 != -1) ? substr($b, $posB1, $posB2-$posB1) : substr($b, $posB1); my $n = scalar($subA) - scalar($subB); if ($n != 0) { return $n; } $posA1 = ($posA2 >= 0) ? $posA2+1 : $posA2; $posB1 = ($posB2 >= 0) ? $posB2+1 : $posB2; } return 0; } sub ip_cmp { ($ao, $bo) = ($a, $b); ($a, $b) = ($_[0], $_[1]); $c = ip_devider_cmp; ($a, $b) = ($ao, $bo); return $c; } sub ip_add { my ($ipa0, $ipa1, $ipa2, $ipa3) = split(/\./, $_[0]); my ($ipb0, $ipb1, $ipb2, $ipb3) = split(/\./, $_[1]); $ipa0 = scalar($ipa0) + scalar($ipb0); $ipa1 = scalar($ipa1) + scalar($ipb1); $ipa2 = scalar($ipa2) + scalar($ipb2); $ipa3 = scalar($ipa3) + scalar($ipb3); if ($ipa3 > 255) { $ipa3 -= 256; $ipa2++; } if ($ipa2 > 255) { $ipa2 -= 256; $ipa1++; } if ($ipa1 > 255) { $ipa1 -= 256; $ipa0++; } # if ($ipa0 > 255) { # die "ip ($ipa0.$ipa1.$ipa2.$ipa3) can't be larger then 255.255.255.255"; # } return "$ipa0.$ipa1.$ipa2.$ipa3"; } sub ip_add_mask { my $mask = $_[1]; my ($ipa, $ip, $ipb) = ("", "", ""); if ($mask == 32) { $ipb .= "0.0.0.0"; $mask = -1; } elsif ($mask >= 24) { $ipa .= "0.0.0."; $mask -= 24; } elsif ($mask >= 16) { $ipa .= "0.0."; $ipb .= ".255"; $mask -= 16; } elsif ($mask >= 8) { $ipa .= "0."; $ipb .= ".255.255"; $mask -= 8; } else { $ipb .= ".255.255.255"; } if ($mask >= 0) { $ip = 1 << (8-$mask); $ip--; } $c = ip_add($_[0], "$ipa$ip$ipb"); return $c; } sub ip_inc { return ip_add($_[0], "0.0.0.1"); } sub ip_base_mask { my ($ip0, $ip1, $ip2, $ip3) = split(/\./, $_[0]); my $mask = $_[1]; if ($mask >= 32) { } elsif ($mask >= 24) { $mask -= 24; $ip3 >>= (8 - $mask); $ip3 <<= (8 - $mask); } elsif ($mask >= 16) { $mask -= 16; $ip2 >>= (8 - $mask); $ip2 <<= (8 - $mask); $ip3 = 0; } elsif ($mask >= 8) { $mask -= 8; $ip1 >>= (8 - $mask); $ip1 <<= (8 - $mask); $ip2 = $ip3 = 0; } else { $ip0 >>= (8 - $mask); $ip0 <<= (8 - $mask); $ip1 = $ip2 = $ip3 = 0; } return "$ip0.$ip1.$ip2.$ip3"; } sub ip_mask { my $mask = 0; while (( ip_cmp(ip_base_mask($_[0], $mask), $_[0]) < 0 || ip_cmp(ip_add_mask($_[0], $mask), $_[1]) > 0 ) && $mask < 32) { $mask++; } return $mask; } sub read_file { local *arr = shift(@_); my $src = $_[0]; open(FILE, "<".$src) or die "Couldn't read $src because $!.\n"; while() { s/\s+$//; if ($_ !~ /^#/ && $_ =~ /:/) { my $index1 = index($_, ":"); my $index2 = $index1; while($index2 != -1) { $index2 = index($_, ":", $index2+1); if ($index2 != -1) { $index1 = $index2; } } $line = substr($_, $index1+1); push(@arr, $line); } } close(FILE); } sub read_dir { local *arr = shift(@_); my $src = $_[0]; opendir(DIR, $src) or die "Coudn't open $src because $!.\n"; while (my $file = readdir(DIR)) { showtime(); next if ($file eq "." || $file eq ".."); if (! -d $src.$file) { warn "Reading $file...\n"; read_file(*arr, $src.$file); } } closedir(DIR); } sub merge_arr { local *org = $_[0]; my @arr; my ($ip1, $ip2) = split(/-/, shift(@org)); foreach $line (@org) { my ($ipa, $ipb) = split(/-/, $line); # Als ip1 <= ipa <= ip2+1 ($ip1, $ip2) = ($ip1, $ipb); # else ($ip1, $ip2) = ($ipa, $ipb); if (ip_cmp($ip1, $ipa) <= 0 && ip_cmp($ipa, ip_inc($ip2)) <= 0) { $ip2 = $ipb; } else { push(@arr, "$ip1-$ip2"); ($ip1, $ip2) = ($ipa, $ipb); } } return @arr; } sub toipfw { my ($ip, $mask) = ($_[0], $_[1]); my ($ip0, $ip1, $ip2, $ip3) = split(/\./, $ip); my $n = 1 + (scalar($ip0) >> 2); print "add ".($rulesRangeInStart+$n)." deny ip from $ip/$mask to any\n"; print "add ".($rulesRangeOutStart+$n)." reject ip from any to $ip/$mask\n"; } sub toipfw_setup { my ($ip, $mask, $n) = ($_[0], $_[1], $_[2]); print "add $rulesRangeInStart skipto ".($rulesRangeInStart+$n); print " ip from $ip/$mask to any\n"; print "add $rulesRangeOutStart skipto ".($rulesRangeOutStart+$n); print " ip from any to $ip/$mask\n"; } sub toipfw_close { my ($ip, $mask, $n) = ($_[0], $_[1], $_[2]); print "add ".($rulesRangeInStart+$n). " skipto $rulesRangeInClose"; print " ip from $ip/$mask to any\n"; print "add ".($rulesRangeOutStart+$n). " skipto $rulesRangeOutClose"; print " ip from any to $ip/$mask\n"; } sub tofirewall { local *arr = $_[0]; $f = *toipfw; $f_setup = *toipfw_setup; $f_close = *toipfw_close; my ($i, $j) = (0, 0); for ($i = 0; $i < 255; $i += 4) { &$f_setup("$i.0.0.0", 6, 1 + ($i >> 2)); } $i = 0; foreach $line (@arr) { ($a, $b) = split(/-/, $line); while(ip_devider_cmp() <= 0) { my $mask = ip_mask($a, $b); my $c = ip_add_mask($a, $mask); &$f($a, $mask); $a = ip_inc($c); $j++; } $i++; } $i = 0; for ($i = 0; $i < 255; $i += 4) { &$f_close("$i.0.0.0", 6, 1 + ($i >> 2)); } } sub show_arr { local *arr = $_[0]; foreach $line (@arr) { print "$line\n"; } } @arr = (); # Read into array read_dir(*arr, $location_lists); # Sort & Merge array showtime(); warn "Sorting...\n"; @arr = sort ip_devider_cmp @arr; showtime(); warn "Merging...\n"; @arr = merge_arr(*arr); # 4 Convert array to ipfw rules showtime(); warn "Converting...\n"; $ipfw = *toipfw; tofirewall(*arr, $ipfw); # 5 Done showtime(); warn "Done...\n"; ##show_arr(*arr); showtime();