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 J. 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             # J. Maslak
22             # Dave Plonka
23             # Philip Prindeville
24             # Anton Berezin
25              
26             package JCM::Net::Patricia;
27              
28 3     3   235473 use strict;
  3         8  
  3         76  
29 3     3   15 use warnings;
  3         4  
  3         91  
30              
31             require 5.008;
32              
33 3     3   645 use version;
  3         4486  
  3         16  
34 3     3   211 use Carp;
  3         6  
  3         229  
35 3     3   19 use vars qw($VERSION @ISA @EXPORT);
  3         5  
  3         144  
36 3     3   1127 use Socket qw(AF_INET AF_INET6);
  3         9163  
  3         616  
37              
38             BEGIN {
39 3     3   24 require Exporter;
40 3         10 require DynaLoader;
41 3         39 @ISA = qw(Exporter DynaLoader);
42 3         1896 @EXPORT = qw(AF_INET AF_INET6);
43             }
44              
45             '$Revision: 1.03 $' =~ m/(\d+)\.(\d+)((_\d+)|)/ && ( $VERSION = "$1.$2$3");
46              
47             bootstrap JCM::Net::Patricia $VERSION;
48              
49             sub new {
50 7     7 1 5241 my ($class, $type) = @_;
51              
52 7   100     41 $type ||= AF_INET;
53              
54 7 100       37 if ($type == AF_INET) {
55 4         46 return bless _new(32), 'JCM::Net::Patricia::AF_INET';
56             }
57              
58 3 50       13 if ($type == AF_INET6) {
59 3 50       12 if (JCM::Net::Patricia::have_ipv6()) {
60 3         29 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   136 my ($self, $str) = @_;
75 69         91 my $bits;
76              
77 69 100       137 if (ref ($self) eq 'JCM::Net::Patricia::AF_INET6') {
78 15 100       91 $bits = ($str =~ s|/(\d+)$||) ? $1 : 128;
79             } else {
80 54 100       244 $bits = ($str =~ s|/(\d+)$||) ? $1 : 32;
81             }
82 69         225 ($str,$bits);
83             }
84              
85             sub add_string {
86 38 50 33 38 1 5604 croak "add_string: wrong number of args" if (@_ < 2 || @_ > 3);
87 38         82 my ($self,$str,$data) = @_;
88 38 100       73 $data = $str unless @_ > 2;
89 38         93 $self->add($self->_ip_bits($str),$data);
90             }
91              
92             sub match_string {
93 17 50   17 1 3577 croak "match_string: wrong number of args" if (@_ != 2);
94 17         30 my ($self,$str) = @_;
95 17         41 $self->match($self->_ip_bits($str))
96             }
97              
98             sub matching_prefix_string {
99 8 50   8 1 2339 croak "matching_prefix_string: wrong number of args" if (@_ != 2);
100 8         16 my ($self,$str) = @_;
101 8         26 $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 2380 shift->exact_integer(@_)
112             }
113              
114             sub remove_string {
115 4 50   4 1 430 croak "remove_string: wrong number of args" if (@_ != 2);
116 4         10 my ($self,$str) = @_;
117 4         12 $self->remove($self->_ip_bits($str))
118             }
119              
120 0         0 BEGIN {
121 3     3   10 eval {
122 3         7 my $class = 'Net::CIDR::Lite';
123 3         185 eval "require $class";
124             };
125 3 50       10102 last if (@_);
126              
127             sub add_cidr {
128 1 50   1 0 305 croak "add_cidr: wrong number of args" if (@_ != 3);
129 1         5 my ($self, $range, $data) = @_;
130 1         11 my $cidr = Net::CIDR::Lite->new();
131 1         16 $cidr->add_range($range);
132              
133 1         341 my @list = ();
134 1         7 for ($cidr->list()) {
135 2 50       140 push(@list, $_) if ($self->add_string($_, $data));
136             }
137 1         17 @list;
138             }
139              
140             sub remove_cidr {
141 1 50   1 0 529 croak "remove_cidr: wrong number of args" if (@_ != 2);
142 1         3 my ($self, $range) = @_;
143 1         5 my $cidr = Net::CIDR::Lite->new();
144 1         11 $cidr->add_range($range);
145              
146 1         147 my @list = ();
147 1         5 for ($cidr->list()) {
148 2 50       139 push(@list, $_) if ($self->remove_string($_));
149             }
150 1         6 @list;
151             }
152             }
153              
154             ##
155             ## AF_INET
156             ##
157              
158             package JCM::Net::Patricia::AF_INET;
159              
160 3     3   35 use Carp;
  3         7  
  3         140  
161 3     3   15 use Socket qw(AF_INET inet_aton inet_ntoa);
  3         6  
  3         125  
162 3     3   23 use vars qw(@ISA @EXPORT);
  3         58  
  3         1819  
163              
164             BEGIN {
165 3     3   17 require Exporter;
166 3         9 require DynaLoader;
167 3         52 @ISA = qw(Exporter DynaLoader JCM::Net::Patricia);
168 3         1814 @EXPORT = qw(AF_INET);
169             }
170              
171             sub add {
172 29 50 33 29   101 croak "add: wrong number of args" if (@_ < 2 || @_ > 4);
173 29         58 my ($self, $ip, $bits, $data) = @_;
174 29 0       53 $data = (defined $bits ? "$ip/$bits" : $ip) if (@_ < 4);
    50          
175 29         12875 my $packed = inet_aton($ip);
176 29 100       399 croak("invalid key") unless (defined $packed);
177 28 50       60 $bits = 32 if (@_ < 3);
178 28         155 $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   996 croak "match_integer: wrong number of args" if (@_ < 2 || @_ > 3);
194 6         13 my ($self, $num, $bits) = @_;
195 6 50       12 $bits = 32 if (@_ < 3);
196 6         57 $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   26 croak "exact_integer: wrong number of args" if (@_ < 2 || @_ > 3);
208 6         12 my ($self, $num, $bits) = @_;
209 6 100       11 $bits = 32 if (@_ < 3);
210 6         58 $self->SUPER::_exact(AF_INET, pack("N",$num), $bits);
211             }
212              
213             sub match {
214 15 50 33 15   62 croak "match: wrong number of args" if (@_ < 2 || @_ > 3);
215 15         30 my ($self, $ip, $bits) = @_;
216 15         51 my $packed = inet_aton($ip);
217 15 50       37 croak("invalid key") unless (defined $packed);
218 15 50       27 $bits = 32 if (@_ < 3);
219 15         108 $self->SUPER::_match(AF_INET, $packed, $bits);
220             }
221              
222             sub matching_prefix {
223 4 50 33 4   17 croak "matching_prefix: wrong number of args" if (@_ < 2 || @_ > 3);
224 4         8 my ($self, $ip, $bits) = @_;
225 4         13 my $packed = inet_aton($ip);
226 4 50       9 croak("invalid key") unless (defined $packed);
227 4 50       7 $bits = 32 if (@_ < 3);
228 4         28 $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         4 my ($self, $ip, $bits) = @_;
234 2         8 my $packed = inet_aton($ip);
235 2 50       5 croak("invalid key") unless (defined $packed);
236 2 50       7 $bits = 32 if (@_ < 3);
237 2         14 $self->SUPER::_exact(AF_INET, $packed, $bits);
238             }
239              
240             sub remove {
241 4 50 33 4   20 croak "remove: wrong number of args" if (@_ < 2 || @_ > 3);
242 4         10 my ($self, $ip, $bits) = @_;
243 4         17 my $packed = inet_aton($ip);
244 4 50       10 croak("invalid key") unless (defined $packed);
245 4 50       11 $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   18 use Carp;
  3         5  
  3         137  
263 3     3   14 use Socket qw(AF_INET6);
  3         8  
  3         87  
264 3     3   954 use Socket6 qw(inet_pton inet_ntop);
  3         2522  
  3         251  
265 3     3   20 use vars qw(@ISA @EXPORT);
  3         3  
  3         175  
266              
267             BEGIN {
268 3     3   15 require Exporter;
269 3         7 require DynaLoader;
270 3         38 @ISA = qw(Exporter DynaLoader JCM::Net::Patricia);
271 3         1917 @EXPORT = qw(AF_INET6);
272             }
273              
274             sub add {
275 9 50 33 9   43 croak "add: wrong number of args" if (@_ < 2 || @_ > 4);
276 9         24 my ($self, $ip, $bits, $data) = @_;
277 9 0       21 $data = (defined $bits ? "$ip/$bits" : $ip) if (@_ < 3);
    50          
278 9         38 my $packed = inet_pton(AF_INET6, $ip);
279 9 50       22 croak("invalid key") unless (defined $packed);
280 9 50       19 $bits = 128 if (@_ < 4);
281 9         63 $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   11 croak "match: wrong number of args" if (@_ < 2 || @_ > 3);
318 2         5 my ($self, $ip, $bits) = @_;
319 2         7 my $packed = inet_pton(AF_INET6, $ip);
320 2 50       6 croak("invalid key") unless (defined $packed);
321 2 50       8 $bits = 128 if (@_ < 3);
322 2         26 $self->SUPER::_match(AF_INET6, $packed, $bits);
323             }
324              
325             sub matching_prefix {
326 4 50 33 4   29 croak "matching_prefix: wrong number of args" if (@_ < 2 || @_ > 3);
327 4         9 my ($self, $ip, $bits) = @_;
328 4         15 my $packed = inet_pton(AF_INET6, $ip);
329 4 50       12 croak("invalid key") unless (defined $packed);
330 4 50       9 $bits = 128 if (@_ < 3);
331 4         41 $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__