📄 snmp.pm
字号:
# SNMP.pm -- Perl 5 interface to the UCD SNMP toolkit## written by G. S. Marzot (gmarzot@nortelnetworks.com)## Copyright (c) 1995-2000 G. S. Marzot. All rights reserved.# This program is free software; you can redistribute it and/or# modify it under the same terms as Perl itself.package SNMP;$VERSION = '4.2.6'; # current release version numberrequire Exporter;require DynaLoader;require AutoLoader;@SNMP::ISA = qw(Exporter AutoLoader DynaLoader);# Items to export into callers namespace by default. Note: do not export# names by default without a very good reason. Use EXPORT_OK instead.# Do not simply export all your public functions/methods/constants.@SNMP::EXPORT = qw( RECEIVED_MESSAGE SNMPERR_BAD_ADDRESS SNMPERR_BAD_LOCPORT SNMPERR_BAD_SESSION SNMPERR_GENERR SNMPERR_TOO_LONG SNMP_DEFAULT_ADDRESS SNMP_DEFAULT_COMMUNITY_LEN SNMP_DEFAULT_ENTERPRISE_LENGTH SNMP_DEFAULT_ERRINDEX SNMP_DEFAULT_ERRSTAT SNMP_DEFAULT_PEERNAME SNMP_DEFAULT_REMPORT SNMP_DEFAULT_REQID SNMP_DEFAULT_RETRIES SNMP_DEFAULT_TIME SNMP_DEFAULT_TIMEOUT SNMP_DEFAULT_VERSION TIMED_OUT snmp_get snmp_getnext snmp_set snmp_trap);sub AUTOLOAD { # This AUTOLOAD is used to 'autoload' constants from the constant() # XS function. If a constant is not found then control is passed # to the AUTOLOAD in AutoLoader. my($val,$pack,$file,$line); local($constname); ($constname = $AUTOLOAD) =~ s/.*:://; # croak "&$module::constant not defined" if $constname eq 'constant'; $val = constant($constname, @_ ? $_[0] : 0); if ($! != 0) { if ($! =~ /Invalid/) { $AutoLoader::AUTOLOAD = $AUTOLOAD; goto &AutoLoader::AUTOLOAD; } else { ($pack,$file,$line) = caller; die "Your vendor has not defined SNMP macro $constname, used at $file line $line."; } } eval "sub $AUTOLOAD { $val }"; goto &$AUTOLOAD;}bootstrap SNMP;# Preloaded methods go here.# Package variablestie $SNMP::debugging, SNMP::DEBUGGING;tie $SNMP::debug_internals, SNMP::DEBUG_INTERNALS;tie $SNMP::dump_packet, SNMP::DUMP_PACKET;tie %SNMP::MIB, SNMP::MIB;tie $SNMP::save_descriptions, SNMP::MIB::SAVE_DESCR;%SNMP::V3_SEC_LEVEL_MAP = (noAuthNoPriv => 1, authNoPriv => 2, authPriv =>3);$auto_init_mib = 1; # enable automatic MIB loading at session creation time$use_long_names = 0; # non-zero to prefer longer mib textual identifiers rather # than just leaf indentifiers (see translateObj) # may also be set on a per session basis(see UseLongNames)$use_sprint_value = 0; # non-zero to enable formatting of response values # using the snmp libraries "sprint_value" # may also be set on a per session basis(see UseSprintValue) # note: returned values not suitable for 'set' operations$use_enums = 0; # non-zero to return integers as enums and allow sets # using enums where appropriate - integer data will # still be accepted for set operations # may also be set on a per session basis (see UseEnums)$use_numeric = 0; # non-zero to return object tags as numeric OID's instead # of converting to textual representations. use_long_names, # if non-zero, returns the entire OID, otherwise, return just # the label portion. Probably want to use_long_names in most # cases.%MIB = (); # tied hash to access libraries internal mib tree structure # parsed in from mib files$verbose = 0; # controls warning/info output of SNMP module, # 0 => no output, 1 => enables warning and info # output from SNMP module itself (is also controlled # by SNMP::debugging)$debugging = 0; # non-zero to globally enable libsnmp do_debugging output # set to >= 2 to enabling packet dumping (see below)$dump_packet = 0; # non-zero to globally enable libsnmp dump_packet output. # is also enabled when $debugging >= 2$save_descriptions = 0; #tied scalar to control saving descriptions during # mib parsing - must be set prior to mib loading$best_guess = 0; # determine whether or not to enable best-guess regular # expression object name translation$timestamp_vars = 0; # Add a timestamp to each Varbindsub setMib {# loads mib from file name provided# setting second arg to true causes currently loaded mib to be replaced# otherwise mib file will be added to existing loaded mib database# NOTE: now deprecated in favor of addMibFiles and new module based funcs my $file = shift; my $force = shift || '0'; return 0 if $file and not (-r $file); SNMP::_read_mib($file,$force);}sub initMib {# eqivalent to calling the snmp library init_mib if Mib is NULL# if Mib is already loaded this function does nothing# Pass a zero valued argument to get minimal mib tree initialzation# If non zero agrgument or no argument then full mib initialization if (defined $_[0] and $_[0] == 0) { SNMP::_init_mib_internals(); } else { SNMP::_read_mib(""); }}sub addMibDirs {# adds directories to search path when a module is requested to be loaded foreach (@_) { SNMP::_add_mib_dir($_) or return undef; } return 1;}sub addMibFiles {# adds mib definitions to currently loaded mib database from# file(s) supplied foreach (@_) { SNMP::_read_mib($_) or return undef; } return 1;}sub loadModules {# adds mib module definitions to currently loaded mib database.# Modules will be searched from previously defined mib search dirs# Passing and arg of 'ALL' will cause all known modules to be loaded foreach (@_) { SNMP::_read_module($_) or return undef; } return 1;}sub unloadModules {# causes modules to be unloaded from mib database# Passing and arg of 'ALL' will cause all known modules to be unloaded warn("SNMP::unloadModules not implemented! (yet)");}sub translateObj {# translate object identifier(tag or numeric) into alternate representation# (i.e., sysDescr => '.1.3.6.1.2.1.1.1' and '.1.3.6.1.2.1.1.1' => sysDescr)# when $SNMP::use_long_names or second arg is non-zero the translation will# return longer textual identifiers (e.g., system.sysDescr)# if Mib is not loaded and $SNMP::auto_init_mib is enabled Mib will be loaded# returns 'undef' upon failure my $obj = shift; my $long_names = shift || $SNMP::use_long_names; return undef if not defined $obj; my $res; if ($obj =~ /^\.?(\d+\.)*\d+$/) { $res = SNMP::_translate_obj($obj,1,$long_names,$SNMP::auto_init_mib,0); } elsif ($obj =~ /(\.\d+)*$/ && $SNMP::best_guess == 0) { $res = SNMP::_translate_obj($`,0,$long_names,$SNMP::auto_init_mib,0); $res .= $& if defined $res and defined $&; } elsif ($SNMP::best_guess) { $res = SNMP::_translate_obj($obj,0,$long_names,$SNMP::auto_init_mib,$SNMP::best_guess); } return($res);}sub getType {# return SNMP data type for given textual identifier# OBJECTID, OCTETSTR, INTEGER, NETADDR, IPADDR, COUNTER# GAUGE, TIMETICKS, OPAQUE, or undef my $tag = shift; SNMP::_get_type($tag);}sub mapEnum {# return the corresponding integer value *or* tag for a given MIB attribute# and value. The function will sense which direction to perform the conversion# various arg formats are supported# $val = SNMP::mapEnum($varbind); # note: will update $varbind# $val = SNMP::mapEnum('ipForwarding', 'forwarding');# $val = SNMP::mapEnum('ipForwarding', 1);# my $var = shift; my ($tag, $val, $update); if (ref($var) =~ /ARRAY/ or ref($var) =~ /Varbind/) { $tag = $var->[$SNMP::Varbind::tag_f]; $val = $var->[$SNMP::Varbind::val_f]; $update = 1; } else { $tag = $var; $val = shift; } my $iflag = $val =~ /^\d+$/; my $res = SNMP::_map_enum($tag, $val, $iflag); if ($update and defined $res) { $var->[$SNMP::Varbind::val_f] = $res; } return($res);}%session_params = (DestHost => 1, Community => 1, Version => 1, Timeout => 1, Retries => 1, RemotePort => 1);sub strip_session_params { my @params; my @args; my $param; while ($param = shift) { push(@params,$param, shift), next if $session_params{$param}; push(@args,$param); } @_ = @args; @params;}sub snmp_get {# procedural form of 'get' method. sometimes quicker to code# but is less efficient since the Session is created and destroyed# with each call. Takes all the parameters of both SNMP::Session::new and# SNMP::Session::get (*NOTE*: this api does not support async callbacks) my @sess_params = &strip_session_params; my $sess = new SNMP::Session(@sess_params); $sess->get(@_);}sub snmp_getnext {# procedural form of 'getnext' method. sometimes quicker to code# but is less efficient since the Session is created and destroyed# with each call. Takes all the parameters of both SNMP::Session::new and# SNMP::Session::getnext (*NOTE*: this api does not support async callbacks) my @sess_params = &strip_session_params; my $sess = new SNMP::Session(@sess_params); $sess->getnext(@_);}sub snmp_set {# procedural form of 'set' method. sometimes quicker to code# but is less efficient since the Session is created and destroyed# with each call. Takes all the parameters of both SNMP::Session::new and# SNMP::Session::set (*NOTE*: this api does not support async callbacks) my @sess_params = &strip_session_params; my $sess = new SNMP::Session(@sess_params); $sess->set(@_);}sub snmp_trap {# procedural form of 'trap' method. sometimes quicker to code# but is less efficient since the Session is created and destroyed# with each call. Takes all the parameters of both SNMP::TrapSession::new and# SNMP::TrapSession::trap my @sess_params = &strip_session_params; my $sess = new SNMP::TrapSession(@sess_params); $sess->trap(@_);}sub MainLoop { my $time = shift; my $callback = shift; my $time_sec = ($time ? int $time : 0); my $time_usec = ($time ? int(($time-$time_sec)*1000000) : 0); SNMP::_main_loop($time_sec,$time_usec,$callback);}sub finish { SNMP::_mainloop_finish();}sub reply_cb { # callback function for async snmp calls # when triggered, will do a SNMP read on the # given fd my $fd = shift; SNMP::_read_on_fd($fd);}sub select_info { # retrieves SNMP used fd's and timeout info # calculates timeout in fractional seconds # ( easy to use with select statement ) my($block, $to_sec, $to_usec, @fd_set)=SNMP::_get_select_info(); my $time_sec_dec = ($block? 0 : $to_sec + $to_usec * 1e-6); #print "fd's for snmp -> ", @fd_set, "\n"; #print "block -> ", $block, "\n"; #print "timeout_sec -> ", $to_sec, "\n"; #print "timeout_usec -> ", $to_usec, "\n"; #print "timeout dec -> ", $time_sec_dec, "\n"; return ($time_sec_dec,@fd_set);}sub check_timeout { # check to see if a snmp session # timed out, and if so triggers # the callback function SNMP::_check_timeout(); # check to see when have to check again my($block, $to_sec, $to_usec, @fd_set)=SNMP::_get_select_info(); my $time_sec_dec = ($block? 0 : $to_sec + $to_usec * 1e-6); #print "fd's for snmp -> ", @fd_set, "\n"; #print "block -> ", $block, "\n"; #print "timeout_sec -> ", $to_sec, "\n"; #print "timeout_usec -> ", $to_usec, "\n"; #print "timeout dec -> ", $time_sec_dec, "\n"; return ($time_sec_dec);}sub _tie {# this is a little implementation hack so ActiveState can access pp_tie# thru perl code. All other environments allow the calling of pp_tie from# XS code but AS was not exporting it when PERL_OBJECT was used.## short term solution was call this perl func which calls 'tie'## longterm fix is to supply a patch which allows AS to export pp_tie in# such a way that it can be called from XS code. gsarathy says:# a patch to util.c is needed to provide access to PL_paddr# so it is possible to call PL_paddr[OP_TIE] as the compiler does tie($_[0],$_[1],$_[2],$_[3]);}package SNMP::Session;sub new { my $type = shift; my $this = {}; my ($name, $aliases, $host_type, $len, $thisaddr); %$this = @_; $this->{ErrorStr} = ''; # if methods return undef check for expln. $this->{ErrorNum} = 0; # contains SNMP error return # v1 or v2, defaults to v1 $this->{Version} ||= 1; # allow override of remote SNMP port $this->{RemotePort} ||= 161; # destination host defaults to localhost $this->{DestHost} ||= 'localhost'; # community defaults to public $this->{Community} ||= 'public'; # number of retries before giving up, defaults to SNMP_DEFAULT_RETRIES $this->{Retries} = SNMP::SNMP_DEFAULT_RETRIES() unless defined($this->{Retries}); # timeout before retry, defaults to SNMP_DEFAULT_TIMEOUT $this->{Timeout} = SNMP::SNMP_DEFAULT_TIMEOUT() unless defined($this->{Timeout}); # flag to enable fixing pdu and retrying with a NoSuch error $this->{RetryNoSuch} ||= 0; # convert to dotted ip addr if needed if ($this->{DestHost} =~ /\d+\.\d+\.\d+\.\d+/) { $this->{DestAddr} = $this->{DestHost}; } else { if (($name, $aliases, $host_type, $len, $thisaddr) = gethostbyname($this->{DestHost})) { $this->{DestAddr} = join('.', unpack("C4", $thisaddr)); } else { warn("unable to resolve destination address($this->{DestHost}!") if $SNMP::verbose; return undef; } } if ($this->{Version} eq '1' or $this->{Version} eq '2' or $this->{Version} eq '2c') { $this->{SessPtr} = SNMP::_new_session($this->{Version}, $this->{Community}, $this->{DestAddr}, $this->{RemotePort}, $this->{Retries}, $this->{Timeout}, ); } elsif ($this->{Version} eq '3' ) { $this->{SecName} ||= 'initial'; $this->{SecLevel} ||= 'noAuthNoPriv'; $this->{SecLevel} = $SNMP::V3_SEC_LEVEL_MAP{$this->{SecLevel}} if $this->{SecLevel} !~ /^\d+$/; $this->{SecEngineId} ||= ''; $this->{ContextEngineId} ||= $this->{SecEngineId}; $this->{Context} ||= ''; $this->{AuthProto} ||= 'MD5'; $this->{AuthPass} ||= ''; $this->{PrivProto} ||= 'DES'; $this->{PrivPass} ||= ''; $this->{EngineBoots} = 0 if not defined $this->{EngineBoots}; $this->{EngineTime} = 0 if not defined $this->{EngineTime}; $this->{SessPtr} = SNMP::_new_v3_session($this->{Version}, $this->{DestAddr}, $this->{RemotePort}, $this->{Retries}, $this->{Timeout}, $this->{SecName}, $this->{SecLevel}, $this->{SecEngineId}, $this->{ContextEngineId}, $this->{Context}, $this->{AuthProto}, $this->{AuthPass}, $this->{PrivProto}, $this->{PrivPass}, $this->{EngineBoots}, $this->{EngineTime}, ); } unless ($this->{SessPtr}) { warn("unable to create session") if $SNMP::verbose; return undef; } SNMP::initMib($SNMP::auto_init_mib); # ensures that *some* mib is loaded $this->{UseLongNames} ||= $SNMP::use_long_names; $this->{UseSprintValue} ||= $SNMP::use_sprint_value; $this->{UseEnums} ||= $SNMP::use_enums; $this->{UseNumeric} ||= $SNMP::use_numeric; $this->{TimeStamp} ||= $SNMP::timestamp_vars; bless $this, $type;}sub update {# *Not Implemented*# designed to update the fields of session to allow retargettinf to different# host, community name change, timeout, retry changes etc. Unfortunately not# working yet because some updates (the address in particular) need to be# done on the internal session pointer which cannot be fetched w/o touching# globals at this point which breaks win32. A patch to the ucd-snmp toolkit# is needed my $this = shift; my ($name, $aliases, $host_type, $len, $thisaddr); my %new_fields = @_; @$this{keys %new_fields} = values %new_fields; # convert to dotted ip addr if needed if (exists $new_fields{DestHost}) { if ($this->{DestHost} =~ /\d+\.\d+\.\d+\.\d+/) { $this->{DestAddr} = $this->{DestHost}; } else { if (($name, $aliases, $host_type, $len, $thisaddr) = gethostbyname($this->{DestHost})) { $this->{DestAddr} = join('.', unpack("C4", $thisaddr)); } else { warn("unable to resolve destination address($this->{DestHost}!") if $SNMP::verbose; return undef;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -