From 6504fe49b5f37c5a17de7e2f01f2acdbfbcb9cd0 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Wed, 18 Mar 2020 10:28:50 +0100 Subject: [PATCH] intentation to spaces (2) and minor fix --- .../include/javascript/pandora_taskList.js | 2 +- .../lib/PandoraFMS/DiscoveryServer.pm | 1745 +++++------ pandora_server/lib/PandoraFMS/Recon/Base.pm | 2609 +++++++++-------- 3 files changed, 2182 insertions(+), 2174 deletions(-) diff --git a/pandora_console/include/javascript/pandora_taskList.js b/pandora_console/include/javascript/pandora_taskList.js index be10ffe773..0a61e1a831 100644 --- a/pandora_console/include/javascript/pandora_taskList.js +++ b/pandora_console/include/javascript/pandora_taskList.js @@ -50,7 +50,7 @@ function progress_task_list(id, title) { if (!$elem.dialog("isOpen")) timeoutRef = setInterval(function() { xhr = fetchTaskList(id, handleFetchTaskList); - }, 300000); + }, 3000); xhr = fetchTaskList(id, handleFetchTaskList); } diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm index ae857deefd..b9ccafbf2a 100644 --- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm +++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm @@ -54,552 +54,555 @@ my $TaskSem :shared; # IDs from tconfig_os. use constant { - OS_OTHER => 10, - OS_ROUTER => 17, - OS_SWITCH => 18, - STEP_SCANNING => 1, - STEP_AFT => 2, - STEP_TRACEROUTE => 3, - STEP_GATEWAY => 4, - STEP_STATISTICS => 1, - STEP_APP_SCAN => 2, - STEP_CUSTOM_QUERIES => 3, - DISCOVERY_HOSTDEVICES => 0, - DISCOVERY_HOSTDEVICES_CUSTOM => 1, - DISCOVERY_CLOUD_AWS => 2, - DISCOVERY_APP_VMWARE => 3, - DISCOVERY_APP_MYSQL => 4, - DISCOVERY_APP_ORACLE => 5, - DISCOVERY_CLOUD_AWS_EC2 => 6, - DISCOVERY_CLOUD_AWS_RDS => 7, - DISCOVERY_CLOUD_AZURE_COMPUTE => 8, - DISCOVERY_DEPLOY_AGENTS => 9, - DISCOVERY_APP_SAP => 10, + OS_OTHER => 10, + OS_ROUTER => 17, + OS_SWITCH => 18, + STEP_SCANNING => 1, + STEP_AFT => 2, + STEP_TRACEROUTE => 3, + STEP_GATEWAY => 4, + STEP_STATISTICS => 1, + STEP_APP_SCAN => 2, + STEP_CUSTOM_QUERIES => 3, + DISCOVERY_HOSTDEVICES => 0, + DISCOVERY_HOSTDEVICES_CUSTOM => 1, + DISCOVERY_CLOUD_AWS => 2, + DISCOVERY_APP_VMWARE => 3, + DISCOVERY_APP_MYSQL => 4, + DISCOVERY_APP_ORACLE => 5, + DISCOVERY_CLOUD_AWS_EC2 => 6, + DISCOVERY_CLOUD_AWS_RDS => 7, + DISCOVERY_CLOUD_AZURE_COMPUTE => 8, + DISCOVERY_DEPLOY_AGENTS => 9, + DISCOVERY_APP_SAP => 10, + DISCOVERY_SEARCH => 0, + DISCOVERY_STANDARD => 1, + DISCOVERY_RESULTS => 2, }; ################################################################################ # Discovery Server class constructor. ################################################################################ sub new ($$$$$$) { - my ($class, $config, $dbh) = @_; - - return undef unless (defined($config->{'reconserver'}) && $config->{'reconserver'} == 1) - || (defined($config->{'discoveryserver'}) && $config->{'discoveryserver'} == 1); - - if (! -e $config->{'nmap'}) { - logger ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1); - print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1); - return undef; - } + my ($class, $config, $dbh) = @_; + + return undef unless (defined($config->{'reconserver'}) && $config->{'reconserver'} == 1) + || (defined($config->{'discoveryserver'}) && $config->{'discoveryserver'} == 1); + + if (! -e $config->{'nmap'}) { + logger ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1); + print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1); + return undef; + } - # Initialize semaphores and queues - @TaskQueue = (); - %PendingTasks = (); - $Sem = Thread::Semaphore->new; - $TaskSem = Thread::Semaphore->new (0); - - # Restart automatic recon tasks. - db_do ($dbh, 'UPDATE trecon_task SET utimestamp = 0 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep > 0', - get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER)); + # Initialize semaphores and queues + @TaskQueue = (); + %PendingTasks = (); + $Sem = Thread::Semaphore->new; + $TaskSem = Thread::Semaphore->new (0); + + # Restart automatic recon tasks. + db_do ($dbh, 'UPDATE trecon_task SET utimestamp = 0 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep > 0', + get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER)); - # Reset (but do not restart) manual recon tasks. - db_do ($dbh, 'UPDATE trecon_task SET status = -1 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep = 0', - get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER)); + # Reset (but do not restart) manual recon tasks. + db_do ($dbh, 'UPDATE trecon_task SET status = -1 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep = 0', + get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER)); - # Call the constructor of the parent class - my $self = $class->SUPER::new($config, DISCOVERYSERVER, \&PandoraFMS::DiscoveryServer::data_producer, \&PandoraFMS::DiscoveryServer::data_consumer, $dbh); - - bless $self, $class; - return $self; + # Call the constructor of the parent class + my $self = $class->SUPER::new($config, DISCOVERYSERVER, \&PandoraFMS::DiscoveryServer::data_producer, \&PandoraFMS::DiscoveryServer::data_consumer, $dbh); + + bless $self, $class; + return $self; } ################################################################################ # Run. ################################################################################ sub run ($) { - my $self = shift; - my $pa_config = $self->getConfig (); - my $dbh = $self->getDBH(); - - print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1); - my $threads = $pa_config->{'recon_threads'}; + my $self = shift; + my $pa_config = $self->getConfig (); + my $dbh = $self->getDBH(); + + print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1); + my $threads = $pa_config->{'recon_threads'}; - # Use hightest value - if ($pa_config->{'discovery_threads'} > $pa_config->{'recon_threads'}) { - $threads = $pa_config->{'discovery_threads'}; - } - $self->setNumThreads($threads); - $self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem); + # Use hightest value + if ($pa_config->{'discovery_threads'} > $pa_config->{'recon_threads'}) { + $threads = $pa_config->{'discovery_threads'}; + } + $self->setNumThreads($threads); + $self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem); } ################################################################################ # Data producer. ################################################################################ sub data_producer ($) { - my $self = shift; - my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); - - my @tasks; - - my $server_id = get_server_id ($dbh, $pa_config->{'servername'}, $self->getServerType ()); - return @tasks unless defined ($server_id); - - # Manual tasks have interval_sweep = 0 - # Manual tasks are "forced" like the other, setting the utimestamp to 1 - # By default, after create a tasks it takes the utimestamp to 0 - # Status -1 means "done". - my @rows; - if (pandora_is_master($pa_config) == 0) { - @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task - WHERE id_recon_server = ? - AND disabled = 0 - AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1) - OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id); - } else { - @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task - WHERE (id_recon_server = ? OR id_recon_server = ANY(SELECT id_server FROM tserver WHERE status = 0 AND server_type = ?)) - AND disabled = 0 - AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1) - OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id, DISCOVERYSERVER); - } + my $self = shift; + my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); + + my @tasks; + + my $server_id = get_server_id ($dbh, $pa_config->{'servername'}, $self->getServerType ()); + return @tasks unless defined ($server_id); + + # Manual tasks have interval_sweep = 0 + # Manual tasks are "forced" like the other, setting the utimestamp to 1 + # By default, after create a tasks it takes the utimestamp to 0 + # Status -1 means "done". + my @rows; + if (pandora_is_master($pa_config) == 0) { + @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task + WHERE id_recon_server = ? + AND disabled = 0 + AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1) + OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id); + } else { + @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task + WHERE (id_recon_server = ? OR id_recon_server = ANY(SELECT id_server FROM tserver WHERE status = 0 AND server_type = ?)) + AND disabled = 0 + AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1) + OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id, DISCOVERYSERVER); + } - foreach my $row (@rows) { - - # Update task status - update_recon_task ($dbh, $row->{'id_rt'}, 1); - - push (@tasks, $row->{'id_rt'}); - } + foreach my $row (@rows) { - return @tasks; + # Update task status + update_recon_task ($dbh, $row->{'id_rt'}, 1); + + push (@tasks, $row->{'id_rt'}); + } + + return @tasks; } ################################################################################ # Data consumer. ################################################################################ sub data_consumer ($$) { - my ($self, $task_id) = @_; - my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); + my ($self, $task_id) = @_; + my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); - # Get server id. - my $server_id = get_server_id($dbh, $pa_config->{'servername'}, $self->getServerType()); + # Get server id. + my $server_id = get_server_id($dbh, $pa_config->{'servername'}, $self->getServerType()); - # Get recon task data - my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id); - return -1 unless defined ($task); + # Get recon task data + my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id); + return -1 unless defined ($task); - # Is it a recon script? - if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) { - exec_recon_script ($pa_config, $dbh, $task); - return; - } else { - logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10); + # Is it a recon script? + if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) { + exec_recon_script ($pa_config, $dbh, $task); + return; + } else { + logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10); + } + + eval { + my @subnets = split(/,/, safe_output($task->{'subnet'})); + my @communities = split(/,/, safe_output($task->{'snmp_community'})); + my @auth_strings = (); + if(defined($task->{'auth_strings'})) { + @auth_strings = split(/,/, safe_output($task->{'auth_strings'})); } - eval { - my @subnets = split(/,/, safe_output($task->{'subnet'})); - my @communities = split(/,/, safe_output($task->{'snmp_community'})); - my @auth_strings = (); - if(defined($task->{'auth_strings'})) { - @auth_strings = split(/,/, safe_output($task->{'auth_strings'})); - } + my $main_event = pandora_event($pa_config, "[Discovery] Execution summary",$task->{'id_group'}, 0, 0, 0, 0, 'system', 0, $dbh); - my $main_event = pandora_event($pa_config, "[Discovery] Execution summary",$task->{'id_group'}, 0, 0, 0, 0, 'system', 0, $dbh); - - my %cnf_extra; - - my $r = enterprise_hook('discovery_generate_extra_cnf',[$pa_config, $dbh, $task, \%cnf_extra]); - if (defined($r) && $r eq 'ERR') { - # Could not generate extra cnf, skip this task. - return; - } - - - if ($task->{'type'} == DISCOVERY_APP_SAP) { - # SAP TASK, retrieve license. - $task->{'sap_license'} = pandora_get_config_value( - $dbh, - 'sap_license' - ); - - # Retrieve credentials for task (optional). - if (defined($task->{'auth_strings'}) - && $task->{'auth_strings'} ne '' - ) { - my $key = credential_store_get_key( - $pa_config, - $dbh, - $task->{'auth_strings'} - ); - - # Inside an eval, here it shouln't fail unless bad configured. - $task->{'username'} = $key->{'username'}; - $task->{'password'} = $key->{'password'}; - - } - } - - my $recon = new PandoraFMS::Recon::Base( - communities => \@communities, - dbh => $dbh, - group_id => $task->{'id_group'}, - id_os => $task->{'id_os'}, - id_network_profile => $task->{'id_network_profile'}, - os_detection => $task->{'os_detect'}, - parent_detection => $task->{'parent_detection'}, - parent_recursion => $task->{'parent_recursion'}, - 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'}, - wmi_enabled => $task->{'wmi_enabled'}, - auth_strings_array => \@auth_strings, - autoconfiguration_enabled => $task->{'autoconfiguration_enabled'}, - main_event_id => $main_event, - server_id => $server_id, - %{$pa_config}, - task_data => $task, - public_url => PandoraFMS::Config::pandora_get_tconfig_token($dbh, 'public_url', ''), - %cnf_extra - ); - - $recon->scan(); - - # Clean tmp file. - if (defined($cnf_extra{'creds_file'}) - && -f $cnf_extra{'creds_file'}) { - unlink($cnf_extra{'creds_file'}); - } - - - # Clean one shot tasks - if ($task->{'type'} eq DISCOVERY_DEPLOY_AGENTS) { - db_delete_limit($dbh, ' trecon_task ', ' id_rt = ? ', 1, $task->{'id_rt'}); - } - }; - if ($@) { - logger( - $pa_config, - 'Cannot execute Discovery task: ' . safe_output($task->{'name'}) . $@, - 10 - ); - update_recon_task ($dbh, $task_id, -1); - return; + my %cnf_extra; + + my $r = enterprise_hook('discovery_generate_extra_cnf',[$pa_config, $dbh, $task, \%cnf_extra]); + if (defined($r) && $r eq 'ERR') { + # Could not generate extra cnf, skip this task. + return; } + + + if ($task->{'type'} == DISCOVERY_APP_SAP) { + # SAP TASK, retrieve license. + $task->{'sap_license'} = pandora_get_config_value( + $dbh, + 'sap_license' + ); + + # Retrieve credentials for task (optional). + if (defined($task->{'auth_strings'}) + && $task->{'auth_strings'} ne '' + ) { + my $key = credential_store_get_key( + $pa_config, + $dbh, + $task->{'auth_strings'} + ); + + # Inside an eval, here it shouln't fail unless bad configured. + $task->{'username'} = $key->{'username'}; + $task->{'password'} = $key->{'password'}; + + } + } + + my $recon = new PandoraFMS::Recon::Base( + communities => \@communities, + dbh => $dbh, + group_id => $task->{'id_group'}, + id_os => $task->{'id_os'}, + id_network_profile => $task->{'id_network_profile'}, + os_detection => $task->{'os_detect'}, + parent_detection => $task->{'parent_detection'}, + parent_recursion => $task->{'parent_recursion'}, + 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'}, + wmi_enabled => $task->{'wmi_enabled'}, + auth_strings_array => \@auth_strings, + autoconfiguration_enabled => $task->{'autoconfiguration_enabled'}, + main_event_id => $main_event, + server_id => $server_id, + %{$pa_config}, + task_data => $task, + public_url => PandoraFMS::Config::pandora_get_tconfig_token($dbh, 'public_url', ''), + %cnf_extra + ); + + $recon->scan(); + + # Clean tmp file. + if (defined($cnf_extra{'creds_file'}) + && -f $cnf_extra{'creds_file'}) { + unlink($cnf_extra{'creds_file'}); + } + + + # Clean one shot tasks + if ($task->{'type'} eq DISCOVERY_DEPLOY_AGENTS) { + db_delete_limit($dbh, ' trecon_task ', ' id_rt = ? ', 1, $task->{'id_rt'}); + } + }; + if ($@) { + logger( + $pa_config, + 'Cannot execute Discovery task: ' . safe_output($task->{'name'}) . $@, + 10 + ); + update_recon_task ($dbh, $task_id, -1); + return; + } } ################################################################################ # Update recon task status. ################################################################################ sub update_recon_task ($$$) { - my ($dbh, $id_task, $status) = @_; - - db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task); + my ($dbh, $id_task, $status) = @_; + + db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task); } ################################################################################ # Executes recon scripts ################################################################################ sub exec_recon_script ($$$) { - my ($pa_config, $dbh, $task) = @_; - - # Get recon plugin data - my $script = get_db_single_row ($dbh, 'SELECT * FROM trecon_script WHERE id_recon_script = ?', $task->{'id_recon_script'}); - return -1 unless defined ($script); - - logger($pa_config, 'Executing recon script ' . safe_output($script->{'name'}), 10); - - my $command = safe_output($script->{'script'}); - - my $macros = safe_output($task->{'macros'}); + my ($pa_config, $dbh, $task) = @_; + + # Get recon plugin data + my $script = get_db_single_row ($dbh, 'SELECT * FROM trecon_script WHERE id_recon_script = ?', $task->{'id_recon_script'}); + return -1 unless defined ($script); + + logger($pa_config, 'Executing recon script ' . safe_output($script->{'name'}), 10); + + my $command = safe_output($script->{'script'}); + + my $macros = safe_output($task->{'macros'}); - # \r and \n should be escaped for decode_json(). - $macros =~ s/\n/\\n/g; - $macros =~ s/\r/\\r/g; - my $decoded_macros; - - if ($macros) { - eval { - $decoded_macros = decode_json(encode_utf8($macros)); - }; - } - - my $macros_parameters = ''; - - # Add module macros as parameter - if(ref($decoded_macros) eq "HASH") { - # Convert the hash to a sorted array - my @sorted_macros; - while (my ($i, $m) = each (%{$decoded_macros})) { - $sorted_macros[$i] = $m; - } - - # Remove the 0 position - shift @sorted_macros; - - foreach my $m (@sorted_macros) { - $macros_parameters = $macros_parameters . ' "' . $m->{"value"} . '"'; - } + # \r and \n should be escaped for decode_json(). + $macros =~ s/\n/\\n/g; + $macros =~ s/\r/\\r/g; + my $decoded_macros; + + if ($macros) { + eval { + $decoded_macros = decode_json(encode_utf8($macros)); + }; + } + + my $macros_parameters = ''; + + # Add module macros as parameter + if(ref($decoded_macros) eq "HASH") { + # Convert the hash to a sorted array + my @sorted_macros; + while (my ($i, $m) = each (%{$decoded_macros})) { + $sorted_macros[$i] = $m; } - my $ent_script = 0; - my $args = enterprise_hook('discovery_custom_recon_scripts',[$pa_config, $dbh, $task, $script]); - if (!$args) { - $args = "$task->{'id_rt'} $task->{'id_group'} $task->{'create_incident'} $macros_parameters"; - } else { - $ent_script = 1; - } - - if (-x $command) { - my $exec_output = `$command $args`; - logger($pa_config, "Execution output: \n". $exec_output, 10); - } else { - logger($pa_config, "Cannot execute recon task command $command.", 10); - } - - # Only update the timestamp in case something went wrong. The script should set the status. - db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ? WHERE id_rt = ?', time (), $task->{'id_rt'}); + # Remove the 0 position + shift @sorted_macros; - if ($ent_script == 1) { - enterprise_hook('discovery_clean_custom_recon',[$pa_config, $dbh, $task, $script]); + foreach my $m (@sorted_macros) { + $macros_parameters = $macros_parameters . ' "' . $m->{"value"} . '"'; } - - logger($pa_config, 'Done executing recon script ' . safe_output($script->{'name'}), 10); - return 0; + } + + my $ent_script = 0; + my $args = enterprise_hook('discovery_custom_recon_scripts',[$pa_config, $dbh, $task, $script]); + if (!$args) { + $args = "$task->{'id_rt'} $task->{'id_group'} $task->{'create_incident'} $macros_parameters"; + } else { + $ent_script = 1; + } + + if (-x $command) { + my $exec_output = `$command $args`; + logger($pa_config, "Execution output: \n". $exec_output, 10); + } else { + logger($pa_config, "Cannot execute recon task command $command.", 10); + } + + # Only update the timestamp in case something went wrong. The script should set the status. + db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ? WHERE id_rt = ?', time (), $task->{'id_rt'}); + + if ($ent_script == 1) { + enterprise_hook('discovery_clean_custom_recon',[$pa_config, $dbh, $task, $script]); + } + + logger($pa_config, 'Done executing recon script ' . safe_output($script->{'name'}), 10); + return 0; } ################################################################################ # Guess the OS using xprobe2 or nmap. ################################################################################ sub PandoraFMS::Recon::Base::guess_os($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - $DEVNULL = '/dev/null' if (!defined($DEVNULL)); - $DEVNULL = '/NUL' if ($^O =~ /win/i && !defined($DEVNULL)); + $DEVNULL = '/dev/null' if (!defined($DEVNULL)); + $DEVNULL = '/NUL' if ($^O =~ /win/i && !defined($DEVNULL)); - # OS detection disabled. Use the device type. - if ($self->{'os_detection'} == 0) { - my $device_type = $self->get_device_type($device); - return OS_OTHER unless defined($device_type); - - return OS_ROUTER if ($device_type eq 'router'); - return OS_SWITCH if ($device_type eq 'switch'); - return OS_OTHER; - } - - # Use xprobe2 if available - if (-x $self->{'pa_config'}->{'xprobe2'}) { - my $return = `"$self->{pa_config}->{xprobe2}" $device 2>$DEVNULL`; - if ($? == 0) { - if($return =~ /Running OS:(.*)/) { - return pandora_get_os($self->{'dbh'}, $1); - } - } - } - - # Use nmap by default - if (-x $self->{'pa_config'}->{'nmap'}) { - my $return = `"$self->{pa_config}->{nmap}" -F -O $device 2>$DEVNULL`; - return OS_OTHER if ($? != 0); - - if ($return =~ /Aggressive OS guesses:\s*(.*)/) { - return pandora_get_os($self->{'dbh'}, $1); - } - } + # OS detection disabled. Use the device type. + if ($self->{'os_detection'} == 0) { + my $device_type = $self->get_device_type($device); + return OS_OTHER unless defined($device_type); + return OS_ROUTER if ($device_type eq 'router'); + return OS_SWITCH if ($device_type eq 'switch'); return OS_OTHER; + } + + # Use xprobe2 if available + if (-x $self->{'pa_config'}->{'xprobe2'}) { + my $return = `"$self->{pa_config}->{xprobe2}" $device 2>$DEVNULL`; + if ($? == 0) { + if($return =~ /Running OS:(.*)/) { + return pandora_get_os($self->{'dbh'}, $1); + } + } + } + + # Use nmap by default + if (-x $self->{'pa_config'}->{'nmap'}) { + my $return = `"$self->{pa_config}->{nmap}" -F -O $device 2>$DEVNULL`; + return OS_OTHER if ($? != 0); + + if ($return =~ /Aggressive OS guesses:\s*(.*)/) { + return pandora_get_os($self->{'dbh'}, $1); + } + } + + return OS_OTHER; } ################################################################################ # Returns the number of open ports from the given list. ################################################################################ sub PandoraFMS::Recon::Base::tcp_scan ($$) { - my ($self, $host) = @_; + my ($self, $host) = @_; - my $r = `"$self->{pa_config}->{nmap}" -p$self->{recon_ports} $host`; + my $r = `"$self->{pa_config}->{nmap}" -p$self->{recon_ports} $host`; - # Same as ""| grep open | wc -l" but multi-OS; - my $open_ports = () = $r =~ /open/gm; + # Same as ""| grep open | wc -l" but multi-OS; + my $open_ports = () = $r =~ /open/gm; - return $open_ports; + return $open_ports; } ################################################################################ # Create network profile modules for the given agent. ################################################################################ sub PandoraFMS::Recon::Base::create_network_profile_modules($$$) { - my ($self, $agent_id, $device) = @_; + my ($self, $agent_id, $device) = @_; - # - # Plugin - # SNMP - # WMI - # ICMP - # + # + # Plugin + # SNMP + # WMI + # ICMP + # - return if empty($self->{'id_network_profile'}); + return if empty($self->{'id_network_profile'}); - my @templates = split /,/, $self->{'id_network_profile'}; + my @templates = split /,/, $self->{'id_network_profile'}; - # Get network components associated to the network profile. - my @np_components = get_db_rows($self->{'dbh'}, 'SELECT * FROM tnetwork_profile_component WHERE id_np = ?', $self->{'id_network_profile'}); - foreach my $np_component (@np_components) { + # Get network components associated to the network profile. + my @np_components = get_db_rows($self->{'dbh'}, 'SELECT * FROM tnetwork_profile_component WHERE id_np = ?', $self->{'id_network_profile'}); + foreach my $np_component (@np_components) { - # Get network component data - my $component = get_db_single_row($self->{'dbh'}, 'SELECT * FROM tnetwork_component WHERE id_nc = ?', $np_component->{'id_nc'}); - if (!defined ($component)) { - $self->call('message', "Network component ID " . $np_component->{'id_nc'} . " not found.", 5); - next; - } - - ## XXX Puede tener varios penes. - #next if (defined($template->{'pen'}) - # && get_enterprise_oid($device) != $template->{'pen'} ); - - # 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'}); + # Get network component data + my $component = get_db_single_row($self->{'dbh'}, 'SELECT * FROM tnetwork_component WHERE id_nc = ?', $np_component->{'id_nc'}); + if (!defined ($component)) { + $self->call('message', "Network component ID " . $np_component->{'id_nc'} . " not found.", 5); + next; } + + ## XXX Puede tener varios penes. + #next if (defined($template->{'pen'}) + # && get_enterprise_oid($device) != $template->{'pen'} ); + + # 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'}); + } } ################################################################################ # Create agents and modules reported by Recon::Base. ################################################################################ sub PandoraFMS::Recon::Base::report_scanned_agents($) { - my ($self) = @_; + my ($self) = @_; - if(defined($self->{'task_data'}{'direct_report'}) - && $self->{'task_data'}{'direct_report'} eq "2" - ) { - # Load cache. - my @rows = get_db_rows( - $self->{'dbh'}, - 'SELECT * FROM tdiscovery_tmp_agents WHERE `id_rt`=?', - $self->{'task_data'}{'id_rt'} + if(defined($self->{'task_data'}{'direct_report'}) + && $self->{'task_data'}{'direct_report'} == DISCOVERY_RESULTS + ) { + # Load cache. + my @rows = get_db_rows( + $self->{'dbh'}, + 'SELECT * FROM tdiscovery_tmp_agents WHERE `id_rt`=?', + $self->{'task_data'}{'id_rt'} + ); + + foreach my $row (@rows) { + my $name = safe_output($row->{'label'}); + my $data; + eval { + $data = decode_json(decode_base64($row->{'data'})); + }; + + # Store. + $self->{'agents_found'}{$name} = $data; + } + } + + foreach my $label (keys %{$self->{'agents_found'}}) { + if (!is_enabled($self->{'direct_report'})) { + # Store temporally. Wait user approval. + my $encoded; + eval { + local $SIG{__DIE__}; + $encoded = encode_base64(encode_json($self->{'agents_found'})); + }; + + my $id = get_db_value( + $self->{'dbh'}, + 'SELECT id FROM tdiscovery_tmp_agents WHERE id_rt = ? AND label = ?', + $self->{'task_data'}{'id_rt'}, + safe_input($label) + ); + + if (defined($id)) { + # Already defined. + $self->{'agents_found'}{$label}{'id'} = $id; + + db_do( + $self->{'dbh'}, + 'UPDATE tdiscovery_tmp_agents SET `data` = ? ' + .'WHERE `id_rt` = ? AND `label` = ?', + $encoded, + $self->{'task_data'}{'id_rt'}, + safe_input($label) ); + next; + } - foreach my $row (@rows) { - my $name = safe_output($row->{'label'}); - my $data; - eval { - $data = decode_json(decode_base64($row->{'data'})); - }; - - # Store. - $self->{'agents_found'}{$name} = $data; - } - } - - foreach my $label (keys %{$self->{'agents_found'}}) { - if (!is_enabled($self->{'direct_report'})) { - # Store temporally. Wait user approval. - my $encoded; - eval { - local $SIG{__DIE__}; - $encoded = encode_base64(encode_json($self->{'agents_found'})); - }; - - my $id = get_db_value( - $self->{'dbh'}, - 'SELECT id FROM tdiscovery_tmp_agents WHERE id_rt = ? AND label = ?', - $self->{'task_data'}{'id_rt'}, - safe_input($label) - ); - - if (defined($id)) { - # Already defined. - $self->{'agents_found'}{$label}{'id'} = $id; - - db_do( - $self->{'dbh'}, - 'UPDATE tdiscovery_tmp_agents SET `data` = ? ' - .'WHERE `id_rt` = ? AND `label` = ?', - $encoded, - $self->{'task_data'}{'id_rt'}, - safe_input($label) - ); - next; - } - - # Insert. - $self->{'agents_found'}{$label}{'id'} = db_insert( - $self->{'dbh'}, - 'id', - 'INSERT INTO tdiscovery_tmp_agents (`id_rt`,`label`,`data`,`created`) ' - .'VALUES (?, ?, ?, now())', - $self->{'task_data'}{'id_rt'}, - safe_input($label), - $encoded - ); - } else { - # Create agents. - } + # Insert. + $self->{'agents_found'}{$label}{'id'} = db_insert( + $self->{'dbh'}, + 'id', + 'INSERT INTO tdiscovery_tmp_agents (`id_rt`,`label`,`data`,`created`) ' + .'VALUES (?, ?, ?, now())', + $self->{'task_data'}{'id_rt'}, + safe_input($label), + $encoded + ); + } else { + # Create agents. } + } } ################################################################################ # Connect the given devices in the Pandora FMS database. ################################################################################ sub PandoraFMS::Recon::Base::connect_agents($$$$$) { - my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_; + my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_; - # Get the agent for the first device. - my $agent_1 = get_agent_from_addr($self->{'dbh'}, $dev_1); - if (!defined($agent_1)) { - $agent_1 = get_agent_from_name($self->{'dbh'}, $dev_1); - } - return unless defined($agent_1); + # Get the agent for the first device. + my $agent_1 = get_agent_from_addr($self->{'dbh'}, $dev_1); + if (!defined($agent_1)) { + $agent_1 = get_agent_from_name($self->{'dbh'}, $dev_1); + } + return unless defined($agent_1); - # Get the agent for the second device. - my $agent_2 = get_agent_from_addr($self->{'dbh'}, $dev_2); - if (!defined($agent_2)) { - $agent_2 = get_agent_from_name($self->{'dbh'}, $dev_2); - } - return unless defined($agent_2); + # Get the agent for the second device. + my $agent_2 = get_agent_from_addr($self->{'dbh'}, $dev_2); + if (!defined($agent_2)) { + $agent_2 = get_agent_from_name($self->{'dbh'}, $dev_2); + } + return unless defined($agent_2); - # Use ping modules by default. - $if_1 = 'Host Alive' if ($if_1 eq ''); - $if_2 = 'Host Alive' if ($if_2 eq ''); + # Use ping modules by default. + $if_1 = 'Host Alive' if ($if_1 eq ''); + $if_2 = 'Host Alive' if ($if_2 eq ''); - # Check whether the modules exists. - my $module_name_1 = $if_1 eq 'Host Alive' ? 'Host Alive' : "${if_1}_ifOperStatus"; - my $module_name_2 = $if_2 eq 'Host Alive' ? 'Host Alive' : "${if_2}_ifOperStatus"; - my $module_id_1 = get_agent_module_id($self->{'dbh'}, $module_name_1, $agent_1->{'id_agente'}); - if ($module_id_1 <= 0) { - $self->call('message', "ERROR: Module " . safe_output($module_name_1) . " does not exist for agent $dev_1.", 5); - return; - } - my $module_id_2 = get_agent_module_id($self->{'dbh'}, $module_name_2, $agent_2->{'id_agente'}); - if ($module_id_2 <= 0) { - $self->call('message', "ERROR: Module " . safe_output($module_name_2) . " does not exist for agent $dev_2.", 5); - return; - } + # Check whether the modules exists. + my $module_name_1 = $if_1 eq 'Host Alive' ? 'Host Alive' : "${if_1}_ifOperStatus"; + my $module_name_2 = $if_2 eq 'Host Alive' ? 'Host Alive' : "${if_2}_ifOperStatus"; + my $module_id_1 = get_agent_module_id($self->{'dbh'}, $module_name_1, $agent_1->{'id_agente'}); + if ($module_id_1 <= 0) { + $self->call('message', "ERROR: Module " . safe_output($module_name_1) . " does not exist for agent $dev_1.", 5); + return; + } + my $module_id_2 = get_agent_module_id($self->{'dbh'}, $module_name_2, $agent_2->{'id_agente'}); + if ($module_id_2 <= 0) { + $self->call('message', "ERROR: Module " . safe_output($module_name_2) . " does not exist for agent $dev_2.", 5); + return; + } - # Connect the modules if they are not already connected. - my $connection_id = get_db_value($self->{'dbh'}, 'SELECT id FROM tmodule_relationship WHERE (module_a = ? AND module_b = ? AND `type` = "direct") OR (module_b = ? AND module_a = ? AND `type` = "direct")', $module_id_1, $module_id_2, $module_id_1, $module_id_2); - if (! defined($connection_id)) { - db_do($self->{'dbh'}, 'INSERT INTO tmodule_relationship (`module_a`, `module_b`, `id_rt`) VALUES(?, ?, ?)', $module_id_1, $module_id_2, $self->{'task_id'}); - } + # Connect the modules if they are not already connected. + my $connection_id = get_db_value($self->{'dbh'}, 'SELECT id FROM tmodule_relationship WHERE (module_a = ? AND module_b = ? AND `type` = "direct") OR (module_b = ? AND module_a = ? AND `type` = "direct")', $module_id_1, $module_id_2, $module_id_1, $module_id_2); + if (! defined($connection_id)) { + db_do($self->{'dbh'}, 'INSERT INTO tmodule_relationship (`module_a`, `module_b`, `id_rt`) VALUES(?, ?, ?)', $module_id_1, $module_id_2, $self->{'task_id'}); + } } @@ -611,98 +614,98 @@ sub PandoraFMS::Recon::Base::connect_agents($$$$$) { # ] ################################################################################ sub PandoraFMS::Recon::Base::create_agents($$) { - my ($self, $data) = @_; + my ($self, $data) = @_; - my $pa_config = $self->{'pa_config'}; - my $dbh = $self->{'dbh'}; - my $server_id = $self->{'server_id'}; + my $pa_config = $self->{'pa_config'}; + my $dbh = $self->{'dbh'}; + my $server_id = $self->{'server_id'}; - return undef if (ref($data) ne "ARRAY"); + return undef if (ref($data) ne "ARRAY"); - foreach my $information (@{$data}) { - my $agent = $information->{'agent_data'}; - my $modules = $information->{'module_data'}; - my $force_processing = 0; + foreach my $information (@{$data}) { + my $agent = $information->{'agent_data'}; + my $modules = $information->{'module_data'}; + my $force_processing = 0; - # Search agent - my $current_agent = PandoraFMS::Core::locate_agent( - $pa_config, $dbh, $agent->{'agent_name'} - ); + # Search agent + my $current_agent = PandoraFMS::Core::locate_agent( + $pa_config, $dbh, $agent->{'agent_name'} + ); - my $parent_id; - if (defined($agent->{'parent_agent_name'})) { - $parent_id = PandoraFMS::Core::locate_agent( - $pa_config, $dbh, $agent->{'parent_agent_name'} - ); - if ($parent_id) { - $parent_id = $parent_id->{'id_agente'}; - } - } - - my $agent_id; - my $os_id = get_os_id($dbh, $agent->{'os'}); - - if ($os_id < 0) { - $os_id = get_os_id($dbh, 'Other'); - } - - if (!$current_agent) { - # Create agent. - $agent_id = pandora_create_agent( - $pa_config, $pa_config->{'servername'}, $agent->{'agent_name'}, - $agent->{'address'}, $agent->{'id_group'}, $parent_id, - $os_id, $agent->{'description'}, - $agent->{'interval'}, $dbh, $agent->{'timezone_offset'} - ); - - $current_agent = $parent_id = PandoraFMS::Core::locate_agent( - $pa_config, $dbh, $agent->{'agent_name'} - ); - - $force_processing = 1; - - } else { - $agent_id = $current_agent->{'id_agente'}; - } - - if (!defined($agent_id)) { - return undef; - } - - if (defined($agent->{'address'}) && $agent->{'address'} ne '') { - pandora_add_agent_address( - $pa_config, $agent_id, $agent->{'agent_name'}, - $agent->{'address'}, $dbh - ); - } - - # Update agent information - pandora_update_agent( - $pa_config, strftime("%Y-%m-%d %H:%M:%S", localtime()), $agent_id, - $agent->{'os_version'}, $agent->{'agent_version'}, - $agent->{'interval'}, $dbh, undef, $parent_id - ); - - # Add modules. - if (ref($modules) eq "ARRAY") { - foreach my $module (@{$modules}) { - next unless ref($module) eq 'HASH'; - # Translate data structure to simulate XML parser return. - my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module}; - - # Process modules. - PandoraFMS::DataServer::process_module_data ( - $pa_config, \%data_translated, - $server_id, $current_agent, - $module->{'name'}, $module->{'type'}, - $agent->{'interval'}, - strftime ("%Y/%m/%d %H:%M:%S", localtime()), - $dbh, $force_processing - ); - } - } + my $parent_id; + if (defined($agent->{'parent_agent_name'})) { + $parent_id = PandoraFMS::Core::locate_agent( + $pa_config, $dbh, $agent->{'parent_agent_name'} + ); + if ($parent_id) { + $parent_id = $parent_id->{'id_agente'}; + } } + my $agent_id; + my $os_id = get_os_id($dbh, $agent->{'os'}); + + if ($os_id < 0) { + $os_id = get_os_id($dbh, 'Other'); + } + + if (!$current_agent) { + # Create agent. + $agent_id = pandora_create_agent( + $pa_config, $pa_config->{'servername'}, $agent->{'agent_name'}, + $agent->{'address'}, $agent->{'id_group'}, $parent_id, + $os_id, $agent->{'description'}, + $agent->{'interval'}, $dbh, $agent->{'timezone_offset'} + ); + + $current_agent = $parent_id = PandoraFMS::Core::locate_agent( + $pa_config, $dbh, $agent->{'agent_name'} + ); + + $force_processing = 1; + + } else { + $agent_id = $current_agent->{'id_agente'}; + } + + if (!defined($agent_id)) { + return undef; + } + + if (defined($agent->{'address'}) && $agent->{'address'} ne '') { + pandora_add_agent_address( + $pa_config, $agent_id, $agent->{'agent_name'}, + $agent->{'address'}, $dbh + ); + } + + # Update agent information + pandora_update_agent( + $pa_config, strftime("%Y-%m-%d %H:%M:%S", localtime()), $agent_id, + $agent->{'os_version'}, $agent->{'agent_version'}, + $agent->{'interval'}, $dbh, undef, $parent_id + ); + + # Add modules. + if (ref($modules) eq "ARRAY") { + foreach my $module (@{$modules}) { + next unless ref($module) eq 'HASH'; + # Translate data structure to simulate XML parser return. + my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module}; + + # Process modules. + PandoraFMS::DataServer::process_module_data ( + $pa_config, \%data_translated, + $server_id, $current_agent, + $module->{'name'}, $module->{'type'}, + $agent->{'interval'}, + strftime ("%Y/%m/%d %H:%M:%S", localtime()), + $dbh, $force_processing + ); + } + } + } + } @@ -711,407 +714,407 @@ sub PandoraFMS::Recon::Base::create_agents($$) { # existing) agent, undef on error. ################################################################################ sub PandoraFMS::Recon::Base::create_agent($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Clean name. - $device = clean_blank($device); + # Clean name. + $device = clean_blank($device); - # Resolve hostnames. - my $host_name = (($self->{'resolve_names'} == 1) ? gethostbyaddr(inet_aton($device), AF_INET) : $device); - # Fallback to device IP if host name could not be resolved. - $host_name = $device if (!defined($host_name) || $host_name eq ''); - my $agent = locate_agent($self->{'pa_config'}, $self->{'dbh'}, $host_name); + # Resolve hostnames. + my $host_name = (($self->{'resolve_names'} == 1) ? gethostbyaddr(inet_aton($device), AF_INET) : $device); + # Fallback to device IP if host name could not be resolved. + $host_name = $device if (!defined($host_name) || $host_name eq ''); + my $agent = locate_agent($self->{'pa_config'}, $self->{'dbh'}, $host_name); - my ($agent_id, $agent_learning); - if (!defined($agent)) { - $host_name = $device unless defined ($host_name); + my ($agent_id, $agent_learning); + if (!defined($agent)) { + $host_name = $device unless defined ($host_name); - # Guess the OS. - my $id_os = $self->guess_os($device); + # Guess the OS. + my $id_os = $self->guess_os($device); - # Are we filtering hosts by OS? - return if ($self->{'id_os'} > 0 && $id_os != $self->{'id_os'}); + # Are we filtering hosts by OS? + return if ($self->{'id_os'} > 0 && $id_os != $self->{'id_os'}); - # Are we filtering hosts by TCP port? - return if ($self->{'recon_ports'} ne '' && $self->tcp_scan($device) == 0); - my $location = get_geoip_info($self->{'pa_config'}, $device); - $agent_id = pandora_create_agent( - $self->{'pa_config'}, $self->{'pa_config'}->{'servername'}, - $host_name, $device, $self->{'group_id'}, 0, $id_os, - '', 300, $self->{'dbh'}, undef, $location->{'longitude'}, - $location->{'latitude'} - ); - return undef unless defined ($agent_id) and ($agent_id > 0); + # Are we filtering hosts by TCP port? + return if ($self->{'recon_ports'} ne '' && $self->tcp_scan($device) == 0); + my $location = get_geoip_info($self->{'pa_config'}, $device); + $agent_id = pandora_create_agent( + $self->{'pa_config'}, $self->{'pa_config'}->{'servername'}, + $host_name, $device, $self->{'group_id'}, 0, $id_os, + '', 300, $self->{'dbh'}, undef, $location->{'longitude'}, + $location->{'latitude'} + ); + return undef unless defined ($agent_id) and ($agent_id > 0); - # Autoconfigure agent - if (defined($self->{'autoconfiguration_enabled'}) && $self->{'autoconfiguration_enabled'} == 1) { - my $agent_data = PandoraFMS::DB::get_db_single_row($self->{'dbh'}, 'SELECT * FROM tagente WHERE id_agente = ?', $agent_id); - # Update agent configuration once, after create agent. - enterprise_hook('autoconfigure_agent', [$self->{'pa_config'}, $host_name, $agent_id, $agent_data, $self->{'dbh'}, 1]); - } - - if (defined($self->{'main_event_id'})) { - my $addresses_str = join(',', safe_output($self->get_addresses($device))); - pandora_extended_event( - $self->{'pa_config'}, $self->{'dbh'}, $self->{'main_event_id'}, - "[Discovery] New " . safe_output($self->get_device_type($device)) . " found " . $host_name . " (" . $addresses_str . ") Agent $agent_id." - ); - - } - - $agent_learning = 1; - - # Create network profile modules for the agent - $self->create_network_profile_modules($agent_id, $device); + # Autoconfigure agent + if (defined($self->{'autoconfiguration_enabled'}) && $self->{'autoconfiguration_enabled'} == 1) { + my $agent_data = PandoraFMS::DB::get_db_single_row($self->{'dbh'}, 'SELECT * FROM tagente WHERE id_agente = ?', $agent_id); + # Update agent configuration once, after create agent. + enterprise_hook('autoconfigure_agent', [$self->{'pa_config'}, $host_name, $agent_id, $agent_data, $self->{'dbh'}, 1]); } - else { - $agent_id = $agent->{'id_agente'}; - $agent_learning = $agent->{'modo'}; - } - - # Do not create any modules if the agent is not in learning mode. - return unless ($agent_learning == 1); - - # Add found IP addresses to the agent. - foreach my $ip_addr ($self->get_addresses($device)) { - my $addr_id = get_addr_id($self->{'dbh'}, $ip_addr); - $addr_id = add_address($self->{'dbh'}, $ip_addr) unless ($addr_id > 0); - next unless ($addr_id > 0); - - # Assign the new address to the agent - my $agent_addr_id = get_agent_addr_id($self->{'dbh'}, $addr_id, $agent_id); - if ($agent_addr_id <= 0) { - db_do($self->{'dbh'}, 'INSERT INTO taddress_agent (`id_a`, `id_agent`) - VALUES (?, ?)', $addr_id, $agent_id); - } - } - - # Create a ping module. - my $module_id = get_agent_module_id($self->{'dbh'}, "ping", $agent_id); - if ($module_id <= 0) { - my %module = ('id_tipo_modulo' => 6, - 'id_modulo' => 2, - 'nombre' => "ping", - 'descripcion' => '', - 'id_agente' => $agent_id, - 'ip_target' => $device); - pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'}); - } - - # 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); - - my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX); - foreach my $if_index (@output) { - next unless ($if_index =~ /^[0-9]+$/); - - # Check the status of the interface. - if ($self->{'all_ifaces'} == 0) { - my $if_status = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index"); - next unless $if_status == 1; - } - - # Fill the module description with the IP and MAC addresses. - my $mac = $self->get_if_mac($device, $if_index); - my $ip = $self->get_if_ip($device, $if_index); - my $if_desc = ($mac ne '' ? "MAC $mac " : '') . ($ip ne '' ? "IP $ip" : ''); - - # Get the name of the network interface. - my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index"); - $if_name = "if$if_index" unless defined ($if_name); - $if_name =~ s/"//g; - $if_name = clean_blank($if_name); - - # Check whether the module already exists. - my $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifOperStatus', $agent_id); - - next if ($module_id > 0 && !$agent_learning); - # Encode problematic characters. - $if_desc = safe_input($if_desc); + if (defined($self->{'main_event_id'})) { + my $addresses_str = join(',', safe_output($self->get_addresses($device))); + pandora_extended_event( + $self->{'pa_config'}, $self->{'dbh'}, $self->{'main_event_id'}, + "[Discovery] New " . safe_output($self->get_device_type($device)) . " found " . $host_name . " (" . $addresses_str . ") Agent $agent_id." + ); - # Interface status module. - $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifOperStatus', $agent_id); - if ($module_id <= 0) { - my %module = ('id_tipo_modulo' => 18, - 'id_modulo' => 2, - 'nombre' => safe_input($if_name)."_ifOperStatus", - 'descripcion' => $if_desc, - 'id_agente' => $agent_id, - 'ip_target' => $device, - '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" - ); - pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'}); - } else { - my %module = ( - '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'}); - } + } + + $agent_learning = 1; - # Incoming traffic module. - my $if_hc_in_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index"); - if (defined($if_hc_in_octets)) { - $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifHCInOctets', $agent_id); - if ($module_id <= 0) { - my %module = ('id_tipo_modulo' => 16, - 'id_modulo' => 2, - 'nombre' => safe_input($if_name)."_ifHCInOctets", - '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' => $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'}); - } else { - 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'}); - } - } - # ifInOctets - elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index"))) { - $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifInOctets', $agent_id); - if ($module_id <= 0) { - my %module = ('id_tipo_modulo' => 16, - 'id_modulo' => 2, - 'nombre' => safe_input($if_name)."_ifInOctets", - 'descripcion' => 'The total number of octets received on the interface, including framing characters.', - 'id_agente' => $agent_id, - 'ip_target' => $device, - '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'}); - } else { - 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'}); - } - } + # Create network profile modules for the agent + $self->create_network_profile_modules($agent_id, $device); + } + else { + $agent_id = $agent->{'id_agente'}; + $agent_learning = $agent->{'modo'}; + } - # Outgoing traffic module. - my $if_hc_out_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index"); - if (defined($if_hc_out_octets)) { - $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifHCOutOctets', $agent_id); - if ($module_id <= 0) { - my %module = ('id_tipo_modulo' => 16, - 'id_modulo' => 2, - 'nombre' => safe_input($if_name)."_ifHCOutOctets", - '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' => $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'}); - } else { - 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'}); - } - } - # ifOutOctets - elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index"))) { - $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOutOctets", $agent_id); - if ($module_id <= 0) { - my %module = ('id_tipo_modulo' => 16, - 'id_modulo' => 2, - 'nombre' => safe_input($if_name)."_ifOutOctets", - 'descripcion' => 'The total number of octets received on the interface, including framing characters.', - 'id_agente' => $agent_id, - 'ip_target' => $device, - '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'}); - } else { - 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'}); - } - } + # Do not create any modules if the agent is not in learning mode. + return unless ($agent_learning == 1); + + # Add found IP addresses to the agent. + foreach my $ip_addr ($self->get_addresses($device)) { + my $addr_id = get_addr_id($self->{'dbh'}, $ip_addr); + $addr_id = add_address($self->{'dbh'}, $ip_addr) unless ($addr_id > 0); + next unless ($addr_id > 0); + + # Assign the new address to the agent + my $agent_addr_id = get_agent_addr_id($self->{'dbh'}, $addr_id, $agent_id); + if ($agent_addr_id <= 0) { + db_do($self->{'dbh'}, 'INSERT INTO taddress_agent (`id_a`, `id_agent`) + VALUES (?, ?)', $addr_id, $agent_id); + } + } + + # Create a ping module. + my $module_id = get_agent_module_id($self->{'dbh'}, "ping", $agent_id); + if ($module_id <= 0) { + my %module = ('id_tipo_modulo' => 6, + 'id_modulo' => 2, + 'nombre' => "ping", + 'descripcion' => '', + 'id_agente' => $agent_id, + 'ip_target' => $device); + pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'}); + } + + # 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); + + my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX); + foreach my $if_index (@output) { + next unless ($if_index =~ /^[0-9]+$/); + + # Check the status of the interface. + if ($self->{'all_ifaces'} == 0) { + my $if_status = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index"); + next unless $if_status == 1; } - return $agent_id; + # Fill the module description with the IP and MAC addresses. + my $mac = $self->get_if_mac($device, $if_index); + my $ip = $self->get_if_ip($device, $if_index); + my $if_desc = ($mac ne '' ? "MAC $mac " : '') . ($ip ne '' ? "IP $ip" : ''); + + # Get the name of the network interface. + my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index"); + $if_name = "if$if_index" unless defined ($if_name); + $if_name =~ s/"//g; + $if_name = clean_blank($if_name); + + # Check whether the module already exists. + my $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifOperStatus', $agent_id); + + next if ($module_id > 0 && !$agent_learning); + + # Encode problematic characters. + $if_desc = safe_input($if_desc); + + # Interface status module. + $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifOperStatus', $agent_id); + if ($module_id <= 0) { + my %module = ('id_tipo_modulo' => 18, + 'id_modulo' => 2, + 'nombre' => safe_input($if_name)."_ifOperStatus", + 'descripcion' => $if_desc, + 'id_agente' => $agent_id, + 'ip_target' => $device, + '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" + ); + pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'}); + } else { + my %module = ( + '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'}); + } + + # Incoming traffic module. + my $if_hc_in_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index"); + if (defined($if_hc_in_octets)) { + $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifHCInOctets', $agent_id); + if ($module_id <= 0) { + my %module = ('id_tipo_modulo' => 16, + 'id_modulo' => 2, + 'nombre' => safe_input($if_name)."_ifHCInOctets", + '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' => $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'}); + } else { + 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'}); + } + } + # ifInOctets + elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index"))) { + $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifInOctets', $agent_id); + if ($module_id <= 0) { + my %module = ('id_tipo_modulo' => 16, + 'id_modulo' => 2, + 'nombre' => safe_input($if_name)."_ifInOctets", + 'descripcion' => 'The total number of octets received on the interface, including framing characters.', + 'id_agente' => $agent_id, + 'ip_target' => $device, + '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'}); + } else { + 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'}); + } + } + + # Outgoing traffic module. + my $if_hc_out_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index"); + if (defined($if_hc_out_octets)) { + $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifHCOutOctets', $agent_id); + if ($module_id <= 0) { + my %module = ('id_tipo_modulo' => 16, + 'id_modulo' => 2, + 'nombre' => safe_input($if_name)."_ifHCOutOctets", + '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' => $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'}); + } else { + 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'}); + } + } + # ifOutOctets + elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index"))) { + $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOutOctets", $agent_id); + if ($module_id <= 0) { + my %module = ('id_tipo_modulo' => 16, + 'id_modulo' => 2, + 'nombre' => safe_input($if_name)."_ifOutOctets", + 'descripcion' => 'The total number of octets received on the interface, including framing characters.', + 'id_agente' => $agent_id, + 'ip_target' => $device, + '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'}); + } else { + 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'}); + } + } + } + + return $agent_id; } ################################################################################ # Delete already existing connections. ################################################################################ sub PandoraFMS::Recon::Base::delete_connections($) { - my ($self) = @_; + my ($self) = @_; - $self->call('message', "Deleting connections...", 10); - db_do($self->{'dbh'}, 'DELETE FROM tmodule_relationship WHERE id_rt=?', $self->{'task_id'}); + $self->call('message', "Deleting connections...", 10); + db_do($self->{'dbh'}, 'DELETE FROM tmodule_relationship WHERE id_rt=?', $self->{'task_id'}); } ################################################################################ # Print log messages. ################################################################################ sub PandoraFMS::Recon::Base::message($$$) { - my ($self, $message, $verbosity) = @_; + my ($self, $message, $verbosity) = @_; - logger($self->{'pa_config'}, "[Recon task " . $self->{'task_id'} . "] $message", $verbosity); + logger($self->{'pa_config'}, "[Recon task " . $self->{'task_id'} . "] $message", $verbosity); } ################################################################################ # Connect the given hosts to its parent. ################################################################################ sub PandoraFMS::Recon::Base::set_parent($$$) { - my ($self, $host, $parent) = @_; + my ($self, $host, $parent) = @_; - return unless ($self->{'parent_detection'} == 1); + return unless ($self->{'parent_detection'} == 1); - # Get the agent for the host. - my $agent = get_agent_from_addr($self->{'dbh'}, $host); - if (!defined($agent)) { - $agent = get_agent_from_name($self->{'dbh'}, $host); - } - return unless defined($agent); + # Get the agent for the host. + my $agent = get_agent_from_addr($self->{'dbh'}, $host); + if (!defined($agent)) { + $agent = get_agent_from_name($self->{'dbh'}, $host); + } + return unless defined($agent); - # Check if the parent agent exists. - my $agent_parent = get_agent_from_addr($self->{'dbh'}, $parent); - if (!defined($agent_parent)) { - $agent_parent = get_agent_from_name($self->{'dbh'}, $parent); - } - return unless (defined ($agent_parent)); + # Check if the parent agent exists. + my $agent_parent = get_agent_from_addr($self->{'dbh'}, $parent); + if (!defined($agent_parent)) { + $agent_parent = get_agent_from_name($self->{'dbh'}, $parent); + } + return unless (defined ($agent_parent)); - # Is the agent in learning mode? - return unless ($agent_parent->{'modo'} == 1); + # Is the agent in learning mode? + return unless ($agent_parent->{'modo'} == 1); - # Connect the host to its parent. - db_do($self->{'dbh'}, 'UPDATE tagente SET id_parent=? WHERE id_agente=?', $agent_parent->{'id_agente'}, $agent->{'id_agente'}); + # Connect the host to its parent. + db_do($self->{'dbh'}, 'UPDATE tagente SET id_parent=? WHERE id_agente=?', $agent_parent->{'id_agente'}, $agent->{'id_agente'}); } ################################################################################ # Create a WMI module for the given agent. ################################################################################ sub PandoraFMS::Recon::Base::wmi_module { - my ($self, $agent_id, $target, $wmi_query, $wmi_auth, $column, - $module_name, $module_description, $module_type, $unit) = @_; + my ($self, $agent_id, $target, $wmi_query, $wmi_auth, $column, + $module_name, $module_description, $module_type, $unit) = @_; - # Check whether the module already exists. - my $module_id = get_agent_module_id($self->{'dbh'}, $module_name, $agent_id); - return if ($module_id > 0); + # Check whether the module already exists. + my $module_id = get_agent_module_id($self->{'dbh'}, $module_name, $agent_id); + return if ($module_id > 0); - my ($user, $pass) = ($wmi_auth ne '') ? split('%', $wmi_auth) : (undef, undef); - my %module = ( - 'descripcion' => safe_input($module_description), - 'id_agente' => $agent_id, - 'id_modulo' => 6, - 'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module_type), - 'ip_target' => $target, - 'nombre' => safe_input($module_name), - 'plugin_pass' => defined($pass) ? $pass : '', - 'plugin_user' => defined($user) ? $user : '', - 'snmp_oid' => $wmi_query, - 'tcp_port' => $column, - 'unit' => defined($unit) ? $unit : '' - ); - - pandora_create_module_from_hash($self->{'pa_config'}, \%module, $self->{'dbh'}); + my ($user, $pass) = ($wmi_auth ne '') ? split('%', $wmi_auth) : (undef, undef); + my %module = ( + 'descripcion' => safe_input($module_description), + 'id_agente' => $agent_id, + 'id_modulo' => 6, + 'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module_type), + 'ip_target' => $target, + 'nombre' => safe_input($module_name), + 'plugin_pass' => defined($pass) ? $pass : '', + 'plugin_user' => defined($user) ? $user : '', + 'snmp_oid' => $wmi_query, + 'tcp_port' => $column, + 'unit' => defined($unit) ? $unit : '' + ); + + pandora_create_module_from_hash($self->{'pa_config'}, \%module, $self->{'dbh'}); } ################################################################################ # Update recon task status. ################################################################################ sub PandoraFMS::Recon::Base::update_progress ($$) { - my ($self, $progress) = @_; + my ($self, $progress) = @_; - my $stats = {}; - if (defined($self->{'summary'}) && $self->{'summary'} ne '') { - $stats->{'summary'} = $self->{'summary'}; - } - $stats->{'step'} = $self->{'step'}; - $stats->{'c_network_name'} = $self->{'c_network_name'}; - $stats->{'c_network_percent'} = $self->{'c_network_percent'}; + my $stats = {}; + if (defined($self->{'summary'}) && $self->{'summary'} ne '') { + $stats->{'summary'} = $self->{'summary'}; + } + $stats->{'step'} = $self->{'step'}; + $stats->{'c_network_name'} = $self->{'c_network_name'}; + $stats->{'c_network_percent'} = $self->{'c_network_percent'}; - # Store progress, last contact and overall status. - db_do ($self->{'dbh'}, 'UPDATE trecon_task SET utimestamp = ?, status = ?, summary = ? WHERE id_rt = ?', - time (), $progress, encode_json($stats), $self->{'task_id'}); + # Store progress, last contact and overall status. + db_do ($self->{'dbh'}, 'UPDATE trecon_task SET utimestamp = ?, status = ?, summary = ? WHERE id_rt = ?', + time (), $progress, encode_json($stats), $self->{'task_id'}); } 1; diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm index 279c84e337..49868448a7 100644 --- a/pandora_server/lib/PandoraFMS/Recon/Base.pm +++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm @@ -18,24 +18,27 @@ use PandoraFMS::Recon::Util; # Constants. use constant { - STEP_SCANNING => 1, - STEP_AFT => 2, - STEP_TRACEROUTE => 3, - STEP_GATEWAY => 4, - STEP_STATISTICS => 1, - STEP_APP_SCAN => 2, - STEP_CUSTOM_QUERIES => 3, - DISCOVERY_HOSTDEVICES => 0, - DISCOVERY_HOSTDEVICES_CUSTOM => 1, - DISCOVERY_CLOUD_AWS => 2, - DISCOVERY_APP_VMWARE => 3, - DISCOVERY_APP_MYSQL => 4, - DISCOVERY_APP_ORACLE => 5, - DISCOVERY_CLOUD_AWS_EC2 => 6, - DISCOVERY_CLOUD_AWS_RDS => 7, - DISCOVERY_CLOUD_AZURE_COMPUTE => 8, - DISCOVERY_DEPLOY_AGENTS => 9, - DISCOVERY_APP_SAP => 10, + STEP_SCANNING => 1, + STEP_AFT => 2, + STEP_TRACEROUTE => 3, + STEP_GATEWAY => 4, + STEP_STATISTICS => 1, + STEP_APP_SCAN => 2, + STEP_CUSTOM_QUERIES => 3, + DISCOVERY_HOSTDEVICES => 0, + DISCOVERY_HOSTDEVICES_CUSTOM => 1, + DISCOVERY_CLOUD_AWS => 2, + DISCOVERY_APP_VMWARE => 3, + DISCOVERY_APP_MYSQL => 4, + DISCOVERY_APP_ORACLE => 5, + DISCOVERY_CLOUD_AWS_EC2 => 6, + DISCOVERY_CLOUD_AWS_RDS => 7, + DISCOVERY_CLOUD_AZURE_COMPUTE => 8, + DISCOVERY_DEPLOY_AGENTS => 9, + DISCOVERY_APP_SAP => 10, + DISCOVERY_SEARCH => 0, + DISCOVERY_STANDARD => 1, + DISCOVERY_RESULTS => 2, }; # $DEVNULL @@ -104,268 +107,268 @@ our @EXPORT = qw( # Create a new ReconTask object. ################################################################################ sub new { - my $class = shift; + my $class = shift; - my $self = { + my $self = { - # Known aliases (multiple IP addresses for the same host. - aliases => {}, + # Known aliases (multiple IP addresses for the same host. + aliases => {}, - # Keep our own ARP cache to connect hosts to switches/routers. - arp_cache => {}, + # Keep our own ARP cache to connect hosts to switches/routers. + arp_cache => {}, - # Found children. - children => {}, + # Found children. + children => {}, - # Working SNMP community for each device. - community_cache => {}, + # Working SNMP community for each device. + community_cache => {}, - # Cache of deviced discovered. - dicovered_cache => {}, + # Cache of deviced discovered. + dicovered_cache => {}, - # Connections between devices. - connections => {}, + # Connections between devices. + connections => {}, - # Devices by type. - hosts => [], - routers => [], - switches => [], + # Devices by type. + hosts => [], + routers => [], + switches => [], - # Found interfaces. - ifaces => {}, + # Found interfaces. + ifaces => {}, - # Found parents. - parents => {}, + # Found parents. + parents => {}, - # Route cache. - routes => [], - default_gw => undef, + # Route cache. + routes => [], + default_gw => undef, - # SNMP query cache. - snmp_cache => {}, + # SNMP query cache. + snmp_cache => {}, - # Globally enable/disable SNMP scans. - snmp_enabled => 1, + # Globally enable/disable SNMP scans. + snmp_enabled => 1, - # Globally enable/disable WMI scans. - wmi_enabled => 0, - auth_strings_array => [], - wmi_timeout => 3, - timeout_cmd => '', + # Globally enable/disable WMI scans. + wmi_enabled => 0, + auth_strings_array => [], + wmi_timeout => 3, + timeout_cmd => '', - # Switch to switch connections. Used to properly connect hosts - # that are connected to a switch wich is in turn connected to another switch, - # since the hosts will show up in the latter's switch AFT too. - switch_to_switch => {}, + # Switch to switch connections. Used to properly connect hosts + # that are connected to a switch wich is in turn connected to another switch, + # since the hosts will show up in the latter's switch AFT too. + switch_to_switch => {}, - # Visited devices (initially empty). - visited_devices => {}, + # Visited devices (initially empty). + visited_devices => {}, - # Per device VLAN cache. - vlan_cache => {}, - vlan_cache_enabled => 1, # User configuration. Globally disables the VLAN cache. - __vlan_cache_enabled__ => 0, # Internal state. Allows us to enable/disable the VLAN cache on a per SNMP query basis. + # Per device VLAN cache. + vlan_cache => {}, + vlan_cache_enabled => 1, # User configuration. Globally disables the VLAN cache. + __vlan_cache_enabled__ => 0, # Internal state. Allows us to enable/disable the VLAN cache on a per SNMP query basis. - # Configuration parameters. - all_ifaces => 0, - communities => [], - icmp_checks => 2, - icmp_timeout => 2, - id_os => 0, - id_network_profile => 0, - nmap => '/usr/bin/nmap', - parent_detection => 1, - parent_recursion => 5, - os_detection => 0, - 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 => [], - autoconfiguration_enabled => 0, + # Configuration parameters. + all_ifaces => 0, + communities => [], + icmp_checks => 2, + icmp_timeout => 2, + id_os => 0, + id_network_profile => 0, + nmap => '/usr/bin/nmap', + parent_detection => 1, + parent_recursion => 5, + os_detection => 0, + 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 => [], + autoconfiguration_enabled => 0, - # Store progress summary - Discovery progress view. - step => 0, - c_network_name => '', - c_network_percent => 0.0, - summary => { - SNMP => 0, - WMI => 0, - discovered => 0, - alive => 0, - not_alive => 0 - }, - @_, + # Store progress summary - Discovery progress view. + step => 0, + c_network_name => '', + c_network_percent => 0.0, + summary => { + SNMP => 0, + WMI => 0, + discovered => 0, + alive => 0, + not_alive => 0 + }, + @_, - }; + }; - # Perform some sanity checks. - die("No subnet was specified.") unless defined($self->{'subnets'}); + # Perform some sanity checks. + die("No subnet was specified.") unless defined($self->{'subnets'}); - $self = bless($self, $class); + $self = bless($self, $class); - # Check SNMP params id SNMP is enabled - if ($self->{'snmp_enabled'}) { + # 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 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') { + # Check the version 3 parameters + if ($self->{'snmp_version'} eq '3') { - # Fixed some vars - $self->{'communities'} = []; + # 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 { + # 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'} = ''; + # 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 (ref($self->{'communities'}) ne "ARRAY" || scalar(@{$self->{'communities'}}) == 0) { - $self->{'snmp_enabled'} = 0; - $self->call('message', "There is no SNMP community configured.", 5); + # Disable SNMP scans if no community was given. + if (ref($self->{'communities'}) ne "ARRAY" || scalar(@{$self->{'communities'}}) == 0) { + $self->{'snmp_enabled'} = 0; + $self->call('message', "There is no SNMP community configured.", 5); - } - } - } + } + } + } - # Prepare auth array. - # WMI could be launched with '-N' - no pass - argument. - if ($self->{'wmi_enabled'} == 1){ - if (defined($self->{'auth_strings_str'})) { - @{$self->{'auth_strings_array'}} = split(',', $self->{'auth_strings_str'}); - } + # Prepare auth array. + # WMI could be launched with '-N' - no pass - argument. + if ($self->{'wmi_enabled'} == 1){ + if (defined($self->{'auth_strings_str'})) { + @{$self->{'auth_strings_array'}} = split(',', $self->{'auth_strings_str'}); + } - # Timeout available only in linux environments. - if ($^O =~ /lin/i && defined($self->{'plugin_exec'}) && defined($self->{'wmi_timeout'})) { - $self->{'timeout_cmd'} = $self->{'plugin_exec'}.' '.$self->{'wmi_timeout'}.' '; - } - } + # Timeout available only in linux environments. + if ($^O =~ /lin/i && defined($self->{'plugin_exec'}) && defined($self->{'wmi_timeout'})) { + $self->{'timeout_cmd'} = $self->{'plugin_exec'}.' '.$self->{'wmi_timeout'}.' '; + } + } - # 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'} = ''; - } + # 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 $self; + return $self; } ################################################################################ # Add an address to a device. ################################################################################ sub add_addresses($$$) { - my ($self, $device, $ip_address) = @_; + my ($self, $device, $ip_address) = @_; - $self->{'visited_devices'}->{$device}->{'addr'}->{$ip_address} = ''; + $self->{'visited_devices'}->{$device}->{'addr'}->{$ip_address} = ''; } ################################################################################ # Add a MAC/IP address to the ARP cache. ################################################################################ sub add_mac($$$) { - my ($self, $mac, $ip_addr) = @_; + my ($self, $mac, $ip_addr) = @_; - $mac = parse_mac($mac); - $self->{'arp_cache'}->{$mac} = $ip_addr; + $mac = parse_mac($mac); + $self->{'arp_cache'}->{$mac} = $ip_addr; } ################################################################################ # Add an interface/MAC to the interface cache. ################################################################################ sub add_iface($$$) { - my ($self, $iface, $mac) = @_; + my ($self, $iface, $mac) = @_; - $iface =~ s/"//g; - $self->{'ifaces'}->{$mac} = $iface; + $iface =~ s/"//g; + $self->{'ifaces'}->{$mac} = $iface; } ################################################################################ # Discover connectivity from address forwarding tables. ################################################################################ sub aft_connectivity($$) { - my ($self, $switch) = @_; - my (%mac_temp, @aft_temp); + my ($self, $switch) = @_; + my (%mac_temp, @aft_temp); - return unless ($self->is_snmp_discovered($switch)); + return unless ($self->is_snmp_discovered($switch)); - $self->enable_vlan_cache(); + $self->enable_vlan_cache(); - # Get the address forwarding table (AFT) of each switch. - my @aft; - foreach my $mac ($self->snmp_get_value_array($switch, $DOT1DTPFDBADDRESS)) { - push(@aft, parse_mac($mac)); - } + # Get the address forwarding table (AFT) of each switch. + my @aft; + foreach my $mac ($self->snmp_get_value_array($switch, $DOT1DTPFDBADDRESS)) { + push(@aft, parse_mac($mac)); + } - # Search for matching entries. - foreach my $aft_mac (@aft) { + # Search for matching entries. + foreach my $aft_mac (@aft) { - # Do we know who this is? - my $host = $self->get_ip_from_mac($aft_mac); - next unless defined($host) and $host ne ''; + # Do we know who this is? + my $host = $self->get_ip_from_mac($aft_mac); + next unless defined($host) and $host ne ''; - # Get the name of the host interface if available. - my $host_if_name = $self->get_iface($aft_mac); - $host_if_name = defined($host_if_name) ? $host_if_name : 'ping'; + # Get the name of the host interface if available. + my $host_if_name = $self->get_iface($aft_mac); + $host_if_name = defined($host_if_name) ? $host_if_name : 'ping'; - # Get the interface associated to the port were we found the MAC address. - my $switch_if_name = $self->get_if_from_aft($switch, $aft_mac); - next unless defined($switch_if_name) and ($switch_if_name ne ''); + # Get the interface associated to the port were we found the MAC address. + my $switch_if_name = $self->get_if_from_aft($switch, $aft_mac); + next unless defined($switch_if_name) and ($switch_if_name ne ''); - # Do not connect a host to a switch twice using the same interface. - # The switch is probably connected to another switch. - next if ($self->is_switch_connected($host, $host_if_name)); - $self->mark_switch_connected($host, $host_if_name); + # Do not connect a host to a switch twice using the same interface. + # The switch is probably connected to another switch. + next if ($self->is_switch_connected($host, $host_if_name)); + $self->mark_switch_connected($host, $host_if_name); - # The switch and the host are already connected. - next if ($self->are_connected($switch, $switch_if_name, $host, $host_if_name)); + # The switch and the host are already connected. + next if ($self->are_connected($switch, $switch_if_name, $host, $host_if_name)); - # Connect! - $self->mark_connected($switch, $switch_if_name, $host, $host_if_name); - $self->call('message', "Switch $switch (if $switch_if_name) is connected to host $host (if $host_if_name).", 5); - } + # Connect! + $self->mark_connected($switch, $switch_if_name, $host, $host_if_name); + $self->call('message', "Switch $switch (if $switch_if_name) is connected to host $host (if $host_if_name).", 5); + } - $self->disable_vlan_cache(); + $self->disable_vlan_cache(); } @@ -373,22 +376,22 @@ sub aft_connectivity($$) { # Return 1 if the given devices are connected to each other, 0 otherwise. ################################################################################ sub are_connected($$$$$) { - my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_; + my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_; - # Check for aliases! - $dev_1 = $self->{'aliases'}->{$dev_1} if defined($self->{'aliases'}->{$dev_1}); - $dev_2 = $self->{'aliases'}->{$dev_2} if defined($self->{'aliases'}->{$dev_2}); + # Check for aliases! + $dev_1 = $self->{'aliases'}->{$dev_1} if defined($self->{'aliases'}->{$dev_1}); + $dev_2 = $self->{'aliases'}->{$dev_2} if defined($self->{'aliases'}->{$dev_2}); - # Use ping modules when interfaces are unknown. - $if_1 = "ping" if $if_1 eq ''; - $if_2 = "ping" if $if_2 eq ''; + # Use ping modules when interfaces are unknown. + $if_1 = "ping" if $if_1 eq ''; + $if_2 = "ping" if $if_2 eq ''; - if ( defined($self->{'connections'}->{"${dev_1}\t${if_1}\t${dev_2}\t${if_2}"}) - ||defined($self->{'connections'}->{"${dev_2}\t${if_2}\t${dev_1}\t${if_1}"})) { - return 1; - } + if ( defined($self->{'connections'}->{"${dev_1}\t${if_1}\t${dev_2}\t${if_2}"}) + ||defined($self->{'connections'}->{"${dev_2}\t${if_2}\t${dev_1}\t${if_1}"})) { + return 1; + } - return 0; + return 0; } ################################################################################ @@ -396,19 +399,19 @@ sub are_connected($$$$$) { # Already discovered by scan_subnet. ################################################################################ sub icmp_discovery($$) { - my ($self, $addr) = @_; + my ($self, $addr) = @_; - $self->prepare_agent($addr); + $self->prepare_agent($addr); - $self->add_module($addr, 'icmp', - { - 'ip_target' => $addr, - 'name' => "Host Alive", - 'description' => '', - 'type' => 'generic_data', - 'id_modulo' => 2, - } - ); + $self->add_module($addr, 'icmp', + { + 'ip_target' => $addr, + 'name' => "Host Alive", + 'description' => '', + 'type' => 'generic_data', + 'id_modulo' => 2, + } + ); } @@ -416,46 +419,46 @@ sub icmp_discovery($$) { # Discover as much information as possible from the given device using SNMP. ################################################################################ sub snmp_discovery($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Have we already visited this device? - return if ($self->is_visited($device)); + # Have we already visited this device? + return if ($self->is_visited($device)); - # Mark the device as visited. - $self->mark_visited($device); + # Mark the device as visited. + $self->mark_visited($device); - # Are SNMP scans enabled? - if ($self->{'snmp_enabled'} == 1) { + # Are SNMP scans enabled? + if ($self->{'snmp_enabled'} == 1) { - # Try to find the MAC with an ARP request. - $self->get_mac_from_ip($device); + # Try to find the MAC with an ARP request. + $self->get_mac_from_ip($device); - # Check if the device responds to SNMP. - if ($self->snmp_responds($device)) { - $self->{'summary'}->{'SNMP'} += 1; + # Check if the device responds to SNMP. + if ($self->snmp_responds($device)) { + $self->{'summary'}->{'SNMP'} += 1; - # Fill the VLAN cache. - $self->find_vlans($device); + # Fill the VLAN cache. + $self->find_vlans($device); - # Guess the device type. - $self->guess_device_type($device); + # Guess the device type. + $self->guess_device_type($device); - # Find aliases for the device. - $self->find_aliases($device); + # Find aliases for the device. + $self->find_aliases($device); - # Find interfaces for the device. - $self->find_ifaces($device); + # Find interfaces for the device. + $self->find_ifaces($device); - # Check remote ARP caches. - $self->remote_arp($device); + # Check remote ARP caches. + $self->remote_arp($device); - # Get PEN. - $self->snmp_pen($device); - } - } + # Get PEN. + $self->snmp_pen($device); + } + } - # Create an agent for the device and add it to the list of known hosts. - $self->add_agent($device); + # Create an agent for the device and add it to the list of known hosts. + $self->add_agent($device); } @@ -463,252 +466,252 @@ sub snmp_discovery($$) { # Try to call the given function on the given object. ################################################################################ sub call { - my $self = shift; - my $func = shift; - my @params = @_; + my $self = shift; + my $func = shift; + my @params = @_; - if ($self->can($func)) { - $self->$func(@params); - } + if ($self->can($func)) { + $self->$func(@params); + } } ################################################################################ # Disable the VLAN cache. ################################################################################ sub disable_vlan_cache($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - $self->{'__vlan_cache_enabled__'} = 0; + $self->{'__vlan_cache_enabled__'} = 0; } ################################################################################ # Enable the VLAN cache. ################################################################################ sub enable_vlan_cache($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - return if ($self->{'vlan_cache_enabled'} == 0); - $self->{'__vlan_cache_enabled__'} = 1; + return if ($self->{'vlan_cache_enabled'} == 0); + $self->{'__vlan_cache_enabled__'} = 1; } ################################################################################ # Connect the given hosts to its gateway. ################################################################################ sub gateway_connectivity($$) { - my ($self, $host) = @_; + my ($self, $host) = @_; - my $gw = $self->get_gateway($host); - return unless defined($gw); + my $gw = $self->get_gateway($host); + return unless defined($gw); - # Check for aliases! - $host = $self->{'aliases'}->{$host} if defined($self->{'aliases'}->{$host}); - $gw = $self->{'aliases'}->{$gw} if defined($self->{'aliases'}->{$gw}); + # Check for aliases! + $host = $self->{'aliases'}->{$host} if defined($self->{'aliases'}->{$host}); + $gw = $self->{'aliases'}->{$gw} if defined($self->{'aliases'}->{$gw}); - # Same host, different IP addresses. - return if ($host eq $gw); + # Same host, different IP addresses. + return if ($host eq $gw); - $self->call('message', "Host $host is reached via gateway $gw.", 5); - $self->mark_connected($gw, '', $host, ''); + $self->call('message', "Host $host is reached via gateway $gw.", 5); + $self->mark_connected($gw, '', $host, ''); } ################################################################################ # Find IP address aliases for the given device. ################################################################################ sub find_aliases($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Get ARP cache. - my @ip_addresses = $self->snmp_get_value_array($device, $IPENTADDR); - foreach my $ip_address (@ip_addresses) { + # Get ARP cache. + my @ip_addresses = $self->snmp_get_value_array($device, $IPENTADDR); + foreach my $ip_address (@ip_addresses) { - # Skip broadcast and localhost addresses. - next if ($ip_address =~ m/\.255$|\.0$|127\.0\.0\.1$/); + # Skip broadcast and localhost addresses. + next if ($ip_address =~ m/\.255$|\.0$|127\.0\.0\.1$/); - # Sometimes we find the same IP address we had. - next if ($ip_address eq $device); + # Sometimes we find the same IP address we had. + next if ($ip_address eq $device); - $self->add_addresses($device, $ip_address); + $self->add_addresses($device, $ip_address); - # Try to find the MAC with an ARP request. - $self->get_mac_from_ip($ip_address); + # Try to find the MAC with an ARP request. + $self->get_mac_from_ip($ip_address); - $self->call('message', "Found address $ip_address for host $device.", 5); + $self->call('message', "Found address $ip_address for host $device.", 5); - # Is this address an alias itself? - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - next if ($ip_address eq $device); + # Is this address an alias itself? + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + next if ($ip_address eq $device); - # Link the two addresses. - $self->{'aliases'}->{$ip_address} = $device; - } + # Link the two addresses. + $self->{'aliases'}->{$ip_address} = $device; + } } ################################################################################ # Find all the interfaces for the given host. ################################################################################ sub find_ifaces($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Does it respond to SNMP? - return unless ($self->is_snmp_discovered($device)); + # Does it respond to SNMP? + return unless ($self->is_snmp_discovered($device)); - my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX); - foreach my $if_index (@output) { + my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX); + foreach my $if_index (@output) { - next unless ($if_index =~ /^[0-9]+$/); + next unless ($if_index =~ /^[0-9]+$/); - # Ignore virtual interfaces. - next if ($self->get_if_type($device, $if_index) eq '53'); + # Ignore virtual interfaces. + next if ($self->get_if_type($device, $if_index) eq '53'); - # Get the MAC. - my $mac = $self->get_if_mac($device, $if_index); - next unless (defined($mac) && $mac ne ''); + # Get the MAC. + my $mac = $self->get_if_mac($device, $if_index); + next unless (defined($mac) && $mac ne ''); - # Save it. - $self->add_mac($mac, $device); + # Save it. + $self->add_mac($mac, $device); - # Get the name of the network interface. - my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index"); - next unless defined($if_name); + # Get the name of the network interface. + my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index"); + next unless defined($if_name); - # Save it. - $self->add_iface($if_name, $mac); + # Save it. + $self->add_iface($if_name, $mac); - $self->call('message', "Found interface $if_name MAC $mac for host $device.", 5); - } + $self->call('message', "Found interface $if_name MAC $mac for host $device.", 5); + } } ################################################################################ # Find the device's VLANs and fill the VLAN cache. ################################################################################ sub find_vlans ($$) { - my ($self, $device) = @_; - my %vlan_hash; + my ($self, $device) = @_; + my %vlan_hash; - foreach my $vlan ($self->snmp_get_value_array($device, $VTPVLANIFINDEX)) { - next if $vlan eq '0'; - $vlan_hash{$vlan} = 1; - } - my @vlans = keys(%vlan_hash); + foreach my $vlan ($self->snmp_get_value_array($device, $VTPVLANIFINDEX)) { + next if $vlan eq '0'; + $vlan_hash{$vlan} = 1; + } + my @vlans = keys(%vlan_hash); - $self->{'vlan_cache'}->{$device} = []; - push(@{$self->{'vlan_cache'}->{$device}}, @vlans) if (scalar(@vlans) > 0); + $self->{'vlan_cache'}->{$device} = []; + push(@{$self->{'vlan_cache'}->{$device}}, @vlans) if (scalar(@vlans) > 0); } ################################################################################ # Return the addresses of the given device as an array. ################################################################################ sub get_addresses($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - if (defined($self->{'visited_devices'}->{$device})) { - return keys(%{$self->{'visited_devices'}->{$device}->{'addr'}}); - } + if (defined($self->{'visited_devices'}->{$device})) { + return keys(%{$self->{'visited_devices'}->{$device}->{'addr'}}); + } - # By default return the given address. - return ($device); + # By default return the given address. + return ($device); } ################################################################################ # Return a device structure from an IP address. ################################################################################ sub get_device($$) { - my ($self, $addr) = @_; + my ($self, $addr) = @_; - if (defined($self->{'visited_devices'}->{$addr})) { - return $self->{'visited_devices'}->{$addr}; - } + if (defined($self->{'visited_devices'}->{$addr})) { + return $self->{'visited_devices'}->{$addr}; + } - return undef; + return undef; } ################################################################################ # Get the SNMP community of the given device. Returns undef if no community was found. ################################################################################ sub get_community($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - return '' if ($self->{'snmp_version'} eq "3"); + return '' if ($self->{'snmp_version'} eq "3"); - if (defined($self->{'community_cache'}->{$device})) { - return $self->{'community_cache'}->{$device}; - } + if (defined($self->{'community_cache'}->{$device})) { + return $self->{'community_cache'}->{$device}; + } - return ''; + return ''; } ################################################################################ # Return the connection hash. ################################################################################ sub get_connections($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'connections'}; + return $self->{'connections'}; } ################################################################################ # Return the parent relationship hash. ################################################################################ sub get_parents($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'parents'}; + return $self->{'parents'}; } ################################################################################ # Get the type of the given device. ################################################################################ sub get_device_type($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - if (defined($self->{'visited_devices'}->{$device})) { - return $self->{'visited_devices'}->{$device}->{'type'}; - } + if (defined($self->{'visited_devices'}->{$device})) { + return $self->{'visited_devices'}->{$device}->{'type'}; + } - # Assume 'host' by default. - return 'host'; + # Assume 'host' by default. + return 'host'; } ################################################################################ # Return all known hosts that are not switches or routers. ################################################################################ sub get_hosts($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'hosts'}; + return $self->{'hosts'}; } ################################################################################ # Add an interface/MAC to the interface cache. ################################################################################ sub get_iface($$) { - my ($self, $mac) = @_; + my ($self, $mac) = @_; - return undef unless defined($self->{'ifaces'}->{$mac}); + return undef unless defined($self->{'ifaces'}->{$mac}); - return $self->{'ifaces'}->{$mac}; + return $self->{'ifaces'}->{$mac}; } ################################################################################ # Get an interface name from an AFT entry. Returns undef on error. ################################################################################ sub get_if_from_aft($$$) { - my ($self, $switch, $mac) = @_; + my ($self, $switch, $mac) = @_; - # Get the port associated to the MAC. - my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); - return '' unless defined($port); + # Get the port associated to the MAC. + my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); + return '' unless defined($port); - # Get the interface index associated to the port. - my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); - return '' unless defined($if_index); + # Get the interface index associated to the port. + my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); + return '' unless defined($if_index); - # Get the interface name. - my $if_name = $self->snmp_get_value($switch, "$IFNAME.$if_index"); - return "if$if_index" unless defined($if_name); + # Get the interface name. + my $if_name = $self->snmp_get_value($switch, "$IFNAME.$if_index"); + return "if$if_index" unless defined($if_name); - $if_name =~ s/"//g; - return $if_name; + $if_name =~ s/"//g; + return $if_name; } @@ -716,214 +719,214 @@ sub get_if_from_aft($$$) { # Get an interface name from an IP address. ################################################################################ sub get_if_from_ip($$$) { - my ($self, $device, $ip_addr) = @_; + my ($self, $device, $ip_addr) = @_; - # Get the port associated to the IP address. - my $if_index = $self->snmp_get_value($device, "$IPROUTEIFINDEX.$ip_addr"); - return '' unless defined($if_index); + # Get the port associated to the IP address. + my $if_index = $self->snmp_get_value($device, "$IPROUTEIFINDEX.$ip_addr"); + return '' unless defined($if_index); - # Get the name of the interface associated to the port. - my $if_name = $self->snmp_get_value($device, "$IFNAME.$if_index"); - return '' unless defined($if_name); + # Get the name of the interface associated to the port. + my $if_name = $self->snmp_get_value($device, "$IFNAME.$if_index"); + return '' unless defined($if_name); - $if_name =~ s/"//g; - return $if_name; + $if_name =~ s/"//g; + return $if_name; } ################################################################################ # Get an interface name from a MAC address. ################################################################################ sub get_if_from_mac($$$) { - my ($self, $device, $mac) = @_; + my ($self, $device, $mac) = @_; - # Get the port associated to the IP address. - my @output = $self->snmp_get($device, $IFPHYSADDRESS); - foreach my $line (@output) { - chomp($line); - next unless $line =~ /^IFPHYSADDRESS.(\S+)\s+=\s+\S+:\s+(.*)$/; - my ($if_index, $if_mac) = ($1, $2); + # Get the port associated to the IP address. + my @output = $self->snmp_get($device, $IFPHYSADDRESS); + foreach my $line (@output) { + chomp($line); + next unless $line =~ /^IFPHYSADDRESS.(\S+)\s+=\s+\S+:\s+(.*)$/; + my ($if_index, $if_mac) = ($1, $2); - # Make sure the MAC addresses match. - next unless (mac_matches($mac, $if_mac) == 1); + # Make sure the MAC addresses match. + next unless (mac_matches($mac, $if_mac) == 1); - # Pupulate the ARP cache. - $self->add_mac($mac, $device); + # Pupulate the ARP cache. + $self->add_mac($mac, $device); - # Get the name of the interface associated to the port. - my $if_name = $self->snmp_get_value($device, "$IFNAME.$if_index"); - return '' unless defined($if_name); + # Get the name of the interface associated to the port. + my $if_name = $self->snmp_get_value($device, "$IFNAME.$if_index"); + return '' unless defined($if_name); - $if_name =~ s/"//g; - return $if_name; - } + $if_name =~ s/"//g; + return $if_name; + } - return ''; + return ''; } ################################################################################ # Get an interface name from a port number. Returns '' on error. ################################################################################ sub get_if_from_port($$$) { - my ($self, $switch, $port) = @_; + my ($self, $switch, $port) = @_; - # Get the interface index associated to the port. - my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); - return '' unless defined($if_index); + # Get the interface index associated to the port. + my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); + return '' unless defined($if_index); - # Get the interface name. - my $if_name = $self->snmp_get_value($switch, "$IFNAME.$if_index"); - return "if$if_index" unless defined($if_name); + # Get the interface name. + my $if_name = $self->snmp_get_value($switch, "$IFNAME.$if_index"); + return "if$if_index" unless defined($if_name); - $if_name =~ s/"//g; - return $if_name; + $if_name =~ s/"//g; + return $if_name; } ################################################################################ # Returns the IP address of the given interface (by index). ################################################################################ sub get_if_ip($$$) { - my ($self, $device, $if_index) = @_; + my ($self, $device, $if_index) = @_; - my @output = $self->snmp_get($device, $IPADENTIFINDEX); - foreach my $line (@output) { - chomp($line); - return $1 if ($line =~ m/^$IPADENTIFINDEX.(\S+)\s+=\s+\S+:\s+$if_index$/); - } + my @output = $self->snmp_get($device, $IPADENTIFINDEX); + foreach my $line (@output) { + chomp($line); + return $1 if ($line =~ m/^$IPADENTIFINDEX.(\S+)\s+=\s+\S+:\s+$if_index$/); + } - return ''; + return ''; } ################################################################################ # Returns the MAC address of the given interface (by index). ################################################################################ sub get_if_mac($$$) { - my ($self, $device, $if_index) = @_; + my ($self, $device, $if_index) = @_; - my $mac = $self->snmp_get_value($device, "$IFPHYSADDRESS.$if_index"); - return '' unless defined($mac); + my $mac = $self->snmp_get_value($device, "$IFPHYSADDRESS.$if_index"); + return '' unless defined($mac); - # Clean-up the MAC address. - $mac = parse_mac($mac); + # Clean-up the MAC address. + $mac = parse_mac($mac); - return $mac; + return $mac; } ################################################################################ # Returns the type of the given interface (by index). ################################################################################ sub get_if_type($$$) { - my ($self, $device, $if_index) = @_; + my ($self, $device, $if_index) = @_; - my $type = $self->snmp_get_value($device, "$IFTYPE.$if_index"); - return '' unless defined($type); + my $type = $self->snmp_get_value($device, "$IFTYPE.$if_index"); + return '' unless defined($type); - return $type; + return $type; } ################################################################################ # Get an IP address from the ARP cache given the MAC address. ################################################################################ sub get_ip_from_mac($$) { - my ($self, $mac_addr) = @_; + my ($self, $mac_addr) = @_; - if (defined($self->{'arp_cache'}->{$mac_addr})) { - return $self->{'arp_cache'}->{$mac_addr}; - } + if (defined($self->{'arp_cache'}->{$mac_addr})) { + return $self->{'arp_cache'}->{$mac_addr}; + } - return undef; + return undef; } ################################################################################ # Attemtps to find ################################################################################ sub get_mac_from_ip($$) { - my ($self, $host) = @_; - my $mac = undef; + my ($self, $host) = @_; + my $mac = undef; - eval { - $mac = `arping -c 1 $host 2>$DEVNULL`; - $mac = undef unless ($? == 0); - }; + eval { + $mac = `arping -c 1 $host 2>$DEVNULL`; + $mac = undef unless ($? == 0); + }; - return unless defined($mac); + return unless defined($mac); - ($mac) = $mac =~ /\[(.*?)\]/ if defined($mac); + ($mac) = $mac =~ /\[(.*?)\]/ if defined($mac); - # Clean-up the MAC address. - chomp($mac); - $mac = parse_mac($mac); - $self->add_mac($mac, $host); + # Clean-up the MAC address. + chomp($mac); + $mac = parse_mac($mac); + $self->add_mac($mac, $host); - $self->call('message', "Found MAC $mac for host $host in the local ARP cache.", 5); + $self->call('message', "Found MAC $mac for host $host in the local ARP cache.", 5); } ################################################################################ # Get a port number from an AFT entry. Returns undef on error. ################################################################################ sub get_port_from_aft($$$) { - my ($self, $switch, $mac) = @_; + my ($self, $switch, $mac) = @_; - # Get the port associated to the MAC. - my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); - return '' unless defined($port); + # Get the port associated to the MAC. + my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); + return '' unless defined($port); - return $port; + return $port; } ################################################################################ # Fill the route cache. ################################################################################ sub get_routes($) { - my ($self) = @_; + my ($self) = @_; - # Empty the current route cache. - $self->{'routes'} = []; + # Empty the current route cache. + $self->{'routes'} = []; - # Parse route's output. - my @output = `route -n 2>$DEVNULL`; - foreach my $line (@output) { - chomp($line); - if ($line =~ /^0\.0\.0\.0\s+(\d+\.\d+\.\d+\.\d+).*/) { - $self->{'default_gw'} = $1; - } elsif ($line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+).*/) { - push(@{$self->{'routes'}}, { dest => $1, gw => $2, mask => $3 }); - } - } + # Parse route's output. + my @output = `route -n 2>$DEVNULL`; + foreach my $line (@output) { + chomp($line); + if ($line =~ /^0\.0\.0\.0\s+(\d+\.\d+\.\d+\.\d+).*/) { + $self->{'default_gw'} = $1; + } elsif ($line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+).*/) { + push(@{$self->{'routes'}}, { dest => $1, gw => $2, mask => $3 }); + } + } - # Replace 0.0.0.0 with the default gateway's IP. - return unless defined($self->{'default_gw'}); - foreach my $route (@{$self->{'routes'}}) { - $route->{gw} = $self->{'default_gw'} if ($route->{'gw'} eq '0.0.0.0'); - } + # Replace 0.0.0.0 with the default gateway's IP. + return unless defined($self->{'default_gw'}); + foreach my $route (@{$self->{'routes'}}) { + $route->{gw} = $self->{'default_gw'} if ($route->{'gw'} eq '0.0.0.0'); + } } ################################################################################ # Get the gateway to reach the given host. ################################################################################ sub get_gateway($) { - my ($self, $host) = @_; + my ($self, $host) = @_; - # Look for a specific route to the given host. - foreach my $route (@{$self->{'routes'}}) { - if (subnet_matches($host, $route->{'dest'}, $route->{'mask'})) { - return $route->{'gw'}; - } - } + # Look for a specific route to the given host. + foreach my $route (@{$self->{'routes'}}) { + if (subnet_matches($host, $route->{'dest'}, $route->{'mask'})) { + return $route->{'gw'}; + } + } - # Return the default gateway. - return $self->{'default_gw'} if defined($self->{'default_gw'}); + # Return the default gateway. + return $self->{'default_gw'} if defined($self->{'default_gw'}); - # Ops! - return undef; + # Ops! + return undef; } ################################################################################ # Return a pointer to an array containing configured subnets. ################################################################################ sub get_subnets($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'subnets'}; + return $self->{'subnets'}; } ################################################################################ @@ -932,150 +935,150 @@ sub get_subnets($) { # like get_hosts, get_switches, get_routers and get_all_devices. ################################################################################ sub get_visited_devices($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'visited_devices'}; + return $self->{'visited_devices'}; } ################################################################################ # Returns an array of found VLAN IDs. ################################################################################ sub get_vlans($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Disabled in verison 3 - return () if ($self->{'snmp_version'} eq "3"); + # Disabled in verison 3 + return () if ($self->{'snmp_version'} eq "3"); - # Is the VLAN cache disabled? - return () unless ($self->{'__vlan_cache_enabled__'} == 1); + # Is the VLAN cache disabled? + return () unless ($self->{'__vlan_cache_enabled__'} == 1); - return () unless defined($self->{'vlan_cache'}->{$device}); + return () unless defined($self->{'vlan_cache'}->{$device}); - return @{$self->{'vlan_cache'}->{$device}}; + return @{$self->{'vlan_cache'}->{$device}}; } ################################################################################ # Guess the type of the given device. ################################################################################ sub guess_device_type($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Get the value of sysServices. - my $services = $self->snmp_get_value($device, "$SYSSERVICES.0"); - return unless defined($services); + # Get the value of sysServices. + my $services = $self->snmp_get_value($device, "$SYSSERVICES.0"); + return unless defined($services); - # Check the individual bits. - my @service_bits = split('', unpack('b8', pack('C', $services))); + # Check the individual bits. + my @service_bits = split('', unpack('b8', pack('C', $services))); - # Check for layer 2 connectivity support. - my $bridge_mib = $self->snmp_get_value($device, $DOT1DBASEBRIDGEADDRESS); + # Check for layer 2 connectivity support. + my $bridge_mib = $self->snmp_get_value($device, $DOT1DBASEBRIDGEADDRESS); - # L2? - my $device_type; - if ($service_bits[1] == 1) { + # L2? + my $device_type; + if ($service_bits[1] == 1) { - # L3? - if ($service_bits[2] == 1) { + # L3? + if ($service_bits[2] == 1) { - # Bridge MIB? - if (defined($bridge_mib)) { - $device_type = 'switch'; - } else { + # Bridge MIB? + if (defined($bridge_mib)) { + $device_type = 'switch'; + } else { - # L7? - if ($service_bits[6] == 1) { - $device_type = 'host'; - } else { - $device_type = 'router'; - } - } - }else { + # L7? + if ($service_bits[6] == 1) { + $device_type = 'host'; + } else { + $device_type = 'router'; + } + } + }else { - # Bridge MIB? - if (defined($bridge_mib)) { - $device_type = 'switch'; - } else { - $device_type = 'host'; - } - } - }else { + # Bridge MIB? + if (defined($bridge_mib)) { + $device_type = 'switch'; + } else { + $device_type = 'host'; + } + } + }else { - # L3? - if ($service_bits[2] == 1) { + # L3? + if ($service_bits[2] == 1) { - # L4? - if ($service_bits[3] == 1) { - $device_type = 'switch'; - } else { + # L4? + if ($service_bits[3] == 1) { + $device_type = 'switch'; + } else { - # L7? - if ($service_bits[6] == 1) { - $device_type = 'host'; - } else { - $device_type = 'router'; - } - } - }else { + # L7? + if ($service_bits[6] == 1) { + $device_type = 'host'; + } else { + $device_type = 'router'; + } + } + }else { - # Printer MIB? - my $printer_mib = $self->snmp_get_value($device, $PRTMARKERINDEX); - if (defined($printer_mib)) { - $device_type = 'printer'; - } else { - $device_type = 'host'; - } - } - } + # Printer MIB? + my $printer_mib = $self->snmp_get_value($device, $PRTMARKERINDEX); + if (defined($printer_mib)) { + $device_type = 'printer'; + } else { + $device_type = 'host'; + } + } + } - # Set the type of the device. - $self->set_device_type($device, $device_type); + # Set the type of the device. + $self->set_device_type($device, $device_type); } ################################################################################ # Return 1 if the given device has children. ################################################################################ sub has_children($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - return 1 if (defined($self->{'children'}->{$device})); + return 1 if (defined($self->{'children'}->{$device})); - return 0; + return 0; } ################################################################################ # Return 1 if the given device has a parent. ################################################################################ sub has_parent($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - return 1 if (defined($self->{'parents'}->{$device})); + return 1 if (defined($self->{'parents'}->{$device})); - return 0; + return 0; } ################################################################################ # Returns 1 if the device belongs to one of the scanned subnets. ################################################################################ sub in_subnet($$) { - my ($self, $device) = @_; - $device = ip_to_long($device); + my ($self, $device) = @_; + $device = ip_to_long($device); - # No subnets specified. - return 1 if (scalar(@{$self->{'subnets'}}) <= 0); + # No subnets specified. + return 1 if (scalar(@{$self->{'subnets'}}) <= 0); - foreach my $subnet (@{$self->{'subnets'}}) { - if (subnet_matches($device, $subnet)) { - return 1; - } - } + foreach my $subnet (@{$self->{'subnets'}}) { + if (subnet_matches($device, $subnet)) { + return 1; + } + } - return 0; + return 0; } ################################################################################ @@ -1083,30 +1086,30 @@ sub in_subnet($$) { # up in a switch/router's port. ################################################################################ sub is_switch_connected($$$) { - my ($self, $device, $iface) = @_; + my ($self, $device, $iface) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - return 1 if defined($self->{'switch_to_switch'}->{"${device}\t${iface}"}); + return 1 if defined($self->{'switch_to_switch'}->{"${device}\t${iface}"}); - return 0; + return 0; } ################################################################################ # Returns 1 if the given device has already been visited, 0 otherwise. ################################################################################ sub is_visited($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - if (defined($self->{'visited_devices'}->{$device})) { - return 1; - } + if (defined($self->{'visited_devices'}->{$device})) { + return 1; + } - return 0; + return 0; } ################################################################################ @@ -1114,74 +1117,74 @@ sub is_visited($$) { # Returns 0 otherwise. ################################################################################ sub is_snmp_discovered($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Check if device is into discovered cache - return (defined($self->{'discovered_cache'}->{$device})) ? 1 : 0; + # 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. ################################################################################ sub mark_connected($$;$$$) { - my ($self, $parent, $parent_if, $child, $child_if) = @_; + my ($self, $parent, $parent_if, $child, $child_if) = @_; - # Check for aliases! - $parent = $self->{'aliases'}->{$parent} if defined($self->{'aliases'}->{$parent}); - $child = $self->{'aliases'}->{$child} if defined($self->{'aliases'}->{$child}); + # Check for aliases! + $parent = $self->{'aliases'}->{$parent} if defined($self->{'aliases'}->{$parent}); + $child = $self->{'aliases'}->{$child} if defined($self->{'aliases'}->{$child}); - # Use ping modules when interfaces are unknown. - $parent_if = "Host Alive" if $parent_if eq ''; - $child_if = "Host Alive" if $child_if eq ''; + # Use ping modules when interfaces are unknown. + $parent_if = "Host Alive" if $parent_if eq ''; + $child_if = "Host Alive" if $child_if eq ''; - # Do not connect devices using ping modules. A parent-child relationship is enough. - if ($parent_if ne "Host Alive" || $child_if ne "Host Alive") { - $self->{'connections'}->{"${parent}\t${parent_if}\t${child}\t${child_if}"} = 1; - $self->call('connect_agents', $parent, $parent_if, $child, $child_if); - } + # Do not connect devices using ping modules. A parent-child relationship is enough. + if ($parent_if ne "Host Alive" || $child_if ne "Host Alive") { + $self->{'connections'}->{"${parent}\t${parent_if}\t${child}\t${child_if}"} = 1; + $self->call('connect_agents', $parent, $parent_if, $child, $child_if); + } - # Prevent parent-child loops. - if (!defined($self->{'parents'}->{$parent}) - ||$self->{'parents'}->{$parent} ne $child) { + # Prevent parent-child loops. + if (!defined($self->{'parents'}->{$parent}) + ||$self->{'parents'}->{$parent} ne $child) { - # A parent-child relationship is always created to help complete the map with - # layer 3 information. - $self->{'parents'}->{$child} = $parent; - $self->{'children'}->{$parent} = $child; - $self->call('set_parent', $child, $parent); - } + # A parent-child relationship is always created to help complete the map with + # layer 3 information. + $self->{'parents'}->{$child} = $parent; + $self->{'children'}->{$parent} = $child; + $self->call('set_parent', $child, $parent); + } } ################################################################################ # Mark the given switch as having a connection on the given interface. ################################################################################ sub mark_switch_connected($$$) { - my ($self, $device, $iface) = @_; + my ($self, $device, $iface) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - $self->{'switch_to_switch'}->{"${device}\t${iface}"} = 1; + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + $self->{'switch_to_switch'}->{"${device}\t${iface}"} = 1; } ################################################################################ # Mark the given device as visited. ################################################################################ sub mark_visited($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - $self->{'visited_devices'}->{$device} = { - 'addr' => { $device => '' }, - 'type' => 'host' - }; + $self->{'visited_devices'}->{$device} = { + 'addr' => { $device => '' }, + 'type' => 'host' + }; } ################################################################################ # Mark the given device as snmp discovered. ################################################################################ sub mark_discovered($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - $self->{'discovered_cache'}->{$device} = 1; + $self->{'discovered_cache'}->{$device} = 1; } ################################################################################ @@ -1190,13 +1193,13 @@ sub mark_discovered($$) { # Updates the SNMP community cache on v1, v2 and v2c. ################################################################################ sub snmp_responds($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - return 1 if($self->is_snmp_discovered($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); + return ($self->{'snmp_version'} eq "3") + ? $self->snmp_responds_v3($device) + : $self->snmp_responds_v122c($device); } ################################################################################ @@ -1204,23 +1207,23 @@ sub snmp_responds($$) { # found, 0 otherwise. Updates the SNMP community cache. ################################################################################ sub snmp_responds_v122c($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - foreach my $community (@{$self->{'communities'}}) { + foreach my $community (@{$self->{'communities'}}) { - # Clean blanks. - $community =~ s/\s+//g; + # Clean blanks. + $community =~ s/\s+//g; - my $command = $self->snmp_get_command($device, ".0", $community); - `$command`; - if ($? == 0) { - $self->set_community($device, $community); - $self->mark_discovered($device); - return 1; - } - } + my $command = $self->snmp_get_command($device, ".0", $community); + `$command`; + if ($? == 0) { + $self->set_community($device, $community); + $self->mark_discovered($device); + return 1; + } + } - return 0; + return 0; } @@ -1229,279 +1232,279 @@ sub snmp_responds_v122c($$) { # Returns 1 if successfull snmp contact, 0 otherwise. ################################################################################ sub snmp_responds_v3($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - my $command = $self->snmp_get_command($device, ".0"); - `$command`; + my $command = $self->snmp_get_command($device, ".0"); + `$command`; - if ($? == 0) { - $self->mark_discovered($device); - return 1; - } + if ($? == 0) { + $self->mark_discovered($device); + return 1; + } - return 0; + return 0; } ################################################################################ # Parse the local ARP cache. ################################################################################ sub local_arp($) { - my ($self) = @_; + my ($self) = @_; - my @output = `arp -an 2>$DEVNULL`; - foreach my $line (@output) { - next unless ($line =~ m/\((\S+)\) at ([0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)/); - $self->add_mac(parse_mac($2), $1); - } + my @output = `arp -an 2>$DEVNULL`; + foreach my $line (@output) { + next unless ($line =~ m/\((\S+)\) at ([0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)/); + $self->add_mac(parse_mac($2), $1); + } } ################################################################################ # Parse remote SNMP ARP caches. ################################################################################ sub remote_arp($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Try to learn more MAC addresses from the device's ARP cache. - my @output = $self->snmp_get($device, $IPNETTOMEDIAPHYSADDRESS); - foreach my $line (@output) { - next unless ($line =~ /^$IPNETTOMEDIAPHYSADDRESS\.\d+\.(\S+)\s+=\s+\S+:\s+(.*)$/); - my ($ip_addr, $mac_addr) = ($1, $2); + # Try to learn more MAC addresses from the device's ARP cache. + my @output = $self->snmp_get($device, $IPNETTOMEDIAPHYSADDRESS); + foreach my $line (@output) { + next unless ($line =~ /^$IPNETTOMEDIAPHYSADDRESS\.\d+\.(\S+)\s+=\s+\S+:\s+(.*)$/); + my ($ip_addr, $mac_addr) = ($1, $2); - # Skip broadcast, net and local addresses. - next if ($ip_addr =~ m/\.255$|\.0$|127\.0\.0\.1$/); + # Skip broadcast, net and local addresses. + next if ($ip_addr =~ m/\.255$|\.0$|127\.0\.0\.1$/); - $mac_addr = parse_mac($mac_addr); - $self->add_mac($mac_addr, $ip_addr); - $self->call('message', "Found MAC $mac_addr for host $ip_addr in the ARP cache of host $device.", 5); - } + $mac_addr = parse_mac($mac_addr); + $self->add_mac($mac_addr, $ip_addr); + $self->call('message', "Found MAC $mac_addr for host $ip_addr in the ARP cache of host $device.", 5); + } - # Look in atPhysAddress for MAC addresses too. - @output = $self->snmp_get($device, $ATPHYSADDRESS); - foreach my $line (@output) { - next unless ($line =~ m/^$ATPHYSADDRESS\.\d+\.\d+\.(\S+)\s+=\s+\S+:\s+(.*)$/); - my ($ip_addr, $mac_addr) = ($1, $2); + # Look in atPhysAddress for MAC addresses too. + @output = $self->snmp_get($device, $ATPHYSADDRESS); + foreach my $line (@output) { + next unless ($line =~ m/^$ATPHYSADDRESS\.\d+\.\d+\.(\S+)\s+=\s+\S+:\s+(.*)$/); + my ($ip_addr, $mac_addr) = ($1, $2); - # Skip broadcast, net and local addresses. - next if ($ip_addr =~ m/\.255$|\.0$|127\.0\.0\.1$/); + # Skip broadcast, net and local addresses. + next if ($ip_addr =~ m/\.255$|\.0$|127\.0\.0\.1$/); - $mac_addr = parse_mac($mac_addr); - $self->add_mac($mac_addr, $ip_addr); - $self->call('message', "Found MAC $mac_addr for host $ip_addr in the ARP cache (atPhysAddress) of host $device.", 5); - } + $mac_addr = parse_mac($mac_addr); + $self->add_mac($mac_addr, $ip_addr); + $self->call('message', "Found MAC $mac_addr for host $ip_addr in the ARP cache (atPhysAddress) of host $device.", 5); + } } ################################################################################ # Add agent to pool (will be registered at the end of the scan). ################################################################################ sub prepare_agent($$) { - my ($self, $addr) = @_; - $self->{'agents_found'} = {} if ref($self->{'agents_found'}) ne 'HASH'; + my ($self, $addr) = @_; + $self->{'agents_found'} = {} if ref($self->{'agents_found'}) ne 'HASH'; - # Already initialized. - return if ref($self->{'agents_found'}->{$addr}) eq 'HASH'; + # Already initialized. + return if ref($self->{'agents_found'}->{$addr}) eq 'HASH'; - $self->{'agents_found'}->{$addr} = { - 'agent' => { - 'nombre' => $addr, - 'direccion' => $addr, - 'alias' => $addr, - }, - 'pen' => $self->{'pen'}{$addr}, - 'modules' => [], - }; + $self->{'agents_found'}->{$addr} = { + 'agent' => { + 'nombre' => $addr, + 'direccion' => $addr, + 'alias' => $addr, + }, + 'pen' => $self->{'pen'}{$addr}, + 'modules' => [], + }; } ################################################################################ # Add agent to pool (will be registered at the end of the scan). ################################################################################ sub add_agent($$) { - my ($self, $addr) = @_; - - $self->prepare_agent($addr); + my ($self, $addr) = @_; + + $self->prepare_agent($addr); } ################################################################################ # Add module to agent (tmp pool) (will be registered at the end of the scan). ################################################################################ sub add_module($$$$) { - my ($self, $agent, $type, $data) = @_; + my ($self, $agent, $type, $data) = @_; - $self->prepare_agent($agent); + $self->prepare_agent($agent); - push @{$self->{'agents_found'}->{$agent}->{'modules'}}, $data; - + push @{$self->{'agents_found'}->{$agent}->{'modules'}}, $data; + } ################################################################################ # Test target address (methods). ################################################################################ sub test_capabilities($$) { - my ($self, $addr) = @_; + my ($self, $addr) = @_; - $self->icmp_discovery($addr); + $self->icmp_discovery($addr); - if (is_enabled($self->{'snmp_enabled'})) { - # SNMP discovery. - $self->snmp_discovery($addr); - } + if (is_enabled($self->{'snmp_enabled'})) { + # SNMP discovery. + $self->snmp_discovery($addr); + } - # WMI discovery. - if (is_enabled($self->{'wmi_enabled'})) { - # Add wmi scan if enabled. - $self->wmi_scan($addr); - } + # WMI discovery. + if (is_enabled($self->{'wmi_enabled'})) { + # Add wmi scan if enabled. + $self->wmi_scan($addr); + } } ################################################################################ # Scan the given subnet. ################################################################################ sub scan_subnet($) { - my ($self) = @_; - my $progress = 1; + my ($self) = @_; + my $progress = 1; - my @subnets = @{$self->get_subnets()}; - foreach my $subnet (@subnets) { - $self->{'c_network_percent'} = 0; - $self->{'c_network_name'} = $subnet; - $self->call('update_progress', ceil($progress)); + my @subnets = @{$self->get_subnets()}; + foreach my $subnet (@subnets) { + $self->{'c_network_percent'} = 0; + $self->{'c_network_name'} = $subnet; + $self->call('update_progress', ceil($progress)); - # Clean blanks. - $subnet =~ s/\s+//g; + # Clean blanks. + $subnet =~ s/\s+//g; - my $net_addr = new NetAddr::IP($subnet); - if (!defined($net_addr)) { - $self->call('message', "Invalid network: $subnet", 3); - next; - } + my $net_addr = new NetAddr::IP($subnet); + if (!defined($net_addr)) { + $self->call('message', "Invalid network: $subnet", 3); + next; + } - # Save the network and broadcast addresses. - my $network = $net_addr->network(); - my $broadcast = $net_addr->broadcast(); + # Save the network and broadcast addresses. + my $network = $net_addr->network(); + my $broadcast = $net_addr->broadcast(); - my @hosts = map { (split('/', $_))[0] } $net_addr->hostenum; - my $total_hosts = scalar(@hosts); - my %hosts_alive = (); + my @hosts = map { (split('/', $_))[0] } $net_addr->hostenum; + my $total_hosts = scalar(@hosts); + my %hosts_alive = (); - # By default 200, (20 * 10) - my $host_block_size = $self->{'block_size'}; + # By default 200, (20 * 10) + my $host_block_size = $self->{'block_size'}; - # The first 50% of the recon task approx. - my $step = 40.0 / scalar(@subnets) / (($total_hosts / $host_block_size)+1); - my $subnet_step = 50.0 / (($total_hosts / $host_block_size)+1); + # The first 50% of the recon task approx. + my $step = 40.0 / scalar(@subnets) / (($total_hosts / $host_block_size)+1); + my $subnet_step = 50.0 / (($total_hosts / $host_block_size)+1); - for (my $block_index=0; - $block_index < $total_hosts; - $block_index += $host_block_size - ) { - # Update the recon task - # Increase self summary.alive hosts. - $self->call('message', "Searching for hosts (".$block_index." / ".$total_hosts.")", 5); - my $to = $host_block_size + $block_index; - $to = $total_hosts if $to >= $total_hosts; + for (my $block_index=0; + $block_index < $total_hosts; + $block_index += $host_block_size + ) { + # Update the recon task + # Increase self summary.alive hosts. + $self->call('message', "Searching for hosts (".$block_index." / ".$total_hosts.")", 5); + my $to = $host_block_size + $block_index; + $to = $total_hosts if $to >= $total_hosts; - my $c_block_size = $to - $block_index; - my @block = pandora_block_ping( - { - 'fping' => $self->{'fping'}, - # XXX CAMBIAR POR 0.5 - 'networktimeout' => 0.01 # use fping defaults - }, - @hosts[$block_index .. $to - 1] - ); + my $c_block_size = $to - $block_index; + my @block = pandora_block_ping( + { + 'fping' => $self->{'fping'}, + # XXX CAMBIAR POR 0.5 + 'networktimeout' => 0.01 # use fping defaults + }, + @hosts[$block_index .. $to - 1] + ); - # check alive hosts in current block - %hosts_alive = ( - %hosts_alive, - map {chomp; $_ => 1} @block - ); + # check alive hosts in current block + %hosts_alive = ( + %hosts_alive, + map {chomp; $_ => 1} @block + ); - $self->{'summary'}->{'not_alive'} += $c_block_size - (scalar @block); - $self->{'summary'}->{'alive'} += scalar @block; + $self->{'summary'}->{'not_alive'} += $c_block_size - (scalar @block); + $self->{'summary'}->{'alive'} += scalar @block; - # Update progress. - $progress += $step; - $self->{'c_network_percent'} += $subnet_step; + # Update progress. + $progress += $step; + $self->{'c_network_percent'} += $subnet_step; - # Populate. - $self->call('update_progress', ceil($progress)); - } + # Populate. + $self->call('update_progress', ceil($progress)); + } - # Update progress. - $self->call('message', "Searching for hosts (".$total_hosts." / ".$total_hosts.")", 5); - $progress = ceil($progress); - $self->{'c_network_percent'} = 50; + # Update progress. + $self->call('message', "Searching for hosts (".$total_hosts." / ".$total_hosts.")", 5); + $progress = ceil($progress); + $self->{'c_network_percent'} = 50; - # Populate. - $self->call('update_progress', ceil($progress)); + # Populate. + $self->call('update_progress', ceil($progress)); - $total_hosts = scalar keys %hosts_alive; - $step = 40.0 / scalar(@subnets) / $total_hosts; - $subnet_step = 50.0 / $total_hosts; - foreach my $addr (keys %hosts_alive) { - # Increase self summary.alive hosts. - $self->call('message', "Scanning host: $addr", 5); + $total_hosts = scalar keys %hosts_alive; + $step = 40.0 / scalar(@subnets) / $total_hosts; + $subnet_step = 50.0 / $total_hosts; + foreach my $addr (keys %hosts_alive) { + # Increase self summary.alive hosts. + $self->call('message', "Scanning host: $addr", 5); - # Update progress. - $progress += $step; - $self->{'c_network_percent'} += $subnet_step; + # Update progress. + $progress += $step; + $self->{'c_network_percent'} += $subnet_step; - # Populate. - $self->call('update_progress', ceil($progress)); + # Populate. + $self->call('update_progress', ceil($progress)); - # Enable/ disable capabilities. - $self->test_capabilities($addr); - } - } + # Enable/ disable capabilities. + $self->test_capabilities($addr); + } + } } ################################################################################ # Perform a Cloud scan ################################################################################ sub cloud_scan($) { - my $self = shift; - my ($progress, $step); + my $self = shift; + my ($progress, $step); - my $type = ''; + my $type = ''; - if ( $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_EC2 - || $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) { - $type = 'Aws'; - } else { + if ( $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_EC2 + || $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) { + $type = 'Aws'; + } else { - # Unrecognized task type. - $self->call('message', 'Unrecognized task type', 1); - $self->call('update_progress', -1); - return; - } + # Unrecognized task type. + $self->call('message', 'Unrecognized task type', 1); + $self->call('update_progress', -1); + return; + } - # Initialize cloud object. - my $cloudObj = PandoraFMS::Recon::Util::enterprise_new( - 'PandoraFMS::Recon::Cloud::'.$type, - [ - task_data => $self->{'task_data'}, - aws_access_key_id => $self->{'aws_access_key_id'}, - aws_secret_access_key => $self->{'aws_secret_access_key'}, - cloud_util_path => $self->{'cloud_util_path'}, - creds_file => $self->{'creds_file'}, - parent => $self - ] + # Initialize cloud object. + my $cloudObj = PandoraFMS::Recon::Util::enterprise_new( + 'PandoraFMS::Recon::Cloud::'.$type, + [ + task_data => $self->{'task_data'}, + aws_access_key_id => $self->{'aws_access_key_id'}, + aws_secret_access_key => $self->{'aws_secret_access_key'}, + cloud_util_path => $self->{'cloud_util_path'}, + creds_file => $self->{'creds_file'}, + parent => $self + ] - ); + ); - if (!$cloudObj) { + if (!$cloudObj) { - # Failed to initialize, check Cloud credentials or anything. - $self->call('message', 'Unable to initialize PandoraFMS::Recon::Cloud::'.$type, 3); - } else { + # Failed to initialize, check Cloud credentials or anything. + $self->call('message', 'Unable to initialize PandoraFMS::Recon::Cloud::'.$type, 3); + } else { - # Let Cloud object manage scan. - $cloudObj->scan(); - } + # Let Cloud object manage scan. + $cloudObj->scan(); + } - # Update progress. - # Done! - $self->{'step'} = ''; - $self->call('update_progress', -1); + # Update progress. + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); } @@ -1509,78 +1512,78 @@ sub cloud_scan($) { # Performs a database scan. ################################################################################ sub database_scan($$$) { - my ($self, $type, $obj, $global_percent, $targets) = @_; + my ($self, $type, $obj, $global_percent, $targets) = @_; - my @data; - my @modules; + my @data; + my @modules; - my $dbObjCfg = $obj->get_config(); + my $dbObjCfg = $obj->get_config(); - $self->{'summary'}->{'discovered'} += 1; - $self->{'summary'}->{'alive'} += 1; + $self->{'summary'}->{'discovered'} += 1; + $self->{'summary'}->{'alive'} += 1; - push @modules, - { - name => $type . ' connection', - type => 'generic_proc', - data => 1, - description => $type . ' availability' - }; + push @modules, + { + name => $type . ' connection', + type => 'generic_proc', + data => 1, + description => $type . ' availability' + }; - # Analyze. - $self->{'step'} = STEP_STATISTICS; - $self->{'c_network_percent'} = 30; - $self->call('update_progress', $global_percent + (30 / (scalar @$targets))); - $self->{'c_network_name'} = $obj->get_host(); + # Analyze. + $self->{'step'} = STEP_STATISTICS; + $self->{'c_network_percent'} = 30; + $self->call('update_progress', $global_percent + (30 / (scalar @$targets))); + $self->{'c_network_name'} = $obj->get_host(); - # Retrieve connection statistics. - # Retrieve uptime statistics - # Retrieve query stats - # Retrieve connections - # Retrieve innodb - # Retrieve cache - $self->{'c_network_percent'} = 50; - $self->call('update_progress', $global_percent + (50 / (scalar @$targets))); - push @modules, $obj->get_statistics(); + # Retrieve connection statistics. + # Retrieve uptime statistics + # Retrieve query stats + # Retrieve connections + # Retrieve innodb + # Retrieve cache + $self->{'c_network_percent'} = 50; + $self->call('update_progress', $global_percent + (50 / (scalar @$targets))); + push @modules, $obj->get_statistics(); - # Custom queries. - $self->{'step'} = STEP_CUSTOM_QUERIES; - $self->{'c_network_percent'} = 80; - $self->call('update_progress', $global_percent + (80 / (scalar @$targets))); - push @modules, $obj->execute_custom_queries(); + # Custom queries. + $self->{'step'} = STEP_CUSTOM_QUERIES; + $self->{'c_network_percent'} = 80; + $self->call('update_progress', $global_percent + (80 / (scalar @$targets))); + push @modules, $obj->execute_custom_queries(); - if (defined($dbObjCfg->{'scan_databases'}) - && "$dbObjCfg->{'scan_databases'}" eq "1") { + if (defined($dbObjCfg->{'scan_databases'}) + && "$dbObjCfg->{'scan_databases'}" eq "1") { - # Skip database scan in Oracle tasks - next if defined($self->{'type'}) && $self->{'type'} == DISCOVERY_APP_ORACLE; + # Skip database scan in Oracle tasks + next if defined($self->{'type'}) && $self->{'type'} == DISCOVERY_APP_ORACLE; - my $__data = $obj->scan_databases(); + my $__data = $obj->scan_databases(); - if (ref($__data) eq "ARRAY") { - if (defined($dbObjCfg->{'agent_per_database'}) - && $dbObjCfg->{'agent_per_database'} == 1) { + if (ref($__data) eq "ARRAY") { + if (defined($dbObjCfg->{'agent_per_database'}) + && $dbObjCfg->{'agent_per_database'} == 1) { - # Agent per database detected. - push @data, @{$__data}; + # Agent per database detected. + push @data, @{$__data}; - } else { + } else { - # Merge modules into engine agent. - my @_modules = map { - map { $_ } - @{$_->{'module_data'}} - } @{$__data}; + # Merge modules into engine agent. + my @_modules = map { + map { $_ } + @{$_->{'module_data'}} + } @{$__data}; - push @modules, @_modules; - } - } - } + push @modules, @_modules; + } + } + } - return { - 'modules' => \@modules, - 'data' => \@data - }; + return { + 'modules' => \@modules, + 'data' => \@data + }; } @@ -1588,153 +1591,153 @@ sub database_scan($$$) { # Perform an Application scan. ################################################################################ sub app_scan($) { - my ($self) = @_; - my ($progress, $step); + my ($self) = @_; + my ($progress, $step); - my $type = ''; - my $db_scan = 0; + my $type = ''; + my $db_scan = 0; - # APP object initialization. - if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL) { - $type = 'MySQL'; - } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) { - $type = 'Oracle'; - } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { - $type = 'SAP'; - } else { - # Unrecognized task type. - $self->call('message', 'Unrecognized task type', 1); - $self->call('update_progress', -1); - return; - } + # APP object initialization. + if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL) { + $type = 'MySQL'; + } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) { + $type = 'Oracle'; + } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { + $type = 'SAP'; + } else { + # Unrecognized task type. + $self->call('message', 'Unrecognized task type', 1); + $self->call('update_progress', -1); + return; + } - my @targets = split /,/, $self->{'task_data'}->{'subnet'}; + my @targets = split /,/, $self->{'task_data'}->{'subnet'}; - my $global_step = 100 / (scalar @targets); - my $global_percent = 0; - my $i = 0; - foreach my $target (@targets) { - if ( !defined($target) - || $target eq '' - || $target =~ /^#/) { - # Ignore empty target or commented one. - next; - } + my $global_step = 100 / (scalar @targets); + my $global_percent = 0; + my $i = 0; + foreach my $target (@targets) { + if ( !defined($target) + || $target eq '' + || $target =~ /^#/) { + # Ignore empty target or commented one. + next; + } - my @data; - my @modules; + my @data; + my @modules; - $self->{'step'} = STEP_APP_SCAN; - $self->{'c_network_name'} = $target; - $self->{'c_network_percent'} = 0; + $self->{'step'} = STEP_APP_SCAN; + $self->{'c_network_name'} = $target; + $self->{'c_network_percent'} = 0; - # Send message - $self->call('message', 'Checking target ' . $target, 10); + # Send message + $self->call('message', 'Checking target ' . $target, 10); - # Force target acquirement. - $self->{'task_data'}->{'dbhost'} = $target; - $self->{'task_data'}->{'target_index'} = $i++; + # Force target acquirement. + $self->{'task_data'}->{'dbhost'} = $target; + $self->{'task_data'}->{'target_index'} = $i++; - # Update progress - $self->{'c_network_percent'} = 10; - $self->call('update_progress', $global_percent + (10 / (scalar @targets))); + # Update progress + $self->{'c_network_percent'} = 10; + $self->call('update_progress', $global_percent + (10 / (scalar @targets))); - # Connect to target. - my $obj = PandoraFMS::Recon::Util::enterprise_new( - 'PandoraFMS::Recon::Applications::'.$type, - { - %{$self->{'task_data'}}, - 'target' => $target, - 'pa_config' => $self->{'pa_config'}, - 'parent' => $self - }, - ); + # Connect to target. + my $obj = PandoraFMS::Recon::Util::enterprise_new( + 'PandoraFMS::Recon::Applications::'.$type, + { + %{$self->{'task_data'}}, + 'target' => $target, + 'pa_config' => $self->{'pa_config'}, + 'parent' => $self + }, + ); - if (defined($obj)) { + if (defined($obj)) { - # Verify if object is connected. If cannot connect to current target - # return with module. - if (!$obj->is_connected()) { - $self->call('message', 'Cannot connect to target ' . $target, 3); - $global_percent += $global_step; - $self->{'c_network_percent'} = 90; + # Verify if object is connected. If cannot connect to current target + # return with module. + if (!$obj->is_connected()) { + $self->call('message', 'Cannot connect to target ' . $target, 3); + $global_percent += $global_step; + $self->{'c_network_percent'} = 90; - # Update progress - $self->call('update_progress', $global_percent + (90 / (scalar @targets))); - $self->{'summary'}->{'not_alive'} += 1; - push @modules, { - name => $type . ' connection', - type => 'generic_proc', - data => 0, - description => $type . ' availability' - }; + # Update progress + $self->call('update_progress', $global_percent + (90 / (scalar @targets))); + $self->{'summary'}->{'not_alive'} += 1; + push @modules, { + name => $type . ' connection', + type => 'generic_proc', + data => 0, + description => $type . ' availability' + }; - } else { - # - # $results is always a hash with: - # @modules => 'global' modules. - # @data => { - # 'agent_data' => {} - # 'module_data' => [] - # } - my $results; + } else { + # + # $results is always a hash with: + # @modules => 'global' modules. + # @data => { + # 'agent_data' => {} + # 'module_data' => [] + # } + my $results; - # Scan connected obj. - if ( $self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL - || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) { + # Scan connected obj. + if ( $self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL + || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) { - # Database. - $results = $self->database_scan($type, $obj, $global_percent, \@targets); + # Database. + $results = $self->database_scan($type, $obj, $global_percent, \@targets); - } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { + } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { - # SAP scan - $results = $obj->scan(); + # SAP scan + $results = $obj->scan(); - } + } - # Add results. - if (ref($results) eq 'HASH') { - if (defined($results->{'modules'})) { - push @modules, @{$results->{'modules'}}; - } + # Add results. + if (ref($results) eq 'HASH') { + if (defined($results->{'modules'})) { + push @modules, @{$results->{'modules'}}; + } - if (defined($results->{'data'})) { - push @data, @{$results->{'data'}}; - } - } - } + if (defined($results->{'data'})) { + push @data, @{$results->{'data'}}; + } + } + } - # Put engine agent at the beginning of the list. - my $version = $obj->get_version(); - unshift @data, { - 'agent_data' => { - 'agent_name' => $obj->get_agent_name(), - 'os' => $type, - 'os_version' => (defined($version) ? $version : 'Discovery'), - 'interval' => $self->{'task_data'}->{'interval_sweep'}, - 'id_group' => $self->{'task_data'}->{'id_group'}, - 'address' => $obj->get_host(), - 'description' => '', - }, - 'module_data' => \@modules, - }; + # Put engine agent at the beginning of the list. + my $version = $obj->get_version(); + unshift @data, { + 'agent_data' => { + 'agent_name' => $obj->get_agent_name(), + 'os' => $type, + 'os_version' => (defined($version) ? $version : 'Discovery'), + 'interval' => $self->{'task_data'}->{'interval_sweep'}, + 'id_group' => $self->{'task_data'}->{'id_group'}, + 'address' => $obj->get_host(), + 'description' => '', + }, + 'module_data' => \@modules, + }; - $self->call('create_agents', \@data); + $self->call('create_agents', \@data); - # Destroy item. - undef($obj); - } + # Destroy item. + undef($obj); + } - $global_percent += $global_step; - $self->{'c_network_percent'} = 100; - $self->call('update_progress', $global_percent); - } + $global_percent += $global_step; + $self->{'c_network_percent'} = 100; + $self->call('update_progress', $global_percent); + } - # Update progress. - # Done! - $self->{'step'} = ''; - $self->call('update_progress', -1); + # Update progress. + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); } @@ -1743,35 +1746,35 @@ sub app_scan($) { # Perform a deployment scan. ################################################################################ sub deploy_scan($) { - my $self = shift; - my ($progress, $step); + my $self = shift; + my ($progress, $step); - my $type = ''; + my $type = ''; - # Initialize deployer object. - my $deployer = PandoraFMS::Recon::Util::enterprise_new( - 'PandoraFMS::Recon::Deployer', - [ - task_data => $self->{'task_data'}, - parent => $self - ] + # Initialize deployer object. + my $deployer = PandoraFMS::Recon::Util::enterprise_new( + 'PandoraFMS::Recon::Deployer', + [ + task_data => $self->{'task_data'}, + parent => $self + ] - ); + ); - if (!$deployer) { + if (!$deployer) { - # Failed to initialize, check Cloud credentials or anything. - $self->call('message', 'Unable to initialize PandoraFMS::Recon::Deployer', 3); - } else { + # Failed to initialize, check Cloud credentials or anything. + $self->call('message', 'Unable to initialize PandoraFMS::Recon::Deployer', 3); + } else { - # Let deployer object manage scan. - $deployer->scan(); - } + # Let deployer object manage scan. + $deployer->scan(); + } - # Update progress. - # Done! - $self->{'step'} = ''; - $self->call('update_progress', -1); + # Update progress. + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); } @@ -1779,111 +1782,113 @@ sub deploy_scan($) { # Perform a network scan. ################################################################################ sub scan($) { - my ($self) = @_; - my ($progress, $step) = 1, 0; + my ($self) = @_; + my ($progress, $step) = 1, 0; - # 1% - $self->call('update_progress', 1); + # 1% + $self->call('update_progress', 1); - if (defined($self->{'task_data'})) { - if ( $self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL - || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE - || $self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { - # Application scan. - $self->call('message', "Scanning application ...", 6); - return $self->app_scan(); - } + if (defined($self->{'task_data'})) { + if ( $self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL + || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE + || $self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { + # Application scan. + $self->call('message', "Scanning application ...", 6); + return $self->app_scan(); + } - if ($self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) { + if ($self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) { - # Cloud scan. - return $self->cloud_scan(); - } + # Cloud scan. + return $self->cloud_scan(); + } - if($self->{'task_data'}->{'type'} == DISCOVERY_DEPLOY_AGENTS) { - return $self->deploy_scan(); - } - } + if($self->{'task_data'}->{'type'} == DISCOVERY_DEPLOY_AGENTS) { + return $self->deploy_scan(); + } + } + # XXX + print "Metodo: ".$self->{'task_data'}{'direct_report'}."\n"; + + if(defined($self->{'task_data'}{'direct_report'}) + && $self->{'task_data'}{'direct_report'} == DISCOVERY_RESULTS + ) { + # Use Cached results. + return $self->call('report_scanned_agents'); + } - if(defined($self->{'task_data'}{'direct_report'}) - && $self->{'task_data'}{'direct_report'} eq "2" - ) { - # Use Cached results. - return $self->call('report_scanned_agents'); - } + # Find devices. + $self->call('message', "[1/4] Scanning the network...", 3); + $self->{'step'} = STEP_SCANNING; + $self->call('update_progress', $progress); - # Find devices. - $self->call('message', "[1/4] Scanning the network...", 3); - $self->{'step'} = STEP_SCANNING; - $self->call('update_progress', $progress); + $self->scan_subnet(); + # Read the local ARP cache. + $self->local_arp(); - $self->scan_subnet(); - # Read the local ARP cache. - $self->local_arp(); + # Get a list of found hosts. + my @hosts = @{$self->get_hosts()}; + if (scalar(@hosts) > 0 && $self->{'parent_detection'} == 1) { - # Get a list of found hosts. - my @hosts = @{$self->get_hosts()}; - if (scalar(@hosts) > 0 && $self->{'parent_detection'} == 1) { + # Delete previous connections. + $self->call('delete_connections'); - # Delete previous connections. - $self->call('delete_connections'); + # Connectivity from address forwarding tables. + $self->call('message', "[2/4] Finding address forwarding table connectivity...", 3); + $self->{'step'} = STEP_AFT; + ($progress, $step) = (80, 8.0 / scalar(@hosts)); # From 50% to 70%. + for (my $i = 0; defined($hosts[$i]); $i++) { + $self->call('update_progress', $progress); + $progress += $step; + $self->aft_connectivity($hosts[$i]); + } - # Connectivity from address forwarding tables. - $self->call('message', "[2/4] Finding address forwarding table connectivity...", 3); - $self->{'step'} = STEP_AFT; - ($progress, $step) = (80, 8.0 / scalar(@hosts)); # From 50% to 70%. - for (my $i = 0; defined($hosts[$i]); $i++) { - $self->call('update_progress', $progress); - $progress += $step; - $self->aft_connectivity($hosts[$i]); - } + # Connect hosts that are still unconnected using traceroute. + $self->call('message', "[3/4] Finding traceroute connectivity.", 3); + $self->{'step'} = STEP_TRACEROUTE; + ($progress, $step) = (88, 8.0 / scalar(@hosts)); # From 70% to 90%. + foreach my $host (@hosts) { + $self->call('update_progress', $progress); + $progress += $step; + next if ($self->has_parent($host) || $self->has_children($host)); + $self->traceroute_connectivity($host); + } - # Connect hosts that are still unconnected using traceroute. - $self->call('message', "[3/4] Finding traceroute connectivity.", 3); - $self->{'step'} = STEP_TRACEROUTE; - ($progress, $step) = (88, 8.0 / scalar(@hosts)); # From 70% to 90%. - foreach my $host (@hosts) { - $self->call('update_progress', $progress); - $progress += $step; - next if ($self->has_parent($host) || $self->has_children($host)); - $self->traceroute_connectivity($host); - } + # Connect hosts that are still unconnected using known gateways. + $self->call('message', "[4/4] Finding host to gateway connectivity.", 3); + $self->{'step'} = STEP_GATEWAY; + ($progress, $step) = (94, 6.0 / scalar(@hosts)); # From 70% to 90%. + $self->get_routes(); # Update the route cache. + foreach my $host (@hosts) { + $self->call('update_progress', $progress); + $progress += $step; + next if ($self->has_parent($host)); + $self->gateway_connectivity($host); + } + } - # Connect hosts that are still unconnected using known gateways. - $self->call('message', "[4/4] Finding host to gateway connectivity.", 3); - $self->{'step'} = STEP_GATEWAY; - ($progress, $step) = (94, 6.0 / scalar(@hosts)); # From 70% to 90%. - $self->get_routes(); # Update the route cache. - foreach my $host (@hosts) { - $self->call('update_progress', $progress); - $progress += $step; - next if ($self->has_parent($host)); - $self->gateway_connectivity($host); - } - } + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); - # Done! - $self->{'step'} = ''; - $self->call('update_progress', -1); + # Print debug information on found devices. + $self->call('message', "[Summary]", 3); + foreach my $host (@hosts) { + my $device = $self->get_device($host); + next unless defined($device); - # Print debug information on found devices. - $self->call('message', "[Summary]", 3); - foreach my $host (@hosts) { - my $device = $self->get_device($host); - next unless defined($device); + # Print device information. + my $dev_info = "Device: " . $device->{'type'} . " ("; + foreach my $ip_address ($self->get_addresses($host)) { + $dev_info .= "$ip_address,"; + } + chop($dev_info); + $dev_info .= ')'; + $self->call('message', $dev_info, 3); + } - # Print device information. - my $dev_info = "Device: " . $device->{'type'} . " ("; - foreach my $ip_address ($self->get_addresses($host)) { - $dev_info .= "$ip_address,"; - } - chop($dev_info); - $dev_info .= ')'; - $self->call('message', $dev_info, 3); - } - - # Send agent information to Database (Discovery) or XML (satellite.). - $self->call('report_scanned_agents', $self->{'agents_found'}); + # Send agent information to Database (Discovery) or XML (satellite.). + $self->call('report_scanned_agents', $self->{'agents_found'}); } @@ -1891,33 +1896,33 @@ sub scan($) { # Set an SNMP community for the given device. ################################################################################ sub set_community($$$) { - my ($self, $device, $community) = @_; + my ($self, $device, $community) = @_; - $self->{'community_cache'}->{$device} = $community; + $self->{'community_cache'}->{$device} = $community; } ################################################################################ # Set the type of the given device. ################################################################################ sub set_device_type($$$) { - my ($self, $device, $type) = @_; + my ($self, $device, $type) = @_; - $self->{'visited_devices'}->{$device}->{'type'} = $type; + $self->{'visited_devices'}->{$device}->{'type'} = $type; } ################################################################################ # Calculate ################################################################################ sub snmp_pen($$) { - my ($self, $addr) = @_; + my ($self, $addr) = @_; - $self->{'pen'} = {} if ref($self->{'pen'}) ne 'HASH'; + $self->{'pen'} = {} if ref($self->{'pen'}) ne 'HASH'; - $self->{'pen'}{$addr} = $self->snmp_get($addr, $PEN_OID); + $self->{'pen'}{$addr} = $self->snmp_get($addr, $PEN_OID); - if(defined($self->{'pen'}{$addr})) { - ($self->{'pen'}{$addr}) = $self->{'pen'}{$addr} =~ /\.\d+\.\d+\.\d+\.\d+\.\d+\.\d+\.(\d+?)\./ - } + if(defined($self->{'pen'}{$addr})) { + ($self->{'pen'}{$addr}) = $self->{'pen'}{$addr} =~ /\.\d+\.\d+\.\d+\.\d+\.\d+\.\d+\.(\d+?)\./ + } } @@ -1925,65 +1930,65 @@ sub snmp_pen($$) { # Performs an SNMP WALK and returns the response as an array. ################################################################################ sub snmp_get($$$) { - my ($self, $device, $oid) = @_; - my @output; + my ($self, $device, $oid) = @_; + my @output; - return () unless defined $self->is_snmp_discovered($device); - my $community = $self->get_community($device); + return () unless defined $self->is_snmp_discovered($device); + my $community = $self->get_community($device); - # Check the SNMP query cache first. - if (defined($self->{'snmp_cache'}->{"${device}_${oid}"})) { - return @{$self->{'snmp_cache'}->{"${device}_${oid}"}}; - } + # Check the SNMP query cache first. + if (defined($self->{'snmp_cache'}->{"${device}_${oid}"})) { + return @{$self->{'snmp_cache'}->{"${device}_${oid}"}}; + } - # Check VLANS. - my @vlans = $self->get_vlans($device); - if (scalar(@vlans) == 0) { - my $command = $self->snmp_get_command($device, $oid, $community); - @output = `$command`; - }else { + # Check VLANS. + my @vlans = $self->get_vlans($device); + if (scalar(@vlans) == 0) { + my $command = $self->snmp_get_command($device, $oid, $community); + @output = `$command`; + }else { - # Handle duplicate lines. - my %output_hash; - foreach my $vlan (@vlans) { - my $command = $self->snmp_get_command($device, $oid, $community, $vlan); - foreach my $line (`$command`) { - $output_hash{$line} = 1; - } - } - push(@output, keys(%output_hash)); - } + # Handle duplicate lines. + my %output_hash; + foreach my $vlan (@vlans) { + my $command = $self->snmp_get_command($device, $oid, $community, $vlan); + foreach my $line (`$command`) { + $output_hash{$line} = 1; + } + } + push(@output, keys(%output_hash)); + } - # Update the SNMP query cache. - $self->{'snmp_cache'}->{"${device}_${oid}"} = [@output]; + # Update the SNMP query cache. + $self->{'snmp_cache'}->{"${device}_${oid}"} = [@output]; - return @output; + 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 ($self, $device, $oid, $community, $vlan) = @_; + $vlan = defined($vlan) ? "\@" . $vlan : ''; - my $command = "snmpwalk -M$DEVNULL -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v$self->{'snmp_version'} -On -Oe "; - if ($self->{'snmp_version'} eq "3") { - if ($self->{'community'}) { # Context - $command .= " -N $self->{'community'} "; - } - $command .= " -l$self->{'snmp_security_level'} "; - 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 "; - } + my $command = "snmpwalk -M$DEVNULL -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v$self->{'snmp_version'} -On -Oe "; + if ($self->{'snmp_version'} eq "3") { + if ($self->{'community'}) { # Context + $command .= " -N $self->{'community'} "; + } + $command .= " -l$self->{'snmp_security_level'} "; + 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>$DEVNULL"; + return "$command $device $oid 2>$DEVNULL"; } @@ -1992,86 +1997,86 @@ sub snmp_get_command { # on error. ################################################################################ sub snmp_get_value($$$) { - my ($self, $device, $oid) = @_; + my ($self, $device, $oid) = @_; - my @output = $self->snmp_get($device, $oid); - foreach my $line (@output) { - chomp($line); - return $1 if ($line =~ /^$oid\s+=\s+\S+:\s+(.*)$/); - } + my @output = $self->snmp_get($device, $oid); + foreach my $line (@output) { + chomp($line); + return $1 if ($line =~ /^$oid\s+=\s+\S+:\s+(.*)$/); + } - return undef; + return undef; } ################################################################################ # Performs an SNMP WALK and returns an array of values. ################################################################################ sub snmp_get_value_array($$$) { - my ($self, $device, $oid) = @_; - my @values; + my ($self, $device, $oid) = @_; + my @values; - my @output = $self->snmp_get($device, $oid); - foreach my $line (@output) { - chomp($line); - push(@values, $1) if ($line =~ /^$oid\S*\s+=\s+\S+:\s+(.*)$/); - } + my @output = $self->snmp_get($device, $oid); + foreach my $line (@output) { + chomp($line); + push(@values, $1) if ($line =~ /^$oid\S*\s+=\s+\S+:\s+(.*)$/); + } - return @values; + return @values; } ################################################################################ # Performs an SNMP WALK and returns a hash of values. ################################################################################ sub snmp_get_value_hash($$$) { - my ($self, $device, $oid) = @_; - my %values; + my ($self, $device, $oid) = @_; + my %values; - my @output = $self->snmp_get_value_array($device, $oid); - foreach my $line (@output) { - $values{$line} = ''; - } + my @output = $self->snmp_get_value_array($device, $oid); + foreach my $line (@output) { + $values{$line} = ''; + } - return %values; + return %values; } ################################################################################ # Connect the given host to its parent using traceroute. ################################################################################ sub traceroute_connectivity($$) { - my ($self, $host) = @_; + my ($self, $host) = @_; - # Perform a traceroute. - my $nmap_args = '-nsP -PE --traceroute --max-retries '.$self->{'icmp_checks'}.' --host-timeout '.$self->{'icmp_timeout'}.'s -T'.$self->{'recon_timing_template'}; - my $np = PandoraFMS::Recon::NmapParser->new(); - eval {$np->parsescan($self->{'nmap'}, $nmap_args, ($host));}; - return if ($@); + # Perform a traceroute. + my $nmap_args = '-nsP -PE --traceroute --max-retries '.$self->{'icmp_checks'}.' --host-timeout '.$self->{'icmp_timeout'}.'s -T'.$self->{'recon_timing_template'}; + my $np = PandoraFMS::Recon::NmapParser->new(); + eval {$np->parsescan($self->{'nmap'}, $nmap_args, ($host));}; + return if ($@); - # Get hops to the host. - my ($h) = $np->all_hosts(); - return unless defined($h); - my @hops = $h->all_trace_hops(); + # Get hops to the host. + my ($h) = $np->all_hosts(); + return unless defined($h); + my @hops = $h->all_trace_hops(); - # Skip the target host. - pop(@hops); + # Skip the target host. + pop(@hops); - # Reverse the host order (closest hosts first). - @hops = reverse(@hops); + # Reverse the host order (closest hosts first). + @hops = reverse(@hops); - # Look for parents. - my $device = $host; - for (my $i = 0; $i < $self->{'parent_recursion'}; $i++) { - next unless defined($hops[$i]); - my $parent = $hops[$i]->ipaddr(); + # Look for parents. + my $device = $host; + for (my $i = 0; $i < $self->{'parent_recursion'}; $i++) { + next unless defined($hops[$i]); + my $parent = $hops[$i]->ipaddr(); - # Create an agent for the parent. - $self->add_agent($parent); + # Create an agent for the parent. + $self->add_agent($parent); - $self->call('message', "Host $device is one hop away from host $parent.", 5); - $self->mark_connected($parent, '', $device, ''); + $self->call('message', "Host $device is one hop away from host $parent.", 5); + $self->mark_connected($parent, '', $device, ''); - # Move on to the next hop. - $device = $parent; - } + # Move on to the next hop. + $device = $parent; + } } ################################################################################ @@ -2079,94 +2084,94 @@ sub traceroute_connectivity($$) { # undef if it does not respond to WMI. ################################################################################ sub responds_to_wmi { - my ($self, $target) = @_; + my ($self, $target) = @_; - foreach my $auth (@{$self->{'auth_strings_array'}}) { - my @output; - if ($auth ne '') { - @output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -U $auth //$target "SELECT * FROM Win32_ComputerSystem" 2>&1`; - } else { - @output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -N //$target "SELECT * FROM Win32_ComputerSystem" 2>&1`; - } + foreach my $auth (@{$self->{'auth_strings_array'}}) { + my @output; + if ($auth ne '') { + @output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -U $auth //$target "SELECT * FROM Win32_ComputerSystem" 2>&1`; + } else { + @output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -N //$target "SELECT * FROM Win32_ComputerSystem" 2>&1`; + } - foreach my $line (@output) { - chomp($line); - return $auth if ($line =~ m/^CLASS: Win32_ComputerSystem$/); - } - } + foreach my $line (@output) { + chomp($line); + return $auth if ($line =~ m/^CLASS: Win32_ComputerSystem$/); + } + } - return undef; + return undef; } ################################################################################ # Add wmi modules to the given host. ################################################################################ sub wmi_scan { - my ($self, $target) = @_; + my ($self, $target) = @_; - $self->call('message', "[".$target."] Checking WMI.", 5); + $self->call('message', "[".$target."] Checking WMI.", 5); - my $auth = $self->responds_to_wmi($target); - return unless defined($auth); + my $auth = $self->responds_to_wmi($target); + return unless defined($auth); - $self->{'summary'}->{'WMI'} += 1; + $self->{'summary'}->{'WMI'} += 1; - $self->call('message', "[".$target."] WMI available.", 10); + $self->call('message', "[".$target."] WMI available.", 10); - # Register agent. - $self->add_agent($target); + # Register agent. + $self->add_agent($target); - # Add modules. - # CPU. - my @cpus = $self->wmi_get_value_array($target, $auth, 'SELECT DeviceId FROM Win32_Processor', 0); - foreach my $cpu (@cpus) { - $self->add_module($target, 'wmi', - { - 'target' => $target, - 'query' => "SELECT LoadPercentage FROM Win32_Processor WHERE DeviceId='$cpu'", - 'auth' => $auth, - 'column' => 1, - 'name' => "CPU Load $cpu", - 'description' => "Load for $cpu (%)", - 'type' => 'generic_data', - 'unit' => '%', - } - ); - } + # Add modules. + # CPU. + my @cpus = $self->wmi_get_value_array($target, $auth, 'SELECT DeviceId FROM Win32_Processor', 0); + foreach my $cpu (@cpus) { + $self->add_module($target, 'wmi', + { + 'target' => $target, + 'query' => "SELECT LoadPercentage FROM Win32_Processor WHERE DeviceId='$cpu'", + 'auth' => $auth, + 'column' => 1, + 'name' => "CPU Load $cpu", + 'description' => "Load for $cpu (%)", + 'type' => 'generic_data', + 'unit' => '%', + } + ); + } - # Memory. - my $mem = $self->wmi_get_value($target, $auth, 'SELECT FreePhysicalMemory FROM Win32_OperatingSystem', 0); - if (defined($mem)) { - $self->add_module($target, 'wmi', - { - 'target' => $target, - 'query' => "SELECT FreePhysicalMemory, TotalVisibleMemorySize FROM Win32_OperatingSystem", - 'auth' => $auth, - 'column' => 0, - 'name' => 'FreeMemory', - 'description' => 'Free memory', - 'type' => 'generic_data', - 'unit' => 'KB', - } - ); - } + # Memory. + my $mem = $self->wmi_get_value($target, $auth, 'SELECT FreePhysicalMemory FROM Win32_OperatingSystem', 0); + if (defined($mem)) { + $self->add_module($target, 'wmi', + { + 'target' => $target, + 'query' => "SELECT FreePhysicalMemory, TotalVisibleMemorySize FROM Win32_OperatingSystem", + 'auth' => $auth, + 'column' => 0, + 'name' => 'FreeMemory', + 'description' => 'Free memory', + 'type' => 'generic_data', + 'unit' => 'KB', + } + ); + } - # Disk. - my @units = $self->wmi_get_value_array($target, $auth, 'SELECT DeviceID FROM Win32_LogicalDisk', 0); - foreach my $unit (@units) { - $self->add_module($target, 'wmi', - { - 'target' => $target, - 'query' => "SELECT FreeSpace FROM Win32_LogicalDisk WHERE DeviceID='$unit'", - 'auth' => $auth, - 'column' => 1, - 'name' => "FreeDisk $unit", - 'description' => 'Available disk space in kilobytes', - 'type' => 'generic_data', - 'unit' => 'KB', - } - ); - } + # Disk. + my @units = $self->wmi_get_value_array($target, $auth, 'SELECT DeviceID FROM Win32_LogicalDisk', 0); + foreach my $unit (@units) { + $self->add_module($target, 'wmi', + { + 'target' => $target, + 'query' => "SELECT FreeSpace FROM Win32_LogicalDisk WHERE DeviceID='$unit'", + 'auth' => $auth, + 'column' => 1, + 'name' => "FreeDisk $unit", + 'description' => 'Available disk space in kilobytes', + 'type' => 'generic_data', + 'unit' => 'KB', + } + ); + } } @@ -2178,19 +2183,19 @@ sub wmi_scan { # Performs a wmi get requests and returns the response as an array. ################################################################################ sub wmi_get { - my ($self, $target, $auth, $query) = @_; + my ($self, $target, $auth, $query) = @_; - my @output; - if (defined($auth) && $auth ne '') { - @output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -U $auth //$target "$query" 2>&1`; - }else { - @output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -N //$target "$query" 2>&1`; - } + my @output; + if (defined($auth) && $auth ne '') { + @output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -U $auth //$target "$query" 2>&1`; + }else { + @output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -N //$target "$query" 2>&1`; + } - # Something went wrong. - return () if ($? != 0); + # Something went wrong. + return () if ($? != 0); - return @output; + return @output; } ################################################################################ @@ -2198,18 +2203,18 @@ sub wmi_get { # Returns undef on error. ################################################################################ sub wmi_get_value { - my ($self, $target, $auth, $query, $column) = @_; - my @result; + my ($self, $target, $auth, $query, $column) = @_; + my @result; - my @output = $self->wmi_get($target, $auth, $query); - return undef unless defined($output[2]); + my @output = $self->wmi_get($target, $auth, $query); + return undef unless defined($output[2]); - my $line = $output[2]; - chomp($line); - my @columns = split(/\|/, $line); - return undef unless defined($columns[$column]); + my $line = $output[2]; + chomp($line); + my @columns = split(/\|/, $line); + return undef unless defined($columns[$column]); - return $columns[$column]; + return $columns[$column]; } ################################################################################ @@ -2217,19 +2222,19 @@ sub wmi_get_value { # in an array. ################################################################################ sub wmi_get_value_array { - my ($self, $target, $auth, $query, $column) = @_; - my @result; + my ($self, $target, $auth, $query, $column) = @_; + my @result; - my @output = $self->wmi_get($target, $auth, $query); - foreach (my $i = 2; defined($output[$i]); $i++) { - my $line = $output[$i]; - chomp($line); - my @columns = split(/\|/, $line); - next unless defined($columns[$column]); - push(@result, $columns[$column]); - } + my @output = $self->wmi_get($target, $auth, $query); + foreach (my $i = 2; defined($output[$i]); $i++) { + my $line = $output[$i]; + chomp($line); + my @columns = split(/\|/, $line); + next unless defined($columns[$column]); + push(@result, $columns[$column]); + } - return @result; + return @result; } ################################################################################