prva verzija za stretch
[ocsinventory-agent-cn.git] / Networks.pm
1 package Ocsinventory::Agent::Backend::OS::Linux::Network::Networks;
2
3 use strict;
4 use warnings;
5 use Data::Dumper;
6 use File::stat;
7 use Time::Local;
8
9 sub check {
10     my $params = shift;
11     my $common = $params->{common};
12     return unless ($common->can_run("ifconfig") || $common->can_run("ip")) && $common->can_run("route") && $common->can_load("Net::IP qw(:PROC)");
13     1;
14 }
15
16 sub getLeaseFile {
17
18     my $if = @_; 
19     my @directories = qw( 
20         /var/db
21         /var/lib/dhclient
22         /var/lib/dhcp3
23         /var/lib/dhcp
24         /var/lib/NetworkManager
25     );
26     my @patterns = ("*$if*.lease", "*.lease", "dhclient.leases.$if");
27     my @files;
28     
29     foreach my $directory (@directories) {
30         next unless -d $directory;
31         foreach my $pattern (@patterns) {
32             push @files,
33                  grep { -s $_ }
34                  glob("$directory/$pattern");
35         }
36     }   
37     return unless @files;
38     @files = 
39         map {$_->[0]}
40         sort {$a->[1]->ctime()<=>$b->[1]->ctime()}
41         map {[$_,stat($_)]}
42         @files;
43     return $files[-1];
44
45 }
46
47 sub _ipdhcp {
48
49     my $if = shift;
50     my $path;
51     my $dhcp;
52     my $ipdhcp;
53     my $leasepath;
54
55     if( $leasepath = getLeaseFile($if) ) {
56         if (open DHCP, $leasepath) {
57             my $lease;
58             while(<DHCP>){
59                 $lease = 1 if(/lease\s*{/i);
60                 $lease = 0 if(/^\s*}\s*$/);
61                 #Interface name
62                 if ($lease) { #inside a lease section
63                     if (/interface\s+"(.+?)"\s*/){
64                         $dhcp = ($1 =~ /^$if$/);
65                     }
66                     #Server IP
67                     if (/option\s+dhcp-server-identifier\s+(\d{1,3}(?:\.\d{1,3}){3})\s*;/ and $dhcp){
68                         $ipdhcp = $1;
69                     }
70                 }
71             }
72             close DHCP or warn;
73         } else {
74             warn "Can't open $leasepath\n";
75         }
76     }
77     return $ipdhcp;
78 }
79
80 # Initialise the distro entry
81 sub run {
82
83     my $params = shift;
84     my $common = $params->{common};
85     my $logger = $params->{logger};
86
87     my $description;
88     my $driver;
89     my $ipaddress;
90     my $ipgateway;
91     my $ipmask;
92     my $ipsubnet;
93     my $macaddr;
94     my $pcislot;
95     my $status;
96     my $type;
97     my $virtualdev;
98     my $settings;
99     my $speed;
100     my $current_speed;
101     my $duplex;
102     my $ssid;
103     my $bssid;
104     my $mode;
105     my $version;
106     my $bitrate;
107     my $address;
108     my $mask4;
109     my $mask6;
110     my $binip;
111     my $binmask;
112     my $binsubnet;
113     my $mtu;
114
115     my %gateway;
116
117     if ($common->can_run("ip")){
118         my @ipLink = `ip -o link`;
119         foreach my $line (`ip -o addr`) {
120             $ipsubnet = $ipaddress = $ipmask = $ipgateway = $macaddr = $status = $type = $speed = $duplex = $driver = $pcislot = $virtualdev = $mtu = undef;
121             $description = "";
122             if ($line =~ /lo.*(127\.0\.0\.1\/8)/) { # ignore default loopback interface
123                    next;
124             }   
125             if ($line =~ /lo.*(::1\/128)/) { # ignore default loopback interface
126                    next;
127             }   
128             
129             $description = $1 if ($line =~ /\d:\s+([\w\d]+)\s+/i);
130
131             if ($line =~ /inet (\S+)\/(\d{2})/i){
132                 $ipaddress = $1; 
133                 $mask4 = $2; 
134             } elsif ($line =~ /inet6 (\S+)\/(\d{2})/i){
135                 $ipaddress = $1; 
136                 $mask6 = $2; 
137             }
138     
139             if (ip_is_ipv4($ipaddress)){
140                 foreach (`route -n`) {
141                     if (/^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)/) {
142                         $gateway{$1} = $2;
143                     }
144                 }
145
146                 if (defined ($gateway{'0.0.0.0'})) {
147                     $common->setHardware({
148                         DEFAULTGATEWAY => $gateway{'0.0.0.0'}
149                     });
150                 }
151             
152             
153                 $ipmask = ip_bintoip(ip_get_mask($mask4,4),4) if $mask4;
154                 $binip = ip_iptobin($ipaddress,4) if $ipaddress;
155                 $binmask = ip_iptobin($ipmask,4) if $ipmask;
156                 $binsubnet = $binip & $binmask if ($binip && $binmask);
157                 $ipsubnet = ip_bintoip($binsubnet,4) if $binsubnet;
158             } elsif (ip_is_ipv6($ipaddress)) {
159             
160                 foreach (`route -nA inet6`) {
161                     if(/^(\S+)\/\d{1,3}\s+(\S+)/) {
162                         next if ($1 eq $2);
163                         $gateway{$1} = $2;
164                     }
165                 }
166
167                 $ipmask = ip_bintoip(ip_get_mask($mask6,6),6) if $mask6;;
168                 $binip = ip_iptobin(ip_expand_address($ipaddress,6),6) if $ipaddress;
169                 $binmask = ip_iptobin(ip_expand_address($ipmask,6),6) if $ipmask;
170                 $binsubnet = $binip & $binmask if ($binip && $binmask);
171                 $ipsubnet = ip_compress_address(ip_bintoip($binsubnet,6),6) if $binsubnet;
172             }
173
174             my @line1 = split " ", $line;
175             my @linkData = split " ", (grep {/$line1[1]/} @ipLink)[0];
176             $macaddr = uc $linkData[-3];
177             $mtu = $linkData[4];
178
179             if ($linkData[2] =~ /,UP/) {
180                 $status = "UP";
181             } else {
182                 $status = "DOWN";
183             }
184
185             $type = $linkData[-4];
186             if ($type =~ /ether/){
187                 $type = "Ethernet";
188             } elsif ($type =~ /loopback/) {
189                 $type = "Loopback";
190             }
191
192             $ipgateway = $gateway{$ipsubnet} if $ipsubnet;
193             # replace '0.0.0.0' and '::' (ie 'default gateway') by the default gateway IP address if it exists
194             if (defined($ipgateway) and $ipgateway eq '0.0.0.0' and defined($gateway{'0.0.0.0'})) {
195                 $ipgateway = $gateway{'0.0.0.0'};
196             }
197             if (defined($ipgateway) and $ipgateway eq '::' and defined($gateway{'::'})) {
198                 $ipgateway = $gateway{'::'};
199             }
200
201             if (open UEVENT, "</sys/class/net/$description/device/uevent") {
202                 foreach (<UEVENT>) {
203                     $driver = $1 if /^DRIVER=(\S+)/;
204                     $pcislot = $1 if /^PCI_SLOT_NAME=(\S+)/;
205                 }
206                 close UEVENT;
207             }
208
209             # Retrieve speed from /sys/class/net/$description/speed
210             if ( ! -z "/sys/class/net/$description/speed") {
211                 if(open SPEED, "</sys/class/net/$description/speed") {
212                     foreach (<SPEED>){
213                          $current_speed=$_;
214                        }
215                     close SPEED;
216                 }
217                 
218                 if (defined $current_speed) {
219                     chomp($current_speed);
220                     if ($current_speed eq "65535"){
221                         $current_speed = 0;
222                     } elsif ( $current_speed gt 100 ){
223                         $speed = ($current_speed/1000)." Gbps";
224                       } else {
225                         $speed = $current_speed." Mbps";
226                     }
227                 }
228             }
229  
230             # Retrieve duplex from /sys/class/net/$description/duplex
231             if (open DUPLEX, "</sys/class/net/$description/duplex"){
232                 foreach (<DUPLEX>){
233                     $duplex=chomp($_);
234                 }
235                 close DUPLEX;
236             }
237  
238             # Reliable way to get the info
239             if (-d "/sys/devices/virtual/net/") {
240                 $virtualdev = (-d "/sys/devices/virtual/net/$description")?"1":"0";
241             } elsif ($common->can_run("brctl")) {
242                 # Let's guess
243                 my %bridge;
244                 foreach (`brctl show`) {
245                       next if /^bridge name/;
246                       $bridge{$1} = 1 if /^(\w+)\s/;
247                 }
248                 if ($pcislot) {
249                       $virtualdev = "1";
250                 } elsif ($bridge{$description}) {
251                       $virtualdev = "0";
252                 }
253                 $type = "bridge";
254             }
255
256             if (-d "/sys/class/net/$description/wireless"){
257                 my @wifistatus = `iwconfig $description`;
258                 foreach my $line (@wifistatus){
259                     $ssid = $1 if ($line =~ /ESSID:(\S+)/);
260                     $version = $1 if ($line =~ /IEEE (\S+)/);
261                     $mode = $1 if ($line =~ /Mode:(\S+)/);
262                     $bssid = $1 if ($line =~ /Access Point: (\S+)/);
263                     $bitrate = $1 if ($line =~ /Bit\sRate=\s*(\S+\sMb\/s)/i);
264                 }
265                 $type = "Wifi";
266             }
267             if ($description ne "") {
268                 if ($type eq "Wifi") {
269                       $common->addNetwork({
270                           DESCRIPTION => $description,
271                           DRIVER => $driver,
272                           IPADDRESS => $ipaddress,
273                           IPDHCP => _ipdhcp($description),
274                           IPGATEWAY => $ipgateway,
275                           IPMASK => $ipmask,
276                           IPSUBNET => $ipsubnet,
277                           MACADDR => $macaddr,
278                           PCISLOT => $pcislot,
279                           STATUS => $status,
280                           TYPE => $type,
281                           SPEED => $bitrate,
282                           SSID => $ssid,
283                           BSSID => $bssid,
284                           IEEE => $version,
285                           MODE => $mode,
286                     });
287                 } else { 
288                       $common->addNetwork({
289                           DESCRIPTION => $description,
290                           DRIVER => $driver,
291                           IPADDRESS => $ipaddress,
292                           IPDHCP => _ipdhcp($description),
293                           IPGATEWAY => $ipgateway,
294                           IPMASK => $ipmask,
295                           IPSUBNET => $ipsubnet,
296                           MACADDR => $macaddr,
297                           PCISLOT => $pcislot,
298                           STATUS => $status,
299                           TYPE => $type,
300                           VIRTUALDEV => $virtualdev,
301                           DUPLEX => $duplex?"Full":"Half",
302                           SPEED => $speed,
303                           MTU => $mtu,
304                     });
305                 }
306             }
307         }
308     }
309
310     elsif ($common->can_run("ifconfig")){
311         foreach my $line (`ifconfig -a`) {
312             if ($line =~ /^$/ && $description && $macaddr) {
313             # end of interface section
314             # I write the entry
315                 if (ip_is_ipv4($ipaddress)){
316                     foreach (`route -n`) {
317                         if (/^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)/) {
318                             $gateway{$1} = $2;
319                         }
320                     }
321
322                     if (defined ($gateway{'0.0.0.0'})) {
323                         $common->setHardware({
324                             DEFAULTGATEWAY => $gateway{'0.0.0.0'}
325                         });
326                     }
327
328                     $binip = ip_iptobin ($ipaddress ,4) if $ipaddress;
329                     $binmask = ip_iptobin ($ipmask,4) if $ipmask;
330                     $binsubnet = $binip & $binmask if ($binip && $binmask);
331                     $ipsubnet = ip_bintoip($binsubnet,4) if $binsubnet;
332                 } elsif (ip_is_ipv6($ipaddress)) {
333                     # Table de routage IPv6 du noyau
334                     # Destination                    Next Hop                   Flag Met Ref Use If
335                     # fe80::/64                      [::]                       U    256 0     0 wlp6s0
336                     # foreach (`route -6`) {
337                     #    if (/^(\S+\/\d{2})\s+(\S+)/) {
338                     #        $gateway{$1} = $2;
339                     #    }
340                     #}
341                     #if (defined ($gateway{'fe80::/64'})) {
342                     #    $common->setHardware({
343                     #        DEFAULTGATEWAY => $gateway{'fe80::/64'}
344                     #    });
345                     #}
346                     
347                     foreach (`route -nA inet6`) {
348                         if(/^(\S+)\/\d{1,3}\s+(\S+)/) {
349                             next if ($1 eq $2);
350                             $gateway{$1} = $2;
351                         }
352                     }
353                     
354                     
355                     $ipmask = ip_bintoip(ip_get_mask($mask6,6),6) if $mask6;;
356                     $binip = ip_iptobin(ip_expand_address($ipaddress,6),6) if $ipaddress;
357                     $binmask = ip_iptobin(ip_expand_address($ipmask,6),6) if $ipmask;
358                     $binsubnet = $binip & $binmask if ($binip && $binmask);
359                     $ipsubnet = ip_compress_address(ip_bintoip($binsubnet,6),6) if $binsubnet;
360                 }
361
362                 $ipgateway = $gateway{$ipsubnet} if $ipsubnet;
363
364                 if (-d "/sys/class/net/$description/wireless"){
365                     my @wifistatus = `iwconfig $description`;
366                     foreach my $line (@wifistatus){
367                         $ssid = $1 if ($line =~ /ESSID:(\S+)/);
368                         $version = $1 if ($line =~ /IEEE (\S+)/);
369                         $mode = $1 if ($line =~ /Mode:(\S+)/);
370                         $bssid = $1 if ($line =~ /Access Point: (\S+)/);
371                         $bitrate = $1 if ($line =~ /Bit\sRate=\s*(\S+\sMb\/s)/i);
372                     }
373                     $type = "Wifi";
374                 } 
375
376                 if (-f "/sys/class/net/$description/mode"){
377                     $type = "infiniband";
378                 }
379
380                 # replace '0.0.0.0' and '::' (ie 'default gateway') by the default gateway IP address if it exists
381                 if (defined($ipgateway) and $ipgateway eq '0.0.0.0' and defined($gateway{'0.0.0.0'})) {
382                     $ipgateway = $gateway{'0.0.0.0'};
383                 }
384                 if (defined($ipgateway) and $ipgateway eq '::' and defined($gateway{'::'})) {
385                     $ipgateway = $gateway{'::'};
386                 }
387
388                 if (open UEVENT, "</sys/class/net/$description/device/uevent") {
389                     foreach (<UEVENT>) {
390                         $driver = $1 if /^DRIVER=(\S+)/;
391                         $pcislot = $1 if /^PCI_SLOT_NAME=(\S+)/;
392                     }
393                     close UEVENT;
394                 }
395
396                 # Retrieve speed from /sys/class/net/$description/speed
397                 if ( ! -z "/sys/class/net/$description/speed") {
398                     open SPEED, "</sys/class/net/$description/speed";
399                     foreach (<SPEED>){
400                         $current_speed=$_;
401                     }
402                     close SPEED;
403                     chomp($current_speed);
404
405                     $current_speed=0 if $current_speed eq "";
406                     if ($current_speed eq "65535"){
407                         $current_speed = 0;
408                     } 
409                     if ($current_speed gt 100 ){
410                         $speed = ($current_speed/1000)." Gbps";
411                     } else {
412                         $speed = $current_speed." Mbps";
413                     }
414                 }
415  
416                 # Retrieve duplex from /sys/class/net/$description/duplex
417                 if (! -z "/sys/class/net/$description/duplex") {
418                     open DUPLEX, "</sys/class/net/$description/duplex";
419                     foreach (<DUPLEX>){
420                         $duplex=chomp($_);
421                     }
422                     close DUPLEX;
423                 }
424
425                 # Reliable way to get the info
426                 if (-d "/sys/devices/virtual/net/") {
427                     $virtualdev = (-d "/sys/devices/virtual/net/$description")?"1":"0";
428                 } elsif ($common->can_run("brctl")) {
429                     # Let's guess
430                     my %bridge;
431                     foreach (`brctl show`) {
432                         next if /^bridge name/;
433                         $bridge{$1} = 1 if /^(\w+)\s/;
434                     }
435                     if ($pcislot) {
436                         $virtualdev = "1";
437                     } elsif ($bridge{$description}) {
438                         $virtualdev = "0";
439                     }
440                     $type = "bridge";
441                 }
442
443                 if ($type eq "Wifi") {
444                     $common->addNetwork({
445                         DESCRIPTION => $description,
446                         DRIVER => $driver,
447                         IPADDRESS => $ipaddress,
448                         IPDHCP => _ipdhcp($description),
449                         IPGATEWAY => $ipgateway,
450                         IPMASK => $ipmask,
451                         IPSUBNET => $ipsubnet,
452                         MACADDR => $macaddr,
453                         PCISLOT => $pcislot,
454                         STATUS => $status,
455                         TYPE => $type,
456                         SPEED => $bitrate,
457                         SSID => $ssid,
458                         BSSID => $bssid,
459                         IEEE => $version,
460                         MODE => $mode,
461                     });
462                 } else { 
463                     $common->addNetwork({
464                         DESCRIPTION => $description,
465                         DRIVER => $driver,
466                         IPADDRESS => $ipaddress,
467                         IPDHCP => _ipdhcp($description),
468                         IPGATEWAY => $ipgateway,
469                         IPMASK => $ipmask,
470                         IPSUBNET => $ipsubnet,
471                         MACADDR => $macaddr,
472                         PCISLOT => $pcislot,
473                         STATUS => $status,
474                         TYPE => $type,
475                         VIRTUALDEV => $virtualdev,
476                         DUPLEX => $duplex?"Full":"Half",
477                         SPEED => $speed,
478                         MTU => $mtu,
479                     });
480                 }
481             }
482
483             if ($line =~ /^$/) { # End of section
484                 $description = $driver = $ipaddress = $ipgateway = $ipmask = $ipsubnet = $macaddr = $pcislot = $status = $type = $virtualdev = $speed = $duplex = $mtu = undef;
485             } else { # In a section
486                 if ($line =~ /^(\S+):\s\S+\s*mtu\s(\d+)/) {
487                     $description = $1; # Interface name
488                     $mtu = $2; 
489                 }
490                 
491                 $description = $1 if($line =~ /^(\w+)\s+/); # Interface name
492                 
493                 # BUG: ipv4 address gets overwritten by ipv6 address but we want all ip addresses
494                 if ($line =~ /inet add?r:(\S+)/i || $line =~ /^\s*inet\s+(\S+)/i || $line =~ /inet (\S+)\s+netmask/i){ 
495                     $ipaddress=$1;
496                 } elsif ($line =~ /inet6 (\S+)\s+prefixlen\s+(\d{2})/i){
497                     $ipaddress=$1;
498                     $mask6=$2;
499                 }
500                 if ($line =~ /\S*mask:(\S+)/i || $line =~ /\S*netmask (\S+)\s/i){
501                     $ipmask=$1; 
502                 } 
503                 $macaddr = $1 if ($line =~ /hwadd?r\s+(\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})/i || $line =~ /ether\s+(\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})/i);
504                 $status = 1 if ($line =~ /^\s+UP\s/ || $line =~ /flags=.*[<,]UP[,>]/);
505                 $type = $1 if ($line =~ /link encap:(\S+)/i);
506                 $type = $2 if ($line =~ /^\s+(loop|ether).*\((\S+)\)/i);
507                 $mtu = $1 if ($line =~ /MTU:(\d+)/i);
508             }
509         }
510     }
511 }
512
513 1;
514