fix stupid unpad typo in dx command
[spider.git] / perl / DXCIDR.pm
index 2ef0d1937954dccd2f004bd5777e72a9da773e92..0a829bf1f474035eb73e42c85b381569b479d236 100644 (file)
@@ -16,6 +16,7 @@ use DXUtil;
 use DXLog;
 use IO::File;
 use File::Copy;
+
 use Socket qw(AF_INET AF_INET6 inet_pton inet_ntop);
 
 our $active = 0;
@@ -25,107 +26,135 @@ my $ipv6;
 my $count4 = 0;
 my $count6 = 0;
 
-# load the badip file
-sub load
-{
-       if ($active) {
-               $count4 = _load($ipv4, 4);
-               $count6 = _load($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 _load
+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*\#/;
                        next unless /[\.:]/;
-                       $list->add_any($_);
-                       ++$count;
+                       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;
-               $list->prep_find;
-       } 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
 {
+       return 0 unless $active;
        my $count = 0;
        
        for my $ip (@_) {
                # protect against stupid or malicious
-               next if /^127\./;
-               next if /^::1$/;
-               if (/\./) {
-                       if ($ipv4->find($ip)) {
-                               LogDbg('DXProt', "DXCIDR: Ignoring existing IPV4 $ip");
-                               next;
-                       } 
+               next unless is_ipaddr($ip);
+               next if $ip =~ /^127\./;
+               next if $ip =~ /^::1$/;
+               if ($ip =~ /\./) {
                        $ipv4->add_any($ip);
                        ++$count;
                        ++$count4;
-               } elsif (/:/) {
-                       if ($ipv6->find($ip)) {
-                               LogDbg('DXProt', "DXCIDR: Ignoring existing IPV6 $ip");
-                               next;
-                       } 
+               } elsif ($ip =~ /:/) {
                        $ipv6->add_any($ip);
                        ++$count;
                        ++$count6;
-                       LogDbg('DXProt', "DXCIDR: Added IPV6 $ip 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);
        }
-       return $count;
-}
-
-sub save
-{
-       return 0 unless $active;
-       _put($ipv4, 4) if $count4;
-       _put($ipv6, 6) if $count6;
 }
 
 sub _sort
@@ -133,14 +162,16 @@ sub _sort
        my @in;
        my @out;
        for (@_) {
-               push @in, [inet_pton(m|:|?AF_INET6:AF_INET, $_), split m|/|];
+               my @ip = split m|/|;
+               push @in, [inet_pton(m|:|?AF_INET6:AF_INET, $ip[0]), @ip];
        }
-       @out = sort {$a->[0] <=> $b->[0]} @in;
+       @out = sort {$a->[1] cmp $b->[1]} @in;
        return map { "$_->[1]/$_->[2]"} @out;
 }
 
 sub list
 {
+       return () unless $active;
        my @out;
        push @out, $ipv4->list if $count4;
        push @out, $ipv6->list if $count6;
@@ -167,14 +198,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";
+       }
 
-       $active = 1;
-       load();
+       _touch("$fn.local");
+       
+       reload();
+
+}
+
+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;