File Coverage

lib/Data/IPV4/Range/Parse.pm
Criterion Covered Total %
statement 73 75 97.3
branch 31 42 73.8
condition 2 6 33.3
subroutine 20 20 100.0
pod 13 13 100.0
total 139 156 89.1


line stmt bran cond sub pod time code
1             package Data::IPV4::Range::Parse;
2              
3 6     6   199398 use strict;
  6         13  
  6         219  
4 6     6   42 use warnings;
  6         15  
  6         247  
5 6     6   34 use Carp qw(croak);
  6         15  
  6         510  
6 6     6   42 use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK $VERSION @EXPORT);
  6         11  
  6         1260  
7              
8             $VERSION = '1.05';
9              
10             require Exporter;
11             @ISA = qw(Exporter);
12              
13             @EXPORT_OK=qw(
14             ALL_BITS
15             MAX_CIDR
16             MIN_CIDR
17              
18             sort_quad
19             sort_notations
20              
21             int_to_ip
22             ip_to_int
23              
24             parse_ipv4_cidr
25             parse_ipv4_ip
26             parse_ipv4_range
27              
28             broadcast_int
29             base_int
30             size_from_mask
31             hostmask
32             cidr_to_int
33              
34             auto_parse_ipv4_range
35             );
36              
37             %EXPORT_TAGS = (
38             ALL=>\@EXPORT_OK
39             ,CONSTANTS=>[qw(
40             ALL_BITS
41             MAX_CIDR
42             MIN_CIDR
43             )]
44             ,PARSE_RANGE=>[qw(
45             parse_ipv4_cidr
46             parse_ipv4_ip
47             parse_ipv4_range
48             auto_parse_ipv4_range
49             )]
50             ,PARSE_IP=>[qw(
51             int_to_ip
52             ip_to_int
53             )]
54             ,SORT=>[qw(
55             sort_quad
56             sort_notations
57             )]
58             ,COMPUTE_FROM_INT=>[ qw(
59             broadcast_int
60             base_int
61             size_from_mask
62             hostmask
63             cidr_to_int
64             )]
65             );
66              
67 6     6   35 use constant ALL_BITS=>0xffffffff;
  6         11  
  6         712  
68 6     6   29 use constant MAX_CIDR=>32;
  6         14  
  6         286  
69 6     6   34 use constant MIN_CIDR=>0;
  6         10  
  6         7979  
70              
71 2 100   2 1 11 sub int_to_ip ($) { shift if $#_>0;join '.',unpack('C4',(pack('N',$_[0]))) }
  2         22  
72 35 100   35 1 103 sub ip_to_int ($) { shift if $#_>0;unpack('N',pack('C4',split(/\./,$_[0]))) }
  35         258  
73              
74             sub sort_quad ($$) {
75 4     4 1 25 my ($ip_a,$ip_b)=@_;
76 4         9 ip_to_int($ip_a) <=> ip_to_int($ip_b)
77             }
78              
79             sub sort_notations ($$) {
80 2     2 1 959 my ($a_start,$a_end,$b_start,$b_end)=map { auto_parse_ipv4_range($_) } @_;
  4         13  
81 2 50       7 croak 'cannot parse notation a or b'
82             unless defined($b_end);
83 2         3 my $ab_cmp=($a_start<=>$b_start);
84 2 100       622 return $ab_cmp if $ab_cmp!=0;
85 1         3 $a_end <=> $b_end
86             }
87              
88             sub broadcast_int ($$) {
89 8 100   8 1 52 shift if $#_>1;
90 8         45 base_int($_[0],$_[1]) + hostmask($_[1])
91             }
92              
93 16 100   16 1 78 sub base_int ($$) { shift if $#_>1;$_[0] & $_[1] }
  16         52  
94 2 100   2 1 8 sub size_from_mask ($) { shift if $#_>0;1 + hostmask($_[0] ) }
  2         6  
95 12 100   12 1 582 sub hostmask ($) { shift if $#_>0;ALL_BITS & (~(ALL_BITS & $_[0])) }
  12         64  
96             sub cidr_to_int ($) {
97 39 50   39 1 128 shift if $#_>0;
98 39         48 my ($cidr)=@_;
99 39         59 my $shift=MAX_CIDR -$cidr;
100 39 50       72 return undef unless defined($cidr);
101 39 50       191 return undef unless $cidr=~ /^\d{1,2}$/s;
102 39 50 33     202 return undef if $cidr>MAX_CIDR or $cidr
103 39 100       829 return 0 if $shift==MAX_CIDR;
104 38         158 ALL_BITS & (ALL_BITS << $shift)
105             }
106              
107             sub parse_ipv4_cidr {
108 6     6 1 13 my $notation=$_[$#_];
109 6         34 $notation=~ s/(^\s+|\s+$)//g;
110             return ()
111 6 50       46 unless($notation=~ /
112             ^\d{1,3}(\.\d{1,3}){0,3}
113             \s*\/\s*
114             \d{1,3}(\.\d{1,3}){0,3}$
115             /x);
116 6         36 my ($ip,$mask)=split /\s*\/\s*/,$notation;
117 6         16 my $ip_int=ip_to_int($ip);
118 6         14 my $mask_int;
119              
120 6 50 33     49 if($mask=~ /\./) {
    50          
121             # we know its quad notation
122 0         0 $mask_int=ip_to_int($mask);
123             } elsif($mask>=MIN_CIDR && $mask<=MAX_CIDR) {
124 6         17 $mask_int=cidr_to_int($mask);
125             } else {
126 0         0 $mask_int=ip_to_int($mask);
127             }
128 6         21 my $first_int=base_int($ip_int , $mask_int);
129 6         16 my $last_int=broadcast_int( $first_int,$mask_int);
130              
131 6         31 ($first_int,$last_int)
132             }
133              
134             sub parse_ipv4_range {
135 5     5 1 31 my $range=$_[$#_];
136 5 50       17 return () unless defined($range);
137             # lop off start and end spaces
138 5         33 $range=~ s/(^\s+|\s+$)//g;
139              
140 5 50       39 return () unless $range=~ /
141             ^\d{1,3}(\.\d{1,3}){0,3}
142             \s*-\s*
143             \d{1,3}(\.\d{1,3}){0,3}$
144             /x;
145            
146 5         27 my ($start,$end)=split /\s*-\s*/,$range;
147 5         18 ( ip_to_int($start) ,ip_to_int($end))
148             }
149              
150              
151             sub parse_ipv4_ip {
152 3     3 1 6 my $ip=$_[$#_];
153 3 50       8 return () unless defined($ip);
154            
155 3         9 ( ip_to_int($ip) ,ip_to_int($ip))
156             }
157              
158             sub auto_parse_ipv4_range {
159 7     7 1 14 my $source=$_[$#_];
160 7 100       39 return parse_ipv4_cidr($source) if $source=~ /\//;
161 3 100       17 return parse_ipv4_range($source) if $source=~ /-/;
162 1         3 return parse_ipv4_ip($source);
163             }
164              
165             1;
166             __END__