File Coverage

lib/Rex/Hardware/Network/Linux.pm
Criterion Covered Total %
statement 109 208 52.4
branch 38 90 42.2
condition 11 26 42.3
subroutine 13 16 81.2
pod 0 6 0.0
total 171 346 49.4


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             package Rex::Hardware::Network::Linux;
6              
7 6     6   205767 use v5.12.5;
  6         97  
8 6     6   72 use warnings;
  6         38  
  6         633  
9              
10             our $VERSION = '1.14.2.3'; # TRIAL VERSION
11              
12 6     6   1351 use Rex::Logger;
  6         33  
  6         179  
13 6     6   1382 use Rex::Helper::Run;
  6         40  
  6         892  
14 6     6   84 use Rex::Commands::Run;
  6         52  
  6         221  
15 6     6   66 use Rex::Helper::Array;
  6         31  
  6         546  
16 6     6   59 use Data::Dumper;
  6         30  
  6         18224  
17              
18             sub get_bridge_devices {
19 9 50   9 0 215 unless ( can_run("brctl") ) {
20 9         303 Rex::Logger::debug("No brctl available");
21 9         135 return {};
22             }
23              
24 0         0 local $/ = "\n";
25 0         0 my @lines = i_run 'brctl show', fail_ok => 1;
26 0         0 chomp @lines;
27 0         0 shift @lines;
28              
29 0         0 my $current_bridge;
30 0         0 my $data = {};
31 0         0 for my $line (@lines) {
32 0 0       0 if ( $line =~ m/^[A-Za-z0-9_.]+/ ) {
33 0         0 my ( $br, $br_id, $stp, $dev ) = split( /\s+/, $line );
34 0         0 $current_bridge = $br;
35 0         0 $data->{$br}->{stp} = 0;
36 0         0 push @{ $data->{$br}->{devices} }, $dev;
  0         0  
37 0         0 next;
38             }
39              
40 0         0 my ($dev) = ( $line =~ m/([a-zA-Z0-9_.]+)$/ );
41 0 0       0 if ($dev) {
42 0         0 push @{ $data->{$current_bridge}->{devices} }, $dev;
  0         0  
43             }
44             }
45              
46 0         0 return $data;
47             }
48              
49             sub get_network_devices {
50              
51 9 50   9 0 90 my $command = can_run('ip') ? 'ip addr show' : 'ifconfig -a';
52 9         198 my @output = i_run( "$command", fail_ok => 1 );
53              
54 9 50       424 my $devices =
55             ( $command eq 'ip addr show' )
56             ? _parse_ip(@output)
57             : _parse_ifconfig(@output);
58 9         45 my @device_list = keys %{$devices};
  9         157  
59              
60 9         663 return \@device_list;
61             }
62              
63             sub get_network_configuration {
64              
65 9     9 0 60 my $device_info = {};
66              
67 9 50       220 my $command = can_run('ip') ? 'ip addr show' : 'ifconfig -a';
68 9         182 my @output = i_run( "$command", fail_ok => 1 );
69              
70 9         174 my $br_data = get_bridge_devices();
71              
72 9 50       221 my $data =
73             ( $command eq 'ip addr show' )
74             ? _parse_ip(@output)
75             : _parse_ifconfig(@output);
76              
77 9         49 for my $dev ( keys %{$data} ) {
  9         172  
78 27 50       207 if ( exists $br_data->{$dev} ) {
79 0         0 $data->{$dev}->{is_bridge} = 1;
80             }
81             else {
82 27         130 $data->{$dev}->{is_bridge} = 0;
83             }
84             }
85              
86 9         350 return $data;
87             }
88              
89             sub _parse_ifconfig {
90 4     4   10719 my (@ifconfig) = @_;
91              
92 4         12 my $dev = {};
93              
94 4         10 my $cur_dev;
95 4         13 for my $line (@ifconfig) {
96 49 100       113 if ( $line =~ m/^([a-zA-Z0-9:\._]+)/ ) {
97 6         17 my $new_dev = $1;
98 6 100       22 $new_dev = substr( $new_dev, 0, -1 ) if ( $new_dev =~ m/:$/ );
99              
100 6 100 66     24 if ( $cur_dev && $cur_dev ne $new_dev ) {
101 2         5 $cur_dev = $new_dev;
102             }
103              
104 6 100       13 if ( !$cur_dev ) {
105 4         6 $cur_dev = $new_dev;
106             }
107              
108 6         22 $dev->{$cur_dev}->{mac} = "";
109 6         13 $dev->{$cur_dev}->{ip} = "";
110 6         8 $dev->{$cur_dev}->{netmask} = "";
111 6         13 $dev->{$cur_dev}->{broadcast} = "";
112              
113             }
114              
115 49 100       175 if ( $line =~ m/(ether|HWaddr) (..:..:..:..:..:..)/ ) {
116 4         12 $dev->{$cur_dev}->{mac} = $2;
117             }
118              
119 49 100       143 if ( $line =~ m/inet( addr:| )?(\d+\.\d+\.\d+\.\d+)/ ) {
120 5         18 $dev->{$cur_dev}->{ip} = $2;
121             }
122              
123 49 100       110 if ( $line =~ m/(netmask |Mask:)(\d+\.\d+\.\d+\.\d+)/ ) {
124 5         14 $dev->{$cur_dev}->{netmask} = $2;
125             }
126              
127 49 100       114 if ( $line =~ m/(broadcast |Bcast:)(\d+\.\d+\.\d+\.\d+)/ ) {
128 3         9 $dev->{$cur_dev}->{broadcast} = $2;
129             }
130              
131             }
132              
133 4         22 return $dev;
134              
135             }
136              
137             sub _parse_ip {
138 24     24   12542 my (@ip_lines) = @_;
139              
140 24         136 my $dev = {};
141              
142 24         89 my $cur_dev;
143 24         191 for my $line (@ip_lines) {
144 191 100       1213 if ( $line =~ m/^\d+:\s*([^\s]+):/ ) {
145 45         546 my $new_dev = $1;
146              
147 45 100 66     274 if ( $cur_dev && $cur_dev ne $new_dev ) {
148 21         73 $cur_dev = $new_dev;
149             }
150              
151 45 100       148 if ( !$cur_dev ) {
152 24         133 $cur_dev = $new_dev;
153             }
154              
155 45         524 $dev->{$cur_dev}->{ip} = "";
156 45         310 $dev->{$cur_dev}->{mac} = "";
157 45         259 $dev->{$cur_dev}->{netmask} = "";
158 45         188 $dev->{$cur_dev}->{broadcast} = "";
159              
160 45         150 next;
161             }
162              
163 146 100       565 if ( $line =~ m/^\s*link\/ether (..:..:..:..:..:..)/ ) {
164 23         161 $dev->{$cur_dev}->{mac} = $1;
165             }
166              
167             # loopback
168             # if ( $line =~ m/^\s*inet (\d+\.\d+\.\d+\.\d+)\/(\d+) scope host lo/ ) {
169             # $dev->{$cur_dev}->{ip} = $1;
170             # $dev->{$cur_dev}->{netmask} = _convert_cidr_prefix($2);
171             # }
172              
173 146         304 my $sec_i = 1;
174 146 100       901 if ( $line =~
175             m/^\s*inet (\d+\.\d+\.\d+\.\d+)\/(\d+) (brd (\d+\.\d+\.\d+\.\d+) )?scope ([^\s]+) (\w+\s)?(.+?)$/
176             )
177             {
178 45         194 my $ip = $1;
179 45         336 my $cidr_prefix = $2;
180 45   100     702 my $broadcast = $4 || '';
181 45         448 my $scope = $5;
182 45   33     295 my $dev_name = $7 || $6;
183 45         138 chomp $dev_name;
184              
185 45 100 100     644 if ( $scope eq "global" && $dev_name ne $cur_dev ) {
    100 33        
186              
187             # this is an alias
188 19         215 $dev->{$dev_name}->{ip} = $ip;
189 19         85 $dev->{$dev_name}->{broadcast} = $broadcast;
190 19         103 $dev->{$dev_name}->{netmask} = _convert_cidr_prefix($cidr_prefix);
191 19         114 $dev->{$dev_name}->{mac} = $dev->{$cur_dev}->{mac};
192             }
193             elsif ( $dev_name eq $cur_dev && $dev->{$cur_dev}->{ip} ) {
194              
195             # there is already an ip address, so this must be a secondary
196 1         9 $dev->{"${dev_name}_${sec_i}"}->{ip} = $ip;
197 1         4 $dev->{"${dev_name}_${sec_i}"}->{broadcast} = $broadcast;
198             $dev->{"${dev_name}_${sec_i}"}->{netmask} =
199 1         3 _convert_cidr_prefix($cidr_prefix);
200 1         5 $dev->{"${dev_name}_${sec_i}"}->{mac} = $dev->{$cur_dev}->{mac};
201 1         3 $sec_i++;
202             }
203             else {
204 25         159 $dev->{$cur_dev}->{ip} = $ip;
205 25         98 $dev->{$cur_dev}->{broadcast} = $broadcast;
206 25         192 $dev->{$cur_dev}->{netmask} = _convert_cidr_prefix($cidr_prefix);
207             }
208             }
209              
210             # ppp
211 146 100       505 if ( $line =~
212             m/^\s*inet (\d+\.\d+\.\d+\.\d+) peer (\d+\.\d+\.\d+\.\d+)\/(\d+)/ )
213             {
214 1         3 $dev->{$cur_dev}->{ip} = $1;
215 1         4 $dev->{$cur_dev}->{netmask} = _convert_cidr_prefix($3);
216             }
217             }
218              
219 24         124 return $dev;
220             }
221              
222             sub route {
223              
224 0     0 0 0 my @ret = ();
225              
226 0         0 my @route = i_run "netstat -nr", fail_ok => 1;
227 0 0       0 if ( $? != 0 ) {
228 0         0 die("Error running netstat");
229             }
230              
231 0         0 shift @route;
232 0         0 shift @route; # remove first 2 lines
233              
234 0         0 for my $route_entry (@route) {
235 0         0 my ( $dest, $gw, $genmask, $flags, $mss, $window, $irtt, $iface ) =
236             split( /\s+/, $route_entry, 8 );
237 0         0 push(
238             @ret,
239             {
240             destination => $dest,
241             gateway => $gw,
242             genmask => $genmask,
243             flags => $flags,
244             mss => $mss,
245             irtt => $irtt,
246             iface => $iface,
247             }
248             );
249             }
250              
251 0         0 return @ret;
252              
253             }
254              
255             sub default_gateway {
256              
257 0     0 0 0 my ( $class, $new_default_gw ) = @_;
258              
259 0 0       0 if ($new_default_gw) {
260 0 0       0 if ( default_gateway() ) {
261 0         0 i_run "/sbin/route del default", fail_ok => 1;
262 0 0       0 if ( $? != 0 ) {
263 0         0 die("Error running route del default");
264             }
265             }
266              
267 0         0 i_run "/sbin/route add default gw $new_default_gw", fail_ok => 1;
268 0 0       0 if ( $? != 0 ) {
269 0         0 die("Error route add default");
270             }
271              
272             }
273             else {
274 0         0 my @route = route();
275              
276             my ($default_route) = grep {
277 0         0 $_->{"flags"} =~ m/UG/
278             && ( $_->{"destination"} eq "0.0.0.0"
279 0 0 0     0 || $_->{"destination"} eq "default" )
280             } @route;
281 0 0       0 return $default_route->{"gateway"} if $default_route;
282             }
283             }
284              
285             sub netstat {
286              
287 0     0 0 0 my @ret;
288 0         0 my @netstat = i_run "netstat -nap", fail_ok => 1;
289 0 0       0 if ( $? != 0 ) {
290 0         0 die("Error running netstat");
291             }
292 0         0 my ( $in_inet, $in_unix, $in_unknown ) = ( 0, 0, 0 );
293 0         0 for my $line (@netstat) {
294 0 0       0 if ( $in_inet == 1 ) { ++$in_inet; next; }
  0         0  
  0         0  
295 0 0       0 if ( $in_unix == 1 ) { ++$in_unix; next; }
  0         0  
  0         0  
296 0 0       0 if ( $line =~ m/^Active Internet/ ) {
297 0         0 $in_inet = 1;
298 0         0 $in_unix = 0;
299 0         0 $in_unknown = 0;
300 0         0 next;
301             }
302              
303 0 0       0 if ( $line =~ m/^Active UNIX/ ) {
304 0         0 $in_inet = 0;
305 0         0 $in_unix = 1;
306 0         0 $in_unknown = 0;
307 0         0 next;
308             }
309              
310 0 0       0 if ( $line =~ m/^Active/ ) {
311 0         0 $in_inet = 0;
312 0         0 $in_unix = 0;
313 0         0 $in_unknown = 1;
314 0         0 next;
315             }
316              
317 0 0       0 if ($in_unknown) {
318 0         0 next;
319             }
320              
321 0 0       0 if ($in_inet) {
322 0         0 my ( $proto, $recvq, $sendq, $local_addr, $foreign_addr, $state,
323             $pid_cmd );
324              
325 0 0       0 unless ( $line =~ m/^udp/ ) {
326              
327             # no state
328 0         0 ( $proto, $recvq, $sendq, $local_addr, $foreign_addr, $state, $pid_cmd )
329             = split( /\s+/, $line, 7 );
330             }
331             else {
332 0         0 ( $proto, $recvq, $sendq, $local_addr, $foreign_addr, $pid_cmd ) =
333             split( /\s+/, $line, 6 );
334             }
335              
336 0   0     0 $pid_cmd ||= "";
337              
338 0         0 my ( $pid, $cmd ) = split( /\//, $pid_cmd, 2 );
339 0 0       0 if ( $pid =~ m/^-/ ) {
340 0         0 $pid = "";
341             }
342 0   0     0 $cmd ||= "";
343 0   0     0 $state ||= "";
344              
345 0         0 $cmd =~ s/\s+$//;
346              
347 0         0 push(
348             @ret,
349             {
350             proto => $proto,
351             recvq => $recvq,
352             sendq => $sendq,
353             local_addr => $local_addr,
354             foreign_addr => $foreign_addr,
355             state => $state,
356             pid => $pid,
357             command => $cmd,
358             }
359             );
360 0         0 next;
361             }
362              
363 0 0       0 if ($in_unix) {
364              
365 0         0 my ( $proto, $refcnt, $flags, $type, $state, $inode, $pid, $cmd, $path );
366              
367 0 0       0 if ( $line =~
368             m/^([a-z]+)\s+(\d+)\s+\[([^\]]+)\]\s+([a-z]+)\s+([a-z]+)?\s+(\d+)\s+(\d+)\/([^\s]+)\s+(.*)$/i
369             )
370             {
371 0         0 ( $proto, $refcnt, $flags, $type, $state, $inode, $pid, $cmd, $path ) =
372             ( $line =~
373             m/^([a-z]+)\s+(\d+)\s+\[([^\]]+)\]\s+([a-z]+)\s+([a-z]+)?\s+(\d+)\s+(\d+)\/([^\s]+)\s+(.*)$/i
374             );
375             }
376             else {
377 0         0 ( $proto, $refcnt, $flags, $type, $state, $inode, $path ) =
378             ( $line =~
379             m/^([a-z]+)\s+(\d+)\s+\[([^\]]+)\]\s+([a-z]+)\s+([a-z]+)?\s+(\d+)\s+\-\s+(.*)$/i
380             );
381              
382 0         0 $pid = "";
383 0         0 $cmd = "";
384             }
385              
386 0 0       0 $state =~ s/^\s|\s$//g if ($state);
387 0 0       0 $flags =~ s/\s+$// if ($flags);
388 0         0 $cmd =~ s/\s+$//;
389              
390 0         0 my $data = {
391             proto => $proto,
392             refcnt => $refcnt,
393             flags => $flags,
394             type => $type,
395             state => $state,
396             inode => $inode,
397             pid => $pid,
398             command => $cmd,
399             path => $path,
400             };
401              
402 0         0 push( @ret, $data );
403             }
404              
405             }
406              
407 0         0 return @ret;
408              
409             }
410              
411             sub _convert_cidr_prefix {
412 46     46   201 my ($cidr_prefix) = @_;
413              
414             # convert CIDR prefix to dotted decimal notation
415 46         390 my $binary_mask = '1' x $cidr_prefix . '0' x ( 32 - $cidr_prefix );
416 46         649 my $dotted_decimal_mask = join '.', unpack 'C4', pack 'B32', $binary_mask;
417              
418 46         250 return $dotted_decimal_mask;
419             }
420              
421             1;