2011-10-10 16:21:00 +02:00
#!/usr/bin/perl
# (c) Dario Rodriguez 2011 <dario.rodriguez@artica.es>
# Intel DCM Discovery
use POSIX qw( setsid strftime strftime ceil ) ;
use strict ;
use warnings ;
use IO::Socket::INET ;
use NetAddr::IP ;
# Default lib dir for RPM and DEB packages
use lib '/usr/lib/perl5' ;
use PandoraFMS::Tools ;
use PandoraFMS::DB ;
use PandoraFMS::Core ;
use PandoraFMS::Config ;
##########################################################################
# Global variables so set behaviour here:
2015-05-26 20:01:17 +02:00
my $ pkg_count = 2 ; #Number of ping pkgs
my $ pkg_timeout = 1 ; #Pkg ping timeout wait
2011-10-10 16:21:00 +02:00
##########################################################################
# Code begins here, do not touch
##########################################################################
2014-05-10 04:09:44 +02:00
my $ OSNAME = $^O ;
my $ pandora_conf ;
if ( $ OSNAME eq "freebsd" ) {
$ pandora_conf = "/usr/local/etc/pandora/pandora_server.conf" ;
} else {
$ pandora_conf = "/etc/pandora/pandora_server.conf" ;
}
2011-10-10 16:21:00 +02:00
my $ task_id = $ ARGV [ 0 ] ; # Passed automatically by the server
my $ target_group = $ ARGV [ 1 ] ; # Defined by user
my $ create_incident = $ ARGV [ 2 ] ; # Defined by user
# Used Custom Fields in this script
my $ target_network = $ ARGV [ 3 ] ; # Filed1 defined by user
my $ username = $ ARGV [ 4 ] ; # Field2 defined by user
my $ password = $ ARGV [ 5 ] ; # Field3 defined by user
2015-05-26 20:01:17 +02:00
my $ extraopts = $ ARGV [ 6 ] ; # Field4 defined by user
2011-10-10 16:21:00 +02:00
2015-05-27 01:28:00 +02:00
# Map Sensor type to module type and thresholds
# 0 = numeric, record has thresholds
# 1 = simple flag, 0 normal, > 0 critical
# 2 = complex flags, for now ignore alert settings
# 3 = string or unknown
my % sensor_types = (
'Temperature' = > 0 ,
'Voltage' = > 0 ,
'Current' = > 0 ,
'Fan' = > 0 ,
'Physical Security' = > 1 ,
'Platform Security Violation Attempt' = > 1 ,
'Processor' = > 2 ,
'Power Supply' = > 2 ,
'Power Unit' = > 2 ,
'Cooling Device' = > 0 ,
'Other Units Based Sensor' = > 0 ,
'Memory' = > 2 ,
'Drive Slot' = > 3 ,
'POST Memory Resize' = > 3 ,
'System Firmware Progress' = > 1 ,
'Event Logging Disabled' = > 2 ,
'Watchdog 1' = > 2 ,
'System Event' = > 2 ,
'Critical Interrupt' = > 1 ,
'Button Switch' = > 2 ,
'Module Board' = > 3 ,
'Microcontroller Coprocessor' = > 3 ,
'Add In Card' = > 3 ,
'Chassis' = > 3 ,
'Chip Set' = > 3 ,
'Other Fru' = > 3 ,
'Cable Interconnect' = > 3 ,
'Terminator' = > 3 ,
'System Boot Initiated' = > 2 ,
'Boot Error' = > 1 ,
'OS Boot' = > 2 ,
'OS Critical Stop' = > 1 ,
'Slot Connector' = > 2 ,
'System ACPI Power State' = > 2 ,
'Watchdog 2' = > 2 ,
'Platform Alert' = > 2 ,
'Entity Presence' = > 2 ,
'Monitor ASIC IC' = > 3 ,
'LAN' = > 2 ,
'Management Subsystem Health' = > 1 ,
'Battery' = > 2 ,
'Session Audit' = > 3 ,
'Version Change' = > 3 ,
'FRU State' = > 3 ,
'OEM Reserved' = > 3
) ;
2011-10-10 16:21:00 +02:00
##########################################################################
# 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 ) ;
}
##########################################################################
# Show help
##########################################################################
sub show_help {
print "\nSpecific Pandora FMS Intel DCM Discovery\n" ;
print "(c) Artica ST 2011 <info\@artica.es>\n\n" ;
print "Usage:\n\n" ;
2015-05-26 20:01:17 +02:00
print " $0 <task_id> <group_id> <create_incident_flag> <custom_field1> <custom_field2> <custom_field3> <custom_field4>\n\n" ;
2011-10-10 16:21:00 +02:00
print " * custom_field1 = network. i.e.: 192.168.100.0/24\n" ;
print " * custom_field2 = username \n" ;
2015-05-26 20:01:17 +02:00
print " * custom_field3 = password \n" ;
print " * custom_field4 = additional ipmi-sensors options \n" ;
2011-10-10 16:21:00 +02:00
exit ;
}
##########################################################################
# Get SNMP response.
##########################################################################
2012-05-09 09:40:24 +02:00
sub ipmi_ping ($$$) {
2011-10-10 16:21:00 +02:00
my $ addr = shift ;
2012-05-09 09:40:24 +02:00
my $ pkg_count = shift ;
my $ pkg_timeout = shift ;
2011-10-10 16:21:00 +02:00
2012-05-09 09:40:24 +02:00
my $ cmd = "ipmiping $addr -c $pkg_count -t $pkg_timeout" ;
2011-10-10 16:21:00 +02:00
my $ res = `$cmd` ;
2015-05-26 21:12:39 +02:00
if ( $ res =~ / (\d+\.\d+)% packet loss/ ) {
if ( $ 1 ne '100.0' ) {
return 1 ;
}
}
return 0 ;
2011-10-10 16:21:00 +02:00
}
2015-05-26 20:01:17 +02:00
sub create_ipmi_modules ($$$$$$$) {
my ( $ conf , $ dbh , $ addr , $ user , $ pass , $ extraopts , $ id_agent ) = @ _ ;
2011-10-10 16:21:00 +02:00
2015-05-27 01:28:00 +02:00
my $ cmd = "ipmi-sensors -h $addr -u $user -p $pass $extraopts --ignore-not-available-sensors --no-header-output --comma-separated-output --non-abbreviated-units --output-sensor-thresholds --output-event-bitmask" ;
2011-10-10 16:21:00 +02:00
2015-05-27 01:28:00 +02:00
my $ res = `$cmd` ;
2011-10-10 16:21:00 +02:00
my @ lines = split ( /\n/ , $ res ) ;
2012-05-09 09:40:24 +02:00
2011-10-10 16:21:00 +02:00
my $ ipmi_plugin_id = get_db_value ( $ dbh , "SELECT id FROM tplugin WHERE name = '" . safe_input ( "IPMI Plugin" ) . "'" ) ;
2015-05-27 03:35:17 +02:00
for ( my $ i = 0 ; $ i <= $# lines ; $ i + + ) {
2012-05-09 09:40:24 +02:00
my $ line = $ lines [ $ i ] ;
2015-05-27 01:28:00 +02:00
my ( $ sensor , $ name , $ type , $ value , $ units , $ lowerNR , $ lowerC , $ lowerNC , $ upperNC , $ upperC , $ upperNR , $ eventmask ) = split ( /,/ , $ line ) ;
2011-10-10 16:21:00 +02:00
2015-05-27 03:35:17 +02:00
my $ module_name = $ type . ': ' . $ name ;
2011-10-10 16:21:00 +02:00
2015-05-27 01:28:00 +02:00
my $ module_type ;
my $ module_warn_min ;
my $ module_warn_max ;
my $ module_warn_invert ;
my $ module_critical_min ;
my $ module_critical_max ;
my $ module_critical_invert ;
if ( $ sensor_types { $ type } == 0 ) {
2011-10-10 16:21:00 +02:00
$ module_type = "generic_data" ;
2015-05-27 01:28:00 +02:00
if ( $ lowerC ne 'N/A' and $ upperC ne 'N/A' ) {
$ module_critical_min = $ lowerC ;
$ module_critical_max = $ upperC ;
$ module_critical_invert = 1 ;
}
if ( $ lowerNC ne 'N/A' and $ upperNC ne 'N/A' ) {
$ module_warn_min = $ lowerNC ;
$ module_warn_max = $ upperNC ;
$ module_warn_invert = 1 ;
}
} elsif ( $ sensor_types { $ type } == 1 ) {
$ module_type = "generic_data" ;
$ module_critical_min = "1" ;
$ module_critical_max = "0" ;
} elsif ( $ sensor_types { $ type } == 2 ) {
$ module_type = "generic_data" ;
} elsif ( $ sensor_types { $ type } == 3 ) {
$ module_type = "generic_data_string" ;
} else {
$ module_type = "generic_data_string" ;
}
2012-05-09 09:40:24 +02:00
2011-10-10 16:21:00 +02:00
my $ id_module_type = get_module_id ( $ dbh , $ module_type ) ;
2015-05-26 20:01:17 +02:00
my $ macros = '{' .
'"1":{"macro":"_field1_","desc":"' . safe_input ( "Target IP" ) . '","help":"","value":"' . $ addr . '","hide":""},' .
'"2":{"macro":"_field2_","desc":"Username","help":"","value":"' . $ user . '","hide":""},' .
'"3":{"macro":"_field3_","desc":"Password","help":"","value":"' . $ pass . '","hide":"1"},' .
2015-05-27 01:28:00 +02:00
'"4":{"macro":"_field4_","desc":"Sensor","help":"","value":"' . $ sensor . '","hide":""},' .
2015-05-26 20:01:17 +02:00
'"5":{"macro":"_field5_","desc":"' . safe_input ( "Additional Options" ) . '","help":"","value":"' . $ extraopts . '","hide":""}' .
'}' ;
2011-10-10 16:21:00 +02:00
my % parameters ;
2015-05-27 01:28:00 +02:00
$ parameters { "nombre" } = safe_input ( $ module_name ) ;
2011-10-10 16:21:00 +02:00
$ parameters { "id_tipo_modulo" } = $ id_module_type ;
$ parameters { "id_agente" } = $ id_agent ;
$ parameters { "id_plugin" } = $ ipmi_plugin_id ;
$ parameters { "id_modulo" } = 4 ;
2015-05-27 03:35:17 +02:00
$ parameters { "unit" } = $ units if $ units ne 'N/A' ;
2015-05-27 01:28:00 +02:00
$ parameters { "min_warning" } = $ module_warn_min if defined $ module_warn_min ;
$ parameters { "max_warning" } = $ module_warn_max if defined $ module_warn_max ;
$ parameters { "warning_inverse" } = $ module_warn_invert if defined $ module_warn_invert ;
$ parameters { "min_critical" } = $ module_critical_min if defined $ module_critical_min ;
$ parameters { "max_critical" } = $ module_critical_max if defined $ module_critical_max ;
$ parameters { "critical_inverse" } = $ module_critical_invert if defined $ module_critical_invert ;
2015-05-26 20:01:17 +02:00
$ parameters { "macros" } = $ macros ;
2011-10-10 16:21:00 +02:00
pandora_create_module_from_hash ( $ conf , \ % parameters , $ dbh ) ;
}
}
##########################################################################
##########################################################################
# M A I N C O D E
##########################################################################
##########################################################################
if ( $# ARGV == - 1 ) {
show_help ( ) ;
}
# Pandora server configuration
my % conf ;
$ conf { "quiet" } = 0 ;
$ conf { "verbosity" } = 1 ; # Verbose 1 by default
$ conf { "daemon" } = 0 ; # Daemon 0 by default
$ conf { 'PID' } = "" ; # PID file not exist by default
$ conf { 'pandora_path' } = $ pandora_conf ;
# Read config file
pandora_load_config ( \ % conf ) ;
# Connect to the DB
2015-05-12 16:30:05 +02:00
my $ dbh = db_connect ( $ conf { 'dbengine' } , $ conf { 'dbname' } , $ conf { 'dbhost' } , '3306' , $ conf { 'dbuser' } , $ conf { 'dbpass' } ) ;
2011-10-10 16:21:00 +02:00
# Start the network sweep
# Get a NetAddr::IP object for the target network
my $ net_addr = new NetAddr:: IP ( $ target_network ) ;
if ( ! defined ( $ net_addr ) ) {
logger ( \ % conf , "Invalid network " . $ target_network . " for Intel DCM Discovery task" , 1 ) ;
update_recon_task ( $ dbh , $ task_id , - 1 ) ;
return - 1 ;
}
# Scan the network for host
my ( $ total_hosts , $ hosts_found , $ addr_found ) = ( $ net_addr - > num , 0 , '' ) ;
2015-05-26 20:01:17 +02:00
for ( my $ i = 1 ; $ net_addr < $ net_addr - > broadcast ; $ i + + , $ net_addr + + ) {
2011-10-10 16:21:00 +02:00
if ( $ net_addr =~ /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.(\d{1,3})\b/ ) {
if ( $ 1 eq '0' || $ 1 eq '255' ) {
next ;
}
}
my $ addr = ( split ( /\// , $ net_addr ) ) [ 0 ] ;
$ hosts_found + + ;
# Update the recon task
update_recon_task ( $ dbh , $ task_id , ceil ( $ i / ($total_hosts / 100 ) ) ) ;
2012-05-09 09:40:24 +02:00
2011-10-10 16:21:00 +02:00
my $ alive = 0 ;
2012-05-09 09:40:24 +02:00
if ( ipmi_ping ( $ addr , $ pkg_count , $ pkg_timeout ) == 1 ) {
2011-10-10 16:21:00 +02:00
$ alive = 1 ;
}
2012-05-09 09:40:24 +02:00
2011-10-10 16:21:00 +02:00
next unless ( $ alive > 0 ) ;
# Resolve the address
my $ host_name = gethostbyaddr ( inet_aton ( $ addr ) , AF_INET ) ;
$ host_name = $ addr unless defined ( $ host_name ) ;
logger ( \ % conf , "Intel DCM Device found host $host_name." , 10 ) ;
# Check if the agent exists
my $ agent_id = get_agent_id ( $ dbh , $ host_name ) ;
# If the agent doesnt exist we create it
if ( $ agent_id == - 1 ) {
# Create a new agent
$ agent_id = pandora_create_agent ( \ % conf , $ conf { 'servername' } , $ host_name , $ addr , $ target_group , 0 , 11 , '' , 300 , $ dbh ) ;
2015-05-26 20:01:17 +02:00
create_ipmi_modules ( \ % conf , $ dbh , $ addr , $ username , $ password , $ extraopts , $ agent_id ) ;
2011-10-10 16:21:00 +02:00
}
# Generate an event
pandora_event ( \ % conf , "[RECON] New Intel DCM host [$host_name] detected on network [" . $ target_network . ']' , $ target_group , $ agent_id , 2 , 0 , 0 , 'recon_host_detected' , 0 , $ dbh ) ;
}
# Mark recon task as done
update_recon_task ( $ dbh , $ task_id , - 1 ) ;
# End of code