File Coverage

blib/lib/JCM/Net/Patricia.pm
Criterion Covered Total %
statement 159 214 74.3
branch 54 154 35.0
condition 13 65 20.0
subroutine 37 47 78.7
pod 7 9 77.7
total 270 489 55.2


line stmt bran cond sub pod time code
1             # JCM::Net::Patricia - Patricia Trie perl module for fast IP address lookups
2             # Copyright (C) 2000-2005 Dave Plonka
3             # Copyright (C) 2009 Dave Plonka & Philip Prindeville
4             # Parts Copyright(C) 2016 Joelle Maslak
5             #
6             # This program is free software; you can redistribute it and/or modify
7             # it under the terms of the GNU General Public License as published by
8             # the Free Software Foundation; either version 2 of the License, or
9             # (at your option) any later version.
10             #
11             # This program is distributed in the hope that it will be useful,
12             # but WITHOUT ANY WARRANTY; without even the implied warranty of
13             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14             # GNU General Public License for more details.
15             #
16             # You should have received a copy of the GNU General Public License
17             # along with this program; if not, write to the Free Software
18             # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19             # MA 02110-1301, USA.
20              
21             # Joelle Maslak
22             # Dave Plonka
23             # Philip Prindeville
24             # Anton Berezin
25              
26             package JCM::Net::Patricia;
27              
28 3     3   290178 use strict;
  3         19  
  3         91  
29 3     3   16 use warnings;
  3         4  
  3         99  
30              
31             require 5.008;
32              
33 3     3   1302 use version;
  3         5832  
  3         17  
34 3     3   257 use Carp;
  3         6  
  3         269  
35 3     3   20 use vars qw($VERSION @ISA @EXPORT);
  3         5  
  3         151  
36 3     3   1627 use Socket qw(AF_INET AF_INET6);
  3         10292  
  3         593  
37              
38             BEGIN {
39 3     3   24 require Exporter;
40 3         12 require DynaLoader;
41 3         54 @ISA = qw(Exporter DynaLoader);
42 3         1909 @EXPORT = qw(AF_INET AF_INET6);
43             }
44              
45             '$Revision: 1.04 $' =~ m/(\d+)\.(\d+)((_\d+)|)/ && ( $VERSION = "$1.$2$3");
46              
47             bootstrap JCM::Net::Patricia $VERSION;
48              
49             sub new {
50 7     7 1 6205 my ($class, $type) = @_;
51              
52 7   100     39 $type ||= AF_INET;
53              
54 7 100       21 if ($type == AF_INET) {
55 4         58 return bless _new(32), 'JCM::Net::Patricia::AF_INET';
56             }
57              
58 3 50       12 if ($type == AF_INET6) {
59 3 50       16 if (JCM::Net::Patricia::have_ipv6()) {
60 3         27 return bless _new(128), 'JCM::Net::Patricia::AF_INET6';
61             } else {
62 0         0 croak('IPv6 is not available on this platform');
63             }
64             }
65              
66 0         0 croak "new: unimplemented type";
67             }
68              
69             ##
70             ## Compat functions
71             ##
72              
73             sub _ip_bits {
74 69     69   123 my ($self, $str) = @_;
75 69         103 my $bits;
76              
77 69 100       161 if (ref ($self) eq 'JCM::Net::Patricia::AF_INET6') {
78 15 100       96 $bits = ($str =~ s|/(\d+)$||) ? $1 : 128;
79             } else {
80 54 100       300 $bits = ($str =~ s|/(\d+)$||) ? $1 : 32;
81             }
82 69         255 ($str,$bits);
83             }
84              
85             sub add_string {
86 38 50 33 38 1 6788 croak "add_string: wrong number of args" if (@_ < 2 || @_ > 3);
87 38         83 my ($self,$str,$data) = @_;
88 38 100       106 $data = $str unless @_ > 2;
89 38         94 $self->add($self->_ip_bits($str),$data);
90             }
91              
92             sub match_string {
93 17 50   17 1 4326 croak "match_string: wrong number of args" if (@_ != 2);
94 17         38 my ($self,$str) = @_;
95 17         46 $self->match($self->_ip_bits($str))
96             }
97              
98             sub matching_prefix_string {
99 8 50   8 1 3357 croak "matching_prefix_string: wrong number of args" if (@_ != 2);
100 8         21 my ($self,$str) = @_;
101 8         20 $self->matching_prefix($self->_ip_bits($str))
102             }
103              
104             sub match_exact_string {
105 2 50   2 1 7 croak "match_exact_string: wrong number of args" if (@_ != 2);
106 2         5 my ($self,$str) = @_;
107 2         6 $self->exact($self->_ip_bits($str))
108             }
109              
110             sub match_exact_integer {
111 6     6 1 3022 shift->exact_integer(@_)
112             }
113              
114             sub remove_string {
115 4 50   4 1 576 croak "remove_string: wrong number of args" if (@_ != 2);
116 4         9 my ($self,$str) = @_;
117 4         12 $self->remove($self->_ip_bits($str))
118             }
119              
120 0         0 BEGIN {
121 3     3   13 eval {
122 3         7 my $class = 'Net::CIDR::Lite';
123 3         3484 eval "require $class";
124             };
125 3 50       12362 last if (@_);
126              
127             sub add_cidr {
128 1 50   1 0 303 croak "add_cidr: wrong number of args" if (@_ != 3);
129 1         4 my ($self, $range, $data) = @_;
130 1         9 my $cidr = Net::CIDR::Lite->new();
131 1         16 $cidr->add_range($range);
132              
133 1         318 my @list = ();
134 1         5 for ($cidr->list()) {
135 2 50       152 push(@list, $_) if ($self->add_string($_, $data));
136             }
137 1         11 @list;
138             }
139              
140             sub remove_cidr {
141 1 50   1 0 588 croak "remove_cidr: wrong number of args" if (@_ != 2);
142 1         4 my ($self, $range) = @_;
143 1         4 my $cidr = Net::CIDR::Lite->new();
144 1         17 $cidr->add_range($range);
145              
146 1         172 my @list = ();
147 1         4 for ($cidr->list()) {
148 2 50       131 push(@list, $_) if ($self->remove_string($_));
149             }
150 1         10 @list;
151             }
152             }
153              
154             ##
155             ## AF_INET
156             ##
157              
158             package JCM::Net::Patricia::AF_INET;
159              
160 3     3   25 use Carp;
  3         7  
  3         161  
161 3     3   18 use Socket qw(AF_INET inet_aton inet_ntoa);
  3         6  
  3         132  
162 3     3   17 use vars qw(@ISA @EXPORT);
  3         5  
  3         227  
163              
164             BEGIN {
165 3     3   18 require Exporter;
166 3         11 require DynaLoader;
167 3         107 @ISA = qw(Exporter DynaLoader JCM::Net::Patricia);
168 3         2655 @EXPORT = qw(AF_INET);
169             }
170              
171             sub add {
172 29 50 33 29   106 croak "add: wrong number of args" if (@_ < 2 || @_ > 4);
173 29         61 my ($self, $ip, $bits, $data) = @_;
174 29 0       58 $data = (defined $bits ? "$ip/$bits" : $ip) if (@_ < 4);
    50          
175 29         7772 my $packed = inet_aton($ip);
176 29 100       329 croak("invalid key") unless (defined $packed);
177 28 50       66 $bits = 32 if (@_ < 3);
178 28         324 $self->SUPER::_add(AF_INET, $packed, $bits, $data);
179             }
180              
181             sub add_integer {
182 0 0 0 0   0 croak "add_integer: wrong number of args" if (@_ < 2 || @_ > 4);
183 0         0 my ($self, $num, $bits, $data) = @_;
184 0         0 my $packed = pack("N", $num);
185 0         0 my $ip = inet_ntoa($packed);
186 0 0       0 croak("invalid address") unless (defined $ip);
187 0 0       0 $data = (defined $bits ? "$ip/$bits" : $ip) if (@_ < 4);
    0          
188 0 0       0 $bits = 32 if (@_ < 3);
189 0         0 $self->SUPER::_add(AF_INET, $packed, $bits, $data);
190             }
191              
192             sub match_integer {
193 6 50 33 6   1200 croak "match_integer: wrong number of args" if (@_ < 2 || @_ > 3);
194 6         14 my ($self, $num, $bits) = @_;
195 6 50       16 $bits = 32 if (@_ < 3);
196 6         63 $self->SUPER::_match(AF_INET, pack("N",$num), $bits);
197             }
198              
199             sub matching_prefix_integer {
200 0 0 0 0   0 croak "matching_integer: wrong number of args" if (@_ < 2 || @_ > 3);
201 0         0 my ($self, $num, $bits) = @_;
202 0 0       0 $bits = 32 if (@_ < 3);
203 0         0 $self->SUPER::_matching_prefix(AF_INET, pack("N",$num), $bits);
204             }
205              
206             sub exact_integer {
207 6 50 33 6   33 croak "exact_integer: wrong number of args" if (@_ < 2 || @_ > 3);
208 6         12 my ($self, $num, $bits) = @_;
209 6 100       13 $bits = 32 if (@_ < 3);
210 6         63 $self->SUPER::_exact(AF_INET, pack("N",$num), $bits);
211             }
212              
213             sub match {
214 15 50 33 15   70 croak "match: wrong number of args" if (@_ < 2 || @_ > 3);
215 15         34 my ($self, $ip, $bits) = @_;
216 15         65 my $packed = inet_aton($ip);
217 15 50       40 croak("invalid key") unless (defined $packed);
218 15 50       38 $bits = 32 if (@_ < 3);
219 15         127 $self->SUPER::_match(AF_INET, $packed, $bits);
220             }
221              
222             sub matching_prefix {
223 4 50 33 4   22 croak "matching_prefix: wrong number of args" if (@_ < 2 || @_ > 3);
224 4         10 my ($self, $ip, $bits) = @_;
225 4         14 my $packed = inet_aton($ip);
226 4 50       10 croak("invalid key") unless (defined $packed);
227 4 50       10 $bits = 32 if (@_ < 3);
228 4         37 $self->SUPER::_matching_prefix(AF_INET, $packed, $bits);
229             }
230              
231             sub exact {
232 2 50 33 2   14 croak "exact: wrong number of args" if (@_ < 2 || @_ > 3);
233 2         3 my ($self, $ip, $bits) = @_;
234 2         9 my $packed = inet_aton($ip);
235 2 50       5 croak("invalid key") unless (defined $packed);
236 2 50       5 $bits = 32 if (@_ < 3);
237 2         17 $self->SUPER::_exact(AF_INET, $packed, $bits);
238             }
239              
240             sub remove {
241 4 50 33 4   21 croak "remove: wrong number of args" if (@_ < 2 || @_ > 3);
242 4         9 my ($self, $ip, $bits) = @_;
243 4         14 my $packed = inet_aton($ip);
244 4 50       10 croak("invalid key") unless (defined $packed);
245 4 50       9 $bits = 32 if (@_ < 3);
246 4         35 $self->SUPER::_remove(AF_INET, $packed, $bits);
247             }
248              
249             sub remove_integer {
250 0 0 0 0   0 croak "remote_integer: wrong number of args" if (@_ < 2 || @_ > 3);
251 0         0 my ($self, $num, $bits) = @_;
252 0 0       0 $bits = 32 if (@_ < 3);
253 0         0 $self->SUPER::_remove(AF_INET, pack("N",$num), $bits);
254             }
255              
256             ##
257             ## AF_INET6
258             ##
259              
260             package JCM::Net::Patricia::AF_INET6;
261              
262 3     3   24 use Carp;
  3         6  
  3         177  
263 3     3   20 use Socket qw(AF_INET6);
  3         5  
  3         142  
264 3     3   1552 use Socket6 qw(inet_pton inet_ntop);
  3         3314  
  3         317  
265 3     3   21 use vars qw(@ISA @EXPORT);
  3         6  
  3         229  
266              
267             BEGIN {
268 3     3   21 require Exporter;
269 3         10 require DynaLoader;
270 3         61 @ISA = qw(Exporter DynaLoader JCM::Net::Patricia);
271 3         2691 @EXPORT = qw(AF_INET6);
272             }
273              
274             sub add {
275 9 50 33 9   41 croak "add: wrong number of args" if (@_ < 2 || @_ > 4);
276 9         25 my ($self, $ip, $bits, $data) = @_;
277 9 0       19 $data = (defined $bits ? "$ip/$bits" : $ip) if (@_ < 3);
    50          
278 9         60 my $packed = inet_pton(AF_INET6, $ip);
279 9 50       24 croak("invalid key") unless (defined $packed);
280 9 50       23 $bits = 128 if (@_ < 4);
281 9         76 $self->SUPER::_add(AF_INET6, $packed, $bits, $data);
282             }
283              
284             sub add_integer {
285 0 0 0 0   0 croak "add_integer: wrong number of args" if (@_ < 2 || @_ > 4);
286 0         0 my ($self, $num, $bits, $data) = @_;
287 0         0 my $packed = pack("N", $num);
288 0         0 my $ip = inet_ntop(AF_INET6, $packed);
289 0 0       0 croak("invalid address") unless (defined $ip);
290 0 0       0 $data = (defined $bits ? "$ip/$bits" : $ip) if (@_ < 3);
    0          
291 0 0       0 $bits = 128 if (@_ < 4);
292 0         0 $self->SUPER::_add(AF_INET6, $packed, $bits, $data);
293             }
294              
295             sub match_integer {
296 0 0 0 0   0 croak "match_integer: wrong number of args" if (@_ < 2 || @_ > 3);
297 0         0 my ($self, $num, $bits) = @_;
298 0 0       0 $bits = 128 if (@_ < 3);
299 0         0 $self->SUPER::_match(AF_INET6, pack("N",$num), $bits);
300             }
301              
302             sub matching_prefix_integer {
303 0 0 0 0   0 croak "matching_prefix_integer: wrong number of args" if (@_ < 2 || @_ > 3);
304 0         0 my ($self, $num, $bits) = @_;
305 0 0       0 $bits = 128 if (@_ < 3);
306 0         0 $self->SUPER::_matching_prefix(AF_INET6, pack("N",$num), $bits);
307             }
308              
309             sub exact_integer {
310 0 0 0 0   0 croak "exact_integer: wrong number of args" if (@_ < 2 || @_ > 3);
311 0         0 my ($self, $num, $bits) = @_;
312 0 0       0 $bits = 128 if (@_ < 3);
313 0         0 $self->SUPER::_exact(AF_INET6, pack("N",$num), $bits);
314             }
315              
316             sub match {
317 2 50 33 2   12 croak "match: wrong number of args" if (@_ < 2 || @_ > 3);
318 2         8 my ($self, $ip, $bits) = @_;
319 2         8 my $packed = inet_pton(AF_INET6, $ip);
320 2 50       5 croak("invalid key") unless (defined $packed);
321 2 50       6 $bits = 128 if (@_ < 3);
322 2         39 $self->SUPER::_match(AF_INET6, $packed, $bits);
323             }
324              
325             sub matching_prefix {
326 4 50 33 4   31 croak "matching_prefix: wrong number of args" if (@_ < 2 || @_ > 3);
327 4         10 my ($self, $ip, $bits) = @_;
328 4         14 my $packed = inet_pton(AF_INET6, $ip);
329 4 50       11 croak("invalid key") unless (defined $packed);
330 4 50       10 $bits = 128 if (@_ < 3);
331 4         57 $self->SUPER::_matching_prefix(AF_INET6, $packed, $bits);
332             }
333              
334             sub exact {
335 0 0 0 0     croak "exact: wrong number of args" if (@_ < 2 || @_ > 3);
336 0           my ($self, $ip, $bits) = @_;
337 0           my $packed = inet_pton(AF_INET6, $ip);
338 0 0         croak("invalid key") unless (defined $packed);
339 0 0         $bits = 128 if (@_ < 3);
340 0           $self->SUPER::_exact(AF_INET6, $packed, $bits);
341             }
342              
343             sub remove {
344 0 0 0 0     croak "remove: wrong number of args" if (@_ < 2 || @_ > 3);
345 0           my ($self, $ip, $bits) = @_;
346 0           my $packed = inet_pton(AF_INET6, $ip);
347 0 0         croak("invalid key") unless (defined $packed);
348 0 0         $bits = 128 if (@_ < 3);
349 0           $self->SUPER::_remove(AF_INET6, $packed, $bits);
350             }
351              
352             sub remove_integer {
353 0 0 0 0     croak "remote_integer: wrong number of args" if (@_ < 2 || @_ > 3);
354 0           my ($self, $num, $bits) = @_;
355 0 0         $bits = 128 if (@_ < 3);
356 0           $self->SUPER::_remove(AF_INET6, pack("N",$num), $bits);
357             }
358              
359             1;
360             __END__