#!/usr/bin/perl # (c) Ártica ST 2016 # Utility functions for the network topology discovery modules. package PandoraFMS::Recon::Util; use strict; use warnings; # Default lib dir for RPM and DEB packages. use lib '/usr/lib/perl5'; use Socket qw/inet_aton/; our @ISA = ("Exporter"); our %EXPORT_TAGS = ( 'all' => [qw( )] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( enterprise_new ip_to_long mac_matches mac_to_dec parse_mac subnet_matches ); ######################################################################################## # Return an Enterprise Recon object. ######################################################################################## sub enterprise_new($$) { my ($class, $arguments) = @_; my @args; if (ref($arguments) eq "HASH") { @args = %{$arguments}; } if (ref($arguments) eq "ARRAY") { @args = @{$arguments}; } # Try to load the module if ($^O eq 'MSWin32') { # If the Windows service dies the service is stopped, even inside an eval ($RUN is set to 0)! eval 'local $SIG{__DIE__}; require '.$class.';'; }else { eval 'require '.$class.';'; } if ($@) { # Not loaded. return undef; } return new $class(@args); } ######################################################################################## # Return the numeric representation of the given IP address. ######################################################################################## sub ip_to_long($) { my $ip_address = shift; return unpack('N', inet_aton($ip_address)); } ######################################################################################## # Returns 1 if the two given MAC addresses are the same. ######################################################################################## sub mac_matches($$) { my ($mac_1, $mac_2) = @_; if (parse_mac($mac_1) eq parse_mac($mac_2)) { return 1; } return 0; } ######################################################################################## # Convert a MAC address to decimal dotted notation. ######################################################################################## sub mac_to_dec($) { my $mac = shift; my $dec_mac = ''; my @elements = split(/:/, $mac); foreach my $element (@elements) { $dec_mac .= unpack('s', pack 's', hex($element)) . '.'; } chop($dec_mac); return $dec_mac; } ######################################################################################## # Make sure all MAC addresses are in the same format (00 11 22 33 44 55 66). ######################################################################################## sub parse_mac($) { my ($mac) = @_; # Remove leading and trailing whitespaces. $mac =~ s/(^\s+)|(\s+$)//g; # Replace whitespaces and dots with colons. $mac =~ s/\s+|\./:/g; # Convert hex digits to uppercase. $mac =~ s/([a-f])/\U$1/g; # Add a leading 0 to single digits. $mac =~ s/^([0-9A-F]):/0$1:/g; $mac =~ s/:([0-9A-F]):/:0$1:/g; $mac =~ s/:([0-9A-F])$/:0$1/g; return $mac; } ######################################################################################## # Returns 1 if the given IP address belongs to the given subnet. ######################################################################################## sub subnet_matches($$;$) { my ($ipaddr, $subnet, $mask) = @_; my ($netaddr, $netmask); # Decimal dot notation mask. if (defined($mask)) { $netaddr = $subnet; $netmask = ip_to_long($mask); } # CIDR notation. else { ($netaddr, $netmask) = split('/', $subnet); return 0 unless defined($netmask); # Convert the netmask to a numeric format. $netmask = -1 << (32 - $netmask); } if ((ip_to_long($ipaddr) & $netmask) == (ip_to_long($netaddr) & $netmask)) { return 1; } return 0; } 1; __END__