File Coverage

blib/lib/FusionInventory/Agent/Tools/Network.pm
Criterion Covered Total %
statement 24 106 22.6
branch 0 46 0.0
condition 0 21 0.0
subroutine 8 19 42.1
pod 11 11 100.0
total 43 203 21.1


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Tools::Network;
2              
3 62     62   11262956 use strict;
  62         88  
  62         2313  
4 62     62   302 use warnings;
  62         86  
  62         1811  
5 62     62   279 use base 'Exporter';
  62         128  
  62         5742  
6              
7 62     62   319 use English qw(-no_match_vars);
  62         89  
  62         426  
8 62     62   69417 use Net::IP qw(:PROC);
  62         2457790  
  62         29513  
9 62     62   38526 use Net::hostent;
  62         100831  
  62         365  
10 62     62   38923 use Socket;
  62         204369  
  62         31915  
11              
12 62     62   1599 use FusionInventory::Agent::Tools;
  62         93  
  62         79606  
13              
14             our @EXPORT = qw(
15             $mac_address_pattern
16             $ib_mac_address_pattern
17             $any_mac_address_pattern
18             $ip_address_pattern
19             $alt_mac_address_pattern
20             $hex_ip_address_pattern
21             $network_pattern
22             getSubnetAddress
23             getSubnetAddressIPv6
24             getNetworkMask
25             getNetworkMaskIPv6
26             isSameNetwork
27             isSameNetworkIPv6
28             hex2canonical
29             alt2canonical
30             resolve
31             compile
32             isPartOf
33             );
34              
35             my $dec_byte = qr/[0-9]{1,3}/;
36             my $hex_byte = qr/[0-9A-F]{1,2}/i;
37             my $padded_hex_byte = qr/[0-9A-F]{2}/i;
38              
39             our $mac_address_pattern = qr/
40             $hex_byte : $hex_byte : $hex_byte : $hex_byte : $hex_byte : $hex_byte
41             /x;
42              
43             our $ib_mac_address_pattern = qr/
44             $hex_byte : $hex_byte : $hex_byte : $hex_byte : $hex_byte : $hex_byte :
45             $hex_byte : $hex_byte : $hex_byte : $hex_byte : $hex_byte : $hex_byte :
46             $hex_byte : $hex_byte : $hex_byte : $hex_byte : $hex_byte : $hex_byte :
47             $hex_byte : $hex_byte
48             /x;
49              
50             our $any_mac_address_pattern = qr/
51             (?:$ib_mac_address_pattern|$mac_address_pattern)
52             /x;
53              
54             our $ip_address_pattern = qr/
55             $dec_byte \. $dec_byte \. $dec_byte \. $dec_byte
56             /x;
57              
58             our $alt_mac_address_pattern = qr/
59             $padded_hex_byte
60             $padded_hex_byte
61             $padded_hex_byte
62             $padded_hex_byte
63             $padded_hex_byte
64             $padded_hex_byte
65             /x;
66              
67             our $hex_ip_address_pattern = qr/
68             $padded_hex_byte
69             $padded_hex_byte
70             $padded_hex_byte
71             $padded_hex_byte
72             /x;
73              
74             our $network_pattern = qr/
75             $dec_byte (?:\. $dec_byte (?:\. $dec_byte (?:\. $dec_byte)?)?)? \/ \d{1,2}
76             /x;
77              
78             sub getSubnetAddress {
79 0     0 1   my ($address, $mask) = @_;
80              
81 0 0 0       return undef unless $address && $mask; ## no critic (ExplicitReturnUndef)
82              
83 0           my $binaddress = ip_iptobin($address, 4);
84 0           my $binmask = ip_iptobin($mask, 4);
85 0           my $binsubnet = $binaddress & $binmask; ## no critic (ProhibitBitwise)
86              
87 0           return ip_bintoip($binsubnet, 4);
88             }
89              
90             sub getSubnetAddressIPv6 {
91 0     0 1   my ($address, $mask) = @_;
92              
93 0 0 0       return undef unless $address && $mask; ## no critic (ExplicitReturnUndef)
94              
95 0           my $binaddress = ip_iptobin(ip_expand_address($address, 6), 6);
96 0           my $binmask = ip_iptobin(ip_expand_address($mask, 6), 6);
97 0           my $binsubnet = $binaddress & $binmask; ## no critic (ProhibitBitwise)
98              
99 0           return ip_compress_address(ip_bintoip($binsubnet, 6), 6);
100             }
101              
102             sub isSameNetwork {
103 0     0 1   my ($address1, $address2, $mask) = @_;
104              
105             ## no critic (ExplicitReturnUndef)
106 0 0 0       return undef unless $address1 && $address2 && $mask;
      0        
107              
108 0           my $binaddress1 = ip_iptobin($address1, 4);
109 0           my $binaddress2 = ip_iptobin($address2, 4);
110 0           my $binmask = ip_iptobin($mask, 4);
111              
112             ## no critic (ProhibitBitwise)
113 0           return ($binaddress1 & $binmask) eq ($binaddress2 & $binmask);
114             }
115              
116             sub isSameNetworkIPv6 {
117 0     0 1   my ($address1, $address2, $mask) = @_;
118              
119             ## no critic (ExplicitReturnUndef)
120 0 0 0       return undef unless $address1 && $address2 && $mask;
      0        
121              
122 0           my $binaddress1 = ip_iptobin(ip_expand_address($address1, 6), 6);
123 0           my $binaddress2 = ip_iptobin(ip_expand_address($address2, 6), 6);
124 0           my $binmask = ip_iptobin(ip_expand_address($mask, 6), 6);
125              
126             ## no critic (ProhibitBitwise)
127 0           return ($binaddress1 & $binmask) eq ($binaddress2 & $binmask);
128             }
129              
130             sub hex2canonical {
131 0     0 1   my ($address) = @_;
132 0 0         return unless $address;
133              
134 0           my @bytes = $address =~ /^(?:0x)?(..)(..)(..)(..)$/;
135 0           return join('.', map { hex($_) } @bytes);
  0            
136             }
137              
138             sub alt2canonical {
139 0     0 1   my ($address) = @_;
140 0 0         return unless $address;
141              
142 0           my @bytes = $address =~ /^(?:0x)?(..)(..)(..)(..)(..)(..)$/;
143 0           return join(':', @bytes);
144             }
145              
146             sub getNetworkMask {
147 0     0 1   my ($prefix) = @_;
148              
149 0 0         return undef unless $prefix; ## no critic (ExplicitReturnUndef)
150              
151 0           return ip_bintoip(ip_get_mask($prefix, 4), 4);
152             }
153              
154             sub getNetworkMaskIPv6 {
155 0     0 1   my ($prefix) = @_;
156              
157 0 0         return undef unless $prefix; ## no critic (ExplicitReturnUndef)
158              
159 0           return ip_compress_address(ip_bintoip(ip_get_mask($prefix, 6), 6), 6);
160             }
161              
162             sub resolve {
163 0     0 1   my ($name, $logger) = @_;
164              
165 0           my @addresses;
166              
167 0 0         if ($Socket::VERSION >= 1.94) {
168             # IPv6 compatible version
169 0           my ($error, @results) = Socket::getaddrinfo(
170             $name, undef, {
171             family => Socket::AF_UNSPEC(),
172             protocol => Socket::IPPROTO_TCP()
173             }
174             );
175 0 0         if ($error) {
176 0 0         $logger->error(
177             "unable to get address for '$name': $error"
178             ) if $logger;
179 0           return;
180             }
181              
182             # and push all of their addresses in the list
183 0           foreach my $result (@results) {
184 0           my ($error, $address) = Socket::getnameinfo(
185             $result->{addr}, Socket::NI_NUMERICHOST()
186             );
187 0 0         if ($error) {
188 0 0         $logger->error(
189             "unable to translate binary address for '$name': $error"
190             ) if $logger;
191 0           next;
192             }
193              
194             # Drop the zone index, as Net::IP does not support it
195 0           $address =~ s/%.*$//;
196              
197 0           push @addresses, $address;
198             }
199             } else {
200             # IPv4-only version
201 0           my $result = gethostbyname($name);
202 0 0         if (!$result) {
203 0 0         $logger->error(
204             "unable to get address for '$name': $ERRNO"
205             ) if $logger;
206 0           return;
207             }
208 0           foreach my $packed_address (@{$result->addr_list()}) {
  0            
209 0           push @addresses, inet_ntoa($packed_address);
210             }
211             }
212              
213 0           return map { Net::IP->new($_) } @addresses;
  0            
214             }
215              
216             sub compile {
217 0     0 1   my ($string, $logger) = @_;
218              
219 0 0         return unless $string;
220              
221             # that's already an IP address, just convert it
222 0 0         return Net::IP->new($string)
223             if $string =~ /^$ip_address_pattern/;
224              
225             # otherwise resolve the name
226 0           return resolve($string, $logger);
227             }
228              
229             sub isPartOf {
230 0     0 1   my ($string, $ranges, $logger) = @_;
231              
232 0 0         return unless $string;
233 0 0         return unless $ranges;
234              
235 0           my $address = Net::IP->new($string);
236              
237 0 0         if (!$address) {
238 0           $logger->error("Not well formatted source IP: $string");
239 0           return;
240             }
241              
242 0           foreach my $range (@{$ranges}) {
  0            
243 0           my $result = $address->overlaps($range);
244              
245 0 0 0       if (!$result && Net::IP::Error()) {
246 0           $logger->debug("Server: ".Net::IP::Error());
247 0           next;
248             }
249              
250             # included in trusted range
251 0 0         return 1 if $result == $IP_A_IN_B_OVERLAP;
252              
253             # equals trusted address
254 0 0         return 1 if $result == $IP_IDENTICAL;
255             }
256              
257 0           return 0;
258             }
259              
260             1;
261             __END__