File Coverage

blib/lib/Net/ASN.pm
Criterion Covered Total %
statement 192 207 92.7
branch 72 100 72.0
condition 26 60 43.3
subroutine 32 32 100.0
pod 16 16 100.0
total 338 415 81.4


line stmt bran cond sub pod time code
1             # ASN.pm - Perl module to manipulate autonomous system numbers
2             #
3             # Author: David J. Freedman
4             #
5             # Copyright (C) 2008 Convergence Inc.
6             #
7             # This program is free software; you can redistribute it and/or modify
8             # it under the terms as perl itself.
9             #
10              
11             package Net::ASN;
12              
13 1     1   493 use strict;
  1         1  
  1         37  
14 1     1   10 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         1  
  1         140  
15              
16             BEGIN {
17              
18 1     1   4 require Exporter;
19              
20 1         13 @ISA = qw(Exporter);
21              
22 1         1 @EXPORT = qw();
23              
24 1         11 %EXPORT_TAGS = (
25             all => [qw{
26             plaintodot plaintodotplus
27             dottodotplus dottoplain
28             dottoplain16 dotplustodot
29             dotplustoplain dotplustoplain16
30             isprivateasn
31             } ],
32             );
33              
34 1         2 @EXPORT_OK = qw();
35              
36 1         38 Exporter::export_ok_tags('all');
37              
38 1         51 $VERSION = '1.07';
39             }
40              
41             # Preloaded methods go here.
42 1     1   17 use Carp;
  1         2  
  1         118  
43              
44             #Constants
45 1     1   7 use constant AS_TRANS => 23456;
  1         2  
  1         100  
46 1     1   8 use constant AS16_START => 1;
  1         2  
  1         46  
47 1     1   4 use constant AS16_PRIVATE_START => 64512;
  1         1  
  1         40  
48 1     1   3 use constant AS16_PRIVATE_END => 65534;
  1         1  
  1         42  
49 1     1   3 use constant AS16_END => 65535;
  1         1  
  1         76  
50 1     1   6 use constant AS32_START => 65536;
  1         2  
  1         52  
51 1     1   3 use constant AS32_PRIVATE_START => 4200000000;
  1         1  
  1         43  
52 1     1   3 use constant AS32_PRIVATE_END => 4294967294;
  1         1  
  1         47  
53 1     1   3 use constant AS32_END => 4294967295;
  1         1  
  1         2151  
54              
55             ##OO Methods
56              
57             #Initialise with an ASN
58             #
59             sub new {
60              
61 30     30 1 511 my $class = shift;
62 30         67 my $self = {};
63              
64 30         41 my $asn = shift;
65              
66 30         45 my $asasdot = shift;
67              
68 30         49 bless $self, $class;
69              
70 30         74 $self->_parseasn($asn,$asasdot); #Parse the ASN
71              
72 30         153 return $self;
73              
74             }
75              
76             #Parses an ASN, in any format
77             sub _parseasn ($;$) {
78              
79 30     30   35 my $self = shift;
80 30         37 my $inasn = shift;
81 30         33 my $asasdot = shift;
82              
83             #Perform some basic checks
84             #
85             #1) did we even get a parameter?
86 30 50       70 unless ($inasn) {
87 0         0 croak __PACKAGE__, ": ASN not provided";
88             }
89             #2) does the ASN contain a valid character set?
90 30 50       187 unless ($inasn=~m/^[\d\.]+$/) {
91 0         0 croak __PACKAGE__, ": Invalid ASN (Illegal Characters)";
92             }
93             #3) Next, check the format
94              
95 30 100       189 if ($inasn=~m/^(\d+)$/) { #ASN is ASN16 (1-65535) or ASN32 ASPLAIN (1-4294967295) or ASDOT if forced
    50          
96 18 100 66     139 if ($asasdot) {
    100 33        
    50          
97 4 50 33     34 if ($inasn >= AS16_START && $inasn <= AS16_END) {
98 4         15 $self->{_informat} = 'asdot';
99 4         10 $self->{_asdot} = $inasn;
100             }
101             else {
102 0         0 croak __PACKAGE__, ": Invalid ASDOT ASN (ASDOT does NOT permit ASPLAIN notation for ASNs 63356-4294967295)";
103             }
104             }
105             elsif ($inasn >= AS16_START && $inasn <= AS16_END) {
106 7         31 $self->{_informat} = 'asplain16';
107 7         18 $self->{_asplain16} = $inasn;
108             }
109             elsif ($inasn >= AS32_START && $inasn <= AS32_END) {
110 7         22 $self->{_informat} = 'asplain32';
111 7         18 $self->{_asplain32} = $inasn;
112             }
113             else {
114 0         0 croak __PACKAGE__, ": Invalid ASPLAIN ASN (must be between 1-4294967295)";
115             }
116             }
117             elsif ($inasn=~m/^(\d+)\.(\d+)$/) { #ASN is ASN32 ASDOT+ notation or ASDOT if forced
118              
119 12         33 my $firstasn = $1;
120 12         19 my $secondasn = $2;
121              
122 12 50 33     191 unless (
      33        
      33        
      66        
      33        
123             ($firstasn >= 0 && $firstasn <= AS16_END) &&
124             ($secondasn >= 0 && $secondasn <= AS16_END) &&
125             (
126             ($firstasn > 0) ||
127             ($secondasn > 0)
128             )
129             ) {
130 0         0 croak __PACKAGE__, ": Invalid ASDOT(+) ASN (must be between 0-65535.0-65535 and NOT 0.0)";
131             }
132              
133             #Allow input as ASDOT if $asasdot is populated
134 12 100       27 if ($asasdot) {
135 4 50       18 if ($firstasn > 0) {
136 4         15 $self->{_informat} = 'asdot';
137             }
138             else {
139 0         0 croak __PACKAGE__, ": Invalid ASDOT ASN (ASDOT does NOT permit ASDOT+ notation for ASNs 0-65535)";
140             }
141             }
142             else {
143 8         28 $self->{_informat} = 'asdotplus';
144             }
145 12         26 $self->{_asdotsedtet1} = $firstasn;
146 12         25 $self->{_asdotsedtet2} = $secondasn;
147              
148             }
149             else {
150 0         0 croak __PACKAGE__, ": Invalid ASN (Illegal Format)";
151             }
152              
153 30         56 return;
154              
155             }
156              
157             sub _plaintodot ($) {
158            
159 8     8   13 my $self = shift;
160 8         12 my $asplain = shift;
161              
162 8 50       50 unless ($asplain=~m/^(\d+)$/) {
163 0         0 die ("Internal Error: _plaintodot called with invalid plain");
164             }
165             else {
166 8         29 my $asdot=int($asplain/65536);
167 8         16 $asdot .= ".";
168 8         33 $asdot .= ($asplain - ($asdot*65536));
169 8         29 return $asdot;
170             }
171              
172             }
173              
174             sub _dottoplain ($) {
175              
176 6     6   11 my $self = shift;
177 6         11 my $asdot = shift;
178              
179 6 50       40 unless ($asdot=~m/^(\d+)\.(\d+)$/) {
180 0         0 die("Internal Error: _dottoplain called with invalid dot");
181             }
182             else {
183 6         18 my $asplain1 = $1;
184 6         16 my $asplain2 = $2;
185 6         17 my $asplain = (65536 * $asplain1);
186 6         12 $asplain+=$asplain2;
187 6         15 return $asplain;
188             }
189             }
190              
191             ##Produce ASDOT representation of parsed ASN
192             sub toasdot () {
193              
194 10     10 1 17 my $self = shift;
195 10 100       57 if ($self->{_informat} eq 'asdot') { #User wants asdot and we already have it, just return it
    100          
    100          
    50          
196 2 100       9 if ($self->{_asdot}) {
197 1         15 return $self->{_asdot};
198             }
199             else {
200 1         6 my $value = "$self->{_asdotsedtet1}.$self->{_asdotsedtet2}";
201 1         7 return ($value);
202             }
203              
204             }
205             elsif ($self->{_informat} eq 'asdotplus') { #User wants asdot and has given us asdotplus, so return asplain if
206 4 100       15 if ($self->{_asdotsedtet1} == 0) { #If first sedtet is 0, return the second only
207 2         15 return ($self->{_asdotsedtet2});
208             }
209             else { #Else, return both
210 2         9 my $value = "$self->{_asdotsedtet1}.$self->{_asdotsedtet2}";
211 2         15 return ($value);
212             }
213             }
214             elsif ($self->{_informat} eq 'asplain16') { #User wants asdot and has given us an 16 bit asplain (just return asplain)
215 2         5 my $value = $self->{_asplain16};
216 2         15 return ($value);
217             }
218             elsif ($self->{_informat} eq 'asplain32') { #User wants asdot and has given us an 32 bit asplain
219 2         5 my $value = $self->{_asplain32};
220 2         6 $value = $self->_plaintodot($value);
221 2         12 return ($value);
222             }
223             else {
224 0         0 die ("Internal Error: no acceptable informat defined");
225             }
226              
227             }
228              
229             ##Produce ASDOT+ representation of parsed ASN
230             sub toasdotplus () {
231              
232 10     10 1 18 my $self = shift;
233 10 100       65 if ($self->{_informat} eq 'asdot') { #User wants asdotplus and we have asdot
    100          
    100          
    50          
234 4 100       13 if ($self->{_asdot}) {
235 2         18 my $value = $self->_plaintodot($self->{_asdot});
236 2         12 return ($value);
237             }
238             else {
239 2         9 my $value = "$self->{_asdotsedtet1}.$self->{_asdotsedtet2}";
240 2         12 return ($value);
241             }
242             }
243             elsif ($self->{_informat} eq 'asdotplus') { #User wants asdotplus and we have it, just return it
244 2         8 my $value = "$self->{_asdotsedtet1}.$self->{_asdotsedtet2}";
245 2         12 return ($value);
246             }
247             elsif ($self->{_informat} eq 'asplain16') { #User wants asdotplus and has given us an 16 bit asplain
248 2         4 my $value = $self->{_asplain16};
249 2         8 $value = $self->_plaintodot($value);
250 2         12 return ($value);
251             }
252             elsif ($self->{_informat} eq 'asplain32') { #User wants asdotplus and has given us an 32 bit asplain
253 2         5 my $value = $self->{_asplain32};
254 2         6 $value = $self->_plaintodot($value);
255 2         13 return ($value);
256             }
257             else {
258 0         0 die ("Internal Error: no acceptable informat defined");
259             }
260              
261             }
262              
263             ##Produce ASPLAIN representation of parsed ASN (32 bit version)
264             sub toasplain () {
265              
266 18     18 1 31 my $self = shift;
267              
268 18 100       114 if ($self->{_informat} eq 'asdot') { #User wants asplain and we have asdot
    100          
    100          
    50          
269 4 100       13 if ($self->{_asdot}) {
270 2         14 return ($self->{_asdot});
271             }
272             else {
273 2         8 my $value = "$self->{_asdotsedtet1}.$self->{_asdotsedtet2}";
274 2         7 $value = $self->_dottoplain($value);
275 2         15 return ($value);
276             }
277             }
278             elsif ($self->{_informat} eq 'asplain16') { #User wants asplain and we have it
279 5         19 my $value = $self->{_asplain16};
280 5         16 return ($value);
281             }
282             elsif ($self->{_informat} eq 'asplain32') { #User wants asplain and we have it
283 5         11 my $value = $self->{_asplain32};
284 5         15 return ($value);
285             }
286             elsif ($self->{_informat} eq 'asdotplus') { #User wants asplain and has given us asdotplus so return asplain
287 4         14 my $value = "$self->{_asdotsedtet1}.$self->{_asdotsedtet2}";
288 4         13 $value = $self->_dottoplain($value);
289 4         27 return ($value);
290             }
291             else {
292 0         0 die ("Internal Error: no acceptable informat defined");
293             }
294             }
295              
296             ##Produce ASPLAIN representation of parsed ASN (16 bit version)
297             sub toasplain16 () {
298              
299 8     8 1 15 my $self = shift;
300              
301 8 100       53 if ($self->{_informat} eq 'asdot') { #User wants asplain16 and we have asdot
    50          
    100          
    50          
302 3 100       12 if ($self->{_asdot}) {
303 1         7 return ($self->{_asdot});
304             }
305             else {
306 2         14 return (AS_TRANS);
307             }
308             }
309             elsif ($self->{_informat} eq 'asplain16') { #User wants asplain and we have it
310 0         0 my $value = $self->{_asplain16};
311 0         0 return ($value);
312             }
313             elsif ($self->{_informat} eq 'asplain32') { #User wants asplain so return AS_TRANS
314 1         7 return (AS_TRANS);
315             }
316             elsif ($self->{_informat} eq 'asdotplus') { #User wants asplain and has given us asdotplus, return AS_TRANS for 32 bit
317 4 100       12 if ($self->{_asdotsedtet1} == 0) {
318 2         21 return ($self->{_asdotsedtet2});
319             }
320             else {
321 2         13 return (AS_TRANS);
322             }
323             }
324             else {
325 0         0 die ("Internal Error: no acceptable informat defined");
326             }
327             }
328              
329             ##Return parsed type
330             sub gettype () {
331 6     6 1 14 my $self = shift;
332 6         12 my $informat = $self->{_informat};
333 6         22 $informat=~s/\d+//g; #Remove ASPLAIN differentiation
334 6         33 return ($informat);
335             }
336              
337             ##RFC 6996 reserves some ASN's for private use
338             sub isprivate {
339 8     8 1 14 my $self = shift;
340 8         19 my $asn = $self->toasplain;
341 8 100 100     91 if ( ( $asn >= AS16_PRIVATE_START && $asn <= AS16_PRIVATE_END ) ||
      66        
      66        
342             ( $asn >= AS32_PRIVATE_START && $asn <= AS32_PRIVATE_END ) ) {
343 4         24 return 1;
344             }
345 4         27 return 0;
346             }
347              
348             ###NON OO Function wrappers
349             ##toasdot
350             sub plaintodot ($) {
351 2     2 1 4 my $inasn = shift;
352 2 50       10 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
353 2 50       18 croak __PACKAGE__, ": Must provide ASPLAIN" unless ($inasn=~m/^(\d+)$/); #Ensure only numerical is passed
354 2   33     8 my $asn = Net::ASN->new($inasn) || croak __PACKAGE__, ": Could not create new Net::ASN object";
355 2         8 return ($asn->toasdot);
356             }
357             ##toasdotplus
358             sub plaintodotplus ($) {
359 2     2 1 5 my $inasn = shift;
360 2 50       8 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
361 2 50       18 croak __PACKAGE__, ": Must provide ASPLAIN" unless ($inasn=~m/^(\d+)$/); #Ensure only numerical is passed
362 2   33     7 my $asn = Net::ASN->new($inasn) || croak __PACKAGE__, ": Could not create new Net::ASN object";
363 2         9 return ($asn->toasdotplus);
364             }
365             ##toasdotplus
366             sub dottodotplus ($) {
367 2     2 1 6 my $inasn = shift;
368 2 50       8 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
369 2   33     8 my $asn = Net::ASN->new($inasn,1) || croak __PACKAGE__, ": Could not create new Net::ASN object";
370 2         9 return ($asn->toasdotplus);
371             }
372             ##toasplain
373             sub dottoplain ($) {
374 2     2 1 6 my $inasn = shift;
375 2 50       10 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
376 2   33     8 my $asn = Net::ASN->new($inasn,1) || croak __PACKAGE__, ": Could not create new Net::ASN object";
377 2         9 return ($asn->toasplain);
378             }
379             ##toasplain16
380             sub dottoplain16 ($) {
381 2     2 1 6 my $inasn = shift;
382 2 50       9 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
383 2   33     7 my $asn = Net::ASN->new($inasn,1) || croak __PACKAGE__, ": Could not create new Net::ASN object";
384 2         10 return ($asn->toasplain16);
385             }
386             ##toasdot again
387             sub dotplustodot ($) {
388 2     2 1 5 my $inasn = shift;
389 2 50       8 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
390 2 50       11 croak __PACKAGE__, ": Must provide ASDOT+" unless ($inasn=~m/\./); #Ensure only dotted is passed
391 2   33     8 my $asn = Net::ASN->new($inasn) || croak __PACKAGE__, ": Could not create new Net::ASN object";
392 2         8 return ($asn->toasdot);
393             }
394             ##toasplain
395             sub dotplustoplain ($) {
396 2     2 1 7 my $inasn = shift;
397 2 50       7 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
398 2 50       19 croak __PACKAGE__, ": Must provide ASDOT+" unless ($inasn=~m/\./); #Ensure only dotted is passed
399 2   33     6 my $asn = Net::ASN->new($inasn) || croak __PACKAGE__, ": Could not create new Net::ASN object";
400 2         9 return ($asn->toasplain);
401             }
402             ##toasplain16
403             sub dotplustoplain16 ($) {
404 2     2 1 5 my $inasn = shift;
405 2 50       7 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
406 2 50       9 croak __PACKAGE__, ": Must provide ASDOT+" unless ($inasn=~m/\./); #Ensure only dotted is passed
407 2   33     9 my $asn = Net::ASN->new($inasn) || croak __PACKAGE__, ": Could not create new Net::ASN object";
408 2         10 return ($asn->toasplain16);
409             }
410              
411             ##isprivate
412             sub isprivateasn ($) {
413 4     4 1 8 my $inasn = shift;
414 4 50       13 croak __PACKAGE__, ": No ASN specified" unless ($inasn);
415 4   33     24 my $asn = Net::ASN->new($inasn) || croak __PACKAGE__, ": Could not create new Net::ASN object";
416 4         13 return ($asn->isprivate);
417             }
418              
419             1;
420             __END__