2 # IP Address block list / checker
4 # This is a DXSpider compatible, optional skin over Net::CIDR::Lite
5 # If Net::CIDR::Lite is not present, then a find will always returns 0
20 use Socket qw(AF_INET AF_INET6 inet_pton inet_ntop);
23 our $badipfn = "badip";
31 return localdata($badipfn);
38 $fn .= ".$suffix" if $suffix;
39 my $fh = IO::File->new($fn);
52 unless (is_ipaddr($_)) {
54 LogDbg('err', qq(DXCIDR: $fn line $line: '$_' not an ip address));
56 LogDbg('err', qq(DXCIDR: More than 10 errors in $fn at/after line $line: '$_' - INVALID INPUT FILE));
64 LogDbg('err', "DXCIDR: $fn read error ($!)");
71 return unless $active;
73 my @in = _read($suffix);
75 return scalar add(@in);
81 my $fn = _fn() . ".$suffix";
83 my $fh = IO::File->new (">$fn.$r");
86 for ($ipv4->list, $ipv6->list) {
91 LogDbg('cmd', "DXCIDR: put (re-)written $fn");
93 LogDbg('err', "DXCIDR: cannot write $fn.$r $!");
100 return 0 unless $active;
107 my $fn = _fn() . ".$suffix";
108 my $fh = IO::File->new;
109 if ($fh->open("$fn", "a+")) {
110 $fh->seek(0, 2); # belt and braces !!
111 print $fh "$_\n" for @in;
114 LogDbg('err', "DXCIDR::append error appending to $fn $!");
117 LogDbg('err', "DXCIDR::append require badip suffix");
124 return 0 unless $active;
129 # protect against stupid or malicious
130 next unless is_ipaddr($ip);
131 next if $ip =~ /^127\./;
132 next if $ip =~ /^::1$/;
135 eval {$ipv4->add_any($ip)};
142 } elsif ($ip =~ /:/) {
143 eval {$ipv6->add_any($ip)};
151 LogDbg('err', "DXCIDR::add non-ip address '$ip' read");
159 return unless $active;
161 if ($ipv4 && $count4) {
165 if ($ipv6 && $count6) {
179 my @ip = split m|/|, $i;
181 @s = map{$_ ? hex($_) : 0} split /:/, $ip[0];
183 @s = map{$_ ? $_+0 : 0} split /\./, $ip[0];
188 # my $s = pack "S*", reverse @s;
189 my $s = pack "n*", @s;
190 # my $s = join ':', map {sprintf "%04d:", $_} @s;
191 # push @in, [inet_pton(m|:|?AF_INET6:AF_INET, $ip[0]), @ip];
194 @out = sort {$a->[0] cmp $b->[0]} @in;
195 # @out = sort {$a->[0] <=> $b->[0]} @in;
196 return map { "$_->[1]/$_->[2]"} @out;
201 return () unless $active;
203 push @out, $ipv4->list if $count4;
204 push @out, $ipv6->list if $count6;
210 return 0 unless $active;
211 return 0 unless $_[0];
214 return $ipv4->find($_[0]) if $count4;
216 return $ipv6->find($_[0]) if $count6;
221 eval { require Net::CIDR::Lite };
223 LogDbg('DXProt', "DXCIDR: load (cpanm) the perl module Net::CIDR::Lite to check for bad IP addresses (or CIDR ranges)");
227 eval {import Net::CIDR::Lite };
229 LogDbg('DXProt', "DXCIDR: import Net::CIDR::Lite error $@");
237 move $fn, "$fn.base";
251 utime ($now, $now, $fn) || open (TMP, ">>$fn") || LogDbg('err', "DXCIDR::touch: Couldn't touch $fn: $!");
256 return 0 unless $active;
263 LogDbg('DXProt', "DXCIDR::reload reload database" );
266 opendir($dir, $main::local_data);
267 while (my $fn = readdir $dir) {
268 next unless my ($suffix) = $fn =~ /^badip\.(\w+)$/;
269 my $c = _load($suffix);
270 LogDbg('DXProt', "DXCIDR::reload: $fn read containing $c ip addresses" );
276 LogDbg('DXProt', "DXCIDR::reload $count ip addresses found (IPV4: $count4 IPV6: $count6) in $files badip files" );
283 return 0 unless $active;
285 $ipv4 = Net::CIDR::Lite->new;
286 $ipv6 = Net::CIDR::Lite->new;
287 $count4 = $count6 = 0;