X-Git-Url: http://dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXCIDR.pm;h=b702d7b899c197f2647dd92da34d2efb3f502396;hb=d3568fec5fb3e19f72dc4813dd2e18a7031dd6bb;hp=495768edd5217bcc452c3e3a5030ecd6dbf6b28a;hpb=067835d5b0160e10a778252cf0dc6b2e4d1a74cb;p=spider.git diff --git a/perl/DXCIDR.pm b/perl/DXCIDR.pm index 495768ed..b702d7b8 100644 --- a/perl/DXCIDR.pm +++ b/perl/DXCIDR.pm @@ -17,6 +17,8 @@ use DXLog; use IO::File; use File::Copy; +use Socket qw(AF_INET AF_INET6 inet_pton inet_ntop); + our $active = 0; our $badipfn = "badip"; my $ipv4; @@ -24,110 +26,162 @@ my $ipv6; my $count4 = 0; my $count6 = 0; -# load the badip file -sub load -{ - if ($active) { - $count4 = _get($ipv4, 4); - $count6 = _get($ipv6, 6); - } - LogDbg('DXProt', "DXCIDR: loaded $count4 IPV4 addresses and $count6 IPV6 addresses"); - return $count4 + $count6; -} - sub _fn { - return localdata($badipfn) . "$_[0]"; + return localdata($badipfn); } -sub _get +sub _read { - my $list = shift; - my $sort = shift; - my $fn = _fn($sort); + my $suffix = shift; + my $fn = _fn(); + $fn .= ".$suffix" if $suffix; my $fh = IO::File->new($fn); - my $count = 0; + my @out; + my $ecount; + my $line; + if ($fh) { while (<$fh>) { chomp; + ++$line; next if /^\s*\#/; - $list->add($_); - ++$count; + next unless /[\.:]/; + next unless $_; + unless (is_ipaddr($_)) { + ++$ecount; + LogDbg('err', qq(DXCIDR: $fn line $line: '$_' not an ip address)); + if ($ecount > 10) { + LogDbg('err', qq(DXCIDR: More than 10 errors in $fn at/after line $line: '$_' - INVALID INPUT FILE)); + return (); + } + } + push @out, $_; } $fh->close; - $list->clean if $count; - } elsif (-r $fn) { - LogDbg('err', "DXCIDR: $fn not found ($!)"); + } else { + LogDbg('err', "DXCIDR: $fn read error ($!)"); } - return $count; + return @out; +} + +sub _load +{ + my $suffix = shift; + my @in = _read($suffix); + return 0 unless @in; + return scalar add(@in); } sub _put { - my $list = shift; - my $sort = shift; - my $fn = _fn($sort); + my $suffix = shift; + my $fn = _fn() . ".$suffix"; my $r = rand; my $fh = IO::File->new (">$fn.$r"); + my $count = 0; if ($fh) { - for ($list->list) { + for ($ipv4->list, $ipv6->list) { $fh->print("$_\n"); + ++$count; } move "$fn.$r", $fn; + LogDbg('cmd', "DXCIDR: put (re-)written $fn"); } else { LogDbg('err', "DXCIDR: cannot write $fn.$r $!"); } + return $count; +} + +sub append +{ + return 0 unless $active; + + my $suffix = shift; + my @in = @_; + my @out; + + if ($suffix) { + my $fn = _fn() . ".$suffix"; + my $fh = IO::File->new; + if ($fh->open("$fn", "a+")) { + $fh->seek(0, 2); # belt and braces !! + print $fh "$_\n" for @in; + $fh->close; + } else { + LogDbg('err', "DXCIDR::append error appending to $fn $!"); + } + } else { + LogDbg('err', "DXCIDR::append require badip suffix"); + } + return scalar @in; } sub add { - for (@_) { + return 0 unless $active; + my $count = 0; + + for my $ip (@_) { # protect against stupid or malicious - next if /^127\./; - next if /^::1$/; - if (/\./) { - $ipv4->add($_); + next unless is_ipaddr($ip); + next if $ip =~ /^127\./; + next if $ip =~ /^::1$/; + if ($ip =~ /\./) { + $ipv4->add_any($ip); + ++$count; ++$count4; - LogDbg('DXProt', "DXCIDR: Added IPV4 $_ address"); - } else { - $ipv6->add($_); + } elsif ($ip =~ /:/) { + $ipv6->add_any($ip); + ++$count; ++$count6; - LogDbg('DXProt', "DXCIDR: Added IPV6 $_ address"); + } else { + LogDbg('err', "DXCIDR::add non-ip address '$ip' read"); } } + return $count; +} + +sub clean_prep +{ + return unless $active; + if ($ipv4 && $count4) { + $ipv4->clean; $ipv4->prep_find; - _put($ipv4, 4); } if ($ipv6 && $count6) { + $ipv6->clean; $ipv6->prep_find; - _put($ipv6, 6); } } -sub save +sub _sort { - return 0 unless $active; - my $list = $ipv4->list; - _put($list, 4) if $list; - $list = $ipv6->list; - _put($list, 6) if $list; + my @in; + my @out; + for (@_) { + push @in, [inet_pton(m|:|?AF_INET6:AF_INET, $_), split m|/|]; + } + @out = sort {$a->[0] <=> $b->[0]} @in; + return map { "$_->[1]/$_->[2]"} @out; } sub list { + return () unless $active; my @out; - push @out, $ipv4->list; - push @out, $ipv6->list; - return (1, sort @out); + push @out, $ipv4->list if $count4; + push @out, $ipv6->list if $count6; + return _sort(@out); } sub find { return 0 unless $active; return 0 unless $_[0]; - + if ($_[0] =~ /\./) { return $ipv4->find($_[0]) if $count4; } @@ -143,14 +197,61 @@ sub init } import Net::CIDR::Lite; + $active = 1; - $ipv4 = Net::CIDR::Lite->new; - $ipv6 = Net::CIDR::Lite->new; + my $fn = _fn(); + if (-e $fn) { + move $fn, "$fn.base"; + } + + _touch("$fn.local"); + + reload(); - load(); - $active = 1; } +sub _touch +{ + my $fn = shift; + my $now = time; + local (*TMP); + utime ($now, $now, $fn) || open (TMP, ">>$fn") || LogDbg('err', "DXCIDR::touch: Couldn't touch $fn: $!"); +} +sub reload +{ + return 0 unless $active; + + new(); + + my $count = 0; + my $files = 0; + + LogDbg('DXProt', "DXCIDR::reload reload database" ); + + my $dir; + opendir($dir, $main::local_data); + while (my $fn = readdir $dir) { + next unless my ($suffix) = $fn =~ /^badip\.(\w+)$/; + my $c = _load($suffix); + LogDbg('DXProt', "DXCIDR::reload: $fn read containing $c ip addresses" ); + $count += $c; + $files++; + } + closedir $dir; + + LogDbg('DXProt', "DXCIDR::reload $count ip addresses found (IPV4: $count4 IPV6: $count6) in $files badip files" ); + + return $count; +} + +sub new +{ + return 0 unless $active; + + $ipv4 = Net::CIDR::Lite->new; + $ipv6 = Net::CIDR::Lite->new; + $count4 = $count6 = 0; +} 1;