diff --git a/pandora_server/ChangeLog b/pandora_server/ChangeLog index ebe5c5553b..b8e91f721f 100644 --- a/pandora_server/ChangeLog +++ b/pandora_server/ChangeLog @@ -1,3 +1,13 @@ +2014-07-28 Ramon Novoa + + * conf/pandora_server.conf.new, + lib/PandoraFMS/Config.pm: Added configuration tokens to disable the + translation of enterprise strings and variable bindings (SNMP console). + + * lib/PandoraFMS/SNMPServer.pm: Added thread support to the SNMP console. + + * lib/PandoraFMS/DB.pm: Fixed a warning. + 2014-07-25 Miguel de Dios * lib/PandoraFMS/GIS.pm, lib/PandoraFMS/DB.pm, diff --git a/pandora_server/conf/pandora_server.conf.new b/pandora_server/conf/pandora_server.conf.new index 236db1a3e8..4da320f75a 100755 --- a/pandora_server/conf/pandora_server.conf.new +++ b/pandora_server/conf/pandora_server.conf.new @@ -86,6 +86,18 @@ master 1 snmpconsole 0 +# snmpconsole_threads: number of SNMP console threads for processing SNMP traps. + +snmpconsole_threads 1 + +# Attempt to translate variable bindings when processing SNMP traps. 1 enabled, 0 disabled. 0 by default. (ENTERPRISE ONLY). + +translate_variable_bindings 0 + +# Attempt to translate enterprise strings when processing SNMP traps. 1 enabled, 0 disabled. 1 by default. (ENTERPRISE ONLY). + +translate_enterprise_strings 0 + # snmptrapd will ignore authenticationFailure traps if set to 1. snmp_ignore_authfailure 1 diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index cf03b015dc..a4677d2426 100644 --- a/pandora_server/lib/PandoraFMS/Config.pm +++ b/pandora_server/lib/PandoraFMS/Config.pm @@ -248,6 +248,9 @@ sub pandora_load_config { $pa_config->{"snmp_pdu_address"} = 0; # 5.0 $pa_config->{"snmp_storm_protection"} = 0; # 5.0 $pa_config->{"snmp_storm_timeout"} = 600; # 5.0 + $pa_config->{"snmpconsole_threads"} = 1; # 5.1 + $pa_config->{"translate_variable_bindings"} = 0; # 5.1 + $pa_config->{"translate_enterprise_strings"} = 1; # 5.1 # Internal MTA for alerts, each server need its own config. $pa_config->{"mta_address"} = '127.0.0.1'; # Introduced on 2.0 @@ -465,6 +468,15 @@ sub pandora_load_config { elsif ($parametro =~ m/^snmp_storm_timeout\s+(\d+)/i) { $pa_config->{'snmp_storm_timeout'}= clean_blank($1); } + elsif ($parametro =~ m/^snmpconsole_threads\s+(\d+)/i) { + $pa_config->{'snmpconsole_threads'}= clean_blank($1); + } + elsif ($parametro =~ m/^translate_variable_bindings\s+([0-1])/i) { + $pa_config->{'translate_variable_bindings'}= clean_blank($1); + } + elsif ($parametro =~ m/^translate_enterprise_strings\s+([0-1])/i) { + $pa_config->{'translate_enterprise_strings'}= clean_blank($1); + } elsif ($parametro =~ m/^dbengine\s(.*)/i) { $pa_config->{'dbengine'}= clean_blank($1); } diff --git a/pandora_server/lib/PandoraFMS/DB.pm b/pandora_server/lib/PandoraFMS/DB.pm index 1a8ddc2b94..e4c34bb5a9 100644 --- a/pandora_server/lib/PandoraFMS/DB.pm +++ b/pandora_server/lib/PandoraFMS/DB.pm @@ -884,9 +884,8 @@ sub get_alert_template_name ($$) { sub db_concat ($$) { my ($element1, $element2) = @_; - return " concat(" . $element1 . ", ' '," . $element2 . ") " if ($RDBMS eq 'mysql'); - return " " . $element1 . " || ' ' || " . $element2 . " " if ($RDBMS eq 'oracle' or $RDBMS eq 'postgresql'); + return " concat(" . $element1 . ", ' '," . $element2 . ") "; } ######################################################################## diff --git a/pandora_server/lib/PandoraFMS/SNMPServer.pm b/pandora_server/lib/PandoraFMS/SNMPServer.pm index c0a506e5d1..91a49c6460 100644 --- a/pandora_server/lib/PandoraFMS/SNMPServer.pm +++ b/pandora_server/lib/PandoraFMS/SNMPServer.pm @@ -25,6 +25,7 @@ use threads::shared; use Thread::Semaphore; use Time::Local; +use Time::HiRes qw(usleep); use XML::Simple; # Default lib dir for RPM and DEB packages @@ -33,21 +34,27 @@ use lib '/usr/lib/perl5'; use PandoraFMS::Tools; use PandoraFMS::DB; use PandoraFMS::Core; -use PandoraFMS::Server; +use PandoraFMS::ProducerConsumerServer; -# Inherits from PandoraFMS::Server -our @ISA = qw(PandoraFMS::Server); +# Inherits from PandoraFMS::ProducerConsumerServer +our @ISA = qw(PandoraFMS::ProducerConsumerServer); -# Tells the server to keep running -my $RUN :shared; +# Global variables +my @TaskQueue :shared; +my %PendingTasks :shared; +my $Sem :shared; +my $TaskSem :shared; # Trap statistics by agent my %AGENTS = (); +# Index file management +my ($IDX_FILE, $LAST_LINE, $LAST_SIZE) = (); + ######################################################################################## # SNMP Server class constructor. ######################################################################################## -sub new ($$;$) { +sub new ($$$) { my ($class, $config, $dbh) = @_; return undef unless $config->{'snmpconsole'} == 1; @@ -57,15 +64,46 @@ sub new ($$;$) { return undef; } + # Wait for the SNMP log file to be available + my $log_file = $config->{'snmp_logfile'}; + sleep ($config->{'server_threshold'}) if (! -e $log_file); + if (!open (SNMPLOGFILE, $log_file)) { + logger ($config, ' [E] Could not open the SNMP log file ' . $config->{'snmp_logfile'} . ".", 1); + print_message ($config, ' [E] Could not open the SNMP log file ' . $config->{'snmp_logfile'} . ".", 1); + return 1; + } + + # Process index file, if available + ($IDX_FILE, $LAST_LINE, $LAST_SIZE) = ($log_file . '.index', 0, 0); + if (-e $IDX_FILE) { + open (INDEXFILE, $IDX_FILE) or return; + my $idx_data = ; + close INDEXFILE; + ($LAST_LINE, $LAST_SIZE) = split(/\s+/, $idx_data); + } + my $log_size = (stat ($log_file))[7]; + + # New SNMP log file found + if ($log_size < $LAST_SIZE) { + unlink ($IDX_FILE); + ($LAST_LINE, $LAST_SIZE) = (0, 0); + } + + # Skip already processed lines + readline SNMPLOGFILE for (1..$LAST_LINE); + + # Initialize semaphores and queues + @TaskQueue = (); + %PendingTasks = (); + $Sem = Thread::Semaphore->new; + $TaskSem = Thread::Semaphore->new (0); + # Call the constructor of the parent class - my $self = $class->SUPER::new($config, 2, $dbh); + my $self = $class->SUPER::new($config, 2, \&PandoraFMS::SNMPServer::data_producer, \&PandoraFMS::SNMPServer::data_consumer, $dbh); # Save the path of snmptrapd $self->{'snmp_trapd'} = $config->{'snmp_trapd'}; - # Run! - $RUN = 1; - bless $self, $class; return $self; } @@ -77,242 +115,219 @@ sub run ($) { my $self = shift; my $pa_config = $self->getConfig (); - print_message ($pa_config, " [*] Starting Pandora FMS SNMP Console.", 1); - $self->SUPER::run (\&PandoraFMS::SNMPServer::pandora_snmptrapd); + print_message ($pa_config, " [*] Starting Pandora FMS SNMP Console.", 2); + + # Set the initial date for storm protection. + $pa_config->{"__storm_ref__"} = time(); + + # This is the only server that reads from disk instead of from the DB. No need for a higher server threshold. + $pa_config->{'server_threshold'} = 1; + + $self->setNumThreads ($pa_config->{'snmpconsole_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; + + # Slave server + if ($pa_config->{'pandora_master'} == 0 && get_db_value ($dbh, 'SELECT name FROM tserver WHERE name = ANY(SELECT name FROM tserver WHERE status = 0)') == undef) { + return @tasks; + } + + # Reset storm protection counters + my $curr_time = time (); + if ($pa_config->{"__storm_ref__"} + $pa_config->{"snmp_storm_timeout"} < $curr_time) { + $pa_config->{"__storm_ref__"} = $curr_time; + %AGENTS = (); + } + + while (my $line = ) { + $LAST_LINE++; + $LAST_SIZE = (stat ($pa_config->{'snmp_logfile'}))[7]; + chomp ($line); + + # Update index file + open INDEXFILE, '>' . $IDX_FILE; + print INDEXFILE $LAST_LINE . ' ' . $LAST_SIZE; + close INDEXFILE; + + # Skip lines other than SNMP Trap logs + next unless ($line =~ m/^SNMPv[12]\[\*\*\]/); + + # Storm protection. + my ($ver, $date, $time, $source, $null) = split(/\[\*\*\]/, $line, 5); + next unless defined ($source); + if (! defined ($AGENTS{$source})) { + $AGENTS{$source}{'count'} = 1; + $AGENTS{$source}{'event'} = 0; + } else { + $AGENTS{$source}{'count'} += 1; + } + if ($pa_config->{'snmp_storm_protection'} > 0 && $AGENTS{$source}{'count'} > $pa_config->{'snmp_storm_protection'}) { + if ($AGENTS{$source}{'event'} == 0) { + pandora_event ($pa_config, "Too many traps coming from $source. Silenced for " . int ($pa_config->{"snmp_storm_timeout"} / 60) . " minutes.", 0, 0, 4, 0, 0, 'system', 0, $dbh); + } + $AGENTS{$source}{'event'} = 1; + next; + } + + push (@tasks, $line); + } + + return @tasks; +} + +############################################################################### +# Data consumer. +############################################################################### +sub data_consumer ($$) { + my ($self, $task) = @_; + + pandora_snmptrapd ($self->getConfig (), $task, $self->getServerID (), $self->getDBH ()); } ########################################################################## # Process SNMP log file. ########################################################################## sub pandora_snmptrapd { - my $self = shift; - my $pa_config = $self->getConfig (); + my ($pa_config, $line, $server_id, $dbh) = @_; - my $dbh; - eval { - # Connect to the DB - $dbh = db_connect ($pa_config->{'dbengine'}, $pa_config->{'dbname'}, $pa_config->{'dbhost'}, - $pa_config->{'dbport'}, $pa_config->{'dbuser'}, $pa_config->{'dbpass'}); - $self->setDBH ($dbh); + (my $trap_ver, $line) = split(/\[\*\*\]/, $line, 2); - # Wait for the SNMP log file to be available - my $log_file = $pa_config->{'snmp_logfile'}; - sleep ($pa_config->{'server_threshold'}) while (! -e $log_file); - open (SNMPLOGFILE, $log_file) or return; + # Process SNMP filter + next if (matches_filter ($dbh, $pa_config, $line) == 1); - # Process index file, if available - my ($idx_file, $last_line, $last_size) = ($log_file . '.index', 0, 0); - if (-e $idx_file) { - open (INDEXFILE, $idx_file) or return; - my $idx_data = ; - close INDEXFILE; - ($last_line, $last_size) = split(/\s+/, $idx_data); + logger($pa_config, "Reading trap '$line'", 10); + my ($date, $time, $source, $oid, $type, $type_desc, $value, $data) = ('', '', '', '', '', '', '', ''); + + if ($trap_ver eq "SNMPv1") { + ($date, $time, $source, $oid, $type, $type_desc, $value, $data) = split(/\[\*\*\]/, $line, 8); + + $value = limpia_cadena ($value); + + # Try to save as much information as possible if the trap could not be parsed + $oid = $type_desc if ($oid eq '' || $oid eq '.'); + + } elsif ($trap_ver eq "SNMPv2") { + ($date, $time, $source, $data) = split(/\[\*\*\]/, $line, 4); + my @data = split(/\t/, $data); + + shift @data; # Drop unused 1st data. + $oid = shift @data; + + if (!defined($oid)) { + logger($pa_config, "[W] snmpTrapOID not found (Illegal SNMPv2 trap?)", 1); + next; } - - my $log_size = (stat ($log_file))[7]; - - # New SNMP log file found - if ($log_size < $last_size) { - unlink ($idx_file); - ($last_line, $last_size) = (0, 0); - } - - # Skip already processed lines - readline SNMPLOGFILE for (1..$last_line); - - # Main loop - my $storm_ref = time (); - while ($RUN == 1) { - - # Reset storm protection counters - my $curr_time = time (); - if ($storm_ref + $pa_config->{"snmp_storm_timeout"} < $curr_time) { - $storm_ref = $curr_time; - %AGENTS = (); - } - - while (my $line = ) { - $last_line++; - $last_size = (stat ($log_file))[7]; - chomp ($line); - - # Update index file - open INDEXFILE, '>' . $idx_file; - print INDEXFILE $last_line . ' ' . $last_size; - close INDEXFILE; - - # Skip lines other than SNMP Trap logs - next unless ($line =~ m/^SNMPv[12]\[\*\*\]/); - - (my $trap_ver, $line) = split(/\[\*\*\]/, $line, 2); - - # Process SNMP filter - next if (matches_filter ($dbh, $pa_config, $line) == 1); - - logger($pa_config, "Reading trap '$line'", 10); - my ($date, $time, $source, $oid, $type, $type_desc, $value, $data) = ('', '', '', '', '', '', '', ''); - - if ($trap_ver eq "SNMPv1") { - ($date, $time, $source, $oid, $type, $type_desc, $value, $data) = split(/\[\*\*\]/, $line, 8); - - $value = limpia_cadena ($value); - - # Try to save as much information as possible if the trap could not be parsed - $oid = $type_desc if ($oid eq '' || $oid eq '.'); - - } elsif ($trap_ver eq "SNMPv2") { - ($date, $time, $source, $data) = split(/\[\*\*\]/, $line, 4); - my @data = split(/\t/, $data); - - shift @data; # Drop unused 1st data. - $oid = shift @data; - - if (!defined($oid)) { - logger($pa_config, "[W] snmpTrapOID not found (Illegal SNMPv2 trap?)", 1); - next; - } - $oid =~ s/.* = OID: //; - $data = join("\t", @data); - } - - if ($trap_ver eq "SNMPv2" || $pa_config->{'snmp_pdu_address'} eq '1' ) { - # extract IP address from %b part: - # * destination part (->[dest_ip]:dest_port) appears in Net-SNMP > 5.3 - # * protocol name (TCP: or UDP:) and bracketted IP addr w/ port number appear in - # Net-SNMP > 5.1 (Net-SNMP 5.1 has IP addr only). - # * port number is signed (often negative) in Net-SNMP 5.2 - $source =~ s/(?:(?:TCP|UDP):\s*)?\[?([^] ]+)\]?(?::-?\d+)?(?:\s*->.*)?$/$1/; - } - - my $timestamp = $date . ' ' . $time; - my ($custom_oid, $custom_type, $custom_value) = ('', '', ''); - - # custom_type, custom_value is not used since 4.0 version, all custom data goes on custom_oid - $custom_oid = $data; - - # Storm protection - if (! defined ($AGENTS{$source})) { - $AGENTS{$source}{'count'} = 1; - $AGENTS{$source}{'event'} = 0; - } else { - $AGENTS{$source}{'count'} += 1; - } - if ($pa_config->{'snmp_storm_protection'} > 0 && $AGENTS{$source}{'count'} > $pa_config->{'snmp_storm_protection'}) { - if ($AGENTS{$source}{'event'} == 0) { - pandora_event ($pa_config, "Too many traps coming from $source. Silenced for " . int ($pa_config->{"snmp_storm_timeout"} / 60) . " minutes.", 0, 0, 4, 0, 0, 'system', 0, $dbh); - } - $AGENTS{$source}{'event'} = 1; - next; - } - - #Trap forwarding - if ($pa_config->{'snmp_forward_trap'}==1) { - my $trap_data_string = ""; - - #We loop through all the custom data of the received trap, creating the $trap_data_string string to forward the trap properly - while ($data =~ /([\.\d]+)\s=\s([^:]+):\s([\S ]+)/g) { - my ($trap_data, $trap_type, $trap_value) = ($1, $2, $3); - if ($trap_type eq "INTEGER") { - #FIX for translated traps from IF-MIB.txt MIB - $trap_value =~ s/\D//g; - $trap_data_string = $trap_data_string . "$trap_data i $trap_value "; - } - elsif ($trap_type eq "UNSIGNED"){ - $trap_data_string = $trap_data_string . "$trap_data u $trap_value "; - } - elsif ($trap_type eq "COUNTER32"){ - $trap_data_string = $trap_data_string . "$trap_data c $trap_value "; - } - elsif ($trap_type eq "STRING"){ - $trap_data_string = $trap_data_string . "$trap_data s $trap_value "; - } - elsif ($trap_type eq "HEX STRING"){ - $trap_data_string = $trap_data_string . "$trap_data x $trap_value "; - } - elsif ($trap_type eq "DECIMAL STRING"){ - $trap_data_string = $trap_data_string . "$trap_data d $trap_value "; - } - elsif ($trap_type eq "NULLOBJ"){ - $trap_data_string = $trap_data_string . "$trap_data n $trap_value "; - } - elsif ($trap_type eq "OBJID"){ - $trap_data_string = $trap_data_string . "$trap_data o $trap_value "; - } - elsif ($trap_type eq "TIMETICKS"){ - $trap_data_string = $trap_data_string . "$trap_data t $trap_value "; - } - elsif ($trap_type eq "IPADDRESS"){ - $trap_data_string = $trap_data_string . "$trap_data a $trap_value "; - } - elsif ($trap_type eq "BITS"){ - $trap_data_string = $trap_data_string . "$trap_data b $trap_value "; - } - } - - #We distinguish between the three different kinds of SNMP forwarding - if ($pa_config->{'snmp_forward_version'} eq '3') { - system("snmptrap -v $pa_config->{'snmp_forward_version'} -n \"\" -a $pa_config->{'snmp_forward_authProtocol'} -A $pa_config->{'snmp_forward_authPassword'} -x $pa_config->{'snmp_forward_privProtocol'} -X $pa_config->{'snmp_forward_privPassword'} -l $pa_config->{'snmp_forward_secLevel'} -u $pa_config->{'snmp_forward_secName'} -e $pa_config->{'snmp_forward_engineid'} $pa_config->{'snmp_forward_ip'} '' $oid $trap_data_string"); - } - elsif ($pa_config->{'snmp_forward_version'} eq '2' || $pa_config->{'snmp_forward_version'} eq '2c') { - system("snmptrap -v 2c -n \"\" -c $pa_config->{'snmp_forward_community'} $pa_config->{'snmp_forward_ip'} '' $oid $trap_data_string"); - } - elsif ($pa_config->{'snmp_forward_version'} eq '1') { - #Because of tne SNMP v1 protocol, we must perform additional steps for creating the trap - my $value_sending = ""; - my $type_sending = ""; - - if ($value eq ''){ - $value_sending = "\"\""; - } - else { - $value_sending = $value; - $value_sending =~ s/[\$#@~!&*()\[\];.,:?^ `\\\/]+//g; - } - if ($type eq ''){ - $type_sending = "\"\""; - } - else{ - $type_sending = $type; - } - - system("snmptrap -v 1 -c $pa_config->{'snmp_forward_community'} $pa_config->{'snmp_forward_ip'} $oid \"\" $type_sending $value_sending \"\" $trap_data_string"); - } - } - - # Insert the trap into the DB - if (! defined(enterprise_hook ('snmp_insert_trap', [$pa_config, $source, $oid, $type, $value, $custom_oid, $custom_value, $custom_type, $timestamp, $self->getServerID (), $dbh]))) { - my $trap_id = db_insert ($dbh, 'id_trap', 'INSERT INTO ttrap (timestamp, source, oid, type, value, oid_custom, value_custom, type_custom) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', - $timestamp, $source, $oid, $type, $value, $custom_oid, $custom_value, $custom_type); - logger ($pa_config, "Received SNMP Trap from $source", 4); - - # Evaluate alerts for this trap - pandora_evaluate_snmp_alerts ($pa_config, $trap_id, $source, $oid, $type, $oid, $value, $custom_oid, $dbh); - } - } - - sleep ($pa_config->{'server_threshold'}); - } - }; - - if ($@) { - $self->setErrStr ($@); + $oid =~ s/.* = OID: //; + $data = join("\t", @data); } - db_disconnect ($dbh); -} - -######################################################################################## -# Stop the server, killing snmptrapd before. -######################################################################################## -sub stop () { - my $self = shift; - - if ($self->{'snmp_trapd'} ne 'manual') { - system ("kill -9 `cat /var/run/pandora_snmptrapd.pid 2>$DEVNULL`"); - unlink ('/var/run/pandora_snmptrapd.pid'); + if ($trap_ver eq "SNMPv2" || $pa_config->{'snmp_pdu_address'} eq '1' ) { + # extract IP address from %b part: + # * destination part (->[dest_ip]:dest_port) appears in Net-SNMP > 5.3 + # * protocol name (TCP: or UDP:) and bracketted IP addr w/ port number appear in + # Net-SNMP > 5.1 (Net-SNMP 5.1 has IP addr only). + # * port number is signed (often negative) in Net-SNMP 5.2 + $source =~ s/(?:(?:TCP|UDP):\s*)?\[?([^] ]+)\]?(?::-?\d+)?(?:\s*->.*)?$/$1/; + } + + my $timestamp = $date . ' ' . $time; + my ($custom_oid, $custom_type, $custom_value) = ('', '', ''); + + # custom_type, custom_value is not used since 4.0 version, all custom data goes on custom_oid + $custom_oid = $data; + + #Trap forwarding + if ($pa_config->{'snmp_forward_trap'}==1) { + my $trap_data_string = ""; + + #We loop through all the custom data of the received trap, creating the $trap_data_string string to forward the trap properly + while ($data =~ /([\.\d]+)\s=\s([^:]+):\s([\S ]+)/g) { + my ($trap_data, $trap_type, $trap_value) = ($1, $2, $3); + if ($trap_type eq "INTEGER") { + #FIX for translated traps from IF-MIB.txt MIB + $trap_value =~ s/\D//g; + $trap_data_string = $trap_data_string . "$trap_data i $trap_value "; + } + elsif ($trap_type eq "UNSIGNED"){ + $trap_data_string = $trap_data_string . "$trap_data u $trap_value "; + } + elsif ($trap_type eq "COUNTER32"){ + $trap_data_string = $trap_data_string . "$trap_data c $trap_value "; + } + elsif ($trap_type eq "STRING"){ + $trap_data_string = $trap_data_string . "$trap_data s $trap_value "; + } + elsif ($trap_type eq "HEX STRING"){ + $trap_data_string = $trap_data_string . "$trap_data x $trap_value "; + } + elsif ($trap_type eq "DECIMAL STRING"){ + $trap_data_string = $trap_data_string . "$trap_data d $trap_value "; + } + elsif ($trap_type eq "NULLOBJ"){ + $trap_data_string = $trap_data_string . "$trap_data n $trap_value "; + } + elsif ($trap_type eq "OBJID"){ + $trap_data_string = $trap_data_string . "$trap_data o $trap_value "; + } + elsif ($trap_type eq "TIMETICKS"){ + $trap_data_string = $trap_data_string . "$trap_data t $trap_value "; + } + elsif ($trap_type eq "IPADDRESS"){ + $trap_data_string = $trap_data_string . "$trap_data a $trap_value "; + } + elsif ($trap_type eq "BITS"){ + $trap_data_string = $trap_data_string . "$trap_data b $trap_value "; + } + } + + #We distinguish between the three different kinds of SNMP forwarding + if ($pa_config->{'snmp_forward_version'} eq '3') { + system("snmptrap -v $pa_config->{'snmp_forward_version'} -n \"\" -a $pa_config->{'snmp_forward_authProtocol'} -A $pa_config->{'snmp_forward_authPassword'} -x $pa_config->{'snmp_forward_privProtocol'} -X $pa_config->{'snmp_forward_privPassword'} -l $pa_config->{'snmp_forward_secLevel'} -u $pa_config->{'snmp_forward_secName'} -e $pa_config->{'snmp_forward_engineid'} $pa_config->{'snmp_forward_ip'} '' $oid $trap_data_string"); + } + elsif ($pa_config->{'snmp_forward_version'} eq '2' || $pa_config->{'snmp_forward_version'} eq '2c') { + system("snmptrap -v 2c -n \"\" -c $pa_config->{'snmp_forward_community'} $pa_config->{'snmp_forward_ip'} '' $oid $trap_data_string"); + } + elsif ($pa_config->{'snmp_forward_version'} eq '1') { + #Because of tne SNMP v1 protocol, we must perform additional steps for creating the trap + my $value_sending = ""; + my $type_sending = ""; + + if ($value eq ''){ + $value_sending = "\"\""; + } + else { + $value_sending = $value; + $value_sending =~ s/[\$#@~!&*()\[\];.,:?^ `\\\/]+//g; + } + if ($type eq ''){ + $type_sending = "\"\""; + } + else{ + $type_sending = $type; + } + + system("snmptrap -v 1 -c $pa_config->{'snmp_forward_community'} $pa_config->{'snmp_forward_ip'} $oid \"\" $type_sending $value_sending \"\" $trap_data_string"); + } + } + + # Insert the trap into the DB + if (! defined(enterprise_hook ('snmp_insert_trap', [$pa_config, $source, $oid, $type, $value, $custom_oid, $custom_value, $custom_type, $timestamp, $server_id, $dbh]))) { + my $trap_id = db_insert ($dbh, 'id_trap', 'INSERT INTO ttrap (timestamp, source, oid, type, value, oid_custom, value_custom, type_custom) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', + $timestamp, $source, $oid, $type, $value, $custom_oid, $custom_value, $custom_type); + logger ($pa_config, "Received SNMP Trap from $source", 4); + + # Evaluate alerts for this trap + pandora_evaluate_snmp_alerts ($pa_config, $trap_id, $source, $oid, $type, $oid, $value, $custom_oid, $dbh); } - - $self->SUPER::stop (); } ######################################################################################## @@ -328,14 +343,14 @@ sub matches_filter ($$$) { my $eval_result; # eval protects against server down (by invalid regular expressions) - $eval_result = eval { + $eval_result = eval { $string =~ m/$regexp/i ; }; - if ($eval_result) { - logger($pa_config, "Trap '$string' matches filter '$regexp'. Discarding...", 10); - return 1; - } + if ($eval_result) { + logger($pa_config, "Trap '$string' matches filter '$regexp'. Discarding...", 10); + return 1; + } } @@ -393,7 +408,7 @@ sub start_snmptrapd ($) { print_message ($config, " [E] Could not start snmptrapd.", 1); return 1; } - + return 0; } @@ -403,7 +418,10 @@ sub start_snmptrapd ($) { sub DESTROY { my $self = shift; - $RUN = 0; + if ($self->{'snmp_trapd'} ne 'manual') { + system ("kill -9 `cat /var/run/pandora_snmptrapd.pid 2>$DEVNULL`"); + unlink ('/var/run/pandora_snmptrapd.pid'); + } } 1;