prva verzija za stretch
[ocsinventory-agent-cn.git] / Networks.pm
diff --git a/Networks.pm b/Networks.pm
new file mode 100644 (file)
index 0000000..8552c6b
--- /dev/null
@@ -0,0 +1,514 @@
+package Ocsinventory::Agent::Backend::OS::Linux::Network::Networks;
+
+use strict;
+use warnings;
+use Data::Dumper;
+use File::stat;
+use Time::Local;
+
+sub check {
+    my $params = shift;
+    my $common = $params->{common};
+    return unless ($common->can_run("ifconfig") || $common->can_run("ip")) && $common->can_run("route") && $common->can_load("Net::IP qw(:PROC)");
+    1;
+}
+
+sub getLeaseFile {
+
+    my $if = @_; 
+    my @directories = qw( 
+        /var/db
+        /var/lib/dhclient
+        /var/lib/dhcp3
+        /var/lib/dhcp
+        /var/lib/NetworkManager
+    );
+    my @patterns = ("*$if*.lease", "*.lease", "dhclient.leases.$if");
+    my @files;
+    
+    foreach my $directory (@directories) {
+        next unless -d $directory;
+        foreach my $pattern (@patterns) {
+            push @files,
+                 grep { -s $_ }
+                 glob("$directory/$pattern");
+        }
+    }   
+    return unless @files;
+    @files = 
+        map {$_->[0]}
+        sort {$a->[1]->ctime()<=>$b->[1]->ctime()}
+        map {[$_,stat($_)]}
+        @files;
+    return $files[-1];
+
+}
+
+sub _ipdhcp {
+
+    my $if = shift;
+    my $path;
+    my $dhcp;
+    my $ipdhcp;
+    my $leasepath;
+
+    if( $leasepath = getLeaseFile($if) ) {
+        if (open DHCP, $leasepath) {
+            my $lease;
+            while(<DHCP>){
+                $lease = 1 if(/lease\s*{/i);
+                $lease = 0 if(/^\s*}\s*$/);
+                #Interface name
+                if ($lease) { #inside a lease section
+                    if (/interface\s+"(.+?)"\s*/){
+                        $dhcp = ($1 =~ /^$if$/);
+                    }
+                    #Server IP
+                    if (/option\s+dhcp-server-identifier\s+(\d{1,3}(?:\.\d{1,3}){3})\s*;/ and $dhcp){
+                        $ipdhcp = $1;
+                    }
+                }
+            }
+            close DHCP or warn;
+        } else {
+            warn "Can't open $leasepath\n";
+        }
+    }
+    return $ipdhcp;
+}
+
+# Initialise the distro entry
+sub run {
+
+    my $params = shift;
+    my $common = $params->{common};
+    my $logger = $params->{logger};
+
+    my $description;
+    my $driver;
+    my $ipaddress;
+    my $ipgateway;
+    my $ipmask;
+    my $ipsubnet;
+    my $macaddr;
+    my $pcislot;
+    my $status;
+    my $type;
+    my $virtualdev;
+    my $settings;
+    my $speed;
+    my $current_speed;
+    my $duplex;
+    my $ssid;
+    my $bssid;
+    my $mode;
+    my $version;
+    my $bitrate;
+    my $address;
+    my $mask4;
+    my $mask6;
+    my $binip;
+    my $binmask;
+    my $binsubnet;
+    my $mtu;
+
+    my %gateway;
+
+    if ($common->can_run("ip")){
+        my @ipLink = `ip -o link`;
+        foreach my $line (`ip -o addr`) {
+            $ipsubnet = $ipaddress = $ipmask = $ipgateway = $macaddr = $status = $type = $speed = $duplex = $driver = $pcislot = $virtualdev = $mtu = undef;
+            $description = "";
+            if ($line =~ /lo.*(127\.0\.0\.1\/8)/) { # ignore default loopback interface
+                   next;
+            }   
+            if ($line =~ /lo.*(::1\/128)/) { # ignore default loopback interface
+                   next;
+            }   
+            
+            $description = $1 if ($line =~ /\d:\s+([\w\d]+)\s+/i);
+
+            if ($line =~ /inet (\S+)\/(\d{2})/i){
+                $ipaddress = $1; 
+                $mask4 = $2; 
+            } elsif ($line =~ /inet6 (\S+)\/(\d{2})/i){
+                $ipaddress = $1; 
+                $mask6 = $2; 
+            }
+    
+            if (ip_is_ipv4($ipaddress)){
+                foreach (`route -n`) {
+                    if (/^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)/) {
+                        $gateway{$1} = $2;
+                    }
+                }
+
+                if (defined ($gateway{'0.0.0.0'})) {
+                    $common->setHardware({
+                        DEFAULTGATEWAY => $gateway{'0.0.0.0'}
+                    });
+                }
+            
+            
+                $ipmask = ip_bintoip(ip_get_mask($mask4,4),4) if $mask4;
+                $binip = ip_iptobin($ipaddress,4) if $ipaddress;
+                $binmask = ip_iptobin($ipmask,4) if $ipmask;
+                $binsubnet = $binip & $binmask if ($binip && $binmask);
+                $ipsubnet = ip_bintoip($binsubnet,4) if $binsubnet;
+            } elsif (ip_is_ipv6($ipaddress)) {
+            
+                foreach (`route -nA inet6`) {
+                    if(/^(\S+)\/\d{1,3}\s+(\S+)/) {
+                        next if ($1 eq $2);
+                        $gateway{$1} = $2;
+                    }
+                }
+
+                $ipmask = ip_bintoip(ip_get_mask($mask6,6),6) if $mask6;;
+                $binip = ip_iptobin(ip_expand_address($ipaddress,6),6) if $ipaddress;
+                $binmask = ip_iptobin(ip_expand_address($ipmask,6),6) if $ipmask;
+                $binsubnet = $binip & $binmask if ($binip && $binmask);
+                $ipsubnet = ip_compress_address(ip_bintoip($binsubnet,6),6) if $binsubnet;
+            }
+
+            my @line1 = split " ", $line;
+            my @linkData = split " ", (grep {/$line1[1]/} @ipLink)[0];
+            $macaddr = uc $linkData[-3];
+            $mtu = $linkData[4];
+
+            if ($linkData[2] =~ /,UP/) {
+                $status = "UP";
+            } else {
+                $status = "DOWN";
+            }
+
+            $type = $linkData[-4];
+            if ($type =~ /ether/){
+                $type = "Ethernet";
+            } elsif ($type =~ /loopback/) {
+                $type = "Loopback";
+            }
+
+            $ipgateway = $gateway{$ipsubnet} if $ipsubnet;
+            # replace '0.0.0.0' and '::' (ie 'default gateway') by the default gateway IP address if it exists
+            if (defined($ipgateway) and $ipgateway eq '0.0.0.0' and defined($gateway{'0.0.0.0'})) {
+                $ipgateway = $gateway{'0.0.0.0'};
+            }
+            if (defined($ipgateway) and $ipgateway eq '::' and defined($gateway{'::'})) {
+                $ipgateway = $gateway{'::'};
+            }
+
+            if (open UEVENT, "</sys/class/net/$description/device/uevent") {
+                foreach (<UEVENT>) {
+                    $driver = $1 if /^DRIVER=(\S+)/;
+                    $pcislot = $1 if /^PCI_SLOT_NAME=(\S+)/;
+                }
+                close UEVENT;
+            }
+
+            # Retrieve speed from /sys/class/net/$description/speed
+            if ( ! -z "/sys/class/net/$description/speed") {
+                if(open SPEED, "</sys/class/net/$description/speed") {
+                    foreach (<SPEED>){
+                         $current_speed=$_;
+                       }
+                    close SPEED;
+                }
+                
+                if (defined $current_speed) {
+                    chomp($current_speed);
+                    if ($current_speed eq "65535"){
+                        $current_speed = 0;
+                    } elsif ( $current_speed gt 100 ){
+                        $speed = ($current_speed/1000)." Gbps";
+                      } else {
+                        $speed = $current_speed." Mbps";
+                    }
+                }
+            }
+            # Retrieve duplex from /sys/class/net/$description/duplex
+            if (open DUPLEX, "</sys/class/net/$description/duplex"){
+                foreach (<DUPLEX>){
+                    $duplex=chomp($_);
+                }
+                close DUPLEX;
+            }
+            # Reliable way to get the info
+            if (-d "/sys/devices/virtual/net/") {
+                $virtualdev = (-d "/sys/devices/virtual/net/$description")?"1":"0";
+            } elsif ($common->can_run("brctl")) {
+                # Let's guess
+                my %bridge;
+                foreach (`brctl show`) {
+                      next if /^bridge name/;
+                      $bridge{$1} = 1 if /^(\w+)\s/;
+                }
+                if ($pcislot) {
+                      $virtualdev = "1";
+                } elsif ($bridge{$description}) {
+                      $virtualdev = "0";
+                }
+                $type = "bridge";
+            }
+
+            if (-d "/sys/class/net/$description/wireless"){
+                my @wifistatus = `iwconfig $description`;
+                foreach my $line (@wifistatus){
+                    $ssid = $1 if ($line =~ /ESSID:(\S+)/);
+                    $version = $1 if ($line =~ /IEEE (\S+)/);
+                    $mode = $1 if ($line =~ /Mode:(\S+)/);
+                    $bssid = $1 if ($line =~ /Access Point: (\S+)/);
+                    $bitrate = $1 if ($line =~ /Bit\sRate=\s*(\S+\sMb\/s)/i);
+                }
+                $type = "Wifi";
+            }
+            if ($description ne "") {
+                if ($type eq "Wifi") {
+                      $common->addNetwork({
+                          DESCRIPTION => $description,
+                          DRIVER => $driver,
+                          IPADDRESS => $ipaddress,
+                          IPDHCP => _ipdhcp($description),
+                          IPGATEWAY => $ipgateway,
+                          IPMASK => $ipmask,
+                          IPSUBNET => $ipsubnet,
+                          MACADDR => $macaddr,
+                          PCISLOT => $pcislot,
+                          STATUS => $status,
+                          TYPE => $type,
+                          SPEED => $bitrate,
+                          SSID => $ssid,
+                          BSSID => $bssid,
+                          IEEE => $version,
+                          MODE => $mode,
+                    });
+                } else { 
+                      $common->addNetwork({
+                          DESCRIPTION => $description,
+                          DRIVER => $driver,
+                          IPADDRESS => $ipaddress,
+                          IPDHCP => _ipdhcp($description),
+                          IPGATEWAY => $ipgateway,
+                          IPMASK => $ipmask,
+                          IPSUBNET => $ipsubnet,
+                          MACADDR => $macaddr,
+                          PCISLOT => $pcislot,
+                          STATUS => $status,
+                          TYPE => $type,
+                          VIRTUALDEV => $virtualdev,
+                          DUPLEX => $duplex?"Full":"Half",
+                          SPEED => $speed,
+                          MTU => $mtu,
+                    });
+                }
+            }
+        }
+    }
+
+    elsif ($common->can_run("ifconfig")){
+        foreach my $line (`ifconfig -a`) {
+            if ($line =~ /^$/ && $description && $macaddr) {
+            # end of interface section
+            # I write the entry
+                if (ip_is_ipv4($ipaddress)){
+                    foreach (`route -n`) {
+                        if (/^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)/) {
+                            $gateway{$1} = $2;
+                        }
+                    }
+
+                    if (defined ($gateway{'0.0.0.0'})) {
+                        $common->setHardware({
+                            DEFAULTGATEWAY => $gateway{'0.0.0.0'}
+                        });
+                    }
+
+                    $binip = ip_iptobin ($ipaddress ,4) if $ipaddress;
+                    $binmask = ip_iptobin ($ipmask,4) if $ipmask;
+                    $binsubnet = $binip & $binmask if ($binip && $binmask);
+                    $ipsubnet = ip_bintoip($binsubnet,4) if $binsubnet;
+                } elsif (ip_is_ipv6($ipaddress)) {
+                    # Table de routage IPv6 du noyau
+                    # Destination                    Next Hop                   Flag Met Ref Use If
+                    # fe80::/64                      [::]                       U    256 0     0 wlp6s0
+                    # foreach (`route -6`) {
+                    #    if (/^(\S+\/\d{2})\s+(\S+)/) {
+                    #        $gateway{$1} = $2;
+                    #    }
+                    #}
+                    #if (defined ($gateway{'fe80::/64'})) {
+                    #    $common->setHardware({
+                    #        DEFAULTGATEWAY => $gateway{'fe80::/64'}
+                    #    });
+                    #}
+                    
+                    foreach (`route -nA inet6`) {
+                        if(/^(\S+)\/\d{1,3}\s+(\S+)/) {
+                            next if ($1 eq $2);
+                            $gateway{$1} = $2;
+                        }
+                    }
+                    
+                    
+                    $ipmask = ip_bintoip(ip_get_mask($mask6,6),6) if $mask6;;
+                    $binip = ip_iptobin(ip_expand_address($ipaddress,6),6) if $ipaddress;
+                    $binmask = ip_iptobin(ip_expand_address($ipmask,6),6) if $ipmask;
+                    $binsubnet = $binip & $binmask if ($binip && $binmask);
+                    $ipsubnet = ip_compress_address(ip_bintoip($binsubnet,6),6) if $binsubnet;
+                }
+
+                $ipgateway = $gateway{$ipsubnet} if $ipsubnet;
+
+                if (-d "/sys/class/net/$description/wireless"){
+                    my @wifistatus = `iwconfig $description`;
+                    foreach my $line (@wifistatus){
+                        $ssid = $1 if ($line =~ /ESSID:(\S+)/);
+                        $version = $1 if ($line =~ /IEEE (\S+)/);
+                        $mode = $1 if ($line =~ /Mode:(\S+)/);
+                        $bssid = $1 if ($line =~ /Access Point: (\S+)/);
+                        $bitrate = $1 if ($line =~ /Bit\sRate=\s*(\S+\sMb\/s)/i);
+                    }
+                    $type = "Wifi";
+                } 
+
+                if (-f "/sys/class/net/$description/mode"){
+                    $type = "infiniband";
+                }
+
+                # replace '0.0.0.0' and '::' (ie 'default gateway') by the default gateway IP address if it exists
+                if (defined($ipgateway) and $ipgateway eq '0.0.0.0' and defined($gateway{'0.0.0.0'})) {
+                    $ipgateway = $gateway{'0.0.0.0'};
+                }
+                if (defined($ipgateway) and $ipgateway eq '::' and defined($gateway{'::'})) {
+                    $ipgateway = $gateway{'::'};
+                }
+
+                if (open UEVENT, "</sys/class/net/$description/device/uevent") {
+                    foreach (<UEVENT>) {
+                        $driver = $1 if /^DRIVER=(\S+)/;
+                        $pcislot = $1 if /^PCI_SLOT_NAME=(\S+)/;
+                    }
+                    close UEVENT;
+                }
+
+                # Retrieve speed from /sys/class/net/$description/speed
+                if ( ! -z "/sys/class/net/$description/speed") {
+                    open SPEED, "</sys/class/net/$description/speed";
+                    foreach (<SPEED>){
+                        $current_speed=$_;
+                    }
+                    close SPEED;
+                    chomp($current_speed);
+
+                    $current_speed=0 if $current_speed eq "";
+                    if ($current_speed eq "65535"){
+                        $current_speed = 0;
+                    } 
+                    if ($current_speed gt 100 ){
+                        $speed = ($current_speed/1000)." Gbps";
+                    } else {
+                        $speed = $current_speed." Mbps";
+                    }
+                }
+                # Retrieve duplex from /sys/class/net/$description/duplex
+                if (! -z "/sys/class/net/$description/duplex") {
+                    open DUPLEX, "</sys/class/net/$description/duplex";
+                    foreach (<DUPLEX>){
+                        $duplex=chomp($_);
+                    }
+                    close DUPLEX;
+                }
+
+                # Reliable way to get the info
+                if (-d "/sys/devices/virtual/net/") {
+                    $virtualdev = (-d "/sys/devices/virtual/net/$description")?"1":"0";
+                } elsif ($common->can_run("brctl")) {
+                    # Let's guess
+                    my %bridge;
+                    foreach (`brctl show`) {
+                        next if /^bridge name/;
+                        $bridge{$1} = 1 if /^(\w+)\s/;
+                    }
+                    if ($pcislot) {
+                        $virtualdev = "1";
+                    } elsif ($bridge{$description}) {
+                        $virtualdev = "0";
+                    }
+                    $type = "bridge";
+                }
+
+                if ($type eq "Wifi") {
+                    $common->addNetwork({
+                        DESCRIPTION => $description,
+                        DRIVER => $driver,
+                        IPADDRESS => $ipaddress,
+                        IPDHCP => _ipdhcp($description),
+                        IPGATEWAY => $ipgateway,
+                        IPMASK => $ipmask,
+                        IPSUBNET => $ipsubnet,
+                        MACADDR => $macaddr,
+                        PCISLOT => $pcislot,
+                        STATUS => $status,
+                        TYPE => $type,
+                        SPEED => $bitrate,
+                        SSID => $ssid,
+                        BSSID => $bssid,
+                        IEEE => $version,
+                        MODE => $mode,
+                    });
+                } else { 
+                    $common->addNetwork({
+                        DESCRIPTION => $description,
+                        DRIVER => $driver,
+                        IPADDRESS => $ipaddress,
+                        IPDHCP => _ipdhcp($description),
+                        IPGATEWAY => $ipgateway,
+                        IPMASK => $ipmask,
+                        IPSUBNET => $ipsubnet,
+                        MACADDR => $macaddr,
+                        PCISLOT => $pcislot,
+                        STATUS => $status,
+                        TYPE => $type,
+                        VIRTUALDEV => $virtualdev,
+                        DUPLEX => $duplex?"Full":"Half",
+                        SPEED => $speed,
+                        MTU => $mtu,
+                    });
+                }
+            }
+
+            if ($line =~ /^$/) { # End of section
+                $description = $driver = $ipaddress = $ipgateway = $ipmask = $ipsubnet = $macaddr = $pcislot = $status = $type = $virtualdev = $speed = $duplex = $mtu = undef;
+            } else { # In a section
+                if ($line =~ /^(\S+):\s\S+\s*mtu\s(\d+)/) {
+                    $description = $1; # Interface name
+                    $mtu = $2; 
+                }
+                
+                $description = $1 if($line =~ /^(\w+)\s+/); # Interface name
+                
+                # BUG: ipv4 address gets overwritten by ipv6 address but we want all ip addresses
+                if ($line =~ /inet add?r:(\S+)/i || $line =~ /^\s*inet\s+(\S+)/i || $line =~ /inet (\S+)\s+netmask/i){ 
+                    $ipaddress=$1;
+                } elsif ($line =~ /inet6 (\S+)\s+prefixlen\s+(\d{2})/i){
+                    $ipaddress=$1;
+                    $mask6=$2;
+                }
+                if ($line =~ /\S*mask:(\S+)/i || $line =~ /\S*netmask (\S+)\s/i){
+                    $ipmask=$1; 
+                } 
+                $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);
+                $status = 1 if ($line =~ /^\s+UP\s/ || $line =~ /flags=.*[<,]UP[,>]/);
+                $type = $1 if ($line =~ /link encap:(\S+)/i);
+                $type = $2 if ($line =~ /^\s+(loop|ether).*\((\S+)\)/i);
+                $mtu = $1 if ($line =~ /MTU:(\d+)/i);
+            }
+        }
+    }
+}
+
+1;
+