diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm index e0d6ae8fe1..e64e273a1d 100644 --- a/pandora_server/lib/PandoraFMS/Recon/Base.pm +++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm @@ -96,6 +96,9 @@ sub new { # Working SNMP community for each device. community_cache => {}, + # Cache of deviced discovered. + dicovered_cache => {}, + # Connections between devices. connections => {}, @@ -147,8 +150,15 @@ sub new { recon_timing_template => 3, recon_ports => '', resolve_names => 0, + snmp_auth_user => '', + snmp_auth_pass => '', + snmp_auth_method => '', snmp_checks => 2, + snmp_privacy_method => '', + snmp_privacy_pass => '', + snmp_security_level => '', snmp_timeout => 2, + snmp_version => 1, subnets => [], @_, @@ -157,8 +167,66 @@ sub new { # Perform some sanity checks. die("No subnet was specified.") unless defined($self->{'subnets'}); - # Disable SNMP scans if no community was given. - $self->{'snmp_enabled'} = 0 if (scalar(@{$self->{'communities'}}) == 0); + # Check SNMP params id SNMP is enabled + if ($self->{'snmp_enabled'}) { + # Check SNMP version + if ($self->{'snmp_version'} ne '1' && $self->{'snmp_version'} ne '2' + && $self->{'snmp_version'} ne '2c' && $self->{'snmp_version'} ne '3' + ) { + $self->{'snmp_enabled'} = 0; + $self->call('message', "SNMP version " . $self->{'snmp_version'} . " not supported (only 1, 2, 2c and 3).", 5); + } + + # Check the version 3 parameters + if ($self->{'snmp_version'} eq '3') { + # Fixed some vars + $self->{'communities'} = []; + + # SNMP v3 checks + if ( + $self->{'snmp_security_level'} ne 'noAuthNoPriv' && + $self->{'snmp_security_level'} ne 'authNoPriv' && + $self->{'snmp_security_level'} ne 'authPriv' + ) { + $self->{'snmp_enabled'} = 0; + $self->call('message', "Invalid SNMP security level " . $self->{'snmp_security_level'} . ".", 5); + } + if ($self->{'snmp_privacy_method'} ne 'DES' && $self->{'snmp_privacy_method'} ne 'AES') { + $self->{'snmp_enabled'} = 0; + $self->call('message', "Invalid SNMP privacy method " . $self->{'snmp_privacy_method'} . ".", 5); + } + if ($self->{'snmp_auth_method'} ne 'MD5' && $self->{'snmp_auth_method'} ne 'SHA') { + $self->{'snmp_enabled'} = 0; + $self->call('message', "Invalid SNMP authentication method " . $self->{'snmp_auth_method'} . ".", 5); + } + } else { + # Fixed some vars + $self->{'snmp_auth_user'} = ''; + $self->{'snmp_auth_pass'} = ''; + $self->{'snmp_auth_method'} = ''; + $self->{'snmp_privacy_method'} = ''; + $self->{'snmp_privacy_pass'} = ''; + $self->{'snmp_security_level'} = ''; + + # Disable SNMP scans if no community was given. + if (scalar(@{$self->{'communities'}}) == 0) { + $self->{'snmp_enabled'} = 0; + $self->call('message', "There is not any SNMP community configured.", 5); + + } + } + } + + # Remove all snmp related values if disabled + if (!$self->{'snmp_enabled'}) { + $self->{'communities'} = []; + $self->{'snmp_auth_user'} = ''; + $self->{'snmp_auth_pass'} = ''; + $self->{'snmp_auth_method'} = ''; + $self->{'snmp_privacy_method'} = ''; + $self->{'snmp_privacy_pass'} = ''; + $self->{'snmp_security_level'} = ''; + } return bless($self, $class); } @@ -199,7 +267,7 @@ sub aft_connectivity($$) { my ($self, $switch) = @_; my (%mac_temp, @aft_temp); - return unless defined($self->get_community($switch)); + return unless ($self->is_snmp_discovered($switch)); $self->enable_vlan_cache(); @@ -397,8 +465,7 @@ sub find_ifaces($$) { my ($self, $device) = @_; # Does it respond to SNMP? - my $community = $self->get_community($device); - return unless defined($community); + return unless ($self->is_snmp_discovered($device)); my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX); foreach my $if_index (@output) { @@ -476,11 +543,13 @@ sub get_device($$) { sub get_community($$) { my ($self, $device) = @_; + return '' if ($self->{'snmp_version'} eq "3"); + if (defined($self->{'community_cache'}->{$device})) { return $self->{'community_cache'}->{$device}; } - return undef; + return ''; } ######################################################################################## @@ -787,6 +856,9 @@ sub get_visited_devices($) { sub get_vlans($$) { my ($self, $device) = @_; + # Disabled in verison 3 + return () if ($self->{'snmp_version'} eq "3"); + # Is the VLAN cache disabled? return () unless ($self->{'__vlan_cache_enabled__'} == 1); @@ -945,6 +1017,17 @@ sub is_visited($$) { return 0; } +######################################################################################## +# Returns 1 if the given device has responded successfully to a snmp request +# Returns 0 otherwise. +######################################################################################## +sub is_snmp_discovered($$) { + my ($self, $device) = @_; + + # Check if device is into discovered cache + return (defined($self->{'discovered_cache'}->{$device})) ? 1 : 0; +} + ######################################################################################## # Mark the given devices as connected to each other on the given interfaces. ######################################################################################## @@ -999,23 +1082,46 @@ sub mark_visited($$) { } ######################################################################################## -# Looks for a working SNMP community for the given device. Returns 1 if one is -# found, 0 otherwise. Updates the SNMP community cache. +# Mark the given device as snmp discovered. +######################################################################################## +sub mark_discovered($$) { + my ($self, $device) = @_; + + $self->{'discovered_cache'}->{$device} = 1; +} + +######################################################################################## +# Validate the configuration for the given device. +# Returns 1 if successfull snmp contact, 0 otherwise. +# Updates the SNMP community cache on v1, v2 and v2c. ######################################################################################## sub snmp_responds($$) { my ($self, $device) = @_; - # We already have a working SNMP community for this device. - return 1 if (defined($self->get_community($device))); + return 1 if($self->is_snmp_discovered($device)); + + return ($self->{'snmp_version'} eq "3") + ? $self->snmp_responds_v3($device) + : $self->snmp_responds_v122c($device); +} + +######################################################################################## +# Looks for a working SNMP community for the given device. Returns 1 if one is +# found, 0 otherwise. Updates the SNMP community cache. +######################################################################################## +sub snmp_responds_v122c($$) { + my ($self, $device) = @_; foreach my $community (@{$self->{'communities'}}) { # Clean blanks. $community =~ s/\s+//g; - `snmpwalk -M/dev/null -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v1 -On -Oe -c $community $device .0 2>/dev/null`; + my $command = $self->snmp_get_command($device, ".0", $community); + `$command`; if ($? == 0) { $self->set_community($device, $community); + $self->mark_discovered($device); return 1; } } @@ -1023,6 +1129,25 @@ sub snmp_responds($$) { return 0; } + +######################################################################################## +# Validate the SNMP v3 configuration for a device. +# Returns 1 if successfull snmp contact, 0 otherwise. +######################################################################################## +sub snmp_responds_v3($$) { + my ($self, $device) = @_; + + my $command = $self->snmp_get_command($device, ".0"); + `$command`; + + if ($? == 0) { + $self->mark_discovered($device); + return 1; + } + + return 0; +} + ############################################################################## # Parse the local ARP cache. ############################################################################## @@ -1309,8 +1434,8 @@ sub snmp_get($$$) { my ($self, $device, $oid) = @_; my @output; + return () unless defined $self->is_snmp_discovered($device); my $community = $self->get_community($device); - return () unless defined ($community); # Check the SNMP query cache first. if (defined($self->{'snmp_cache'}->{"${device}_${oid}"})) { @@ -1320,13 +1445,15 @@ sub snmp_get($$$) { # Check VLANS. my @vlans = $self->get_vlans($device); if (scalar(@vlans) == 0) { - @output = `snmpwalk -M/dev/null -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v1 -On -Oe -c $community $device $oid 2>/dev/null`; + my $command = $self->snmp_get_command($device, $oid, $community); + @output = `$command`; } else { # Handle duplicate lines. my %output_hash; foreach my $vlan (@vlans) { - foreach my $line (`snmpwalk -M/dev/null -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v1 -On -Oe -c $community\@$vlan $device $oid 2>/dev/null`) { + my $command = $self->snmp_get_command($device, $oid, $community, $vlan); + foreach my $line (`$vlan`) { $output_hash{$line} = 1; } } @@ -1339,6 +1466,31 @@ sub snmp_get($$$) { return @output; } +######################################################################################## +# Get the snmpwalk command seing version 1, 2, 2c or 3. +######################################################################################## +sub snmp_get_command { + my ($self, $device, $oid, $community, $vlan) = @_; + $vlan = defined($vlan) ? "\@" . $vlan : ''; + + my $command = "snmpwalk -M/dev/null -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v$self->{'snmp_version'} -On -Oe "; + if ($self->{'snmp_version'} eq "3") { + $command .= " -l$self->{'snmp_security_level'} "; + print $self->{'snmp_security_level'} . "\n"; + if ($self->{'snmp_security_level'} ne "noAuthNoPriv") { + $command .= " -u$self->{'snmp_auth_user'} -a$self->{'snmp_auth_method'} -A$self->{'snmp_auth_pass'} "; + } + if ($self->{'snmp_security_level'} eq "authPriv") { + $command .= " -x$self->{'snmp_privacy_method'} -X$self->{'snmp_privacy_pass'} "; + } + } else { + $command .= " -c$community$vlan "; + } + + return "$command $device $oid 2>/dev/null"; + +} + ######################################################################################## # Performs an SNMP WALK and returns the value of the given OID. Returns undef # on error. diff --git a/pandora_server/lib/PandoraFMS/ReconServer.pm b/pandora_server/lib/PandoraFMS/ReconServer.pm index f0c272b3c7..13d563cd8e 100644 --- a/pandora_server/lib/PandoraFMS/ReconServer.pm +++ b/pandora_server/lib/PandoraFMS/ReconServer.pm @@ -173,7 +173,16 @@ sub data_consumer ($$) { pa_config => $pa_config, recon_ports => $task->{'recon_ports'}, resolve_names => $task->{'resolve_names'}, + snmp_auth_user => $task->{'snmp_auth_user'}, + snmp_auth_pass => $task->{'snmp_auth_pass'}, + snmp_auth_method => $task->{'snmp_auth_method'}, + snmp_checks => $task->{'snmp_checks'}, snmp_enabled => $task->{'snmp_enabled'}, + snmp_privacy_method => $task->{'snmp_privacy_method'}, + snmp_privacy_pass => $task->{'snmp_privacy_pass'}, + snmp_security_level => $task->{'snmp_security_level'}, + snmp_timeout => $task->{'snmp_timeout'}, + snmp_version => $task->{'snmp_version'}, subnets => \@subnets, task_id => $task->{'id_rt'}, vlan_cache_enabled => $task->{'vlan_enabled'}, @@ -310,10 +319,17 @@ sub PandoraFMS::Recon::Base::create_network_profile_modules($$$) { $self->call('message', "Network component ID " . $np_component->{'id_nc'} . " not found.", 5); next; } - + # Use snmp_community from network task instead the component snmp_community $component->{'snmp_community'} = safe_output($self->get_community($device)); - + $component->{'tcp_send'} = $self->{'snmp_version'}; + $component->{'custom_string_1'} = $self->{'snmp_privacy_method'}; + $component->{'custom_string_2'} = $self->{'snmp_privacy_pass'}; + $component->{'custom_string_3'} = $self->{'snmp_security_level'}; + $component->{'plugin_parameter'} = $self->{'snmp_auth_method'}; + $component->{'plugin_user'} = $self->{'snmp_auth_user'}; + $component->{'plugin_pass'} = $self->{'snmp_auth_pass'}; + pandora_create_module_from_network_component($self->{'pa_config'}, $component, $agent_id, $self->{'dbh'}); } } @@ -466,8 +482,8 @@ sub PandoraFMS::Recon::Base::create_agent($$) { } # Add interfaces to the agent if it responds to SNMP. + return $agent_id unless ($self->is_snmp_discovered($device)); my $community = $self->get_community($device); - return $agent_id unless defined($community); my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX); foreach my $if_index (@output) { @@ -506,7 +522,13 @@ sub PandoraFMS::Recon::Base::create_agent($$) { 'descripcion' => $if_desc, 'id_agente' => $agent_id, 'ip_target' => $device, - 'tcp_send' => 1, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, 'snmp_community' => $community, 'snmp_oid' => "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index" ); @@ -516,6 +538,14 @@ sub PandoraFMS::Recon::Base::create_agent($$) { 'descripcion' => $if_desc, 'ip_target' => $device, 'snmp_community' => $community, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, + 'tcp_send' => $self->{'snmp_version'}, ); pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'}); } @@ -531,7 +561,13 @@ sub PandoraFMS::Recon::Base::create_agent($$) { 'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifInOctets.', 'id_agente' => $agent_id, 'ip_target' => $device, - 'tcp_send' => 1, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, 'snmp_community' => $community, 'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index"); pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'}); @@ -539,6 +575,13 @@ sub PandoraFMS::Recon::Base::create_agent($$) { my %module = ( 'ip_target' => $device, 'snmp_community' => $community, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, ); pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'}); } @@ -553,7 +596,13 @@ sub PandoraFMS::Recon::Base::create_agent($$) { 'descripcion' => 'The total number of octets received on the interface, including framing characters.', 'id_agente' => $agent_id, 'ip_target' => $device, - 'tcp_send' => 1, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, 'snmp_community' => $community, 'snmp_oid' => "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index"); pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'}); @@ -561,6 +610,13 @@ sub PandoraFMS::Recon::Base::create_agent($$) { my %module = ( 'ip_target' => $device, 'snmp_community' => $community, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, ); pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'}); } @@ -577,7 +633,13 @@ sub PandoraFMS::Recon::Base::create_agent($$) { 'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifOutOctets.', 'id_agente' => $agent_id, 'ip_target' => $device, - 'tcp_send' => 1, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, 'snmp_community' => $community, 'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index"); pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'}); @@ -585,6 +647,14 @@ sub PandoraFMS::Recon::Base::create_agent($$) { my %module = ( 'ip_target' => $device, 'snmp_community' => $community, + 'tcp_send' => $self->{'snmp_version'}, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, ); pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'}); } @@ -599,7 +669,13 @@ sub PandoraFMS::Recon::Base::create_agent($$) { 'descripcion' => 'The total number of octets received on the interface, including framing characters.', 'id_agente' => $agent_id, 'ip_target' => $device, - 'tcp_send' => 1, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, 'snmp_community' => $community, 'snmp_oid' => "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index"); pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'}); @@ -607,6 +683,14 @@ sub PandoraFMS::Recon::Base::create_agent($$) { my %module = ( 'ip_target' => $device, 'snmp_community' => $community, + 'tcp_send' => $self->{'snmp_version'}, + 'tcp_send' => $self->{'snmp_version'}, + 'custom_string_1' => $self->{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'snmp_security_level'}, + 'plugin_parameter' => $self->{'snmp_auth_method'}, + 'plugin_user' => $self->{'snmp_auth_user'}, + 'plugin_pass' => $self->{'snmp_auth_pass'}, ); pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'}); }