diff --git a/src/traps/snmptrapd.conf b/src/traps/conf/snmptrapd.conf similarity index 95% rename from src/traps/snmptrapd.conf rename to src/traps/conf/snmptrapd.conf index 351a86b1c..fc8045e4f 100644 --- a/src/traps/snmptrapd.conf +++ b/src/traps/conf/snmptrapd.conf @@ -20,7 +20,7 @@ # # arguments: oid|"default" program args -traphandle default /usr/sbin/snmptt --ini=/etc/snmp/oreon_traps/snmptt.ini +traphandle default /usr/sbin/snmptt --ini=@SNMPTT_INI_FILE@ diff --git a/src/traps/conf/snmptt b/src/traps/conf/snmptt new file mode 100644 index 000000000..ba91e21b8 --- /dev/null +++ b/src/traps/conf/snmptt @@ -0,0 +1,5855 @@ +#!/usr/bin/perl +# +# SNMPTT v1.2beta3 +# +# Copyright 2002-2007 Alex Burger +# alex_b@users.sourceforge.net +# 4/11/2002 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +############################################################################## +# +# http://www.sourceforge.net/projects/snmptt +# +# This script is a snmp trap handler for use with the NET-SNMP / UCD-SNMP +# snmptrapd program. +# +# The script is called by defining a 'traphandle' in snmptrapd.conf. +# For example: +# +# traphandle default /sbin/snmptt +# +# SNMPTRAPD feeds details about the trap to the launched program's standard +# input in the following format (see snmptrapd.conf man page for a complete +# descriptipon) +# +# HOSTNAME: The name of the host in question that sent the trap +# IPADDRESS: The IP address of the host that sent the trap +# VARBINDS: A list of variable bindings that describe the trap and +# the variables enclosed in it. +# +# See the SNMPTT documentation (readme.html) for more information. +# +############################################################################## +# +use strict; + +my $snmptt_version = "v1.2beta3"; + +sub showversion +{ + print "\nSNMPTT $snmptt_version\n"; + print "(c) 2002-2007 Alex Burger\n"; + print "http://snmptt.sourceforge.net\n\n"; +} + +############################################################################## +# Process command line arguments + +use Getopt::Long; + +my $version = 0; +my $daemon = 0; +my $debug = 0; +my $debugfile = ''; +my $dump = 0; +my $help = 0; +my $time = 0; +my $ini = ''; + +GetOptions ('version' => \$version, + 'daemon' => \$daemon, + 'debug:i' => \$debug, + 'debugfile=s' => \$debugfile, + 'dump' => \$dump, + 'help' => \$help, + 'ini=s' => \$ini, + 'time' => \$time); + +if ($version == 1) +{ + &showversion; + exit(0); +} + +if ($help == 1) +{ +my $USAGE = qq/Usage: + snmptt [] +Options: + --daemon Run as a daemon + --debug=n Set debug level (1 or 2) + --debugfile=filename Set debug output file + --dump Dump (display) defined traps + --help Display this message + --ini=filename Set configuration file to load + --version Display author and version information + --time Use to see how long it takes to load and + process trap file (eg: time snmptt --time) +/; + + &showversion; + print $USAGE; + + exit(0); +} + +my $DEBUGGING; +my $debugcmdline; +my $daemoncmdline; +my $DEBUGGING_FILE; +my $debugfilecmdline; + +if ($debug >= 1) +{ + $DEBUGGING = $debug; + $debugcmdline = 1; +} +else +{ + $DEBUGGING = 0; + $debugcmdline = 0; +} + +if ($daemon == 1) +{ + # $daemon = 1; + $daemoncmdline = 1; +} +else +{ + $daemoncmdline = 0; +} + +if ($dump ==1) +{ + $DEBUGGING = 2; + $debugcmdline = 1; + &findsnmpttini; + &loadsnmpttini; + &loadsnmpttconf; # Load SNMPTT.CONF file + print ("\n\n"); + exit(0); +} + +if ($time ==1) +{ + &findsnmpttini; + &loadsnmpttini; + &loadsnmpttconf; # Load SNMPTT.CONF file + exit(0); +} + +if ($debugfile ne '') +{ + $DEBUGGING_FILE = $debugfile; # commandline overpowers snmptt script + $debugfilecmdline = 1; +} +else +{ + $debugfilecmdline = 0; +} + +# Global config file variables +my $snmptt_system_name; +my $daemon; +my $multiple_event; +my $dns_enable; +my $strip_domain; +my @strip_domain_list; +my $net_snmp_perl_enable; +my $net_snmp_perl_best_guess; +my $translate_log_trap_oid; +my $translate_value_oids; +my $resolve_value_ip_addresses; +my $translate_enterprise_oid_format; +my $translate_trap_oid_format; +my $translate_varname_oid_format; +my $translate_integers; +my $wildcard_expansion_separator; +my $mibs_environment; +my $allow_unsafe_regex; +my $remove_backslash_from_quotes; +my $dynamic_nodes; +my $description_mode; +my $description_clean; +my $threads_enable; +my $threads_max; +my $date_format; +my $time_format; +my $date_time_format; +my $date_time_format_sql; +my $stat_time_format_sql; + +# DaemonMode +my $daemon_fork; +my $daemon_uid; +my $pid_file; +my $spool_directory; +my $sleep; +my $use_trap_time; +my $keep_unlogged_traps; + +# Logging +my $stdout_enable; +my $log_enable; +my $log_file; +my $log_system_enable; +my $log_system_file; +my $unknown_trap_log_enable; +my $unknown_trap_log_file; +my $statistics_interval; +my $syslog_enable; +my $syslog_facility; +my @syslog_level_alert; +my @syslog_level_crit; +my @syslog_level_err; +my @syslog_level_warning; +my @syslog_level_notice; +my @syslog_level_info; +my @syslog_level_debug; +my $syslog_level; +my $syslog_system_enable; +my $syslog_system_facility; +my $syslog_system_level; +my $eventlog_enable; +my @eventlog_type_information; +my @eventlog_type_warning; +my @eventlog_type_error; +my $eventlog_type; +my $eventlog_system_enable; + +# Exec +my $exec_enable; +my $pre_exec_enable; +my $unknown_trap_exec; +my $unknown_trap_exec_format; +my $exec_escape; + +# SQL +my $db_translate_enterprise; +my $db_unknown_trap_format; +my $mysql_dbi_enable; +my $mysql_dbi_host; +my $mysql_dbi_port; +my $mysql_dbi_database; +my $mysql_dbi_table; +my $mysql_dbi_table_unknown; +my $mysql_dbi_table_statistics; +my $mysql_dbi_username; +my $mysql_dbi_password; +my $mysql_ping_on_insert; +my $mysql_ping_interval; + +my $postgresql_dbi_enable; +my $postgresql_dbi_module; +my $postgresql_dbi_hostport_enable; +my $postgresql_dbi_host; +my $postgresql_dbi_port; +my $postgresql_dbi_database; +my $postgresql_dbi_table; +my $postgresql_dbi_table_unknown; +my $postgresql_dbi_table_statistics; +my $postgresql_dbi_username; +my $postgresql_dbi_password; +my $postgresql_ping_on_insert; +my $postgresql_ping_interval; + +my $dbd_odbc_enable; +my $dbd_odbc_dsn; +my $dbd_odbc_table; +my $dbd_odbc_table_unknown; +my $dbd_odbc_table_statistics; +my $dbd_odbc_username; +my $dbd_odbc_password; +my $dbd_odbc_ping_on_insert; +my $dbd_odbc_ping_interval; + +my $sql_win32_odbc_enable; +my $sql_win32_odbc_dsn; +my $sql_win32_odbc_table; +my $sql_win32_odbc_table_unknown; +my $sql_win32_odbc_table_statistics; +my $sql_win32_odbc_username; +my $sql_win32_odbc_password; + +my @sql_custom_columns; +my @sql_custom_columns_unknown; + +# TrapFiles +my @snmptt_conf_files; + +############################################################################## +# +# Load config file +# + +&findsnmpttini; +&loadsnmpttini; + +############################################################################## + +use Text::ParseWords; +use POSIX qw(strftime); +use Sys::Hostname; +use File::Basename; + +my $debug_file_used = 0; + +my $g_start_time = time(); + +my $debug_file_open_error = 1; +if ($DEBUGGING >= 1) +{ + if ($DEBUGGING_FILE ne '') + { + if (open DEBUGFILE, ">>$DEBUGGING_FILE") + { + select DEBUGFILE; # change default output to debug file + $debug_file_used = 1; + $debug_file_open_error = 0; + } + else + { + warn "could not open debug output file ($!)"; + } + } + + # print out time + print "********** SNMPTT $snmptt_version started: ",scalar(localtime($g_start_time))," **********\n\n" +} + +if ($threads_enable == 1) +{ + eval 'require threads;'; + if ($@) { + warn $@; + print "\nThreads have been enabled but the threads module is not available. To\n"; + print "enable threads you need the threads module (part of ithreads,not Threads).\n"; + print "This is only available in Perl 5.6.0 and higher.\n"; + die "died"; + } + require threads; + + eval 'require Thread::Semaphore;'; + if ($@) { + warn $@; + print "\nThreads have been enabled but the Thread module is not available.\n"; + die "died"; + } + require Thread::Semaphore; +} + + +if ($syslog_enable == 1 || $syslog_system_enable == 1) +{ + eval 'require Sys::Syslog;'; + if ($@) { + warn $@; + print "\nCould not load Perl module Sys::Syslog! If syslog_system_enable or\n"; + print "syslog_enable is enabled then the Sys::Syslog module is required. Please\n"; + print "see snmptt.html for system requirements.\n\n"; + die "died"; + } + require Sys::Syslog; +} + + +# Win32 constants not available when using 'require' (!) +my $eventlog_error = 1; # EVENTLOG_ERROR_TYPE +my $eventlog_warning = 2; # EVENTLOG_WARNING_TYPE +my $eventlog_information = 4; # EVENTLOG_INFORMATION_TYPE + +if ($eventlog_system_enable == 1 || $eventlog_enable == 1) +{ + eval 'require Win32::EventLog;'; + if ($@) { + warn $@; + print "\nCould not load Perl module Win32::EventLog! If eventlog_system_enable or\n"; + print "eventlog_enable is enabled, then the Win32::EventLog module is required. \n"; + print "Please see snmptt.html for system requirements.\n\n"; + die "died"; + } + require Win32::EventLog; +} + + +if ($syslog_system_enable == 1 && $daemon == 1) +{ + syslog_system("SNMPTT $snmptt_version started"); + if ($debug_file_open_error == 1) { + syslog_system("Could not open debug output file!"); + } +} +if ($log_system_enable == 1 && $daemon == 1) +{ + log_system("SNMPTT $snmptt_version started"); + if ($debug_file_open_error == 1) { + log_system("Could not open debug output file!"); + } +} + +if ($eventlog_system_enable == 1 && $daemon == 1) +{ + eventlog_system("SNMPTT $snmptt_version started",0,$eventlog_information); + if ($debug_file_open_error == 1) { + eventlog_system("Could not open debug output file!",14,$eventlog_warning); + } +} + +if ($net_snmp_perl_enable == 1) +{ + eval 'require SNMP;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module SNMP! If net_snmp_perl_enable is\n"; + print "enabled then the SNMP module is required. Please see snmptt.html\n"; + print "for system requirements. Note: SNMPTT uses the Net-SNMP package's\n"; + print "SNMP module, NOT the CPAN Net::SNMP module!\n\n"; + die "died"; + } + require SNMP; + if (defined ($mibs_environment)) + { + $ENV{'MIBS'} = $mibs_environment; + } + my $noperlwarning; + if ($description_mode == 2) { + $SNMP::save_descriptions = 1; + } + &SNMP::initMib(); + + $SNMP::best_guess = $net_snmp_perl_best_guess; + $noperlwarning = $SNMP::best_guess; # Just to get rid of the Perl warning that var used only once + + $SNMP::use_long_names = 0; # Set to 0, otherwise getType may fail when using a long name on 4.2.x + $noperlwarning = $SNMP::use_long_names; # Just to get rid of the Perl warning that var used only once + + if ($DEBUGGING >= 1) + { + print "********** Net-SNMP version $SNMP::VERSION Perl module enabled **********\n\n"; + if (defined ($mibs_environment)) + { + print "********** MIBS: $mibs_environment **********\n\n"; + } + } +} + +if ($dns_enable == 1) +{ + eval 'require Socket;'; + if ($@) { + warn $@; + print "\nCould not load the Net-SNMP Perl module Socket! If dns_enable\n"; + print "is enabled then the Socket module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require Socket; + if ($DEBUGGING >= 1) + { + print "********** DNS enabled **********\n\n"; + } +} + +if ($mysql_dbi_enable == 1) +{ + eval 'require DBI;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module DBI! If mysql_dbi_enable\n"; + print "is enabled then the DBI module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require DBI; + + eval 'require DBD::mysql;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module DBD::mysql! If mysql_dbi_enable\n"; + print "is enabled then the DBD::mysql module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require DBD::mysql; +} + +if ($postgresql_dbi_enable == 1) +{ + eval 'require DBI;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module DBI! If postgresql_dbi_enable\n"; + print "is enabled then the DBI module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require DBI; + + if ($postgresql_dbi_module == 0) + { + eval 'require DBD::PgPP;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module DBD::PgPP! If postgresql_dbi_module\n"; + print "is set to 0 then the DBD::PgPP module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require DBD::PgPP; + } + else + { + eval 'require DBD::Pg;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module DBD::Pg! If postgresql_dbi_module\n"; + print "is set to 1 then the DBD::Pg module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require DBD::Pg; + } +} + +if ($dbd_odbc_enable == 1) +{ + eval 'require DBI;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module DBI! If dbd_odbc_enable\n"; + print "is enabled then the DBI module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require DBI; + + eval 'require DBD::ODBC;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module DBD::ODBC! If dbd_odbc_enable\n"; + print "is enabled then the DBD::ODBC module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require DBD::ODBC; +} + +if ($sql_win32_odbc_enable == 1) +{ + eval 'require Win32::ODBC;'; + if ($@) { + warn $@; + print "\nCould not load the Perl module Win32::ODBC! If sql_win32_odbc_enable\n"; + print "is enabled then the Win32::ODBC module is required. Please see snmptt.html\n"; + print "for system requirements.\n\n"; + die "died"; + } + require Win32::ODBC; +} + + +############################################################################## +#### MAIN SECTION START + +# Global variables +my %event; # Holds EVENT entries from all .conf files +my $receivedtrap_entry; # Trap received - stored by readtrap() +my $input; # For reading in trap from spool folder or STDIN +my @event2; # Copy of the matched event +my @var; # Variables of trap received by SNMPTRAPD +my @entvar; # Enterprise variable values of trap received by SNMPTRAPD +my @entvarname; # Enterprise variable names of trap received by SNMPTRAPD +my @preexec_var; # PREXEC results +my $receivedtrap; # Received trap +my $receivedtrap_trans; # Translated version of received trap +my $enterprise_trans; # Translated enterprise of received trap +my $agent_dns_name; # DNS name of trap received +my $processed; # Whether or not the trap was processed (found) to determine + # if it should search using wildcards and log to unknown +my $trap_attempted_to_log; # To keep track of whether or not we attempted to log the trap +my $trap_date_time; # Date and time of the trap. Used for log files. +my $trap_date_time_sql; # Date and time of the trap. Used for SQL. +my $trap_successfully_logged; # To keep track of whether or not we successfully logged the trap + # so we know if we should delete the trap file +my $db_enterprise; +my $trap_date; # Date of trap +my $trap_time; # Time of trap +my $trap_date_time_epoch; # Date / time of trap +my $configfile; # .ini file to use + +my $thread_exec_semaphore; # Semaphore for EXEC + +# Global variables for statistics +my $g_total_traps_received = 0; +my $g_total_traps_translated = 0; +my $g_total_traps_ignored = 0; +my $g_total_traps_unknown = 0; +my $g_last_statistics_logged = $g_start_time; + +# Global variables for SQL +my $dbh_mysql; +my $dbh_postgresql; +my $dbh_odbc; +my $dbh_win32_odbc; + +# Global variables for SQL ping +my $g_last_mysql_ping = $g_start_time; +my $g_last_postgresql_ping = $g_start_time; +my $g_last_dbd_odbc_ping = $g_start_time; + +# Global variables for daemon mode +my $timetoreload; +my $timetodie; +my $timetologstatistics; + +if ($daemon == 1) +{ + # Check for old pid file. + my $pid_file_set = 0; + if ($pid_file eq '') { + $pid_file = '/var/run/snmptt.pid'; + } + else { + $pid_file_set = 1; + } + + print STDOUT "$pid_file\n"; + if (-e $pid_file) { + open(OLDPID, "<$pid_file"); + my $old_pid = ; + chomp $old_pid; + close OLDPID; + + warn("There seems to be another SNMPTT process (pid $old_pid) running.\n"); + warn("You may want to kill it and delete the .pid file ($pid_file). Aborting...\n"); + if ($syslog_system_enable == 1) { + syslog_system("There seems to be another SNMPTT process (pid $old_pid) running."); + syslog_system("You may want to kill it and delete the .pid file ($pid_file). Aborting..."); + } + if ($log_system_enable == 1) { + log_system("There seems to be another SNMPTT process (pid $old_pid) running."); + log_system("You may want to kill it and delete the .pid file ($pid_file). Aborting..."); + } + die; + } + + # Check to make sure we can create the .pid file if it was set by the user. + # If the user didn't set it, then we don't really care. + if ($pid_file_set) { + if (! (-w dirname($pid_file))) { + warn("pid file \'$pid_file\' is not writable. Aborting..."); + + if ($syslog_system_enable == 1) { + syslog_system("pid file \'$pid_file\' is not writable. Aborting..."); + } + if ($log_system_enable == 1) { + log_system("pid file \'$pid_file\' is not writable. Aborting..."); + } + die; + } + } + + $SIG{HUP} = \&signal_handler_reload; + + $SIG{TERM} = \&signal_handler_die; + + $SIG{USR1} = \&signal_log_statistics; + + $timetoreload = 0; + $timetodie = 0; + $timetologstatistics = 0; + + &loadsnmpttconf; # Load SNMPTT.CONF file + + # Only fork to the background if not Win32 + if (($^O ne "MSWin32") && ($daemon_fork==1)) + { + use POSIX qw(setsid); + use POSIX qw(signal_h); + use POSIX ":sys_wait_h"; + use Cwd; + my $pid; + my $pid2; + + my $working_dir = cwd; + print "cwd: $working_dir\n"; + + chdir '/' + or die "Can't chdir to /: $!"; + open STDIN, '/dev/null' + or die "Can't read /dev/null: $!"; + open STDOUT, '>>/dev/null' + or die "Can't write to /dev/null: $!"; + open STDERR, '>>/dev/null' + or die "Can't write to /dev/null: $!"; + + # We fork so we can return back to the shell or whatever started snmptt + defined($pid = fork) + or die "Can't fork: $!"; + + # fork returns: child pid to the parent, 0 to the child, undef if it failed. + + # We write PID using the uid of the user that started snmptt. + if ($pid) # This is run in the parent process + { + if (open(PID, ">$pid_file") ) { + print(PID "$pid\n"); + close(PID); + } + else { + $pid_file = "$working_dir/snmptt.pid"; + + if (open(PID, ">$pid_file") ) + { + print(PID "$pid\n"); + close(PID); + } + } + + exit; + } + + POSIX:setsid + or die "Can't start a new session: $!"; + umask 0; + + # We fork again so there are two processes. The first which is run using the uid + # of the user that started snmptt, and the second which is run as the user as + # defined by daemon_uid in snmptt.ini. We do this so we can sit and wait for the + # child to finish so we can clean up the snmptt.pid file. + # We only need to do this if daemon_uid is set.. + if ($^O ne "MSWin32" && $daemon_uid ne '') { + defined($pid2 = fork) + or die "Can't fork: $!"; + + if ($pid2) # This is run in the parent process + { + $SIG{TERM} = \&signal_handler_die; # new signal for parent + + while (1) { + if ($timetodie == 1 || waitpid($pid2, WNOHANG) != 0) { + kill SIGTERM, $pid2; + # Clean up snmptt.pid file + unlink($pid_file); + exit; + } + sleep 3; + } + } + + POSIX:setsid + or die "Can't start a new session: $!"; + umask 0; + } + } + + # Change user if not Windows, and daemon_uid ini parameter not blank + if ($^O ne "MSWin32" && $daemon_uid ne '') + { + my $daemon_uid_name = ''; + + if ($daemon_uid =~ /\D/) + { + # no numbers found, so assume it's a textual name + + $daemon_uid_name = $daemon_uid; + + $daemon_uid = getpwnam($daemon_uid_name); + if (!defined($daemon_uid)) + { + warn("Could not convert user id \'$daemon_uid_name\' to a numeric UID\n"); + + if ($syslog_system_enable == 1) { + syslog_system("Could not convert user id \'$daemon_uid_name\' to a numeric UID\n"); + } + if ($log_system_enable == 1) { + log_system("Could not convert user id \'$daemon_uid_name\' to a numeric UID\n"); + } + } + } + + # Change current uid to new_uid + if (defined($daemon_uid)) + { + if ($daemon_uid_name ne '') + { + if ($syslog_system_enable == 1) { + syslog_system("Changing to UID: $daemon_uid_name \($daemon_uid\)"); + } + if ($log_system_enable == 1) { + log_system("Changing to UID: $daemon_uid_name \($daemon_uid\)"); + } + + if ($DEBUGGING >= 1) + { + print "Changing to UID: $daemon_uid_name \($daemon_uid\)\n"; + } + } + else + { + if ($syslog_system_enable == 1) { + syslog_system("Changing to UID: $daemon_uid"); + } + if ($log_system_enable == 1) { + log_system("Changing to UID: $daemon_uid"); + } + + if ($DEBUGGING >= 1) + { + print "Changing to UID: $daemon_uid\n"; + } + } + + + if ($DEBUGGING >= 1) { + print DEBUGFILE "Closing debug file $DEBUGGING_FILE\n"; + } + # Close debug file (if it is open) before changing users and re-open after + close(DEBUGFILE); + + $> = $daemon_uid; + + $debug_file_open_error = 1; + # Re-open debug file (if needed) as the new user + if ($DEBUGGING >= 1) + { + if ($DEBUGGING_FILE ne '') + { + if (open DEBUGFILE, ">>$DEBUGGING_FILE") + { + select DEBUGFILE; # change default output to debug file + $debug_file_used = 1; + $debug_file_open_error = 0; + print "Debug file $DEBUGGING_FILE re-opened under uid $daemon_uid\n"; + warn "Debug file $DEBUGGING_FILE re-opened under uid $daemon_uid\n"; + } + else + { + warn "could not re-open debug output file ($!)"; + } + if ($syslog_system_enable == 1 && $daemon == 1) + { + if ($debug_file_open_error == 1) { + syslog_system("Could not re-open debug output file!"); + } + } + if ($log_system_enable == 1 && $daemon == 1) + { + if ($debug_file_open_error == 1) { + log_system("Could not re-open debug output file!"); + } + } + } + + if ($eventlog_system_enable == 1 && $daemon == 1){ + if ($debug_file_open_error == 1) { + eventlog_system("Could not re-open debug output file!",14,$eventlog_error); + } + } + } + } + } + + # Open connections to MySQL, PostresQL, ODBC etc + # (Do this after switch user IDs when daemon_uid is defined) + create_db_connections(); + + if ($threads_enable == 1) { + $thread_exec_semaphore = (); + $thread_exec_semaphore = Thread::Semaphore->new($threads_max); + } + + while (!$timetodie) + { + if (! (chdir($spool_directory))) + { + if ($DEBUGGING >= 1) + { + print "Unable to enter spool dir $spool_directory:$!\n"; + } + warn "Unable to enter spool dir $spool_directory:$!\n"; + + if ($syslog_system_enable == 1) + { + syslog_system("Unable to enter spool dir $spool_directory"); + } + if ($log_system_enable == 1) + { + log_system("Unable to enter spool dir $spool_directory"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Unable to enter spool dir $spool_directory",3,$eventlog_error); + } + } + elsif (! (opendir(DIR, "."))) + { + if ($DEBUGGING >= 1) + { + print "Unable to open $spool_directory:$!\n"; + } + warn "Unable to open spool dir $spool_directory:$!\n"; + + if ($syslog_system_enable == 1) + { + syslog_system("Unable to open spool dir $spool_directory"); + } + if ($log_system_enable == 1) + { + log_system("Unable to open spool dir $spool_directory"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Unable to open spool dir $spool_directory",4,$eventlog_error); + } + } + elsif (! (my @filenames = readdir(DIR))) + { + if ($DEBUGGING >= 1) + { + print "Unable to read spool dir $spool_directory:$!\n"; + } + warn "Unable to read spool dir $spool_directory:$!\n"; + + if ($syslog_system_enable == 1) + { + syslog_system("Unable to read spool dir $spool_directory"); + } + if ($log_system_enable == 1) + { + log_system("Unable to read spool dir $spool_directory"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Unable to read spool dir $spool_directory",5,$eventlog_error); + } + } + else + { + closedir(DIR); + + @filenames = sort (@filenames); # Sort list of filenames to ensure they + # are processed in the order they were + # received + + foreach my $file (@filenames) + { + next if ($file eq "."); + next if ($file eq ".."); + + if (lc($file) eq "!reload") + { + $timetoreload = 1; + unless (unlink($file)) + { + if ($DEBUGGING >= 1) + { + print "Unable to delete !reload file from spool dir:$!\n"; + } + warn "Unable to delete !reload file from spool dir:$!\n"; + + if ($syslog_system_enable == 1) + { + syslog_system("Unable to delete !reload file from spool dir"); + } + if ($log_system_enable == 1) + { + log_system("Unable to delete !reload file from spool dir"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Unable to delete !reload file from spool dir",20,$eventlog_error); + } + } + next; + } + + if (lc($file) eq "!statistics") + { + $timetologstatistics = 1; + unless (unlink($file)) + { + if ($DEBUGGING >= 1) + { + print "Unable to delete !statistics file from spool dir:$!\n"; + } + warn "Unable to delete !statistics file from spool dir:$!\n"; + + if ($syslog_system_enable == 1) + { + syslog_system("Unable to delete !statistics file from spool dir"); + } + if ($log_system_enable == 1) + { + log_system("Unable to delete !statistics file from spool dir"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Unable to delete !statistics file from spool dir",21,$eventlog_error); + } + } + next; + } + + if ($DEBUGGING >= 1) + { + print "Processing file: $file\n"; + } + + my $filesuccess = 1; + unless (open FILE, $spool_directory.$file) + { + if ($DEBUGGING >= 1) + { + print "Could not open trap file $spool_directory$file: ($!)\n"; + } + warn "Could not open trap file $spool_directory$file: ($!)\n"; + + if ($syslog_system_enable == 1) + { + syslog_system("Could not open trap file $spool_directory$file"); + } + if ($log_system_enable == 1) + { + log_system("Could not open trap file $spool_directory$file"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Could not open trap file $spool_directory$file",6,$eventlog_error); + } + + $filesuccess = 0; + } + + $input = 'FILE'; + + if (! (&readtrap())) { # Read trap from STDIN or file + print " Error processing trap file $file. Skipping...\n"; + next; + } + + &searchfortrap; # Search for trap snmptt.conf (array) + + close FILE; + + if ($filesuccess == 1) + { + if ($keep_unlogged_traps == 0 || $trap_successfully_logged == 1) + { + unless (unlink($file)) + { + if ($DEBUGGING >= 1) + { + print "Unable to delete trap file $file from spool dir:$!\n"; + } + warn "Unable to delete trap file $file from spool dir:$!\n"; + + if ($syslog_system_enable == 1) + { + syslog_system("Unable to delete trap file $file from spool dir"); + } + if ($log_system_enable == 1) + { + log_system("Unable to delete trap file $file from spool dir"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Unable to delete trap file $file from spool dir",7,$eventlog_error); + } + } + } + } + } + } + + if ($statistics_interval > 0) { + if (time() >= ($g_last_statistics_logged + $statistics_interval)) { + &log_statistics(); + } + } + + if ($mysql_dbi_enable == 1 && $mysql_ping_interval > 0) { + if (time() >= ($g_last_mysql_ping + $mysql_ping_interval)) { + &mysql_ping(); + } + } + + if ($postgresql_dbi_enable == 1 && $postgresql_ping_interval > 0) { + if (time() >= ($g_last_postgresql_ping + $postgresql_ping_interval)) { + &postgresql_ping(); + } + } + + if ($dbd_odbc_enable == 1 && $dbd_odbc_ping_interval > 0) { + if (time() >= ($g_last_dbd_odbc_ping + $dbd_odbc_ping_interval)) { + &dbd_odbc_ping(); + } + } + + if ($timetologstatistics == 1) + { + &log_statistics(); + + $timetologstatistics = 0; + } + + if ($DEBUGGING >= 1) + { + print "Sleeping for $sleep seconds\n\n"; + } + sleep $sleep; + + if ($timetoreload == 1) + { + if ($DEBUGGING >= 1) + { + print "Reloading configuration file\(s\)\n\n"; + } + + if ($syslog_system_enable == 1) + { + syslog_system("Reloading configuration file\(s\)"); + } + if ($log_system_enable == 1) + { + log_system("Reloading configuration file\(s\)"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Reloading configuration file\(s\)",8,$eventlog_information); + } + + &loadsnmpttini; # Load ini file + &loadsnmpttconf; # Load SNMPTT.CONF file + $timetoreload = 0; + } + } + + # If $daemon_uid was not set, clean up pid file here. Otherwise it's cleaned up + # when the child process is finished above. + if ($^O ne "MSWin32" && $daemon_uid eq '') { + # Clean up snmptt.pid file + unlink($pid_file); + } + + if ($DEBUGGING >= 1) + { + print "SNMPTT $snmptt_version shutdown: ",scalar(localtime),"\n\n"; + print "Total traps received: $g_total_traps_received\n"; + print "Total traps translated: $g_total_traps_translated\n"; + print "Total traps ignored: $g_total_traps_ignored\n"; + print "Total unknown traps: $g_total_traps_unknown\n\n"; + } + + if ($syslog_system_enable == 1 && $daemon == 1) + { + syslog_system("SNMPTT $snmptt_version shutdown"); + syslog_system("Total traps received=$g_total_traps_received,Total traps translated=$g_total_traps_translated,Total traps ignored=$g_total_traps_ignored,Total unknown traps=$g_total_traps_unknown"); + #syslog_system("Total traps received: $g_total_traps_received"); + #syslog_system("Total traps translated: $g_total_traps_translated"); + #syslog_system("Total traps ignored $g_total_traps_ignored"); + #syslog_system("Total unknown traps: $g_total_traps_unknown"); + } + if ($log_system_enable == 1 && $daemon == 1) + { + log_system("SNMPTT $snmptt_version shutdown"); + log_system("Total traps received=$g_total_traps_received,Total traps translated=$g_total_traps_translated,Total traps ignored=$g_total_traps_ignored,Total unknown traps=$g_total_traps_unknown"); + #syslog_system("Total traps received: $g_total_traps_received"); + #syslog_system("Total traps translated: $g_total_traps_translated"); + #syslog_system("Total traps ignored $g_total_traps_ignored"); + #syslog_system("Total unknown traps: $g_total_traps_unknown"); + } + if ($eventlog_system_enable == 1 && $daemon == 1) + { + my $message = "SNMPTT $snmptt_version shutdown\n\n" . \ + "Total traps received: $g_total_traps_received\n" . \ + "Total traps translated: $g_total_traps_translated\n" . \ + "Total traps ignored: $g_total_traps_ignored\n" . \ + "Total unknown traps: $g_total_traps_unknown\n"; + + eventlog_system($message,1,$eventlog_information); + } +} +else +{ + # NOT daemon mode... + + # Open connections to MySQL, PostresQL, ODBC etc + create_db_connections(); + + $input = 'STDIN'; + + &readtrap; # Read trap from STDIN or file + + &loadsnmpttconf; # Load SNMPTT.CONF file + + &searchfortrap; # Search for trap snmptt.conf (array) +} + +&close_db_connections(); + +exit(); + +#### MAIN SECTION END + +sub processtrap +{ + # Variables of trap received by SNMPTRAPD: + # + # $var[0] hostname + # $var[1] ip address + # $var[2] uptime + # $var[3] trapname / OID + # $var[4] ip address from trap agent + # $var[5] trap community string + # $var[6] enterprise + # + # $entvarname[0] passed variable name 1 + # $entvarname[1] passed variable name 2 + # + # $entvar[0] passed variable 1 + # $entvar[1] passed variable 2 + # . + # . + # etc.. + # + # $event hash for each trapped defined in snmptt.conf with following values: + # + # 0: name of trap + # 1: category + # 2: severity + # 3: FORMAT string + # 4: EXEC string + # 5: NODES string + # 6: REGEX array + # 7: MATCH array + # 8: DESC array + # 9: PREEXEC string + # + # Example: To access FORMAT string for received trap: + # $event{"$var[3]"}[3] + # + # or + # + # $event{"$receivedtrap_entry"}[3] + ############################################################################### + # if no nodes list, then $hostmatch = 1 so trap is logged etc, otherwise it is not + + my $l = 1; # Start with first event entry + + my $multiple_event_passes = 0; # This variable increases each time we match an EVENT. + # Below, if =1, then abort because we already found a match for + # this trap. This would only happen if you have a trap + # defined multiple times in the config file to allow + # different machines to have different actions based on + # the node name. + + while (defined($event{$receivedtrap_entry}[$l+1])) + { + if (($multiple_event == 0) && ($multiple_event_passes > 0)) + { + if ($DEBUGGING >= 1) + { + print " multiple_event = $multiple_event, multiple_event_passes = " . + "$multiple_event_passes so don't process any more entries\n"; + } + last; # Don't look any further - stop + } + if ($DEBUGGING >= 1) + { + print "Working with EVENT entry: $receivedtrap_entry => $event{$receivedtrap_entry}[0+$l],$event{$receivedtrap_entry}[1+$l],$event{$receivedtrap_entry}[2+$l],$event{$receivedtrap_entry}[5+$l]\n"; + } + + my $hostmatch = 0; + my $nodesmatch = 0; # Match from NODES + my $match_found = 0; # Match from MATCH + + # $event is the hash of events defined in the config file + # $event2 is a copy of the matching event + + # Flush out @event2 + @event2 = (); + + # Flush out @nodes + #@nodes = (); + my @nodes2 = (); + + # $event2[0]=$event{"$receivedtrap_entry"}[0]; # 0: name of trap + # $event2[1]=$event{"$receivedtrap_entry"}[1]; # 1: category + # $event2[2]=$event{"$receivedtrap_entry"}[2]; # 2: severity + # $event2[3]=$event{"$receivedtrap_entry"}[3]; # 3: FORMAT string + # $event2[4]=$event{"$receivedtrap_entry"}[4]; # 4: EXEC string + # $event2[5]=$event{"$receivedtrap_entry"}[5]; # 5: NODES string + + $event2[0]=$event{"$receivedtrap_entry"}[0+$l]; # 0: name of trap + $event2[1]=$event{"$receivedtrap_entry"}[1+$l]; # 1: category + $event2[2]=$event{"$receivedtrap_entry"}[2+$l]; # 2: severity + $event2[3]=$event{"$receivedtrap_entry"}[3+$l]; # 3: FORMAT string + $event2[4]=$event{"$receivedtrap_entry"}[4+$l]; # 4: EXEC string + $event2[5]=$event{"$receivedtrap_entry"}[5+$l]; # 5: NODES string + $event2[6]=$event{"$receivedtrap_entry"}[6+$l]; # 6: REGEX array + $event2[7]=$event{"$receivedtrap_entry"}[7+$l]; # 7: MATCH array + $event2[8]=$event{"$receivedtrap_entry"}[8+$l]; # 8: DESC array + $event2[9]=$event{"$receivedtrap_entry"}[9+$l]; # 9: PREEXEC array + + $l+=11; # Also update in 'Printing out all the events in hash table' + + if ($event2[5] eq '') + { + $nodesmatch = 1; + #$hostmatch = 1; # No nodes defined, so default to all nodes + #$multiple_event_passes++; + #$processed = 1; + if ($DEBUGGING >= 1) + { + print " No nodes defined for this entry so all nodes will match\n"; + } + } + else + { + if ($DEBUGGING >= 1) + { + print " Nodes defined for this entry...\n"; + } + + if ($dynamic_nodes == 0) { + @nodes2 = split /\s/, $event2[5]; + } + else { + @nodes2 = &process_nodes($event2[5]); + } + + if ($DEBUGGING >= 1) + { + print " NODES entries: @nodes2\n"; + } + + my $nodes_mode = 'pos'; # 0 = POSitive match + # nodes2 contains all the node entries after being 'extracted' from multiple + # NODES lines, NODES files etc. + foreach my $a (@nodes2) + { + # Check for MODE statement. Default is POSitive. + if ($a =~ /^mode=(.*)/i) { + if ($1 =~ /^neg/i) { + $nodes_mode = "neg"; + } + next; + } + elsif ($a =~ /^(\d+\.\d+\.\d+\.\d+)/) # NODES entry is an IP address / cidr / range + { + #if ( $a eq $var[1]) # compare against agent ip + if ( checkip($var[4], $a) == 1) + { + $nodesmatch = 1; + } + } + elsif ($dns_enable == 1) # Resolve NODES entry to IP address, and compare + { + my $temp = gethostbyname($a); + if (defined($temp)) + { + $temp = Socket::inet_ntoa(scalar($temp)); + if ($DEBUGGING => 1) + { + print " NODES entry ($a) resolved to: $temp\n"; + } + if ( checkip($var[4], $temp) == 1) + { + $nodesmatch = 1; + } + } + else + { + print " NODES entry ($a) could NOT be resolved.\n"; + } + } + elsif (lc $a eq lc $agent_dns_name) # NODES entry is a host name. Do lowercase compare + { + $nodesmatch = 1; + } + } + + # If NODES MODE=NEG, then reverse the result. + if ($nodes_mode eq 'neg') { + if ($nodesmatch == 0) { + $nodesmatch = 1; + } + else { + $nodesmatch = 0; + } + } + if ($DEBUGGING >= 1) + { + if ($nodesmatch == 1) + { + print " NODES has a positive match (node mode \'$nodes_mode\' and node found in list)\n"; + } + else + { + print " NODES has a negative match (node mode \'$nodes_mode\' and node NOT found in list)\n"; + } + } + } + + # Check for MATCH entries + if ($nodesmatch == 1 && defined($event2[7][0])) # Only if NODES has matched and + { # we have some MATCH statements + my @match = (); + my $match_type; + + for (my $i=0; defined($event2[7][$i]); $i++) + { + my $match_temp = $event2[7][$i]; + $match_temp =~ s/\s//g; # Remove any white space from $match + if ($match_temp =~ /^mode=(.*)/i) + { + $match_type = lc($1); + last; + } + } + if ($match_type ne 'and' && $match_type ne 'or') + { + $match_type = 'or'; + } + if ($DEBUGGING >= 2) + { + print " MATCH statements found\n"; + print " MATCH mode: " . uc($match_type) . "\n"; + } + + for (my $i=0; defined($event2[7][$i]); $i++) + { + my $match_temp = $event2[7][$i]; + + # If it's a regex (has ()) then remove white space before and after ()s. + # Otherwise, remove all white space + #print "!$match_temp!\n"; + if ($match_temp =~ /\(|\)/) + { + $match_temp =~ s/\s*(\(.*\))\s*/$1/g; # Remove any white space from before and after ()'s + + $match_temp =~ s/\)\s*(i)\s*/\)$1/g; # Remove any white space from before and after i modifier + # if there is one + + $match_temp =~ s/\s*(\!.*)/$1/g; # Remvoe any white space in front of the ! if there is one + } + else + { + $match_temp =~ s/\s//g; # Remove any white space from $match + } + #print "!$match_temp!\n"; + + # DEFAULT= line + if ($match_temp =~ /^mode=(.*)/i) + { + next; + } + + if (match($match_temp) == 1) + { + $match_found = 1; + if ($match_type eq "or") + { + last; + } + } + else + { + $match_found = 0; + if (lc($match_type) eq "and") + { + last; + } + } + } + if ($DEBUGGING >= 1) + { + if ($match_found == 1) + { + print " MATCH statement(s) final result = true...\n\n"; + } + else + { + print " MATCH statement(s) final result = false...\n\n"; + } + } + } + else + { + if ($DEBUGGING >= 1) + { + print " No MATCH entries defined for this entry\n"; + } + $match_found = 1; # Default to match_found if no MATCH entries + } + + if ($nodesmatch == 1 && $match_found == 1) + { + $multiple_event_passes++; + $hostmatch = 1; + $processed = 1; + } + + my $message_short; + my $message; + if ($hostmatch == 1 && $event2[1] ne "IGNORE") + { + $message_short = ""; + + # Trap received exists in our list of trap definitions + + # Statistics + $g_total_traps_translated++; + + + # + # Variable substitution for PREEXEC string + # + + if ($DEBUGGING >= 1) + { + print "\nTrap defined, processing...\n\n"; + print "\n\nPREEXEC line(s):\n"; + } + + if (defined ($event2[9][0])) # if PREEXEC string has been defined + { + print "PREEXEC defined\n"; + if (defined ($event2[9][0])) + { + for (my $i=0; defined($event2[9][$i]); $i++) + { + $_ = $event2[9][$i]; + + print "Performing substitution on PREEXEC line: $_\n"; + &substitute(); + print "Done performing substitution on PREEXEC line: $_\n"; + + my $command = $_; + + if ($pre_exec_enable == 1) + { + if ($DEBUGGING >= 1) + { + print "PREEXEC command: $command\n"; + } + # Execute command + + if ($exec_escape == 1) { + # Escape wildcard characters + $command =~ s/\*/\\\*/g; + $command =~ s/\?/\\\?/g; + } + my $result = `$command`; + chomp $result; + # Remove spaces before and after + $result =~ /^\s*(.*?)\s*$/; + $result = $1; + + if ($result eq '') { + $result = "(no output from PREEXEC)\n"; + } + print " command output: $result\n"; + push (@preexec_var, $result); + } + } + } + else + { + if ($DEBUGGING >= 1) + { + print " PREEXEC line not defined\n"; + } + } + } + + if ($DEBUGGING >= 1) + { + print "\n\nFORMAT line:\n"; + } + + # + # Variable substitution for FORMAT string + # + + if ($event2[3] ne '') # if FORMAT string has been defined + { + # Variable substitution for FORMAT string + + $_ = $event2[3]; # FORMAT string + + # Translate if enabled, and if we can + $receivedtrap_trans = &translate_log_trap_oid_sub($receivedtrap); + + $enterprise_trans = &translate_enterprise_oid_format_sub($var[6]); + + &substitute; + + $message_short = $_; + + $message = "$receivedtrap_trans $event2[2] \"$event2[1]\" $agent_dns_name - $message_short\n"; + + if ($stdout_enable == 1) + { + #select STDOUT; + print STDOUT "$message"; + + #if ($debug_file_used == 1) + #{ + # select DEBUGFILE; + #} + } + + if ($DEBUGGING >= 1) + { + print "$message_short\n"; + print "\n$message"; + } + + if ($log_enable == 1) + { + $trap_attempted_to_log++; + + if (open LOGFILE, ">>$log_file") + { + print LOGFILE $trap_date_time." $message"; + close LOGFILE; + $trap_successfully_logged++; + } + else + { + warn "Can not open log file $log_file: $!"; + + if ($syslog_system_enable == 1) + { + syslog_system("Can not open log file $log_file"); + } + if ($log_system_enable == 1) + { + log_system("Can not open log file $log_file"); + } + if ($eventlog_system_enable == 1) + { + eventlog_system("Can not open log file $log_file",14,$eventlog_error); + } + } + } + + if ($syslog_enable == 1) + { + $trap_attempted_to_log++; + + my $syslog_level_temp = 99; + my $temp; + + foreach $temp (@syslog_level_debug) + { + if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'debug' } + } + foreach $temp (@syslog_level_info) + { + if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'info' } + } + foreach $temp (@syslog_level_notice) + { + if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'notice' } + } + foreach $temp (@syslog_level_warning) + { + if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'warning' } + } + foreach $temp (@syslog_level_err) + { + if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'err' } + } + foreach $temp (@syslog_level_crit) + { + if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'crit' } + } + foreach $temp (@syslog_level_alert) + { + if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'alert' } + } + + if ($syslog_level_temp == 99) + { + $syslog_level_temp = $syslog_level; + } + + #if (Sys::Syslog::openlog('TRAPD', '',$syslog_facility) ) + if (Sys::Syslog::openlog('snmptt[' . $> . ']', '',$syslog_facility) ) + { + Sys::Syslog::syslog ($syslog_level_temp, $message,1); + Sys::Syslog::closelog(); + $trap_successfully_logged++; + } + else + { + warn "Can not open log_file: $!"; + } + } + + if ($eventlog_enable == 1) + { + $trap_attempted_to_log++; + + my $eventlog_type_temp = 99; + my $temp; + + foreach $temp (@eventlog_type_information) + { + if (lc($event2[2]) eq lc($temp)) { $eventlog_type_temp = $eventlog_information } + } + + foreach $temp (@eventlog_type_warning) + { + if (lc($event2[2]) eq lc($temp)) { $eventlog_type_temp = $eventlog_warning } + } + + foreach $temp (@eventlog_type_error) + { + if (lc($event2[2]) eq lc($temp)) { $eventlog_type_temp = $eventlog_error } + } + + if ($eventlog_type_temp == 99) + # Use the default eventlog type + { + if ($eventlog_type =~ /INFORMATION/s) + { + if (eventlog_system($message,2,$eventlog_information) == 0) + { + $trap_successfully_logged++; + } + } + elsif ($eventlog_type =~ /ERROR/s) + { + if (eventlog_system($message,2,$eventlog_error) == 0) + { + $trap_successfully_logged++; + } + } + else + { + if (eventlog_system($message,2,$eventlog_warning) == 0) + { + $trap_successfully_logged++; + } + } + } + else + { + if (eventlog_system($message,2,$eventlog_type_temp) == 0) + { + $trap_successfully_logged++; + } + } + } + + if ($net_snmp_perl_enable == 1 && $db_translate_enterprise == 1) + { + $db_enterprise = $enterprise_trans; + } + else + { + $db_enterprise = $var[6]; + } + + if ($mysql_dbi_enable == 1) + { + $trap_attempted_to_log++; + + # Backslash any quotes + my $message_short2 = $message_short; + $message_short2 =~ s(\')(\\\')g; #' + $message_short2 =~ s(\")(\\\")g; #" + + my $community = $var[5]; + $community =~ s(\')(\\\')g; #' + $community =~ s(\")(\\\")g; #" + + my @t_sql_custom_columns = (); + + if (@sql_custom_columns) { + @t_sql_custom_columns = @sql_custom_columns; + + for (my $i = 1; $i <= $#t_sql_custom_columns; $i+=2) { + $_ = $t_sql_custom_columns[$i]; + print "Performing substitution on custom column: $_\n"; + &substitute(); + print "Done performing substitution on custom column: $_\n"; + $t_sql_custom_columns[$i] = $_; + } + } + + if (&mysql_insert($mysql_dbi_table, + "eventname", $event2[0], # $N + "eventid", $receivedtrap_entry, # $i + "trapoid", $receivedtrap_trans, # $O + "enterprise", $db_enterprise, # $E or $e depending on $db_translate_enterprise + "community", $community, # $C + "hostname", $agent_dns_name, # $A + "agentip", $var[4], # $aA + "category", $event2[1], # $c + "severity", $event2[2], # $s + "uptime", $var[2], # $T + "traptime", $trap_date_time_sql, + "formatline", $message_short2, + @t_sql_custom_columns) == 1 ) { # + $trap_successfully_logged++; + } + } + + if ($postgresql_dbi_enable == 1) + { + $trap_attempted_to_log++; + + # Backslash any quotes + my $message_short2 = $message_short; + $message_short2 =~ s(\')(\\\')g; #' + $message_short2 =~ s(\")(\\\")g; #" + + my $community = $var[5]; + $community =~ s(\')(\\\')g; #' + $community =~ s(\")(\\\")g; #" + + my @t_sql_custom_columns = (); + + if (@sql_custom_columns) { + @t_sql_custom_columns = @sql_custom_columns; + + for (my $i = 1; $i <= $#t_sql_custom_columns; $i+=2) { + $_ = $t_sql_custom_columns[$i]; + print "Performing substitution on custom column: $_\n"; + &substitute(); + print "Done performing substitution on custom column: $_\n"; + $t_sql_custom_columns[$i] = $_; + } + } + + if (&postgresql_insert($postgresql_dbi_table, + "eventname", $event2[0], # $N + "eventid", $receivedtrap_entry, # $i + "trapoid", $receivedtrap_trans, # $O + "enterprise", $db_enterprise, # $E or $e depending on $db_translate_enterprise + "community", $community, # $C + "hostname", $agent_dns_name, # $A + "agentip", $var[4], # $aA + "category", $event2[1], # $c + "severity", $event2[2], # $s + "uptime", $var[2], # $T + "traptime", $trap_date_time_sql, + "formatline", $message_short2, + @t_sql_custom_columns) == 1 ) { # + $trap_successfully_logged++; + } + } + + if ($dbd_odbc_enable == 1) + { + $trap_attempted_to_log++; + + # Double any single quotes + my $message_short2 = $message_short; + $message_short2 =~ s(\')('')g; #' + + my $community = $var[5]; + $community =~ s(\')('')g; #' + + my @t_sql_custom_columns = (); + + if (@sql_custom_columns) { + @t_sql_custom_columns = @sql_custom_columns; + + for (my $i = 1; $i <= $#t_sql_custom_columns; $i+=2) { + $_ = $t_sql_custom_columns[$i]; + print "Performing substitution on custom column: $_\n"; + &substitute(); + print "Done performing substitution on custom column: $_\n"; + $t_sql_custom_columns[$i] = $_; + } + } + + if (&odbc_insert($dbd_odbc_table, + "eventname", $event2[0], # $N + "eventid", $receivedtrap_entry, # $i + "trapoid", $receivedtrap_trans, # $O + "enterprise", $db_enterprise, # $E or $e depending on $db_translate_enterprise + "community", $community, # $C + "hostname", $agent_dns_name, # $A + "agentip", $var[4], # $aA + "category", $event2[1], # $c + "severity", $event2[2], # $s + "uptime", $var[2], # $T + "traptime", $trap_date_time_sql, + "formatline", $message_short2, + @t_sql_custom_columns) == 1 ) { # + $trap_successfully_logged++; + } + } + + if ($sql_win32_odbc_enable) + { + $trap_attempted_to_log++; + + # Double any single quotes + my $message_short2 = $message_short; + $message_short2 =~ s(\')('')g; #' + + my $community = $var[5]; + $community =~ s(\')('')g; #' + + my @t_sql_custom_columns = (); + + if (@sql_custom_columns) { + @t_sql_custom_columns = @sql_custom_columns; + + for (my $i = 1; $i <= $#t_sql_custom_columns; $i+=2) { + $_ = $t_sql_custom_columns[$i]; + print "Performing substitution on custom column: $_\n"; + &substitute(); + print "Done performing substitution on custom column: $_\n"; + $t_sql_custom_columns[$i] = $_; + } + } + + if (&sql_win32_odbc_insert($sql_win32_odbc_table, + "eventname", $event2[0], # $N + "eventid", $receivedtrap_entry, # $i + "trapoid", $receivedtrap_trans, # $O + "enterprise", $db_enterprise, # $E or $e depending on $db_translate_enterprise + "community", $community, # $C + "hostname", $agent_dns_name, # $A + "agentip", $var[4], # $aA + "category", $event2[1], # $c + "severity", $event2[2], # $s + "uptime", $var[2], # $T + "traptime", $trap_date_time_sql, + "formatline", $message_short2, + @t_sql_custom_columns) == 1 ) { # + $trap_successfully_logged++; + } + } + + } # end block for if ($event2[3] ne '') if FORMAT string has been defined + else + { + if ($DEBUGGING >= 1) + { + print " FORMAT line not defined\n"; + } + } + + # + # Variable substitution for EXEC string + # + + if ($DEBUGGING >= 1) + { + print "\n\nEXEC line(s):\n"; + } + + if (defined ($event2[4][0])) # if EXEC string has been defined + { + if (defined ($event2[4][0]) && $event2[1] ne "LOGONLY") + { + for (my $i=0; defined($event2[4][$i]); $i++) + { + $_ = $event2[4][$i]; + + &substitute($message_short); + + my $command = $_; + + if ($exec_enable == 1) + { + if ($DEBUGGING >= 1) + { + print "EXEC command:$command\n"; + } + + # Execute command + if ($threads_enable == 1 && $daemon == 1) { + if ($DEBUGGING >= 1) + { + print "EXEC command - creating thread...\n"; + } + my $exec_thread = threads->new(\&exec_thread_sub, $command); + $exec_thread->detach; # Detach and let it clean up after itself + + sub exec_thread_sub { + my $command = shift; + $thread_exec_semaphore->down; + + if ($exec_escape == 1) { + # Escape wildcard characters + $command =~ s/\*/\\\*/g; + $command =~ s/\?/\\\?/g; + } + if ($DEBUGGING >= 1) + { + print "EXECing command in thread:$command\n"; + } + system $command; + $thread_exec_semaphore->up; + } + } + else { + if ($exec_escape == 1) { + # Escape wildcard characters + $command =~ s/\*/\\\*/g; + $command =~ s/\?/\\\?/g; + } + system $command; + } + } + } + } + elsif ($DEBUGGING >= 1) + { + if ($event2[1] eq "LOGONLY") + { + print "\n\nTrap set to LOGONLY...\n\n"; + } + } + } # end of block if ($event2[4] ne '') + else + { + if ($DEBUGGING >= 1) + { + print " EXEC line not defined\n"; + } + } + + } + else + { + if ($event2[1] eq "IGNORE") { + # Statistics + $g_total_traps_ignored++; + } + + if ($DEBUGGING >= 1) + { + if ($event2[1] eq "IGNORE") + { + print "\nTrap set to IGNORE...\n\n"; + } + else + { + print "\nTrap defined, but NODES or MATCH check failed - skipping this EVENT entry..\n\n"; + } + } + } + } #while defined.. +} + +sub substitute +{ + my $format_line = shift; # Used for $Fz variable substitution for EXEC line. + + # Perform substitution on $_ variable + + # Wildcards - $*, $+*, $-* + # Expand to $1 $2 $3 etc + my $temp_wildcard1 = (); + my $temp_wildcard2 = (); + my $temp_wildcard3 = (); + for(my $i=1;$i <= $#entvar+1; $i++) + { + $temp_wildcard1 = $temp_wildcard1 . "\$$i" . $wildcard_expansion_separator; + $temp_wildcard2 = $temp_wildcard2 . "\$\+$i" . $wildcard_expansion_separator; + $temp_wildcard3 = $temp_wildcard3 . "\$-$i" . $wildcard_expansion_separator; + } + + # Chop off last space + if (defined ( $temp_wildcard1) ) + { + chop ($temp_wildcard1); + chop ($temp_wildcard2); + chop ($temp_wildcard3); + } + + #s(\$\*)($temp_wildcard1)g; + &substitute2 ("\$\*", $temp_wildcard1); + + s(\$\+\*)($temp_wildcard2)g; + &substitute2 ("\$\+\*", $temp_wildcard2); + + s(\$-\*)($temp_wildcard3)g; + &substitute2 ("\$-\*", $temp_wildcard3); + + # $v - Names of variable-bindings + # Count down backwards to make sure 10 is not mistaken for $1 + for(my $i=$#entvarname+1;$i > 0; $i--) + { + if ($net_snmp_perl_enable == 1) + { + my $temp = my_translateObj($entvarname[$i-1],$translate_varname_oid_format); + if (!defined ($temp) ) + { + $temp = $entvarname[$i-1]; + } + #s(\$v$i)($temp)g; + &substitute2 ("\$v$i", $temp); + } + else + { + #s(\$v$i)($entvarname[$i-1])g; + &substitute2 ("\$v$i", $entvarname[$i-1]); + } + } + + # $n - Variable-bindings + # Count down backwards to make sure 10 is not mistaken for $1 + for(my $i=$#entvar+1;$i > 0; $i--) + { + my $val = $entvar[$i-1]; + + if ($DEBUGGING >= 2) + { + print "\nVariable $entvarname[$i-1] with value $entvar[$i-1]\n"; + } + + # This will translate (if enabled) any OIDs found in the VALUE (not the variable name) to the textual + # name if possible. For example, if the value was 'A UPS Alarm (.1.3.6.1.4.1.534.1.7.12) has cleared.', + # it could be translated to: 'A UPS Alarm (xupsBuildingAlarm) has cleared.' + if ($translate_value_oids > 0 && $net_snmp_perl_enable == 1) + { + $val = &translate_value_oids_sub($val); + } + + if ($dns_enable == 1 && $resolve_value_ip_addresses == 1 && $net_snmp_perl_enable == 1) + { + $val = &resolve_value_ip_addresses_sub($val); + } + + if ($translate_integers == 1 && $net_snmp_perl_enable == 1) + { + if (! ($entvar[$i-1] =~ /\D+/)) # Check to see if value is numerical + { + if ($DEBUGGING >= 2) + { + print " Value is numerical\n"; + } + + my $temp_OID_type = uc (my_getType($entvarname[$i-1])); + if ($temp_OID_type eq "INTEGER32" || $temp_OID_type eq "INTEGER") # Make sure it's a SNMP INTEGER type + { + if ($DEBUGGING >= 2) + { + print " Value is defined as an INTEGER in the mib - will attempt to translate\n"; + } + my $val2 = my_mapEnum($entvarname[$i-1], $entvar[$i-1]); + if ($val2 ne '') # Make sure we got something + { + $val = $val2; + + if ($DEBUGGING >= 2) + { + print " Translated to: $val2\n"; + } + } + else + { + $val = $entvar[$i-1]; + if ($DEBUGGING >= 2) + { + print " Could not translate\n"; + } + } + } + else + { + if ($DEBUGGING >= 2) + { + print " Value is NOT defined as an INTEGER or Integer32 in the mib\n"; + } + } + } + } + + if ($net_snmp_perl_enable == 1) + { + #s(\$$i)($val)g; # $n + &substitute2 ("\$$i", $val); + + # Translate for $+n and $-n + my $temp = my_translateObj($entvarname[$i-1],$translate_varname_oid_format); + if (!defined ($temp) ) + { + $temp = $entvarname[$i-1]; + } + + my $temp2 = &my_getType($entvarname[$i-1]); + if (!defined ($temp2)) + { + $temp2 = "unknown"; + } + + #s(\$\+$i)($temp:$val)g; # $+n + &substitute2 ("\$\+$i", "$temp:$val"); + + #s(\$-$i)($temp ($temp2):$val)g; # $-n + &substitute2 ("\$-$i", "$temp ($temp2):$val"); + } + else + { + #s(\$$i)($val)g; # $n + &substitute2 ("\$$i", $val); + + #s(\$\+$i)($entvarname[$i-1]:$val)g; # $+n + &substitute2 ("\$\+$i", "$entvarname[$i-1]:$val"); + + #s(\$-$i)($entvarname[$i-1] (unknown):$val)g; # $-n + &substitute2 ("\$-$i", "$entvarname[$i-1] (unknown):$val"); + } + } + + # $c - Category + #s(\$c)($event2[1])g; + &substitute2 ("\$c", $event2[1]); + + # $C - Trap community string + #s(\$C)($var[5])g; + &substitute2 ("\$C", $var[5]); + + # $E - Enterprise trap (symbolic) + #s(\$E)($enterprise_trans)g; + &substitute2 ("\$E", $enterprise_trans); + + # $e - Enterprise trap (numerical) + #s(\$e)($var[6])g; + &substitute2 ("\$e", $var[6]); + + # $N - Event name + #s(\$N)($event2[0])g; + &substitute2 ("\$N", $event2[0]); + + # $i - Event OID + #s(\$i)($receivedtrap_entry)g; + &substitute2 ("\$i", $receivedtrap_entry); + + # $# - Number of variable-bindings in the trap + my $entvar_temp = $#entvar+1; + #s(\$#)($entvar_temp)g; + &substitute2 ("\$#", $entvar_temp); + + # $O - Received trap (symbolic) + if ($net_snmp_perl_enable == 1) + { + if ($DEBUGGING >= 2) { + print "\nOID of received trap: $receivedtrap. Will attempt to translate to text\n"; + } + my $temp = my_translateObj("$receivedtrap",$translate_trap_oid_format); + if (defined ($temp) ) { + if ($DEBUGGING >= 2) { + print " Translated to $temp\n"; + } + #s(\$O)($temp)g; + &substitute2 ("\$O", $temp); + } + else + { + # Could not translate default to numeric + if ($DEBUGGING >= 2) { + print " Could not translate - defaulting to numeric\n"; + } + #s(\$O)($temp)g; + &substitute2 ("\$O", $temp); + } + } + else + { + #s(\$O)($receivedtrap)g; + &substitute2 ("\$O", $receivedtrap); + } + + # $o - Received trap (numerical) + #s(\$o)($receivedtrap)g; + &substitute2 ("\$o", $receivedtrap); + + # $s - Severity + #s(\$s)($event2[2])g; + &substitute2 ("\$s", $event2[2]); + + # $AR, $ar - IP address + #s(\$aR)($var[1])g; + &substitute2 ("\$aR", $var[1]); + + #s(\$ar)($var[1])g; + &substitute2 ("\$ar", $var[1]); + + # $R, $r - Trap hostname + #s(\$R)($var[0])g; + &substitute2 ("\$R", $var[0]); + + # $H - Host name of the system running SNMPTT + &substitute2 ("\$H", $snmptt_system_name); + + #s(\$r)($var[0])g; + &substitute2 ("\$r", $var[0]); + + # $A, $a - Trap agent IP address + #s(\$aA)($var[4])g; # IP address + &substitute2 ("\$aA", $var[4]); + + #s(\$A)($agent_dns_name)g; # hostname + &substitute2 ("\$A", $agent_dns_name); + + # $T - Uptime + #s(\$T)($var[2])g; + &substitute2 ("\$T", $var[2]); + + # $x - Current date + #s(\$x)($trap_date)g; + &substitute2 ("\$x", $trap_date); + + # $X - Current time + #s(\$X)($trap_time)g; + &substitute2 ("\$X", $trap_time); + + # $@ - Current time since epoch (Jan 1, 1904 for Mac, Jan 1, 1900 for most others) + #s(\$@)($trap_date_time_epoch)g; + &substitute2 ("\$@", $trap_date_time_epoch); + + # iso(1) org(3) dod(6) internet(1) snmpV2(6) snmpModules(3) snmpMIB(1) snmpMIBObjects(1) 5 + # SNMPv2 Generic? 1=coldStart....5=authenticationFailure, 6=egpNeighborLoss so 0=enterprise? + if ($receivedtrap =~ /^.1.3.6.1.6.3.1.1.5/) + { + # It's a generic trap + + # $S - Specific trap number - 0 + #s(\$S)(0)g; + &substitute2 ("\$S", "0"); + + # $G - Generic trap number - last # + my $temp = $_; # Save old $_ + $_ = $receivedtrap; + /(\d+)$/; + my $temp2 = $1; + $_ = $temp; # Restore old $_ + #s(\$G)($temp2)g; + &substitute2 ("\$G", $temp2); + } + else + { + # It's an enterprise trap + + # $S - Specific trap number - last # + my $temp = $_; # Save old $_ + $_ = $receivedtrap; + /(\d+)$/; + my $temp2 = $1; + $_ = $temp; # Restore old $_ + #s(\$S)($temp2)g; + &substitute2 ("\$S", $temp2); + + # $G - Generic trap number - 0 + s(\$G)(0)g; + &substitute2 ("\$G", "0"); + } + + # $D - Description from MIB file (NOT from snmptt.conf) + if ($net_snmp_perl_enable == 1 && $description_mode == 2) { + my $description_temp = $SNMP::MIB{$event2[0]}->{description}; + if ($description_clean == 1) { + $description_temp =~ s/\n\s+/\n/g; + } + s(\$D)($description_temp)g; + &substitute2 ("\$D", $description_temp); + } + elsif ($description_mode == 1) { + my $description_temp; + for (my $i=0; defined($event2[8][$i]); $i++) + { + $description_temp = $description_temp . $event2[8][$i] . "\n"; + } + if ($description_clean == 1) { + $description_temp =~ s/\n\s+/\n/g; + } + &substitute2 ("\$D", $description_temp); + } + else { + #s(\$D)()g; + &substitute2 ("\$D", ""); + } + + # Formatting + # alarm (bell) (BEL) + &substitute2 ("\$Fa", "\a"); + + # form feed (FF) + &substitute2 ("\$Ff", "\f"); + + # newline (LF, NL) + &substitute2 ("\$Fn", "\n"); + + # return (CR) + &substitute2 ("\$Fr", "\r"); + + # tab (HT, TAB) + &substitute2 ("\$Ft", "\t"); + + # $pn - PREEXEC variables + # preexec_var + #&substitute2 ("\$p", "$preexec_var"); + # Count down backwards to make sure 10 is not mistaken for $1 + for(my $i=$#preexec_var+1;$i > 0; $i--) + { + my $val = $preexec_var[$i-1]; + if ($DEBUGGING >= 2) + { + print "\nPREEXEC variable $i: $val\n"; + } + &substitute2 ("\$p$i", $val); + } + + # FORMAT line (only possible when doing EXEC line) + &substitute2 ("\$Fz", "$format_line"); + + # $$ - Print a $ + s(\$\$)(\$)g; + + # Do user defined REGEX on $message + + if ($DEBUGGING >= 2 && defined($event2[6][0])) + { + print "\n$_\n"; + } + + for (my $i=0; defined($event2[6][$i]); $i++) + { + my $regex_temp = $event2[6][$i]; + + #print "!!!!!!$regex_temp\n"; + # Remove starting and ending () + #$regex_temp =~ /^\((.*)\)$/; + $regex_temp =~ /^\((.*)\)(.*)$/; + $regex_temp = $1; + my $modifiers = $2; + + # Split using )( + my @regex_temp2 = split(/\)\(/,$regex_temp,2); + #print "0:$regex_temp2[0]\n"; + #print "1:$regex_temp2[1]\n"; + #print "Modifiers: $modifiers\n"; + + if ($regex_temp2[0] ne '') + { + # allowed modifiers: any combination of: i, g, e, ee+ not permitted + my $modifiers2 = 0; + if ($modifiers =~ /i/) { $modifiers2 = $modifiers2 | 1; } + if ($modifiers =~ /g/) { $modifiers2 = $modifiers2 | 2; } + if ($modifiers =~ /e/) + { + if ($allow_unsafe_regex == 1) + { + $modifiers2 = $modifiers2 | 4; + + # Append a package declaration to the beginning to prevent global variables from being + # visible. Also remove any attempts to access variables from the main:: package. + $regex_temp2[1] = "package regexisoloate;$regex_temp2[1]"; + $regex_temp2[1] =~ s/\$main::/\$/gi; # Remove attempts to access the main package + } + else + { + if ($DEBUGGING >= 2) + { + print " REGEX detected with e modifier, but allow_unsafe_regex is disabled. Removing e modifier\n"; + } + } + } + + #print "modifiers2 = $modifiers2\n"; + + # 0 none + # 1 i + # 2 g + # 3 ig + # 4 e + # 5 ie + # 6 ge + # 7 ige + + if ($DEBUGGING >= 2) + { + print " Doing REGEX: s($regex_temp2[0])($regex_temp2[1])$modifiers\n"; + } + + # If unsafe is off, then don't use the e modifier. This means that variable interopolation + # will not work on the right side. If the user puts a $1 on the right, it will print out $1. + # + # If unsafe is on, then we use the /ee modifier. + # + # With a normal regular expression in a program, the e modifier is not requried for variable + # interopolation to work. If you want to have code executed, then you need at least one e + # modifier in a regular program. + # + # Because we are passing the right side to a perl program instead of hard-coding the right side + # *inside* of the program, we need to handle it differently. These are the rules: + # + # -for interopolation and / or code execution to work, we need to use the /ee modifier inside the + # program (snmptt) + # -if we only want interop and no code execution (same behaviour as a program with no e modifier), + # then we: + # -escape all backslashes + # -escape all double quotes + # -escape all single quotes + # -put quotes around the whole thing + # - One would assume that if we didn't put quotes around everything, and used one /e instead of two, then + # it would work, but it does not.. + # + # -if we want both interop and code to execute (same behaviour as a program with one e modifier), + # then we: + # -do nothing extra (no escaping or putting quotes around it) + # + # With unsafe off, or unsafe no with NO e modifier, whatever the user puts in the right side of the + # REGEX will display exactly, with the only exception of the $n variable interop working with unsafe on. + # + # With unsafe on and one e modifier, the right side is evaluated so any text needs to be in quotes, and + # printable quotes need to be escaped etc just like a normal program. + # + # Example1: + # + # "5 + 5 is ".(5+5)."and \"this is quoted\"" + # will output: + # 5+5 is 10 and "this is quoted" + # + # If unsafe was off, it would output: + # + # "5 + 5 is ".(5+5)."and \"this is quoted\"" + # + # Example2: + # + # "5 + 5 is ".sprintf("%d",(5+5))."and \"this is quoted\"" + # will output: + # 5+5 is 10 and "this is quoted" + # + # If unsafe was off, it would output: + # + # "5 + 5 is ".sprintf("%d",(5+5))."and \"this is quoted\"" + + if ($allow_unsafe_regex == 0) + { + # unsafe_regex is OFF + if ($modifiers2 == 0 ) { s($regex_temp2[0])($regex_temp2[1]); } + elsif ($modifiers2 == 1) { s($regex_temp2[0])($regex_temp2[1])i; } + elsif ($modifiers2 == 2) { s($regex_temp2[0])($regex_temp2[1])g; } + elsif ($modifiers2 == 3) { s($regex_temp2[0])($regex_temp2[1])ig; } + } + else + { + # unsafe_regex is ON + + # If unsafe is on, use two e's. If user does not specify an e, + # escape back slashes and quotes, and put quotes around the whole string + # to prevent functions from being executed + if (! ($modifiers =~ /e/)) + { + # If it contains a \, then escape it + $regex_temp2[1] =~ s/\\/\\\\/g; + # Escape each quote + $regex_temp2[1] =~ s/\"/\\\"/g; # double quotes + $regex_temp2[1] =~ s/\'/\\\'/g; # single quotes + # put quotes around the whole thing + $regex_temp2[1] = "\"$regex_temp2[1]\""; + } + #print "1:$regex_temp2[1]\n"; + if ($modifiers2 == 0 ) { s($regex_temp2[0])($regex_temp2[1])ee; } + elsif ($modifiers2 == 1) { s($regex_temp2[0])($regex_temp2[1])eei; } + elsif ($modifiers2 == 2) { s($regex_temp2[0])($regex_temp2[1])eeg; } + elsif ($modifiers2 == 3) { s($regex_temp2[0])($regex_temp2[1])eeig; } + elsif ($modifiers2 == 4) { s($regex_temp2[0])($regex_temp2[1])ee; } + elsif ($modifiers2 == 5) { s($regex_temp2[0])($regex_temp2[1])eei; } + elsif ($modifiers2 == 6) { s($regex_temp2[0])($regex_temp2[1])eeg; } + elsif ($modifiers2 == 7) { s($regex_temp2[0])($regex_temp2[1])eeig; } + } + } + } +} + +# sub substitute2 (left, right) +# +# left: inside of double quotes with escapes. eg: "\$a" +# right: replacement string eg: $name, "hello", "hi$namebye" +# +# Only substitute if there is an odd number of $ or \ symbols before the +# substitute variable (eg: a in $a). If there is an even number (0,2,4 etc) +# then do NOT substitute. If there is an odd number (1,3,5 etc) then +# substitute. For example, if $a converted to x: +# $a = x +# $$a = $a +# $$$a = $x +# $$$$a = $$a +# $$$$$a = $$x +# +# We need variable length look behind pattern matching to do this, but Perl +# does not support it. As an alternative we can reverse the string, do a +# substitute with look ahead, and reverse it back. +# +sub substitute2 { + my $left = shift; + my $right = shift; + + my $string_r = reverse $_; + my $left_r = reverse $left; + $left_r =~ s/\\/\\\\/g; # escape \ + $left_r =~ s/\$/\\\$/g; # escape $ + $left_r =~ s/\*/\\\*/g; # escape * + $left_r =~ s/\+/\\\+/g; # escape + + my $right_r = reverse $right; + + # The format is: + # s/a\$((?=(\$\$)*(?!\$)))/b/g; + # where 'a\$' is the reverse of what to look for and 'b' is what to replace + # it with (reversed). + + $string_r =~ s/$left_r((?=(\$\$)*(?!\$)))/$right_r/g; + + $_ = reverse $string_r; +} + +sub loadsnmpttconf +{ + # + # snmptt.conf loader. + # This section loads the snmptt.conf which defines the traps and text strings + # that will be used for variable substitution + + # Flush variables in case this is a re-load during run + my @snmpttconf = (); + # @snmptt_conf_files = (); + undef %event; + + foreach my $snmpttconffile (@snmptt_conf_files) + { + if ($DEBUGGING >= 1) + { + print "\n\tLoading $snmpttconffile\n"; + } + + if ($syslog_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + syslog_system("Loading $snmpttconffile"); + } + if ($log_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + log_system("Loading $snmpttconffile"); + } + if ($eventlog_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + eventlog_system("Loading $snmpttconffile",9,$eventlog_information); + } + + unless (open SNMPTTCONF, $snmpttconffile) + { + warn "Could not open configuration file: $snmpttconffile ($!)"; + if ($DEBUGGING >= 1) + { + print "\n\tCould not open configuration file: $snmpttconffile\n"; + } + + if ($syslog_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + syslog_system("Could not open configuration file: $snmpttconffile"); + } + if ($log_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + log_system("Could not open configuration file: $snmpttconffile"); + } + if ($eventlog_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + eventlog_system("Could not open configuration file: $snmpttconffile",10,$eventlog_error); + } + + next; + } + my $tempcount = 0; + while () + { + chomp; #remove at end of line + s/\015//; # Remove any DOS carriage returns + push(@snmpttconf, $_); #add to each line to @trapconf array + $tempcount++; + } + + if ($DEBUGGING >= 1) + { + print "\tFinished loading $tempcount lines from $snmpttconffile\n"; + } + if ($syslog_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + syslog_system("Finished loading $tempcount lines from $snmpttconffile"); + } + if ($log_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + log_system("Finished loading $tempcount lines from $snmpttconffile"); + } + if ($eventlog_system_enable == 1 && $daemon == 1 && $dump == 0 && $time == 0) + { + eventlog_system("Finished loading $tempcount lines from $snmpttconffile",11,$eventlog_information); + } + } + + if ($DEBUGGING >= 1) + { + print "\nFinished loading configuration files\n"; + } + + # Process each line of snmptt.conf loaded into @snmpttconf array. + # Add each EVENT to %event hash + + if ($DEBUGGING >= 1) + { + print "\nProcessing memory copy of configuration files\n"; + } + + my $currentline=0; + my $tempcount=0; + my $tempcount2=0; + + while ($currentline <= $#snmpttconf) + { + my $line = $snmpttconf[$currentline]; + + if ($line =~ /^EVENT/) + { + #EVENT name .x.x.x.x "category" severity (note: .x.x. is FULL OID!) + #0 1 2 3 4 + + # use shellwords to divide the two space separated values + # without messing up quoted text and re-join using :: as the + # delimiter + # + # hash elements: + # 0: name of trap + # 1: category + # 2: severity + # 3: FORMAT string + # 4: EXEC string + # 5: NODES string + # 6: REGEX array + # 7: MATCH array + # 8: DESC array + + $tempcount++; # Temporary counter of the number of EVENTS found + + # Divide up line taking into consideration strings in quotes + my $temp = join "::::", shellwords($line); + + #print "line is: $temp\n"; + + # Split line up into multiple elements of an array using the new delimiter + my @temp = split ("::::",$temp); + + if (! ($temp[2] =~ /^(\.\d+)+$/) && ! ($temp[2] =~ /^(\.\d+)+\.\*$/) && ! + ($temp[2] =~ /^(\.\*)$/) ) + { + # OID contains text, so it's not fully numerical + if ($net_snmp_perl_enable == 1) + { + # Try to convert to numerical + if ($DEBUGGING >= 2) + { + print "Non-numeric OID: $temp[2]. Will attempt to translate to numerical\n"; + } + my $temp2 = SNMP::translateObj("$temp[2]",0); + if (defined ($temp2) ) + { + if ($DEBUGGING >= 2) + { + print " Translated to $temp2\n"; + } + $temp[2] = $temp2; + } + else + { + # Could not translate, so skip this entry + if ($DEBUGGING >= 2) + { + print " Could not translate - skipping entry\n"; + } + $currentline++; # Increment to the next line + next; + } + } + else + { + # Net-SNMP Perl module not enabled, and OID is not numeric so skip this entry + if ($DEBUGGING >= 2) + { + print "Non-numeric OID: $temp[2]. Net-SNMP Perl module not enabled - skipping entry\n"; + } + $currentline++; # Increment to the next line + next; + } + } + + # Clear out the FORMAT, EXEC and NODES lines in case they are not found. Don't want old + # data in them.. + my $lineformat = ''; + my $lineexec = ''; + my $linenodes = ''; + my $lineregex = ''; + my @exec = (); + my @regex = (); + my @match = (); + my @desc = (); + my @preexec = (); + + $currentline++; # Increment to the next line which should be a FORMAT, EXEC or NODES + my $line2 = $snmpttconf[$currentline]; + + while ( ($currentline <= $#snmpttconf) && !($line2 =~ /^EVENT/) ) + { + # Keep going through the file until the next EVENT or the end of snmptt.conf + # is reached + + # Check to see if next line is a FORMAT line (it should be!) + if ($line2 =~ /^FORMAT/) + { + # It's a FORMAT line + + $lineformat = substr($line2,7); + } + elsif ($line2 =~ /^EXEC/) + { + # It's an EXEC line + + $lineexec = substr($line2,5); + + push (@exec,$lineexec); + } + elsif ($line2 =~ /^PREEXEC/) + { + # It's a PREEXEC line + + my $linematch = substr($line2,8); + + push (@preexec,$linematch); + } + elsif ($line2 =~ /^NODES/) + { + # It's a NODES line + # Allow for multiple NODES lines - concatenate them + + $linenodes = $linenodes . substr($line2,6) . " "; + } + elsif ($line2 =~ /^REGEX/) + { + # It's a REGEX line + + $lineregex = substr($line2,6); + + # Remove spaces before and after + $lineregex =~ /^\s*(.*?)\s*$/; + $lineregex = $1; + + # Make sure it looks like ()() before accepting + if ($lineregex =~ /\(.*?\)\(.*?\)/ ) + { + push (@regex,$lineregex); + } + } + elsif ($line2 =~ /^MATCH/) + { + # It's a MATCH line + + my $linematch = substr($line2,6); + + push (@match,$linematch); + } + elsif ( ($line2 =~ /^SDESC/) && ($description_mode== 1) ) + { + # It's a DESC line + + $currentline++; # Increment to the next line + $line2 = $snmpttconf[$currentline]; # Get next line + + while ( ($currentline <= $#snmpttconf) && !($line2 =~ /^EVENT/) && + !($line2 =~ /^EDESC/)) { + print "DESC line: $line2\n"; + push (@desc,$line2); + $currentline++; # Increment to the next line + $line2 = $snmpttconf[$currentline]; # Get next line + } + } + + $currentline++; # Increment to the next line + $line2 = $snmpttconf[$currentline]; # Get next line + } + if ($lineformat ne '' || $exec[0] ne '') + { + # At least the mandatory FORMAT line was defined, so we'll keep it + # Stuff all elements into a one hash + # $event{@temp[2]} = [@temp[1],@temp[3],@temp[4],$lineformat,$lineexec,$linenodes]; + + if (!defined(@{ $event{$temp[2]} }[0])) + { + @{ $event{$temp[2]} }[0] = 0; + } + + #@regex = qw/one two/; + + my $countx = @{ $event{$temp[2]} }[0]; + #print "countx $countx\n"; + @{ $event{$temp[2]} }[1+$countx]= $temp[1]; + @{ $event{$temp[2]} }[2+$countx]= $temp[3]; + @{ $event{$temp[2]} }[3+$countx]= $temp[4]; + @{ $event{$temp[2]} }[4+$countx]= $lineformat; + #@{ $event{$temp[2]} }[5+$countx]= $lineexec; + @{ $event{$temp[2]} }[5+$countx]= [@exec]; + + # If dynamic_nodes is disabled, process the nodes list to load any nodes + # files first so they are not loaded each time a trap is processed + if ($dynamic_nodes == 0) + { + my @nodes2 = &process_nodes($linenodes); + @{ $event{$temp[2]} }[6+$countx]= "@nodes2"; + } + else + { + @{ $event{$temp[2]} }[6+$countx]= $linenodes; + } + + @{ $event{$temp[2]} }[7+$countx]= [@regex]; + @{ $event{$temp[2]} }[8+$countx]= [@match]; + @{ $event{$temp[2]} }[9+$countx]= [@desc]; + @{ $event{$temp[2]} }[10+$countx]= [@preexec]; + @{ $event{$temp[2]} }[0]= 11+ @{ $event{$temp[2]} }[0]; + + $tempcount2++; # Temporary counter of the number of EVENTS found with at + # least a FORMAT line specified + } + + # Change currentline back so the next increment will re-evalutate the last line which + # would have been an EVENT (to get out of the WHILE loop above), or the end of the file + $currentline--; + } + $currentline++; # Increment current line for next loop through snmpttconf array + } + if ($DEBUGGING >= 1) + { + print "$tempcount EVENTs found\n"; + print "$tempcount2 EVENTs found that contain at least the mandatory FORMAT line\n"; + if($tempcount2<$tempcount) + { + print " Warning: EVENT entries were found that did not contain the mandatory FORMAT line!\n"; + print " These EVENTS will be ignored!\n"; + } + print "Finished processing memory copy of configuration files\n\n"; + } + + if ($DEBUGGING >= 2) + { + print "==========================================================\n"; + print "Printing out all the events in hash table:\n\n"; + foreach my $key (sort keys %event) + { + my $l=0; + while (defined($event{$key}[$l+1])) + { + print "Event: $key => $event{$key}[1+$l],$event{$key}[2+$l],$event{$key}[3+$l],$event{$key}[4+$l],$event{$key}[7+$l][0]\n"; + $l+=11; + } + } + print "\nFinished printing out all events in hash table\n"; + print "==========================================================\n"; + + # Print out duplicates if asking for a dump (snmptt --dump) + if ($dump == 1) { + print "Printing out all duplicate events in hash table:\n\n"; + my %temp = (); + foreach my $key (sort keys %event) + { + my $l=0; + while (defined($event{$key}[$l+1])) + { + $temp{$key}++; + $l+=11; + } + } + foreach my $key (sort keys %temp) + { + if ($temp{$key} > 1) { + print "Duplicate event: $key\n"; + } + } + print "\nFinished printing out all duplicate events in hash table\n"; + print "==========================================================\n"; + } + } + + close SNMPTTCONF; +} + +sub readtrap +{ + # Flush out @tempvar, @var and @entvar + my @tempvar = (); + @var = (); + @entvar = (); + @entvarname = (); + @preexec_var = (); + + # Statistics + $g_total_traps_received++; + + if ($DEBUGGING >= 2) + { + print "Reading trap. Current time: " . scalar(localtime()). "\n"; + } + + if ( $daemon == 1) + { + chomp($trap_date_time_epoch = (<$input>)); # Pull time trap was spooled + if ($trap_date_time_epoch eq "") { + if ($DEBUGGING >= 1) { + print " Invalid trap file. Expected a serial time on the first line but got nothing\n"; + return 0; + } + } + + $trap_date_time_epoch =~ s(`)(')g; #` Replace any back ticks with regular single quote + } + else + { + $trap_date_time_epoch = time(); # Use current time as time trap was received + } + + my @localtime_array; + if ( $daemon == 1 && $use_trap_time == 1 ) # Daemon mode only + { + @localtime_array = localtime($trap_date_time_epoch); + + if ($date_time_format eq "") { + $trap_date_time = localtime($trap_date_time_epoch); + } + else { + $trap_date_time = strftime $date_time_format, @localtime_array; + } + + if ($date_time_format_sql eq "") { + $trap_date_time_sql = localtime($trap_date_time_epoch); + } + else { + $trap_date_time_sql = strftime $date_time_format_sql, @localtime_array; + } + + } + else # Standalone mode + { + @localtime_array = localtime(); + + if ($date_time_format eq "") { + $trap_date_time = localtime(); + } + else { + $trap_date_time = strftime $date_time_format, @localtime_array; + } + + if ($date_time_format_sql eq "") { + $trap_date_time_sql = localtime(); + } + else { + $trap_date_time_sql = strftime $date_time_format_sql, @localtime_array; + } + } + + $trap_date = strftime $date_format, @localtime_array; + $trap_time = strftime $time_format, @localtime_array; + + + # Pull in passed SNMP info from snmptrapd via STDIN and place in the array @tempvar + + chomp($tempvar[0]=<$input>); # hostname + $tempvar[0] =~ s(`)(')g; #` Replace any back ticks with regular single quote + if ($tempvar[0] eq "") { + if ($DEBUGGING >= 1) { + print " Invalid trap file. Expected a hostname on line 2 but got nothing\n"; + return 0; + } + } + + chomp($tempvar[1]=<$input>); # ip address + $tempvar[1] =~ s(`)(')g; #` Replace any back ticks with regular single quote + if ($tempvar[1] eq "") { + if ($DEBUGGING >= 1) { + print " Invalid trap file. Expected an IP address on line 3 but got nothing\n"; + return 0; + } + } + + # Some systems pass the IP address as udp:ipaddress:portnumber. This will pull + # out just the IP address + $tempvar[1] =~ /(\d+\.\d+\.\d+\.\d+)/; + $tempvar[1] = $1; + + # Net-SNMP 5.4 has a bug which gives for the hostname + if ($tempvar[0] =~ //) { + $tempvar[0] = $tempvar[1]; + } + + #Process varbinds + #Separate everything out, keeping both the variable name and the value + my $linenum = 1; + while (defined(my $line = <$input>)) + { + $line =~ s(`)(')g; #` Replace any back ticks with regular single quote + + if ($remove_backslash_from_quotes == 1) # Remove escape from quotes if enabled + { + $line =~ s/\\\"/"/g; + } + + my $temp1; + my $temp2; + + ($temp1, $temp2) = split (/ /, $line, 2); + + chomp ($temp1); # Variable NAME + chomp ($temp2); # Variable VALUE + chomp ($line); + + my $variable_fix; + if ($linenum == 1) + { + if (defined($temp2) ) # Check if line 1 contains 'variable value' or just 'value' + { + $variable_fix = 0; + } + else + { + $variable_fix = 1; + } + } + + if ($variable_fix == 0 ) + { + # Make sure variable names are numerical + $temp1 = translate_symbolic_to_oid($temp1); + + # If line begins with a double quote (") but does not END in a double quote then we need to merge + # the following lines together into one until we find the closing double quote. + # Net-SNMP sometimes divides long lines into multiple lines.. + if ( ($temp2 =~ /^\"/) && ( ! ($temp2 =~ /\"$/)) ) + { + if ($DEBUGGING >= 2) { + print " Multi-line value detected - merging onto one line...\n"; + } + chomp $temp2; # Remove the newline character + while (defined(my $line2 = <$input>)) + { + chomp $line2; + $temp2.=" ".$line2; + if ($line2 =~ /\"$/) + { + last; + } + } + } + + # If the value is blank, set it to (null) + if ($temp2 eq "") + { + $temp2 = "(null)"; + } + + if ($temp2 =~ /^\"/ && $temp2 =~ /$\"/) # Have quotes around it? + { + $temp2 = substr($temp2,1,(length($temp2)-2)); # Remove quotes + push(@tempvar, $temp1); + push(@tempvar, $temp2); + } + else + { + push(@tempvar, $temp1); + push(@tempvar, $temp2); + } + } + else + { + # Should have been variable value, but only value found. Workaround + # + # Normally it is expected that a line contains a variable name + # followed by a space followed by the value (except for the + # first line which is the hostname and the second which is the + # IP address). If there is no variable name on the line (only + # one string), then add a variable string called 'variable' so + # it is handled correctly in the next section. + # This happens with ucd-snmp v4.2.3 but not v4.2.1 or v4.2.5. + # This appears to be a bug in ucd-snmp v4.2.3. This works around + # the problem by using 'variable' for the variable name, although + # v4.2.3 should NOT be used with SNMPTT as it prevents SNMP V2 traps + # from being handled correctly. + + if ($DEBUGGING >= 2) + { + print "Data passed from snmptrapd is incorrect. UCD-SNMP v4.2.3 is known to cause this\n"; + } + + # If line begins with a double quote (") but does not END in a double quote then we need to merge + # the following lines together into one until we find the closing double quote. + # Net-SNMP sometimes divides long lines into multiple lines.. + if ( ($line =~ /^\"/) && ( ! ($line =~ /\"$/)) ) + { + if ($DEBUGGING >= 2) { + print " Multi-line value detected - merging onto one line...\n"; + } + chomp $line; # Remove the newline character + while (defined(my $line2 = <$input>)) + { + chomp $line2; + $line.=" ".$line2; + if ($line2 =~ /\"$/) + { + last; + } + } + } + + # If the value is blank, set it to (null) + if ($line eq "") + { + $line = "(null)"; + } + + if ($line =~ /^\"/ && $line =~ /$\"/) # Have quotes around it? + { + $line = substr($line,1,(length($line)-2)); # Remove quotes + push(@tempvar, "variable"); + push(@tempvar, $line); + } + else + { + push(@tempvar, "variable"); + push(@tempvar, $line); + } + } + + $linenum++; + } + + if ($DEBUGGING >= 2) + { + # Print out all items passed from snmptrapd + print "\nItems passed from snmptrapd:\n"; + for (my $i=0;$i <= $#tempvar;$i++) + { + print "value $i: $tempvar[$i]\n\n"; + } + } + + # Copy what I need to new variables to make it easier to manipulate later + + # Standard variables + $var[0] = $tempvar[0]; # hostname + $var[1] = $tempvar[1]; # ip address + $var[2] = $tempvar[3]; # uptime + $var[3] = $tempvar[5]; # trapname / OID - assume first value after uptime is + # the trap OID (value for .1.3.6.1.6.3.1.1.4.1.0) + + $var[4] = ""; # Clear ip address from trap agent + $var[5] = ""; # Clear trap community string + $var[6] = ""; # Clear enterprise + + # Make sure trap OID is numerical as event lookups are done using numerical OIDs only + $var[3] = translate_symbolic_to_oid($var[3]); + + # Cycle through remaining variables searching for for agent IP (.1.3.6.1.6.3.18.1.3.0), + # community name (.1.3.6.1.6.3.18.1.4.0) and enterpise (.1.3.6.1.6.3.1.1.4.3.0) + # All others found are regular passed variables + my $j=0; + for (my $i=6;$i <= $#tempvar; $i+=2) + { + if ($tempvar[$i] =~ /^.1.3.6.1.6.3.18.1.3.0$/) # ip address from trap agent + { + $var[4] = $tempvar[$i+1]; + } + elsif ($tempvar[$i] =~ /^.1.3.6.1.6.3.18.1.4.0$/) # trap community string + { + $var[5] = $tempvar[$i+1]; + } + elsif ($tempvar[$i] =~ /^.1.3.6.1.6.3.1.1.4.3.0$/) # enterprise + { + # $var[6] = $tempvar[$i+1]; + # Make sure enterprise value is numerical + $var[6] = translate_symbolic_to_oid($tempvar[$i+1]); + } + else # application specific variables + { + $entvarname[$j] = $tempvar[$i]; + $entvar[$j] = $tempvar[$i+1]; + $j++; + } + } + + if ($dns_enable == 1 && $var[0] =~ /^\d+\.\d+\.\d+\.\d+$/) # Only if it's not already resolved + { + my $temp = gethostbyaddr(Socket::inet_aton($var[0]),Socket::AF_INET()); + if (defined ($temp)) + { + if ($DEBUGGING => 1) + { + print "Host IP address ($var[0]) resolved to: $temp\n\n"; + } + $var[0] = $temp; + } + else + { + if ($DEBUGGING => 1) + { + print "Host IP address ($var[0]) could not be resolved by DNS. Variable \$r / \$R etc will use the IP address\n\n"; + } + } + } + + # If the agent IP is blank, copy the IP from the host IP. + # var[4] would only be blank if it wasn't passed from snmptrapd, which + # should only happen with ucd-snmp 4.2.3, which you should be using anyway! + if ($var[4] eq '') + { + $var[4] = $var[1]; + if ($DEBUGGING => 1) + { + print "Agent IP address was blank, so setting to the same as the host IP address of $var[1]\n\n"; + } + } + + # If the agent IP is the same as the host IP, then just use the host DNS name, no need + # to look up, as it's obviously the same.. + if ($var[4] eq $var[1]) + { + if ($DEBUGGING => 1) + { + print "Agent IP address ($var[4]) is the same as the host IP, so copying the host name: $var[0]\n\n"; + } + $agent_dns_name = $var[0]; + } + else + { + $agent_dns_name = $var[4]; # Default to IP address + if ($dns_enable == 1 && $var[4] ne '') + { + my $temp = gethostbyaddr(Socket::inet_aton($var[4]),Socket::AF_INET()); + if (defined ($temp)) + { + if ($DEBUGGING => 1) + { + print "Agent IP address ($var[4]) resolved to: $temp\n\n"; + } + $agent_dns_name = $temp; + } + else + { + if ($DEBUGGING => 1) + { + print "Agent IP address ($var[4]) could not be resolved by DNS. Variable \$A etc will use the IP address\n\n"; + } + } + } + } + + if ($strip_domain) + { + $var[0] = strip_domain_name($var[0], $strip_domain); + $agent_dns_name = strip_domain_name($agent_dns_name, $strip_domain); + } + + if ($DEBUGGING >= 1) + { + print "Trap received from $tempvar[0]: $tempvar[5]\n"; + } + + if ($DEBUGGING >= 2) + { + print "0: hostname\n"; + print "1: ip address\n"; + print "2: uptime\n"; + print "3: trapname / OID\n"; + print "4: ip address from trap agent\n"; + print "5: trap community string\n"; + print "6: enterprise\n"; + print "0+: passed variables\n\n"; + + #print out all standard variables + for (my $i=0;$i <= $#var;$i++) + { + print "Value $i: $var[$i]\n\n"; + } + + print "Agent dns name: $agent_dns_name\n\n"; + + #print out all enterprise specific variables + for (my $i=0;$i <= $#entvar;$i++) + { + print "Ent Value $i (\$" . ($i+1) . "): $entvarname[$i]=$entvar[$i]\n\n"; + } + } + + return 1; + + # Variables of trap received by SNMPTRAPD: + # + # $var[0] hostname + # $var[1] ip address + # $var[2] uptime + # $var[3] trapname / OID + # $var[4] ip address from trap agent + # $var[5] trap community string + # $var[6] enterprise + # + # $entvarname[0] passed variable name 1 + # $entvarname[1] passed variable name 2 + # + # $entvar[0] passed variable 1 + # $entvar[1] passed variable 2 + # . + # . + # etc.. + # + ############################################################################## + +} + +sub searchfortrap +{ + + # Variables of trap received by SNMPTRAPD: + # + # $var[0] hostname + # $var[1] ip address + # $var[2] uptime + # $var[3] trapname / OID + # $var[4] ip address from trap agent + # $var[5] trap community string + # $var[6] enterprise + # + # $entvarname[0] passed variable name 1 + # $entvarname[1] passed variable name 2 + # + # $entvar[0] passed variable 1 + # $entvar[1] passed variable 2 + # . + # . + # etc.. + # + # $event hash for each trapped defined in snmptt.conf with following values: + # + # 0: name of trap + # 1: category + # 2: severity + # 3: FORMAT string + # 4: EXEC string + # 5: NODES string + # 6: REGEX array + # 7: MATCH array + # 9: DESC array + # + # Example: To access FORMAT string for received trap: + # $event{"$var[3]"}[3] + # + # or + # + # $event{"$receivedtrap"}[3] + ############################################################################### + # Check to see if received trap is defined in the snmptt.conf, and perform variable + # substitution, logging etc if found + + # Look for matching OID + + $processed = 0; + $receivedtrap = $var[3]; + $receivedtrap_entry = $receivedtrap; # Will be used to processtrap to lookup EVENT info + # Changed to actual EVENT entry if using a wildcard + + $trap_attempted_to_log = 0; + $trap_successfully_logged = 0; + + # Check for exact match + if (exists $event{"$receivedtrap"}) + { + if ($DEBUGGING >= 1) + { + print "Exact match of trap found in EVENT hash table\n\n"; + } + + &processtrap; + } + else + { + if ($DEBUGGING >= 1) + { + print "Exact match of trap NOT found in EVENT hash table\n\n"; + } + } + + # Check for wildcard match in hash table if not already processed + if ($processed == 0) + { + my $receivedtraptemp = $receivedtrap; + + my $counter = 0; # Drill down only 40 times. Should never need this, but + # it's here to prevent an infinite loop in this while statement + # just in case + + if ($DEBUGGING >= 1) + { + print "Looking for wildcards in the EVENT hash table\n"; + } + + while ($counter <= 40 && $receivedtraptemp ne '') + { + # Remove last digit of recevied trap, add a * and look for match + $receivedtraptemp =~ s/(.*)\.\d+$/$1/; + + if ($DEBUGGING >= 2) + { + print "Drilling down looking for wildcards in the EVENT hash table\n"; + print $receivedtraptemp.".\*\n\n"; + } + + if (exists $event{$receivedtraptemp.'.*'}) + { + $receivedtrap_entry = $receivedtraptemp.'.*'; # Set $receivedtrap to matching trap with wildcard + &processtrap; + last; # found, so stop this while loop + } + $counter++; + } + } + + # Log to unknowntraplog etc if no match was found + if ($processed == 0) + { + if ($DEBUGGING >= 1) + { + print "\n\nTrap not defined...\n\n"; + } + + # Statistics + $g_total_traps_unknown++; + + if ($unknown_trap_exec ne "") { + if ($DEBUGGING >= 1) { + print "\n\nUnknown trap EXEC line:\n"; + } + + my $command; + + if ($unknown_trap_exec_format ne "") { + $_ = $unknown_trap_exec_format; + + &substitute; + + $command = $unknown_trap_exec .= " \"$_\""; + } + else { + $command = $unknown_trap_exec . " \""; + $command .= scalar($trap_date_time) . ": Unknown trap ($var[3]) received from $var[0] at:"; + + #print out all standard variables + for (my $i=0;$i <= $#var;$i++) { + $command .= " Value $i: $var[$i]"; + } + + #print out all enterprise specific variables + for (my $i=0;$i <= $#entvar;$i++) { + $command .= " Ent Value $i: $entvarname[$i]=$entvar[$i]"; + } + + $command .= "\""; + } + if ($DEBUGGING >= 1) { + print "Unknown trap EXEC command:$command\n"; + } + + # Execute command + + if ($exec_escape == 1) { + # Escape wildcard characters + $command =~ s/\*/\\\*/g; + $command =~ s/\?/\\\?/g; + } + system $command; + } + + if ($unknown_trap_log_enable == 1) + { + if ($unknown_trap_log_file ne "") { + if (open LOGFILE, ">>$unknown_trap_log_file") + { + print LOGFILE scalar($trap_date_time),": Unknown trap ($var[3]) received from $var[0] at: \n"; + #print out all standard variables + for (my $i=0;$i <= $#var;$i++) + { + print LOGFILE "Value $i: $var[$i]\n"; + } + #print out all enterprise specific variables + for (my $i=0;$i <= $#entvar;$i++) + { + print LOGFILE "Ent Value $i: $entvarname[$i]=$entvar[$i]\n"; + } + print LOGFILE "\n\n"; + close LOGFILE; + } + else + { + warn "Can not open log_file: $!"; + } + } + + my $message_short; + if ( ($mysql_dbi_enable == 1) || + ($postgresql_dbi_enable == 1) || + ($dbd_odbc_enable == 1) || + ($sql_win32_odbc_enable == 1) ) { + + if ($DEBUGGING >= 1) + { + print "Logging unknown trap to SQL\n"; + } + + # Translate if enabled, and if we can + $receivedtrap_trans = &translate_log_trap_oid_sub($receivedtrap); + + $enterprise_trans = &translate_enterprise_oid_format_sub($var[6]); + + if ($net_snmp_perl_enable == 1 && $db_translate_enterprise == 1) + { + $db_enterprise = $enterprise_trans; + } + else + { + $db_enterprise = $var[6]; + } + + $_ = $db_unknown_trap_format; + + &substitute; + + $message_short = $_; + } + + if ($mysql_dbi_enable == 1 && defined ($dbh_mysql) && $mysql_dbi_table_unknown ne "") + { + # Backslash any quotes + my $message_short2 = $message_short; + $message_short2 =~ s(\')(\\\')g; #' + $message_short2 =~ s(\")(\\\")g; #" + + my $community = $var[5]; + $community =~ s(\')(\\\')g; #' + $community =~ s(\")(\\\")g; #" + + my @t_sql_custom_columns_unknown = (); + + if (@sql_custom_columns_unknown) { + @t_sql_custom_columns_unknown = @sql_custom_columns_unknown; + + for (my $i = 1; $i <= $#t_sql_custom_columns_unknown; $i+=2) { + $_ = $t_sql_custom_columns_unknown[$i]; + print "Performing substitution on custom column: $_\n"; + &substitute(); + print "Done performing substitution on custom column: $_\n"; + $t_sql_custom_columns_unknown[$i] = $_; + } + } + + &mysql_insert($mysql_dbi_table_unknown, + "trapoid", $receivedtrap_trans, + "enterprise", $db_enterprise, + "community", $community, + "hostname", $agent_dns_name, + "agentip", $var[4], + "uptime", $var[2], + "traptime", $trap_date_time_sql, + "formatline", $message_short2, + @t_sql_custom_columns_unknown); + } + + if ($postgresql_dbi_enable == 1 && defined ($dbh_postgresql) && $postgresql_dbi_table_unknown ne "") + { + # Backslash any quotes + my $message_short2 = $message_short; + $message_short2 =~ s(\')(\\\')g; #' + $message_short2 =~ s(\")(\\\")g; #" + + my $community = $var[5]; + $community =~ s(\')(\\\')g; #' + $community =~ s(\")(\\\")g; #" + + my @t_sql_custom_columns_unknown = (); + + if (@sql_custom_columns_unknown) { + @t_sql_custom_columns_unknown = @sql_custom_columns_unknown; + + for (my $i = 1; $i <= $#t_sql_custom_columns_unknown; $i+=2) { + $_ = $t_sql_custom_columns_unknown[$i]; + print "Performing substitution on custom column: $_\n"; + &substitute(); + print "Done performing substitution on custom column: $_\n"; + $t_sql_custom_columns_unknown[$i] = $_; + } + } + + &postgresql_insert($postgresql_dbi_table_unknown, + "trapoid", $receivedtrap_trans, + "enterprise", $db_enterprise, + "community", $community, + "hostname", $agent_dns_name, + "agentip", $var[4], + "uptime", $var[2], + "traptime", $trap_date_time_sql, + "formatline", $message_short2, + @t_sql_custom_columns_unknown); + + } + + if ($dbd_odbc_enable == 1 && defined ($dbh_odbc) && $dbd_odbc_table_unknown ne "") + { + # Double any single quotes + my $message_short2 = $message_short; + $message_short2 =~ s(\')('')g; #' + + my $community = $var[5]; + $community =~ s(\')('')g; #' + + my @t_sql_custom_columns_unknown = (); + + if (@sql_custom_columns_unknown) { + @t_sql_custom_columns_unknown = @sql_custom_columns_unknown; + + for (my $i = 1; $i <= $#t_sql_custom_columns_unknown; $i+=2) { + $_ = $t_sql_custom_columns_unknown[$i]; + print "Performing substitution on custom column: $_\n"; + &substitute(); + print "Done performing substitution on custom column: $_\n"; + $t_sql_custom_columns_unknown[$i] = $_; + } + } + + &odbc_insert($dbd_odbc_table_unknown, + "trapoid", $receivedtrap_trans, + "enterprise", $db_enterprise, + "community", $community, + "hostname", $agent_dns_name, + "agentip", $var[4], + "uptime", $var[2], + "traptime", $trap_date_time_sql, + "formatline", $message_short2, + @t_sql_custom_columns_unknown); + + } + + if ($sql_win32_odbc_enable == 1 && defined ($dbh_win32_odbc) && $sql_win32_odbc_table_unknown ne "") + { + # Double any single quotes + my $message_short2 = $message_short; + $message_short2 =~ s(\')('')g; #' + + my $community = $var[5]; + $community =~ s(\')('')g; #' + + my @t_sql_custom_columns_unknown = (); + + if (@sql_custom_columns_unknown) { + @t_sql_custom_columns_unknown = @sql_custom_columns_unknown; + + for (my $i = 1; $i <= $#t_sql_custom_columns_unknown; $i+=2) { + $_ = $t_sql_custom_columns_unknown[$i]; + print "Performing substitution on custom column: $_\n"; + &substitute(); + print "Done performing substitution on custom column: $_\n"; + $t_sql_custom_columns_unknown[$i] = $_; + } + } + + &sql_win32_odbc_insert($sql_win32_odbc_table_unknown, + "trapoid", $receivedtrap_trans, + "enterprise", $db_enterprise, + "community", $community, + "hostname", $agent_dns_name, + "agentip", $var[4], + "uptime", $var[2], + "traptime", $trap_date_time_sql, + "formatline", $message_short2, + @t_sql_custom_columns_unknown); + + } + } + } + + # If keep_unlogged_traps is set to 0, or if we didn't even try to log, set it as a successful log + # so the trap file gets deleted from the spool dir (the trap wasn't found, or a node didn't match) + if ($trap_attempted_to_log == 0 || $keep_unlogged_traps == 0) + { + $trap_successfully_logged = 1; + } + elsif ($keep_unlogged_traps == 1) # Delete spool if ONE successfully logged + { + if ($trap_successfully_logged >= 1) + { + $trap_successfully_logged = 1; + } + else + { + $trap_successfully_logged = 0; + } + } + elsif ($keep_unlogged_traps == 2) # Delete spool if ALL successfully logged + { + if ($trap_successfully_logged == $trap_attempted_to_log) + { + $trap_successfully_logged = 1; + } + else + { + $trap_successfully_logged = 0; + } + } +} + +sub findsnmpttini +{ + ############################################################################## + # Load config file start + # + # For Linux / Unix, try in order: + # /etc/snmp/snmptt.ini + # /etc/snmptt.ini + # /usr/local/etc/snmp/snmptt.ini + # /usr/local/etc/snmptt.ini + # + # + # For Windows, try %SystemRoot%\snmptt.ini only. + # + if ($ini ne '') + { + $configfile = $ini; + } + else + { + if ($^O ne "MSWin32") + { + $configfile = '/etc/snmp/snmptt.ini'; + if( open( CONFIG, '/etc/snmp/snmptt.ini' ) ) + { + $configfile = '/etc/snmp/snmptt.ini'; + close CONFIG; + } + elsif ( open( CONFIG, '/etc/snmptt.ini' ) ) + { + $configfile = '/etc/snmptt.ini'; + close CONFIG; + } + elsif ( open( CONFIG, '/usr/local/etc/snmp/snmptt.ini' ) ) + { + $configfile = '/usr/local/etc/snmp/snmptt.ini'; + close CONFIG; + } + elsif ( open( CONFIG, '/usr/local/etc/snmptt.ini' ) ) + { + $configfile = '/usr/local/etc/snmptt.ini'; + close CONFIG; + } + } + else { + $configfile = $ENV{'SystemRoot'}."\\snmptt.ini"; + } + } +} + +sub loadsnmpttini { + + ############################################################################## + # + # Load config file start + # + # + ############################################################################## + + use Config::IniFiles; + my $cfg; + + if( open( CONFIG, $configfile ) ) { + close CONFIG; + $cfg = new Config::IniFiles( -file => $configfile); + if ($DEBUGGING >= 0) { + print "Config file $configfile loaded\n"; + } + } + else + { + if ($DEBUGGING >= 0) { + print "Config file could not be loaded\n"; + } + exit(1); + } + + if (! $cfg) + { + if ($DEBUGGING >= 0) { + print "Error in config file - please check the syntax in the config file\n"; + } + exit(1); + } + + @snmptt_conf_files = ''; + + # General + if ( ($cfg->val('General', 'mode') eq "daemon") || ($daemoncmdline == 1) ) + { + $daemon = 1; + } + else { + $daemon = 0; + } + + $snmptt_system_name = $cfg->val('General', 'snmptt_system_name'); + $multiple_event = $cfg->val('General', 'multiple_event'); + $dns_enable = $cfg->val('General', 'dns_enable'); + $strip_domain = $cfg->val('General', 'strip_domain'); + @strip_domain_list = $cfg->val('General', 'strip_domain_list'); + $net_snmp_perl_enable = $cfg->val('General', 'net_snmp_perl_enable'); + $net_snmp_perl_best_guess = $cfg->val('General', 'net_snmp_perl_best_guess'); + $translate_log_trap_oid = $cfg->val('General', 'translate_log_trap_oid'); + $translate_value_oids = $cfg->val('General', 'translate_value_oids'); + $resolve_value_ip_addresses = $cfg->val('General', 'resolve_value_ip_addresses'); + $translate_enterprise_oid_format = $cfg->val('General', 'translate_enterprise_oid_format'); + $translate_trap_oid_format = $cfg->val('General', 'translate_trap_oid_format'); + $translate_varname_oid_format = $cfg->val('General', 'translate_varname_oid_format'); + $translate_integers = $cfg->val('General', 'translate_integers'); + $wildcard_expansion_separator = $cfg->val('General', 'wildcard_expansion_separator'); + $mibs_environment = $cfg->val('General', 'mibs_environment'); + $allow_unsafe_regex = $cfg->val('General', 'allow_unsafe_regex'); + $remove_backslash_from_quotes = $cfg->val('General', 'remove_backslash_from_quotes'); + $dynamic_nodes = $cfg->val('General', 'dynamic_nodes'); + $description_mode = $cfg->val('General', 'description_mode'); + $description_clean = $cfg->val('General', 'description_clean'); + $threads_enable = $cfg->val('General', 'threads_enable'); + $threads_max = $cfg->val('General', 'threads_max'); + $date_format = $cfg->val('General', 'date_format'); + $time_format = $cfg->val('General', 'time_format'); + $date_time_format = $cfg->val('General', 'date_time_format'); + + # DaemonMode + $daemon_fork = $cfg->val('DaemonMode', 'daemon_fork'); + $daemon_uid = $cfg->val('DaemonMode', 'daemon_uid'); + $pid_file = $cfg->val('DaemonMode', 'pid_file'); + $spool_directory = $cfg->val('DaemonMode', 'spool_directory'); + $sleep = $cfg->val('DaemonMode', 'sleep'); + $use_trap_time = $cfg->val('DaemonMode', 'use_trap_time'); + $keep_unlogged_traps = $cfg->val('DaemonMode', 'keep_unlogged_traps'); + + # Logging + $stdout_enable = $cfg->val('Logging', 'stdout_enable'); + $log_enable = $cfg->val('Logging', 'log_enable'); + $log_file = $cfg->val('Logging', 'log_file'); + $log_system_enable = $cfg->val('Logging', 'log_system_enable'); + $log_system_file = $cfg->val('Logging', 'log_system_file'); + $unknown_trap_log_enable = $cfg->val('Logging', 'unknown_trap_log_enable'); + $unknown_trap_log_file = $cfg->val('Logging', 'unknown_trap_log_file'); + $statistics_interval = $cfg->val('Logging', 'statistics_interval'); + $syslog_enable = $cfg->val('Logging', 'syslog_enable'); + $syslog_facility = $cfg->val('Logging', 'syslog_facility'); + @syslog_level_alert = $cfg->val('Logging', 'syslog_level_alert'); + @syslog_level_crit = $cfg->val('Logging', 'syslog_level_crit'); + @syslog_level_err = $cfg->val('Logging', 'syslog_level_err'); + @syslog_level_warning = $cfg->val('Logging', 'syslog_level_warning'); + @syslog_level_notice = $cfg->val('Logging', 'syslog_level_notice'); + @syslog_level_info = $cfg->val('Logging', 'syslog_level_info'); + @syslog_level_debug = $cfg->val('Logging', 'syslog_level_debug'); + $syslog_level = $cfg->val('Logging', 'syslog_level'); + $syslog_system_enable = $cfg->val('Logging', 'syslog_system_enable'); + $syslog_system_facility = $cfg->val('Logging', 'syslog_system_facility'); + $syslog_system_level = $cfg->val('Logging', 'syslog_system_level'); + $eventlog_enable = $cfg->val('Logging', 'eventlog_enable'); + @eventlog_type_information = $cfg->val('Logging', 'eventlog_type_information'); + @eventlog_type_warning = $cfg->val('Logging', 'eventlog_type_warning'); + @eventlog_type_error = $cfg->val('Logging', 'eventlog_type_error'); + $eventlog_type = $cfg->val('Logging', 'eventlog_type'); + $eventlog_system_enable = $cfg->val('Logging', 'eventlog_system_enable'); + + # Exec + $exec_enable = $cfg->val('Exec', 'exec_enable'); + $pre_exec_enable = $cfg->val('Exec', 'pre_exec_enable'); + $unknown_trap_exec = $cfg->val('Exec', 'unknown_trap_exec'); + $unknown_trap_exec_format = $cfg->val('Exec', 'unknown_trap_exec_format'); + $exec_escape = $cfg->val('Exec', 'exec_escape'); + + # SQL + $db_translate_enterprise = $cfg->val('SQL', 'db_translate_enterprise'); + $db_unknown_trap_format = $cfg->val('SQL', 'db_unknown_trap_format'); + $mysql_dbi_enable = $cfg->val('SQL', 'mysql_dbi_enable'); + $mysql_dbi_host = $cfg->val('SQL', 'mysql_dbi_host'); + $mysql_dbi_port = $cfg->val('SQL', 'mysql_dbi_port'); + $mysql_dbi_database = $cfg->val('SQL', 'mysql_dbi_database'); + $mysql_dbi_table = $cfg->val('SQL', 'mysql_dbi_table'); + $mysql_dbi_table_unknown = $cfg->val('SQL', 'mysql_dbi_table_unknown'); + $mysql_dbi_table_statistics = $cfg->val('SQL', 'mysql_dbi_table_statistics'); + $mysql_dbi_username = $cfg->val('SQL', 'mysql_dbi_username'); + $mysql_dbi_password = $cfg->val('SQL', 'mysql_dbi_password'); + $mysql_ping_on_insert = $cfg->val('SQL', 'mysql_ping_on_insert'); + $mysql_ping_interval = $cfg->val('SQL', 'mysql_ping_interval'); + + $postgresql_dbi_enable = $cfg->val('SQL', 'postgresql_dbi_enable'); + $postgresql_dbi_module = $cfg->val('SQL', 'postgresql_dbi_module'); + $postgresql_dbi_hostport_enable = $cfg->val('SQL', 'postgresql_dbi_hostport_enable'); + $postgresql_dbi_host = $cfg->val('SQL', 'postgresql_dbi_host'); + $postgresql_dbi_port = $cfg->val('SQL', 'postgresql_dbi_port'); + $postgresql_dbi_database = $cfg->val('SQL', 'postgresql_dbi_database'); + $postgresql_dbi_table = $cfg->val('SQL', 'postgresql_dbi_table'); + $postgresql_dbi_table_unknown = $cfg->val('SQL', 'postgresql_dbi_table_unknown'); + $postgresql_dbi_table_statistics = $cfg->val('SQL', 'postgresql_dbi_table_statistics'); + $postgresql_dbi_username = $cfg->val('SQL', 'postgresql_dbi_username'); + $postgresql_dbi_password = $cfg->val('SQL', 'postgresql_dbi_password'); + $postgresql_ping_on_insert = $cfg->val('SQL', 'postgresql_ping_on_insert'); + $postgresql_ping_interval = $cfg->val('SQL', 'postgresql_ping_interval'); + + $dbd_odbc_enable = $cfg->val('SQL', 'dbd_odbc_enable'); + $dbd_odbc_dsn = $cfg->val('SQL', 'dbd_odbc_dsn'); + $dbd_odbc_table = $cfg->val('SQL', 'dbd_odbc_table'); + $dbd_odbc_table_unknown = $cfg->val('SQL', 'dbd_odbc_table_unknown'); + $dbd_odbc_table_statistics = $cfg->val('SQL', 'dbd_odbc_table_statistics'); + $dbd_odbc_username = $cfg->val('SQL', 'dbd_odbc_username'); + $dbd_odbc_password = $cfg->val('SQL', 'dbd_odbc_password'); + $dbd_odbc_ping_on_insert = $cfg->val('SQL', 'dbd_odbc_ping_on_insert'); + $dbd_odbc_ping_interval = $cfg->val('SQL', 'dbd_odbc_ping_interval'); + + $sql_win32_odbc_enable = $cfg->val('SQL', 'sql_win32_odbc_enable'); + $sql_win32_odbc_dsn = $cfg->val('SQL', 'sql_win32_odbc_dsn'); + $sql_win32_odbc_table = $cfg->val('SQL', 'sql_win32_odbc_table'); + $sql_win32_odbc_table_unknown = $cfg->val('SQL', 'sql_win32_odbc_table_unknown'); + $sql_win32_odbc_table_statistics = $cfg->val('SQL', 'sql_win32_odbc_table_statistics'); + $sql_win32_odbc_username = $cfg->val('SQL', 'sql_win32_odbc_username'); + $sql_win32_odbc_password = $cfg->val('SQL', 'sql_win32_odbc_password'); + + @sql_custom_columns = $cfg->val('SQL', 'sql_custom_columns'); + @sql_custom_columns_unknown = $cfg->val('SQL', 'sql_custom_columns_unknown'); + + $date_time_format_sql = $cfg->val('SQL', 'date_time_format_sql'); + $stat_time_format_sql = $cfg->val('SQL', 'stat_time_format_sql'); + + # Debugging + if ($debugcmdline == 0) { + $DEBUGGING = $cfg->val('Debugging', 'DEBUGGING'); + } + if ($debugfilecmdline == 0) { + $DEBUGGING_FILE = $cfg->val('Debugging', 'DEBUGGING_FILE'); + } + + # TrapFiles + @snmptt_conf_files = $cfg->val('TrapFiles', 'snmptt_conf_files'); + + $cfg->Delete; + + # + # Defaults Start + # + if ($snmptt_system_name eq "") { + if (hostname ne "") { + $snmptt_system_name = hostname; + } + } + if (! defined ($multiple_event)) { $multiple_event = 0} ; + if (! defined ($dns_enable)) { $dns_enable = 0} ; + if (! defined ($strip_domain)) { $strip_domain = 0} ; + if (! defined ($net_snmp_perl_enable)) { $net_snmp_perl_enable = 0} ; + if (! defined ($net_snmp_perl_best_guess)) { $net_snmp_perl_best_guess = 0} ; + if (! defined ($translate_log_trap_oid)) { $translate_log_trap_oid = 0} ; + if (! defined ($translate_value_oids)) { $translate_value_oids = 0} ; + if (! defined ($resolve_value_ip_addresses)) { $resolve_value_ip_addresses = 0} ; + if (! defined ($translate_enterprise_oid_format)) { $translate_enterprise_oid_format = 1} ; + if (! defined ($translate_trap_oid_format)) { $translate_trap_oid_format = 1} ; + if (! defined ($translate_varname_oid_format)) { $translate_varname_oid_format = 1} ; + if (! defined ($translate_integers)) { $translate_integers = 0} ; + if (! defined ($wildcard_expansion_separator)) { $wildcard_expansion_separator = " "} ; + if (! defined ($allow_unsafe_regex)) { $allow_unsafe_regex = 0} ; + if (! defined ($remove_backslash_from_quotes)) { $remove_backslash_from_quotes = 0} ; + if (! defined ($dynamic_nodes)) { $dynamic_nodes = 0} ; + if (! defined ($description_mode)) { $description_mode = 0} ; + if (! defined ($description_clean)) { $description_clean = 1} ; + if (! defined ($threads_enable)) { $threads_enable = 0} ; + if (! defined ($threads_max)) { $threads_max = 10} ; + if (! defined ($date_format)) { $date_format = "%a %b %e %Y"} ; + if (! defined ($time_format)) { $time_format = "%H:%M:%S"} ; + if (! defined ($date_time_format)) { $date_time_format = ""} ; + if (! defined ($date_time_format_sql)) { $date_time_format_sql = ""} ; + if (! defined ($stat_time_format_sql)) { $stat_time_format_sql = ""} ; + + if (! defined ($daemon_fork)) { $daemon_fork = 1} ; + if (! defined ($daemon_uid)) { $daemon_uid = ''} ; + if (! defined ($pid_file)) { $pid_file = ''} ; + if (! defined ($spool_directory)) { $spool_directory = ''} ; + if (! defined ($sleep)) { $sleep = 5} ; + if (! defined ($use_trap_time)) { $use_trap_time = 1} ; + + if (! defined ($keep_unlogged_traps)) { $keep_unlogged_traps = 1} ; + if (! defined ($stdout_enable)) { $stdout_enable = 0} ; + if (! defined ($log_enable)) { $log_enable = 1} ; + if (! defined ($log_file)) { $log_file = ''} ; + if (! defined ($log_system_enable)) { $log_system_enable = 0} ; + if (! defined ($log_system_file)) { $log_system_file = ''} ; + if (! defined ($unknown_trap_log_enable)) { $unknown_trap_log_enable = 0} ; + if (! defined ($unknown_trap_log_file)) { $unknown_trap_log_file = ''} ; + if (! defined ($syslog_enable)) { $syslog_enable = 0} ; + if (! defined ($syslog_facility)) { $syslog_facility = 'local0'} ; + if (! defined ($statistics_interval)) { $statistics_interval = 0} ; + if (! defined ($syslog_level)) { $syslog_level = 'warning'} ; + if (! defined ($syslog_system_enable)) { $syslog_system_enable = 0} ; + if (! defined ($syslog_system_facility)) { $syslog_system_facility = 'local0'} ; + if (! defined ($syslog_system_level)) { $syslog_system_level = 'warning'} ; + if (! defined ($eventlog_enable)) { $eventlog_enable = 0} ; + if (! defined ($eventlog_enable)) { $eventlog_enable = 'WARNING'} ; + if (! defined ($eventlog_system_enable)) { $eventlog_system_enable = 0} ; + if (! defined ($exec_enable)) { $exec_enable = 1} ; + if (! defined ($pre_exec_enable)) { $pre_exec_enable = 1} ; + if (! defined ($unknown_trap_exec)) { $unknown_trap_exec = ''} ; + if (! defined ($unknown_trap_exec_format)) { $unknown_trap_exec_format = ''} ; + if (! defined ($exec_escape)) { + if ($^O =~ /MSWin32/) { + $exec_escape = 0; + } + else { + $exec_escape = 1; + } + } + if (! defined ($db_translate_enterprise)) { $db_translate_enterprise = 0} ; + if (! defined ($db_unknown_trap_format)) { $db_unknown_trap_format = '$-*'} ; + if (! defined ($mysql_dbi_enable)) { $mysql_dbi_enable = 0} ; + if (! defined ($mysql_dbi_host)) { $mysql_dbi_host = 'localhost'} ; + if (! defined ($mysql_dbi_port)) { $mysql_dbi_port = '3306'} ; + if (! defined ($mysql_dbi_database)) { $mysql_dbi_database = ''} ; + if (! defined ($mysql_dbi_table)) { $mysql_dbi_table = ''} ; + if (! defined ($mysql_dbi_table_unknown)) { $mysql_dbi_table_unknown = ''} ; + if (! defined ($mysql_dbi_table_statistics)) { $mysql_dbi_table_statistics = ''} ; + if (! defined ($mysql_dbi_username)) { $mysql_dbi_username = ''} ; + if (! defined ($mysql_dbi_password)) { $mysql_dbi_password = ''} ; + if (! defined ($mysql_ping_on_insert)) { $mysql_ping_on_insert = 1} ; + if (! defined ($mysql_ping_interval)) { $mysql_ping_interval = 500} ; + if (! defined ($postgresql_dbi_enable)) { $postgresql_dbi_enable = 0} ; + if (! defined ($postgresql_dbi_module)) { $postgresql_dbi_module = 0} ; + if (! defined ($postgresql_dbi_hostport_enable)) { $postgresql_dbi_hostport_enable = 0} ; + if (! defined ($postgresql_dbi_host)) { $postgresql_dbi_host = 'localhost'} ; + if (! defined ($postgresql_dbi_port)) { $postgresql_dbi_port = '5432'} ; + if (! defined ($postgresql_dbi_database)) { $postgresql_dbi_database = ''} ; + if (! defined ($postgresql_dbi_table)) { $postgresql_dbi_table = ''} ; + if (! defined ($postgresql_dbi_table_unknown)) { $postgresql_dbi_table_unknown = ''} ; + if (! defined ($postgresql_dbi_table_statistics)) { $postgresql_dbi_table_statistics = ''} ; + if (! defined ($postgresql_dbi_username)) { $postgresql_dbi_username = ''} ; + if (! defined ($postgresql_dbi_password)) { $postgresql_dbi_password = ''} ; + if (! defined ($postgresql_ping_on_insert)) { $postgresql_ping_on_insert = 1} ; + if (! defined ($postgresql_ping_interval)) { $postgresql_ping_interval = 500} ; + if (! defined ($dbd_odbc_enable)) { $dbd_odbc_enable = 0} ; + if (! defined ($dbd_odbc_dsn)) { $dbd_odbc_dsn = ''} ; + if (! defined ($dbd_odbc_table)) { $dbd_odbc_table = ''} ; + if (! defined ($dbd_odbc_table_unknown)) { $dbd_odbc_table_unknown = ''} ; + if (! defined ($dbd_odbc_table_statistics)) { $dbd_odbc_table_statistics = ''} ; + if (! defined ($dbd_odbc_username)) { $dbd_odbc_username = ''} ; + if (! defined ($dbd_odbc_password)) { $dbd_odbc_password = ''} ; + if (! defined ($dbd_odbc_ping_on_insert)) { $dbd_odbc_ping_on_insert = 1} ; + if (! defined ($dbd_odbc_ping_interval)) { $dbd_odbc_ping_interval = 500} ; + if (! defined ($sql_win32_odbc_enable)) { $sql_win32_odbc_enable = 0} ; + if (! defined ($sql_win32_odbc_dsn)) { $sql_win32_odbc_dsn = ''} ; + if (! defined ($sql_win32_odbc_table)) { $sql_win32_odbc_table = ''} ; + if (! defined ($sql_win32_odbc_table_unknown)) { $sql_win32_odbc_table_unknown = ''} ; + if (! defined ($sql_win32_odbc_table_statistics)) { $sql_win32_odbc_table_statistics = ''} ; + if (! defined ($sql_win32_odbc_username)) { $sql_win32_odbc_username = ''} ; + if (! defined ($sql_win32_odbc_password)) { $sql_win32_odbc_password = ''} ; + if (! (@sql_custom_columns)) { @sql_custom_columns = ()} ; + if (! (@sql_custom_columns_unknown)) { @sql_custom_columns_unknown = ()} ; + if (! defined ($DEBUGGING)) { $DEBUGGING = 0} ; + if (! defined ($DEBUGGING_FILE)) { $DEBUGGING_FILE = ''} ; + + # Make sure it's at least 3 characters, and remove quotes around wildcard_expansion_separator + if (length ($wildcard_expansion_separator) < 3) + { + $wildcard_expansion_separator = "x x"; + } + $wildcard_expansion_separator = substr($wildcard_expansion_separator,1,(length($wildcard_expansion_separator)-2)); + # + # Defaults End + # + + # print "Config file loaded\n"; + + # + # Load config file end + # + ############################################################################## +} + +sub signal_handler_reload { + # + # Daemon reload + # + $timetoreload = 1; +} + +sub signal_handler_die { + # + # Daemon die + # + $timetodie = 1; +} + +sub syslog_system { + my $message = $_[0]; + if (Sys::Syslog::openlog('snmptt-sys[' . $> . ']', '',$syslog_system_facility) ) + { + Sys::Syslog::syslog ($syslog_system_level, $message,1); + Sys::Syslog::closelog(); + } + else + { + warn "Can not open log_file: $!"; + print "Can not open syslog. Message to be logged: $message\n" if ($DEBUGGING >= 1); + } + +} + +sub log_system { + my $message = $_[0]; + + my @localtime_array = localtime(); + my $log_time; + + if ($date_time_format eq "") { + $log_time = localtime(); + } + else { + $log_time = strftime $date_time_format, @localtime_array; + } + + if (open LOGSYSFILE, ">>$log_system_file") + { + print LOGSYSFILE $log_time." $message\n"; + close LOGSYSFILE; + } + else + { + warn "Can not open log file $log_system_file: $!"; + print "Can not open syslog. Message to be logged: $message\n" if ($DEBUGGING >= 1); + } +} + +sub eventlog_system { + my $message = $_[0]; + my $eventid = $_[1]; + my $type = $_[2]; + my $trap_log = $_[3]; # Should be 1 if this is a trap log. Used + # to set $trap_successfully_logged variable below. + + my %event_entry = ('Source' => "SNMPTT", + 'EventType' => $type, + 'Category' => '\0', + 'EventID' => $eventid, + 'Strings' => $message); + + if (my $eventlog=Win32::EventLog->new('Application') ) + { + unless ($eventlog->Report(\%event_entry) ) + { + warn "Can not create event log entry: $!"; + $eventlog->Close(); + return 1; + } + $eventlog->Close(); + return 0; + } + else + { + warn "Can not open log_file: $!"; + return 1; + } +} + +sub checkip +{ + my $node1 = $_[0]; # Should be a plain IP address + my $node2 = $_[1]; # Can be a plain IP address, CIDR or range + + # Remove all white space + $node1 =~ s/\s*//g; + $node2 =~ s/\s*//g; + + # Check for an exact match + if ($node1 eq $node2) + { + return 1; + } + + #print "node1:$node1\n"; + + # First is an IP address, and second IP address is a CIDR address + if ($node1 =~ /^\d+\.\d+\.\d+\.\d+$/ && $node2 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/) + { + # Get IP address in binary + $node1 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/; + my $node1_binary = dec2bin($1) . dec2bin($2) .dec2bin($3) .dec2bin($4); + + # Get CIDR network address in binary + $node2 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/; + my $cidr_binary = dec2bin($1) . dec2bin($2) .dec2bin($3) .dec2bin($4); + my $net_bits = $5; + my $host_bits = 32 - $net_bits; + $cidr_binary = substr($cidr_binary, 0, $net_bits); + + # Get network number for ip_address + my $node1_binary_net = substr($node1_binary, 0, $net_bits); + + if ($node1_binary_net eq $cidr_binary) + { + return 1; + } + else + { + return 0; + } + } + # First is an IP address, and second IP address is a network range + elsif ($node1 =~ /^\d+\.\d+\.\d+\.\d+$/ && $node2 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)/) + { + # Get IP address in binary + $node1 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/; + my $node1_binary = dec2bin($1) . dec2bin($2) .dec2bin($3) .dec2bin($4); + + # Get left network address in binary + $node2 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)/; + my $left_binary = dec2bin($1) . dec2bin($2) .dec2bin($3) .dec2bin($4); + my $right_binary = dec2bin($5) . dec2bin($6) .dec2bin($7) .dec2bin($8); + + if (bin2dec($node1_binary) >= bin2dec($left_binary) && + bin2dec($node1_binary) <= bin2dec($right_binary)) + { + return 1; + } + else + { + return 0; + } + } + # Didn't match at all, so return 0. + else + { + return 0; + } + +} + +sub dec2bin { + my $str = unpack("B8", pack("C", shift)); + #$str =~ s/^0+(?=\d)//; # otherwise you'll get leading zeros + return $str; +} + +sub bin2dec { + return unpack("N", pack("B32", substr("0" x 32 . shift, -32))); +} + +sub translate_value_oids_sub +{ + my $string = $_[0]; + + if ($string =~ /\.\d+/) # If it appears to contain an OID + { + if ($DEBUGGING >= 2) + { + print " Value appears to contain an OID or IP address.\n"; + } + my $string_temp = $string; + my @oids = (); + my $done = 1; + my $noinf = 0; + + # Find any IP addresses and remove from $string_temp + + $noinf = 0; + while ($done) + { + my $found; + if ($string_temp =~ /(?= 100) # Safe guard to make sure regex pattern search / replace doesn't cause an + # infinit loop in the while. Shouldn't, but just in case.. + { + $done = 0; + if ($DEBUGGING >= 2) + { + print " Possible infinit loop (1) in translate_value_oids_sub averted.\n"; + } + } + } + + # Find all the OIDs and put them in a @oids array, and remove from $string_temp + $done = 1; + my $oid_found = 0; + $noinf = 0; + while ($done) + { + my $found; + if ($string_temp =~ /(?= 100) # Safe guard to make sure regex pattern search / replace doesn't cause an + # infinit loop in the while. Shouldn't, but just in case.. + { + $done = 0; + if ($DEBUGGING >= 2) + { + print " Possible infinit loop (2) in translate_value_oids_sub averted.\n"; + } + } + } + + if ($oid_found == 1 && $DEBUGGING >= 2) + { + print " Value contains an OID.\n"; + } + + # Reverse sort the list to make sure large OIDs are done first, so we don't get half + # converted OIDs. Probably not needed due to look ahead and behind expression below + @oids = reverse sort(@oids); + + #print "oids: @oids\n"; + + # Replace all OIDs in $string with textual names if possible + foreach my $oid (@oids) + { + my $temp = my_translateObj($oid,$translate_value_oids); + if (defined ($temp)) + { + $string =~ s/(?= 2) + { + print " OID: $oid=$temp\n"; + } + } + } + } + else + { + if ($DEBUGGING >= 2) + { + print " Value does not appear to contain an OID\n"; + } + } + # Return the new string + return $string; +} + +sub resolve_value_ip_addresses_sub +{ + my $string = $_[0]; + + if ($string =~ /(?= 2) + { + print " Value appears to contain an IP address.\n"; + } + my $string_temp = $string; + my @hostnames = (); + my $done = 1; + my $noinf = 0; + + # Find any IP addresses and put them in a @oids array, and remove from $string_temp + + $done = 1; + my $hostname_found = 0; + $noinf = 0; + while ($done) + { + my $found; + if ($string_temp =~ /(?= 100) # Safe guard to make sure regex pattern search / replace doesn't cause an + # infinit loop in the while. Shouldn't, but just in case.. + { + $done = 0; + if ($DEBUGGING >= 2) + { + print " Possible infinit loop (1) in resolve_value_ip_addresses_sub averted.\n"; + } + } + } + + if ($hostname_found == 1 && $DEBUGGING >= 2) + { + print " Value contains an IP address.\n"; + } + + #print "hostnames: @hostnames\n"; + + # Replace all ip addresses in $string with textual names if possible + foreach my $hostname (@hostnames) + { + my $temp = gethostbyaddr(Socket::inet_aton($hostname),Socket::AF_INET()); + if (defined ($temp)) + { + if ($DEBUGGING => 2) + { + print " IP address ($hostname) resolved to: $temp\n"; + } + if ($strip_domain) + { + $temp = strip_domain_name($temp, $strip_domain); + } + $string =~ s/(? 2) + { + print " IP address ($hostname) could not be resolved by DNS.\n"; + } + } + } + } + else + { + if ($DEBUGGING >= 2) + { + print " Value does not appear to contain an IP address\n"; + } + } + # Return the new string + return $string; +} + +sub match +{ + my $match = shift; + my $value; + my $not = 0; + my $result = 0; + + if ($DEBUGGING >= 1) { print " MATCH statement: $match\n"; } + + if ($match =~ /^\$(\d+):(.*)/) { + my $match_var = "\$$1"; + $value = $entvar[$1-1]; + $match = $2; + if ($DEBUGGING >= 1) { print " MATCH variable ($match_var) is an enterprise variable. No substitution needed\n"; } + } + else { + $match =~ /^(\$.*?):(.*)/; + my $match_var = $1; + $_ = $match_var; + $match = $2; + if ($DEBUGGING >= 1) { print " Performing substitution on MATCH variable: $match_var\n"; } + &substitute(); + if ($DEBUGGING >= 1) { print " Done performing substitution on MATCH variable $match_var (converted to: $_)\n"; } + $value = $_; + } + + if ($value eq '' || $match eq '') + { + return 0; + } + if ($match =~ /^\!(.*)/) + { + $not = 1; + $match = $1; + } + else + { + $not = 0; + } + + # Match is a REGEX + if ($match =~ /\(.*\)/) + { + #print "Regex detected\n"; + + $result = match_regex($value, $match); + $result = match_result($result, $not); + if ($DEBUGGING >= 1) + { + print " REGEX: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . " Result=" . + ($result == 1 ? "true" : "false") . "\n"; + } + } + # Match is an IP address + elsif ($match =~ /\d+\.\d+\.\d+\.\d+/) + { + #print "IP address of some sort\n"; + $result = checkip($value, $match); + $result = match_result($result, $not); + if ($DEBUGGING >= 1) + { + print " IP ADDRESS: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . " Result=" . + ($result == 1 ? "true" : "false") . "\n"; + } + } + # Match is a bitwise and + elsif ($match =~ /&\d+/) + { + #print "Bitwise and detected\n"; + $result = match_bitwise_and($value, $match); + $result = match_result($result, $not); + if ($DEBUGGING >= 1) + { + print " BITWISE AND: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . " Result=" . + ($result == 1 ? "true" : "false") . "\n"; + } + } + # Match is a number + elsif ($match =~ /\d+/) + { + #print "Number detected\n"; + $result = match_number($value, $match); + $result = match_result($result, $not); + if ($DEBUGGING >= 1) + { + print " NUMBER: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . " Result=" . + ($result == 1 ? "true" : "false") . "\n"; + } + } + # Unknown entry - ignore it + else + { + if ($DEBUGGING >= 1) + { + print " IGNORED: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . "\n"; + $result = 0; + } + } + + if ($result == 1) + { + #print "true\n"; + return 1; + } + else + { + #print "false\n"; + return 0; + } +} + +sub match_result +{ + my $result = shift; + my $not = shift; + + if ($not == 0) + { + return $result; + } + else + { + if ($result >= 1) + { + return 0; + } + else + { + return 1; + } + } + return 0; +} + +sub match_number +{ + my $value = shift; + my $match = shift; + + my $result; + + if ($match == $value) + { + return 1; + } + elsif ($match =~ /,/) + { + my @temp = split (",",$match); + foreach my $a (@temp) + { + if ($a == $value) + { + return 1; + } + } + } + elsif ($match =~ /^\>(.*)/) + { + if ($value > $1) + { + return 1; + } + } + elsif ($match =~ /^\<(.*)/) + { + if ($value < $1) + { + return 1; + } + } + elsif ($match =~/(\d+)-(\d+)/) + { + if ($value => $1 && $value <= $2) + { + return 1; + } + } + return 0; +} + +sub match_regex +{ + my $value = shift; + my $regex_temp = shift; + + my $result; + my $modifier_i = 0; + + #print "value: $value\n"; + #print "regex: $regex_temp\n"; + + if ($regex_temp =~ /i$/) + { + #print "! i modifier\n"; + $modifier_i = 1; + } + + $regex_temp =~ /\((.*)\)/; + $regex_temp = $1; + + #print ":$regex_temp:\n"; + + if ($regex_temp ne '') + { + if ($DEBUGGING >= 1) + { + print " Doing REGEX MATCH: ($regex_temp)\n"; + } + if ($modifier_i == 1) + { + if ($value =~ /$regex_temp/i) + { + #print "Match!\n"; + return 1; + } + } + else + { + if ($value =~ /$regex_temp/) + { + #print "Match!\n"; + return 1; + } + } + } + return 0; +} + +sub match_bitwise_and +{ + my $value = shift; + my $match = shift; + + # Return if value is not a number + if (! ($value =~ /\d+/)) { + return 0; + } + + # Remove & from value + $match =~ s/^&//; + + my $result; + + # Make sure values are passed as numbers by adding 0 to each + my $temp = 0+$value & 0+$match; + + if ($temp > 0) + { + return 1; + } + return 0; +} + +sub my_translateObj +{ + my $oid = shift; + my $mode = shift; + + my $use_long = 0; + my $include_module = 0; + my $temp; + + if ($mode == 1) # Short text + { + $use_long = 0; + $include_module = 0; + } + elsif ($mode == 2) # Short module::text + { + $use_long = 0; + $include_module = 1; + } + elsif ($mode == 3) # Long text + { + $use_long = 1; + $include_module = 0; + } + elsif ($mode == 4) # Long module::text + { + $use_long = 1; + $include_module = 1; + } + + $temp = &SNMP::translateObj($oid,$use_long,$include_module); + if (defined ($temp)) + { + # If it ends in a single ., chop it off + if ($temp =~ /\.$/) + { + chop $temp; + } + } + return $temp; # Will be either the translated trap, or undef if translateObj failed +} + +# Strip domain name from hostname +sub strip_domain_name +{ + my $name = shift; + my $mode = shift; + + # If mode = 1, strip off all domain names leaving only the host + if ($mode == 1 && !($name =~ /^\d+\.\d+\.\d+\.\d+$/)) + { + if ($name =~ /\./) # Contain a . ? + { + $name =~ /^([^\.]+?)\./; + $name = $1; + } + } + # If mode = 2, strip off the domains as listed in strip_domain_list in .ini file + elsif ($mode == 2 && !($name =~ /^\d+\.\d+\.\d+\.\d+$/)) + { + if (@strip_domain_list) + { + foreach my $strip_domain_list_temp (@strip_domain_list) + { + if ($strip_domain_list_temp =~ /^\..*/) # If domain from list starts with a '.' then remove it first + { + ($strip_domain_list_temp) = $strip_domain_list_temp =~ /^\.(.*)/; + } + + if ($name =~ /^.+\.$strip_domain_list_temp/) # host is something . domain name? + { + $name =~ /(.*)\.$strip_domain_list_temp/; # strip the domain name + $name = $1; + last; # Only process once + } + } + } + } + return $name; +} + +sub my_getType +{ + my $oid = shift; + + # Problem #1: UCD-SNMP 4.2.3 allows getType and mapEnum to be passed a numerical OID. + # Net-SNMP 5.0.8 does not. Because of this, lets try using the OID first. If that + # fails, then we try the short textual OID instead. + + my $type = SNMP::getType($oid); + if (defined($type)) + { + #print "my_getType: numeric\n"; + return $type; + } + else + { + my $temp_textOID = &my_translateObj($oid,0); + #print "temp_textOID:$temp_textOID\n"; + my $type = &SNMP::getType($temp_textOID); + if (defined($type)) + { + #print "my_getType: symbolic\n"; + return $type; + } + else + { + #print "my_getType: failed\n"; + return undef; + } + } +} + +sub my_mapEnum +{ + my $oid = shift; + my $value = shift; + + # Problem #1: UCD-SNMP 4.2.3 allows getType and mapEnum to be passed a numerical OID. + # Net-SNMP 5.0.8 does not. Because of this, lets try using the OID first. If that + # fails, then we try the short textual OID instead. + + my $enum = SNMP::mapEnum($oid, $value); + if (defined($enum)) + { + #print "my_mapEnum: numeric\n"; + return $enum; + } + else + { + my $temp_textOID = &my_translateObj($oid,0); + #print "temp_textOID:$temp_textOID\n"; + my $enum = &SNMP::mapEnum($temp_textOID, $value); + if (defined($enum)) + { + #print "my_mapEnum: symbolic\n"; + return $enum; + } + else + { + #print "my_mapEnum: failed\n"; + return undef; + } + } +} + +sub process_nodes +{ + my $nodes_list = shift; + my @nodes = (); + my @nodes2 = (); + + # print "Processing NODES\n"; + + # Put all the NODES entries into @nodes, and then go through them all and put + # them into @nodes2. This is done so files that are in the NODES list can be + # read in and merged into @nodes2 to allow a NODES line to contain both host + # names / ip addresses AND the entries from nodes files. + @nodes = split /\s/, $nodes_list; + foreach my $a (@nodes) + { + # Contain a \ or /? Must be a filename and not an IP address / network number + if ( ($a =~ /\\|\//) && !($a =~ /\d+\.\d+\.\d+\.\d+/)) + { + #print "!Dynamic enabled\n"; + if (open NODESFILE, $a) + { + while (defined(my $line = )) + { + chomp($line); + # Allow comment lines starting with a # + if (!($line =~ /((^#)|(\s+#)).*/)) + { + my @temp2 = split /\s/, $line; + foreach my $b (@temp2) + { + push (@nodes2, $b); + } + } + } + close NODESFILE; + } + else + { + warn "Can not open NODES file: $a $!"; + } + } + else # Must be a single node + { + push (@nodes2, $a); + } + } + return @nodes2; +} + +# Used when reading received traps to symbolic names in variable names and +# values to numerical +sub translate_symbolic_to_oid +{ + my $temp = shift; + + # Check to see if OID passed from snmptrapd is fully numeric. If not, try to translate + if (! ($temp =~ /^(\.\d+)+$/)) + { + # Not numeric + # Try to convert to numerical + if ($DEBUGGING >= 2) { + print "Symbolic trap variable name detected ($temp). Will attempt to translate to a numerical OID\n"; + } + if ($net_snmp_perl_enable == 1) + { + my $temp3 = SNMP::translateObj("$temp",0); + if (defined ($temp3) ) { + if ($DEBUGGING >= 2) { + print " Translated to $temp3\n\n"; + } + $temp = $temp3; + } + else { + # Could not translate default to numeric + if ($DEBUGGING >= 2) { + print " Could not translate - will leave as-is\n\n"; + } + } + } + else + { + if ($DEBUGGING >= 2) { + print " Could not translate - Net-SNMP Perl module not enabled - will leave as-is\n\n "; + } + } + } + return $temp; +} + +sub translate_log_trap_oid_sub +{ + my $trap_oid_temp = shift; + + if ($net_snmp_perl_enable == 1 && $translate_log_trap_oid) + { + # Try to convert to text + if ($DEBUGGING >= 2) { + print "\nOID of trap: $trap_oid_temp. Will attempt to translate to text\n"; + } + my $temp2 = my_translateObj("$trap_oid_temp",$translate_log_trap_oid); + if (defined ($temp2) ) { + if ($DEBUGGING >= 2) { + print " Translated to $temp2\n"; + } + $trap_oid_temp = $temp2; + } + else { + # Could not translate default to numeric + if ($DEBUGGING >= 2) { + print " Could not translate - defaulting to numeric\n"; + } + } + } + return $trap_oid_temp; +} + +sub translate_enterprise_oid_format_sub +{ + my $enterprise_oid_temp = shift; + + if ($net_snmp_perl_enable == 1 && $var[6] ne '') + { + if ($DEBUGGING >= 2) { + print "\nOID of enterprise: $var[6]. Will attempt to translate to text\n"; + } + my $temp = my_translateObj("$var[6]",$translate_enterprise_oid_format); + if (defined ($temp) ) { + if ($DEBUGGING >= 2) { + print " Translated to $temp\n"; + } + $enterprise_oid_temp = $temp; + } + else + { + # Could not translate default to numeric + if ($DEBUGGING >= 2) { + print " Could not translate - defaulting to numeric\n"; + } + } + } + return $enterprise_oid_temp; +} + +# Log statistics to syslog, event log etc +sub log_statistics { + + if ($DEBUGGING >= 1) + { + print "Total traps received: $g_total_traps_received\n"; + print "Total traps translated: $g_total_traps_translated\n"; + print "Total traps ignored: $g_total_traps_ignored\n"; + print "Total unknown traps: $g_total_traps_unknown\n\n"; + } + + if ($syslog_system_enable == 1) + { + syslog_system("Total traps received=$g_total_traps_received,Total traps translated=$g_total_traps_translated,Total traps ignored=$g_total_traps_ignored,Total unknown traps=$g_total_traps_unknown"); + } + if ($log_system_enable == 1) + { + log_system("Total traps received=$g_total_traps_received,Total traps translated=$g_total_traps_translated,Total traps ignored=$g_total_traps_ignored,Total unknown traps=$g_total_traps_unknown"); + } + if ($eventlog_system_enable == 1) + { + my $message = "" . \ + "Total traps received: $g_total_traps_received\n" . \ + "Total traps translated: $g_total_traps_translated\n" . \ + "Total traps ignored: $g_total_traps_ignored:\n" . \ + "Total unknown traps: $g_total_traps_unknown\n"; + + eventlog_system($message,1,$eventlog_information); + } + + if ($mysql_dbi_enable == 1 && defined ($dbh_mysql) && $mysql_dbi_table_statistics ne "") + { + my $stat_time_temp; + + if ($stat_time_format_sql eq "") { + $stat_time_temp = localtime(); + } + else { + $stat_time_temp = strftime $stat_time_format_sql, localtime(); + } + + &mysql_insert($mysql_dbi_table_statistics, + "stat_time", $stat_time_temp, + "total_received", $g_total_traps_received, + "total_translated", $g_total_traps_translated, + "total_ignored", $g_total_traps_ignored, + "total_unknown", $g_total_traps_unknown); + } + + if ($postgresql_dbi_enable == 1 && defined ($dbh_postgresql) && $postgresql_dbi_table_statistics ne "") + { + my $stat_time_temp; + + if ($stat_time_format_sql eq "") { + $stat_time_temp = localtime(); + } + else { + $stat_time_temp = strftime $stat_time_format_sql, localtime(); + } + + &postgresql_insert($postgresql_dbi_table_statistics, + "stat_time", $stat_time_temp, + "total_received", $g_total_traps_received, + "total_translated", $g_total_traps_translated, + "total_ignored", $g_total_traps_ignored, + "total_unknown", $g_total_traps_unknown); + } + + if ($dbd_odbc_enable == 1 && defined ($dbh_odbc) && $dbd_odbc_table_statistics ne "") + { + my $stat_time_temp; + + if ($stat_time_format_sql eq "") { + $stat_time_temp = localtime(); + } + else { + $stat_time_temp = strftime $stat_time_format_sql, localtime(); + } + + &odbc_insert($dbd_odbc_table_statistics, + "stat_time", $stat_time_temp, + "total_received", $g_total_traps_received, + "total_translated", $g_total_traps_translated, + "total_ignored", $g_total_traps_ignored, + "total_unknown", $g_total_traps_unknown); + } + + if ($sql_win32_odbc_enable == 1 && defined ($dbh_win32_odbc) && $sql_win32_odbc_table_statistics ne "") + { + my $stat_time_temp; + + if ($stat_time_format_sql eq "") { + $stat_time_temp = localtime(); + } + else { + $stat_time_temp = strftime $stat_time_format_sql, localtime(); + } + + &sql_win32_odbc_insert($sql_win32_odbc_table_statistics, + "stat_time", $stat_time_temp, + "total_received", $g_total_traps_received, + "total_translated", $g_total_traps_translated, + "total_ignored", $g_total_traps_ignored, + "total_unknown", $g_total_traps_unknown); + } + + $g_last_statistics_logged = time(); +} + +sub signal_log_statistics { + # + # Statistics log + # + $timetologstatistics = 1; +} + +# Open connections to MySQL, PostresQL, ODBC etc +sub create_db_connections { + &dbh_mysql_connect(); + &dbh_postgresql_connect(); + &dbh_odbc_connect(); + &dbh_win32_odbc_connect(); +} + +sub close_db_connections { + &dbh_mysql_close(); + &dbh_postgresql_close(); + &dbh_odbc_close(); + &dbh_win32_odbc_close(); +} + +sub dbh_mysql_close { + if (defined $dbh_mysql) + { + $dbh_mysql->disconnect; + $dbh_mysql = undef; + } +} + +sub dbh_postgresql_close { + if (defined $dbh_postgresql) + { + $dbh_postgresql->disconnect; + $dbh_postgresql = undef; + } +} + +sub dbh_odbc_close { + if (defined $dbh_odbc) + { + $dbh_odbc->disconnect; + $dbh_odbc = undef; + } +} + +sub dbh_win32_odbc_close { + if (defined $dbh_win32_odbc) + { + $dbh_win32_odbc->Close(); + $dbh_win32_odbc = undef; + } +} + +sub dbh_mysql_connect() { + if ($mysql_dbi_enable == 1) + { + &dbh_mysql_close(); + + unless ($dbh_mysql = DBI->connect("DBI:mysql:database=$mysql_dbi_database;host=$mysql_dbi_host; + port=$mysql_dbi_port",$mysql_dbi_username,$mysql_dbi_password) ) + { + my $msg = "MySQL error: Unable to connect to database: $DBI::errstr"; + warn $msg, "\n"; + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + if ($syslog_system_enable == 1) + { + syslog_system($msg); + } + if ($log_system_enable == 1) + { + log_system($msg); + } + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,12,$eventlog_error); + } + } + } +} + +sub dbh_postgresql_connect() { + if ($postgresql_dbi_enable == 1) + { + my $connect_string; + my $dbi_module; + + if ($postgresql_dbi_module == 0) + { + $dbi_module = "PgPP"; + } + else + { + $dbi_module = "Pg"; + } + + if ($postgresql_dbi_hostport_enable == 0) + { + # No network support + $connect_string = "DBI:$dbi_module:dbname=$postgresql_dbi_database;"; + } + else + { + # Network support - include host and port + $connect_string = "DBI:$dbi_module:dbname=$postgresql_dbi_database;host=$postgresql_dbi_host;port=$postgresql_dbi_port"; + } + + &dbh_postgresql_close(); + + unless ($dbh_postgresql = DBI->connect($connect_string,$postgresql_dbi_username,$postgresql_dbi_password) ) + { + my $msg = "Postgres error: Unable to connect to database: $DBI::errstr"; + warn $msg, "\n"; + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + if ($syslog_system_enable == 1) + { + syslog_system($msg); + } + if ($log_system_enable == 1) + { + log_system($msg); + } + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,18,$eventlog_error); + } + } + } +} + +sub dbh_odbc_connect() { + if ($dbd_odbc_enable == 1) + { + &dbh_odbc_close(); + + unless ($dbh_odbc = DBI->connect("DBI:ODBC:$dbd_odbc_dsn",$dbd_odbc_username,$dbd_odbc_password) ) + { + my $msg = "DBI DBD:ODBC error: Unable to connect to DSN: $DBI::errstr"; + warn $msg, "\n"; + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + if ($syslog_system_enable == 1) + { + syslog_system($msg); + } + if ($log_system_enable == 1) + { + log_system($msg); + } + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,13,$eventlog_error); + } + } + } +} + +sub dbh_win32_odbc_connect() { + if ($sql_win32_odbc_enable == 1) + { + &dbh_win32_odbc_close(); + + unless ($dbh_win32_odbc = new Win32::ODBC("DSN=$sql_win32_odbc_dsn","UID=$sql_win32_odbc_username","PWD=$sql_win32_odbc_password") ) + { + my $msg = "SQL error: Unable to connect to DSN $sql_win32_odbc_dsn:" . Win32::ODBC::Error(); + warn $msg, "\n"; + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,13,$eventlog_error); + } + } + } +} + +sub mysql_ping { + if ($mysql_dbi_enable == 1) { + if (defined ($dbh_mysql)) { + my $rc = $dbh_mysql->ping; + if ($dbh_mysql->{'errno'} != 0) { + &dbh_mysql_connect(); + } + } + else { + &dbh_mysql_connect(); + } + } + + $g_last_mysql_ping = time(); + + if ($DEBUGGING >= 2) + { + print "MYSQL Ping\n" + } +} + +sub postgresql_ping { + if ($postgresql_dbi_enable == 1) { + if (defined ($dbh_postgresql)) { + my $rc = $dbh_postgresql->ping; + if (!$rc) { + &dbh_postgresql_connect(); + } + } + else { + &dbh_postgresql_connect(); + } + } + + $g_last_postgresql_ping = time(); + + if ($DEBUGGING >= 2) + { + print "PostgreSQL Ping\n" + } +} + +sub dbd_odbc_ping { + if ($dbd_odbc_enable == 1) { + if (defined ($dbh_odbc)) { + my $rc = $dbh_odbc->ping; + if (!$rc) { + &dbd_odbc_connect(); + } + } + else { + &dbd_odbc_connect(); + } + } + + $g_last_dbd_odbc_ping = time(); + + if ($DEBUGGING >= 2) + { + print "DBD_ODBC Ping\n" + } +} + +sub mysql_insert { + my $table = shift; + my @data = @_; + + # If the number of elements in @data is odd, remove the last element + # Note: $# returns the last element # so it's reall #$data + 1 + #print "mod :" . $#data % 2 . "\n"; + if ($#data % 2 == 0) { + pop @data; + } + + #print "------------------ mysql_insert ---------------\n"; + + my $sql_prepare = "INSERT INTO $table ("; + my @sql_execute; + + for (my $i = 0; $i < $#data;) { + #print $data[$i]. "\n"; + $sql_prepare .= $data[$i]; + push (@sql_execute, $data[$i+1]); + + $i+=2; + + if ($i < ($#data)) { + $sql_prepare .= ","; + } + } + $sql_prepare .= ") VALUES (?"; + $sql_prepare .= ",?" x ($#data / 2); + $sql_prepare .= ")"; + + #foreach my $x (@sql_execute) { + # print "$x\n"; + #} + + #print "sql_prepare: $sql_prepare\n"; + #print "sql_execute: @sql_execute\n"; + + # Make sure the connection is up + if ($mysql_ping_on_insert == 1) { + &mysql_ping(); + } + + if (defined ($dbh_mysql)) { + my $prepare_successful = 0; + my $do_successful = 0; + + #my $sql_statement = "INSERT INTO $mysql_dbi_table (eventname, eventid, + #trapoid, enterprise, community, hostname, agentip, category, severity, + #uptime, traptime, formatline) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"; + + my $sth_mysql = $dbh_mysql->prepare($sql_prepare); + unless (defined ($sth_mysql)) { + my $msg = "MySQL error " . $dbh_mysql->{'errno'} . ": Unable to perform PREPARE: ".$dbh_mysql->errstr; + warn $msg, "\n"; + + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + + if ($syslog_system_enable == 1) + { + syslog_system($msg); + } + if ($log_system_enable == 1) + { + log_system($msg); + } + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,23,$eventlog_error); + } + } + else { + $prepare_successful = 1; + } + + if ($prepare_successful == 1) + { + unless (defined ($sth_mysql->execute(@sql_execute))) { + my $msg = "MySQL error " . $dbh_mysql->{'errno'} . ": Unable to perform INSERT INTO (EXECUTE): ".$dbh_mysql->errstr; + warn $msg, "\n"; + + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + + if ($syslog_system_enable == 1) + { + syslog_system($msg); + } + + if ($log_system_enable == 1) + { + log_system($msg); + } + + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,15,$eventlog_error); + } + } + else { + $do_successful = 1; + } + } + + if ($do_successful == 1) + { + return 1; + } + } + return 0; +} + +sub postgresql_insert { + my $table = shift; + my @data = @_; + + # If the number of elements in @data is odd, remove the last element + # Note: $# returns the last element # so it's reall #$data + 1 + #print "mod :" . $#data % 2 . "\n"; + if ($#data % 2 == 0) { + pop @data; + } + + #print "------------------ postgresql_insert ---------------\n"; + + my $sql_prepare = "INSERT INTO $table ("; + my @sql_execute; + + for (my $i = 0; $i < $#data;) { + $sql_prepare .= $data[$i]; + push (@sql_execute, $data[$i+1]); + + $i+=2; + + if ($i < ($#data)) { + $sql_prepare .= ","; + } + } + $sql_prepare .= ") VALUES (?"; + $sql_prepare .= ",?" x ($#data / 2); + $sql_prepare .= ")"; + + #foreach my $x (@sql_execute) { + # print "$x\n"; + #} + + #print "sql_prepare: $sql_prepare\n"; + #print "sql_execute: @sql_execute\n"; + + # Make sure the connection is up + if ($postgresql_ping_on_insert == 1) { + &postgresql_ping(); + } + + if (defined ($dbh_postgresql)) { + my $prepare_successful = 0; + my $do_successful = 0; + +# my $sql_statement = "INSERT INTO $postgresql_dbi_table (eventname, eventid, +# trapoid, enterprise, community, hostname, agentip, category, severity, +# uptime, traptime, formatline) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"; + + my $sth_postgresql = $dbh_postgresql->prepare($sql_prepare); + unless (defined ($sth_postgresql)) { + my $msg = "Postgres error: Unable to perform PREPARE: ".$dbh_postgresql->errstr; + warn $msg, "\n"; + + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + + if ($syslog_system_enable == 1) + { + syslog_system($msg); + } + + if ($log_system_enable == 1) + { + log_system($msg); + } + + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,22,$eventlog_error); + } + } + else { + $prepare_successful = 1; + } + + if ($prepare_successful == 1) + { + unless (defined ($sth_postgresql->execute(@sql_execute))) { + my $msg = "Postgres error: Unable to perform INSERT INTO (EXECUTE): ".$dbh_postgresql->errstr; + warn $msg, "\n"; + + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + + if ($syslog_system_enable == 1) + { + syslog_system($msg); + } + if ($log_system_enable == 1) + { + log_system($msg); + } + + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,19,$eventlog_error); + } + } + else { + $do_successful = 1; + } + } + + if ($do_successful == 1) + { + return 1; + } + } + return 0; +} + +sub odbc_insert { + my $table = shift; + my @data = @_; + + # If the number of elements in @data is odd, remove the last element + # Note: $# returns the last element # so it's reall #$data + 1 + #print "mod :" . $#data % 2 . "\n"; + if ($#data % 2 == 0) { + pop @data; + } + + #print "------------------ odbc_insert ---------------\n"; + + my $sql_statement = "INSERT INTO $table ("; + my @sql_values; + + for (my $i = 0; $i < $#data;) { + $sql_statement .= $data[$i]; + push (@sql_values, $data[$i+1]); + + $i+=2; + + if ($i < ($#data)) { + $sql_statement .= ","; + } + } + $sql_statement .= ") VALUES ("; + + for (my $i = 0; $i <= $#sql_values;) { + $sql_statement .= "\'" . @sql_values[$i] . "\'"; + $i++; + + if ($i <= ($#sql_values)) { + $sql_statement .= ","; + } + } + + $sql_statement .= ")"; + + #print "sql_statement: $sql_statement\n"; + + # Make sure the connection is up + if ($dbd_odbc_ping_on_insert == 1) { + &dbd_odbc_ping(); + } + + if (defined ($dbh_odbc)) { + unless (defined ($dbh_odbc->do($sql_statement))) + { + my $msg = warn "DBI DBD::ODBC error: Unable to perform INSERT INTO: ".$dbh_odbc->errstr; + warn $msg, "\n"; + + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + + if ($syslog_system_enable == 1) + { + syslog_system($msg); + } + if ($log_system_enable == 1) + { + log_system($msg); + } + + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,16,$eventlog_error); + } + } + else + { + return 1; + } + return 0; + } +} + +sub sql_win32_odbc_insert { + my $table = shift; + my @data = @_; + + # If the number of elements in @data is odd, remove the last element + # Note: $# returns the last element # so it's reall #$data + 1 + #print "mod :" . $#data % 2 . "\n"; + if ($#data % 2 == 0) { + pop @data; + } + + #print "------------------ sql_win32_odbc_insert ---------------\n"; + + my $sql_statement = "INSERT INTO $table ("; + my @sql_values; + + for (my $i = 0; $i < $#data;) { + $sql_statement .= $data[$i]; + push (@sql_values, $data[$i+1]); + + $i+=2; + + if ($i < ($#data)) { + $sql_statement .= ","; + } + } + $sql_statement .= ") VALUES ("; + + for (my $i = 0; $i <= $#sql_values;) { + $sql_statement .= "\'" . @sql_values[$i] . "\'"; + $i++; + + if ($i <= ($#sql_values)) { + $sql_statement .= ","; + } + } + + $sql_statement .= ")"; + + #print "sql_statement: $sql_statement\n"; + + if (defined ($dbh_win32_odbc)) { + if (defined ($dbh_win32_odbc->Sql($sql_statement))) + { + my $msg = "Win32::ODBC error: Unable to perform INSERT INTO: ".Win32::ODBC::Error(); + warn $msg, "\n"; + + if ($DEBUGGING >= 1) + { + print $msg, "\n"; + } + + if ($eventlog_system_enable == 1) + { + eventlog_system($msg,17,$eventlog_error); + } + } + else + { + return 1; + } + return 0; + } +} diff --git a/src/traps/snmptt.ini b/src/traps/conf/snmptt.ini similarity index 100% rename from src/traps/snmptt.ini rename to src/traps/conf/snmptt.ini diff --git a/src/traps/conf/snmpttconvertmib b/src/traps/conf/snmpttconvertmib new file mode 100644 index 000000000..d3ca2d5c4 --- /dev/null +++ b/src/traps/conf/snmpttconvertmib @@ -0,0 +1,964 @@ +#!/usr/bin/perl +# +# SNMPTTCONVERTMIB v1.2beta3 +# +# Copyright 2002-2007 Alex Burger +# alex_b@users.sourceforge.net +# +# 8/14/2002 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +############################################################################## +# +# http://www.sourceforge.net/projects/snmptt +# +############################################################################### +use strict; + +# +# OPTIONS START +# +# Set this to '' to have no default EXEC line added, or modify as needed. +# Can also set on the command line with --exec='string' +my $defaultexec = ''; + +# Choose what type of quotes (if any) you want around the SUMMARY text pulled from the MIB. +#$defaultexecquote = ''; # no quotes +#$defaultexecquote = "\'"; # single (') quotes +my $defaultexecquote = "\""; # double (") quotes + +# Set this to 1 to have the --TYPE string prepended to the --SUMMARY string. +# Set to 0 to disable +my $prepend_type = 1; + +# +# OPTIONS END +# +############################################################################# +# + +my $snmpttconvertmib_version = "v1.2beta3"; + +sub showversion +{ + print "\nSNMPTTCONVERTMIB $snmpttconvertmib_version\n"; + print "(c) 2002-2007 Alex Burger\n"; + print "http://snmptt.sourceforge.net\n\n"; +} + +############################################################################## +# Process command line arguments + +$| = 1; + +use Getopt::Long; +use File::Basename; +use File::Spec; + +my $DEBUGGING = 0; + +my $version = 0; +my $debug = 0; +my $help = 0; +my $net_snmp_perl = 0; +my $in = ''; +my $out = ''; +my $nodes = ''; +my $no_description = 0; +my $no_variables = 0; +my $no_format_summary = 0; +my $no_format_desc = 0; +my $format = 0; +my $format_desc = 0; +my $no_desc_wildcard = 0; +my $no_severity = 0; +my $severity = 'Normal'; +my $exec = ''; + + +GetOptions ('version' => \$version, + 'debug:i' => \$debug, + 'help' => \$help, + 'in=s' => \$in, + 'out=s' => \$out, + 'net_snmp_perl' => \$net_snmp_perl, + 'nodes=s' => \$nodes, + 'no_description' => \$no_description, + 'no_variables' => \$no_variables, + 'no_format_summary' => \$no_format_summary, + 'no_format_desc' => \$no_format_desc, + 'no_severity' => \$no_severity, + 'severity=s' => \$severity, + 'format=n' => \$format, + 'format_desc=n' => \$format_desc, + 'no_desc_wildcard' => \$no_desc_wildcard, + 'exec=s' => \$exec); + +if ($version == 1) +{ + &showversion; + exit(0); +} + +if ($help == 1) +{ + &show_help(); + exit(0); +} + +# Replace any spaces with -'s in severity +$severity =~ s/ /-/g; + +if ($debug == 1) +{ + $DEBUGGING = 1; +} +if ($debug == 2) +{ + $DEBUGGING = 2; +} + +if (($in eq "") || ($out eq "")) +{ + print "\nMissing arguments!\n"; + &show_help(); + exit 1; +} + +# Get complete path of input file (MIB) in a portable way (needed for -m switch for snmptranslate) +my $dirname = dirname $in; +my $basename = basename $in; +my $input = File::Spec->catfile($dirname, $basename); + +# Get complete path of output file (.conf) in a portable way +$dirname = dirname $out; +$basename = basename $out; +my $output = File::Spec->catfile($dirname, $basename); + +if ($exec ne '') +{ + $defaultexec = $exec; + print "exec: $exec\n"; +} + +#print "nodes: $nodes\n"; + +if ($net_snmp_perl == 1) +{ + print "\n\n***** UCD-SNMP / NET-SNMP Perl module enabled *****\n\n"; +} + +print "\n\n***** Processing MIB file *****\n\n"; +my $snmptranslate_use_On; +check_snmptranslate_version(); + + +print "severity: $severity\n"; +print "\nFile to load is: $input\n"; +print "File to APPEND TO: $output\n"; + +# Set MIBS environment variable to the filename of the MIB file (not the mib name - if a file contains +# multiple MIB definitions in one file, the mib name will not work - at least with 5.0.8 and older) +$ENV{MIBS} = $input; +print "\nMIBS environment var: $ENV{MIBS}\n"; + +if ($DEBUGGING >= 1) +{ + print "\nLoading$input\n"; +} + +unless (open INPUTFILE, "<$input") +{ + die "Cannot open input file: $!"; +} + +my @mibfile; + +while () +{ + chomp; # remove at end of line + s/\015//; # Remove any DOS carriage returns + push(@mibfile, $_); # add to each line to @trapconf array +} + +if ($DEBUGGING >= 1) +{ + print "Finished loading $input\n\n"; +} + +my $currentline=0; + +unless (open OUTPUTFILE, ">>$output") +{ + die "Cannot open output file: $!"; +} + +# A mib file can contain multiple BEGIN definitions. This finds the first on +# to make sure we have at least one definition. +# Determine name of MIB file +my $mib_name = ''; +while ($currentline <= $#mibfile) +{ + my $line = $mibfile[$currentline]; + if ($line =~ /(.*)DEFINITIONS\s*::=\s*BEGIN/) + { + $mib_name = $1; + $mib_name =~ s/\s+//g; + last; + } + $currentline++; +} +print "mib name: $mib_name\n"; +if ($mib_name eq '') +{ + print "\n\nAborting!!!\n"; + print "Could not find DEFINITIONS ::= BEGIN statement in MIB file!\n\n"; + exit (1); +} + +if ($net_snmp_perl == 1) +{ + require SNMP; + $SNMP::save_descriptions = 1; # Need them only for looking up variable descriptions. + # Do TRAP definition by hand to be able to pull out + # the SUMMARY lines + &SNMP::initMib(); + + print "\n\n***** Using UCD-SNMP / NET-SNMP Perl module *****\n\n"; +} + +my $total_translations = 0; +my $successful_translations = 0; +my $failed_translations = 0; +$currentline=0; + +#if ($net_snmp_perl == 0) +if (1) +{ + # Process the trap files by hand + + while ($currentline <= $#mibfile) + { + my $line = $mibfile[$currentline]; + + if ($line =~ /(.*)DEFINITIONS\s*::=\s*BEGIN/) + { + $mib_name = $1; + $mib_name =~ s/\s+//g; + print "\n\nProcessing MIB: $mib_name\n"; + + print OUTPUTFILE "#\n#\n#\n#\n"; + print OUTPUTFILE "MIB: $mib_name (file:$input) converted on " . scalar(localtime) . " using snmpttconvertmib $snmpttconvertmib_version\n"; + + $currentline++; # Increment to the next line + next; + } + + # TRAP-TYPE (V1) / NOTIFICATION-TYPE (V2) + # + # eg: 'mngmtAgentTrap-23003 TRAP-TYPE'; + # eg: 'ciscoSystemClockChanged NOTIFICATION-TYPE'; + if ( $line =~ /(.*)\s*TRAP-TYPE.*/ || + $line =~ /(.*)\s*(?