add DXCIDR, fix version no tracking
[spider.git] / perl / DXCIDR.pm
1 #
2 # IP Address block list / checker
3 #
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
6 #
7
8 package DXCIDR;
9
10 use strict;
11 use warnings;
12 use 5.16.1;
13 use DXVars;
14 use DXDebug;
15 use DXUtil;
16 use DXLog;
17 use IO::File;
18 use File::Copy;
19
20 our $active = 0;
21 our $badipfn = "badip";
22 my $ipv4;
23 my $ipv6;
24 my $count4 = 0;
25 my $count6 = 0;
26
27 # load the badip file
28 sub load
29 {
30         if ($active) {
31                 $count4 = _get($ipv4, 4);
32                 $count6 = _get($ipv6, 6);
33         }
34         LogDbg('DXProt', "DXCIDR: loaded $count4 IPV4 addresses and $count6 IPV6 addresses");
35         return $count4 + $count6;
36 }
37
38 sub _fn
39 {
40         return localdata($badipfn) . "$_[0]";
41 }
42
43 sub _get
44 {
45         my $list = shift;
46         my $sort = shift;
47         my $fn = _fn($sort);
48         my $fh = IO::File->new($fn);
49         my $count = 0;
50         
51         if ($fh) {
52                 while (<$fh>) {
53                         chomp;
54                         next if /^\s*\#/;
55                         $list->add($_);
56                         ++$count;
57                 }
58                 $fh->close;
59                 $list->clean if $count;
60         } elsif (-r $fn) {
61                 LogDbg('err', "DXCIDR: $fn not found ($!)");
62         }
63         return $count;
64 }
65
66 sub _put
67 {
68         my $list = shift;
69         my $sort = shift;
70         my $fn = _fn($sort);
71         my $r = rand;
72         my $fh = IO::File->new (">$fn.$r");
73         if ($fh) {
74                 for ($list->list) {
75                         $fh->print("$_\n");
76                 }
77                 move "$fn.$r", $fn;
78         } else {
79                 LogDbg('err', "DXCIDR: cannot write $fn.$r $!");
80         }
81 }
82
83 sub add
84 {
85         for (@_) {
86                 # protect against stupid or malicious
87                 next if /^127\./;
88                 next if /^::1$/;
89                 if (/\./) {
90                         $ipv4->add($_);
91                         ++$count4;
92                         LogDbg('DXProt', "DXCIDR: Added IPV4 $_ address");
93                 } else {
94                         $ipv6->add($_);
95                         ++$count6;
96                         LogDbg('DXProt', "DXCIDR: Added IPV6 $_ address");
97                 }
98         }
99         if ($ipv4 && $count4) {
100                 $ipv4->prep_find;
101                 _put($ipv4, 4);
102         }
103         if ($ipv6 && $count6) {
104                 $ipv6->prep_find;
105                 _put($ipv6, 6);
106         }
107 }
108
109 sub save
110 {
111         return 0 unless $active;
112         my $list = $ipv4->list;
113         _put($list, 4) if $list;
114         $list = $ipv6->list;
115         _put($list, 6) if $list;
116 }
117
118 sub list
119 {
120         my @out;
121         push @out, $ipv4->list;
122         push @out, $ipv6->list;
123         return (1, sort @out);
124 }
125
126 sub find
127 {
128         return 0 unless $active;
129         return 0 unless $_[0];
130         
131         if ($_[0] =~ /\./) {
132                 return $ipv4->find($_[0]) if $count4;
133         }
134         return $ipv6->find($_[0]) if $count6;
135 }
136
137 sub init
138 {
139         eval { require Net::CIDR::Lite };
140         if ($@) {
141                 LogDbg('DXProt', "DXCIDR: load (cpanm) the perl module Net::CIDR::Lite to check for bad IP addresses (or CIDR ranges)");
142                 return;
143         }
144
145         import Net::CIDR::Lite;
146
147         $ipv4 = Net::CIDR::Lite->new;
148         $ipv6 = Net::CIDR::Lite->new;
149
150         load();
151         $active = 1;
152 }
153
154
155
156 1;