Pre-check modules (SNMP, TCP, ICMP) Discovery

This commit is contained in:
fbsanchez 2020-03-19 14:11:09 +01:00
parent f58276ddbb
commit 99cb286274
4 changed files with 242 additions and 70 deletions

View File

@ -3067,6 +3067,8 @@ sub pandora_create_module_from_network_component ($$$$) {
pandora_create_module_tags ($pa_config, $dbh, $module_id, $component_tags);
logger($pa_config, 'Creating module ' . safe_output ($component->{'nombre'}) . " (ID $module_id) for agent $addr from network component.", 10);
return $module_id;
}
##########################################################################

View File

@ -441,11 +441,133 @@ sub PandoraFMS::Recon::Base::tcp_scan ($$) {
return $open_ports;
}
################################################################################
# Verifies if a module will be normal.
################################################################################
sub PandoraFMS::Recon::Base::test_module($$) {
my ($self, $addr, $module) = @_;
# Default values.
my $test = {
%{$module},
'ip_target' => $addr,
};
if (is_enabled($module->{'__module_component'})) {
# Component. Translate some fields.
$test->{'id_tipo_modulo'} = $module->{'type'};
} else {
# Module.
$test->{'id_tipo_modulo'} = $module->{'id_modulo'};
}
my $value;
# 1. Try to retrieve value.
if ($test->{'id_tipo_modulo'} >= 15 && $test->{'id_tipo_modulo'} <= 18) {
# SNMP
$value = $self->call(
'snmp_get',
$test->{'ip_target'},
$test->{'snmp_oid'}
);
} elsif ($test->{'id_tipo_modulo'} == 6) {
# ICMP - alive - already tested.
$value = 1;
} elsif ($test->{'id_tipo_modulo'} == 7) {
# ICMP - latency
$value = pandora_ping_latency(
$self->{'pa_config'},
$test->{'ip_target'},
$test->{'max_timeout'},
$test->{'max_retries'},
);
} elsif (($test->{'id_tipo_modulo'} >= 1 && $test->{'id_tipo_modulo'} <= 5)
|| ($test->{'id_tipo_modulo'} >= 21 && $test->{'id_tipo_modulo'} <= 23)
&& is_enabled($test->{'id_plugin'})
) {
# Generic, plugins. (21-23 ASYNC)
# XXX TODO: Test plugins.
return 1;
} elsif ($test->{'id_tipo_modulo'} >= 34 && $test->{'id_tipo_modulo'} <= 37) {
# Remote command.
# XXX TODO: Test remote commands.
return 1;
} elsif ($test->{'id_tipo_modulo'} >= 8 && $test->{'id_tipo_modulo'} <= 11) {
# TCP
return 0 unless is_numeric($test->{'tcp_port'})
&& $test->{'tcp_port'} > 0
&& $test->{'tcp_port'} <= 65535;
my $result;
PandoraFMS::NetworkServer::pandora_query_tcp(
$self->{'pa_config'},
$test->{'tcp_port'},
$test->{'ip_target'},
\$result,
\$value,
$test->{'tcp_send'},
$test->{'tcp_rcv'},
$test->{'id_tipo_modulo'},
$test->{'max_timeout'},
$test->{'max_retries'},
'<Discovery testing>',
);
# Result 0 is OK, 1 failed
return 0 unless defined($result) && $result == 0;
return 0 unless defined($value);
}
# Invalid data (empty or not defined)
return 0 if is_empty($value);
# 2. Check if value matches type definition and fits thresholds.
if (is_in_array([1,2,4,5,6,7,8,9,11,15,16,18,21,22,25,30,31,32,34,35,37],$test->{'id_tipo_modulo'})) {
# Numeric.
return 0 unless is_numeric($value);
if (!is_enabled($test->{'critical_inverse'})) {
return 0 if $value >= $test->{'min_critical'} && $value <= $test->{'max_critical'};
} else {
return 0 if $value < $test->{'min_critical'} && $value > $test->{'max_critical'};
}
if (is_in_array([2,6,9,18,21,31,35], $test->{'id_tipo_modulo'})) {
# Boolean.
if (!is_enabled($test->{'critical_inverse'})) {
return 0 if $value == 0;
} else {
return 0 if $value != 0;
}
}
} else {
# String.
if (!is_enabled($test->{'critical_inverse'})) {
return 0 if !is_empty($test->{'str_critical'}) && $value =~ /$test->{'str_critical'}/;
} else {
return 0 if !is_empty($test->{'str_critical'}) && $value !~ /$test->{'str_critical'}/;
}
}
# Success.
return 1;
}
################################################################################
# Create network profile modules for the given agent.
################################################################################
sub PandoraFMS::Recon::Base::create_network_profile_modules($$$) {
my ($self, $agent_id, $device) = @_;
sub PandoraFMS::Recon::Base::create_network_profile_modules($$) {
my ($self, $device) = @_;
#
# Plugin
@ -454,50 +576,61 @@ sub PandoraFMS::Recon::Base::create_network_profile_modules($$$) {
# ICMP
#
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
print Dumper($device);
print Dumper($self->{'task_data'});
die();
return if empty($self->{'id_network_profile'});
return if is_empty($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) {
my $data = $self->{'agents_found'}{$device};
# 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;
foreach my $t_id (@templates) {
# 1. Retrieve template info.
my $template = get_db_single_row(
$self->{'dbh'},
'SELECT * FROM `tnetwork_profile` WHERE `id_np` = ?',
$t_id
);
# 2. Verify Private Enterprise Number matches (PEN)
if (defined($template->{'pen'})) {
my @penes = split(',', $template->{'pen'});
next unless (is_in_array(\@penes, $data->{'pen'}));
}
## 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'}
# 2. retrieve module list from target template.
my @np_components = get_db_rows(
$self->{'dbh'},
'SELECT * FROM tnetwork_profile_component WHERE id_np = ?',
$t_id
);
foreach my $np_component (@np_components) {
# 2. Test each possible module.
my $component = get_db_single_row(
$self->{'dbh'},
'SELECT * FROM tnetwork_component WHERE id_nc = ?',
$np_component->{'id_nc'}
);
$component->{'name'} = safe_output($component->{'name'});
if ($component->{'type'} >= 15 && $component->{'type'} <= 18) {
$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'};
}
$component->{'__module_component'} = 1;
# 3. Try to register module into monitoring list.
$self->call('add_module', $device, $component);
}
}
}
################################################################################
@ -580,9 +713,9 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($) {
$self->call('message', "Agent id: ".$data->{'agent'}{'agent_id'}, 5);
# Create selected modules.
if(ref($data->{'modules'}) eq "ARRAY") {
for (my $i=0; $i < scalar @{$data->{'modules'}}; $i++) {
my $module = $data->{'modules'}[$i];
if(ref($data->{'modules'}) eq "HASH") {
foreach my $i (keys %{$data->{'modules'}}) {
my $module = $data->{'modules'}{$i};
# Do not create any modules if the agent is not in learning mode.
next unless ($agent_learning == 1);
@ -596,22 +729,33 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($) {
my $agentmodule_id = $module->{'agentmodule_id'};
if (!defined($agentmodule_id) || $agentmodule_id == 0) {
# Create module.
$agentmodule_id = pandora_create_module_from_hash(
$self->{'pa_config'},
{
'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module->{'type'}),
'id_modulo' => $module->{'id_modulo'},
'nombre' => safe_input($module->{'name'}),
'descripcion' => '',
'id_agente' => $agent_id,
'ip_target' => $data->{'agent'}{'direccion'}
},
$self->{'dbh'}
);
if (is_enabled($module->{'__module_component'})) {
# Module from network component.
$agentmodule_id = pandora_create_module_from_network_component(
$self->{'pa_config'},
$module,
$agent_id,
$self->{'dbh'}
);
} else {
# Create module - Direct.
$agentmodule_id = pandora_create_module_from_hash(
$self->{'pa_config'},
{
'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module->{'type'}),
'id_modulo' => $module->{'id_modulo'},
'nombre' => safe_input($module->{'name'}),
'descripcion' => '',
'id_agente' => $agent_id,
'ip_target' => $data->{'agent'}{'direccion'}
},
$self->{'dbh'}
);
}
# Store.
$data->{'modules'}[$i]{'agentmodule_id'} = $agentmodule_id;
$data->{'modules'}{$i}{'agentmodule_id'} = $agentmodule_id;
$self->call(
'message',
@ -725,13 +869,11 @@ sub PandoraFMS::Recon::Base::apply_monitoring($) {
# From 80% to 90%.
my ($progress, $step) = (80, 10.0 / scalar(@hosts));
use Data::Dumper;
print Dumper($self->{'task_data'});
foreach my $label (keys %{$self->{'agents_found'}}) {
$self->call('update_progress', $progress);
$progress += $step;
print ">> $label\n";
$self->call('message', "Checking modules for $label", 5);
$self->call('create_network_profile_modules', $label);
}

View File

@ -384,9 +384,9 @@ sub are_connected($$$$$) {
$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 Host Alive modules when interfaces are unknown.
$if_1 = "Host Alive" if $if_1 eq '';
$if_2 = "Host Alive" 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}"})) {
@ -405,7 +405,7 @@ sub icmp_discovery($$) {
$self->prepare_agent($addr);
$self->add_module($addr, 'icmp',
$self->add_module($addr,
{
'ip_target' => $addr,
'name' => "Host Alive",
@ -1328,12 +1328,22 @@ sub add_agent($$) {
################################################################################
# Add module to agent (tmp pool) (will be registered at the end of the scan).
################################################################################
sub add_module($$$$) {
my ($self, $agent, $type, $data) = @_;
sub add_module($$$) {
my ($self, $agent, $data) = @_;
$self->prepare_agent($agent);
push @{$self->{'agents_found'}->{$agent}->{'modules'}}, $data;
$self->{'agents_found'}->{$agent}->{'modules'} = {}
unless ref($self->{'agents_found'}->{$agent}->{'modules'}) eq 'HASH';
# Test module. Is it well defined?
return unless ref($data) eq 'HASH' && defined($data->{'name'})
&& $data->{'name'} ne '';
# Test module. Is it success?
return unless $self->call('test_module', $agent, $data);
$self->{'agents_found'}->{$agent}->{'modules'}{$data->{'name'}} = $data;
}
@ -1409,7 +1419,7 @@ sub scan_subnet($) {
{
'fping' => $self->{'fping'},
# XXX CAMBIAR POR 0.5
'networktimeout' => 0.01 # use fping defaults
'networktimeout' => 0.5 # use fping defaults
},
@hosts[$block_index .. $to - 1]
);
@ -2136,7 +2146,7 @@ sub wmi_scan {
# 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',
$self->add_module($target,
{
'target' => $target,
'query' => "SELECT LoadPercentage FROM Win32_Processor WHERE DeviceId='$cpu'",
@ -2153,7 +2163,7 @@ sub wmi_scan {
# Memory.
my $mem = $self->wmi_get_value($target, $auth, 'SELECT FreePhysicalMemory FROM Win32_OperatingSystem', 0);
if (defined($mem)) {
$self->add_module($target, 'wmi',
$self->add_module($target,
{
'target' => $target,
'query' => "SELECT FreePhysicalMemory, TotalVisibleMemorySize FROM Win32_OperatingSystem",
@ -2170,7 +2180,7 @@ sub wmi_scan {
# 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',
$self->add_module($target,
{
'target' => $target,
'query' => "SELECT FreeSpace FROM Win32_LogicalDisk WHERE DeviceID='$unit'",

View File

@ -113,6 +113,7 @@ our @EXPORT = qw(
is_metaconsole
is_offline
is_empty
is_in_array
to_number
clean_blank
credential_store_get_key
@ -659,6 +660,23 @@ sub is_empty {
return 0;
}
################################################################################
# Check if a value is in an array
################################################################################
sub is_in_array {
my ($array, $value) = @_;
if (is_empty($value)) {
return 0;
}
my %params = map { $_ => 1 } @{$array};
if (exists($params{$value})) {
return 1;
}
return 0;
}
################################################################################
# SUB md5check (param_1, param_2)
# Verify MD5 file .checksum