1# SNMP.pm -- Perl 5 interface to the Net-SNMP toolkit 2# 3# written by G. S. Marzot (marz@users.sourceforge.net) 4# 5# Copyright (c) 1995-2006 G. S. Marzot. All rights reserved. 6# This program is free software; you can redistribute it and/or 7# modify it under the same terms as Perl itself. 8 9package SNMP; 10$VERSION = '5.09'; # current release version number 11 12use strict; 13use warnings; 14 15require Exporter; 16require DynaLoader; 17require AutoLoader; 18 19use NetSNMP::default_store (':all'); 20 21@SNMP::ISA = qw(Exporter AutoLoader DynaLoader); 22# Items to export into callers namespace by default. Note: do not export 23# names by default without a very good reason. Use EXPORT_OK instead. 24# Do not simply export all your public functions/methods/constants. 25@SNMP::EXPORT = qw( 26 RECEIVED_MESSAGE 27 SNMPERR_BAD_ADDRESS 28 SNMPERR_BAD_LOCPORT 29 SNMPERR_BAD_SESSION 30 SNMPERR_GENERR 31 SNMPERR_TOO_LONG 32 SNMP_DEFAULT_ADDRESS 33 SNMP_DEFAULT_COMMUNITY_LEN 34 SNMP_DEFAULT_ENTERPRISE_LENGTH 35 SNMP_DEFAULT_ERRINDEX 36 SNMP_DEFAULT_ERRSTAT 37 SNMP_DEFAULT_PEERNAME 38 SNMP_DEFAULT_REMPORT 39 SNMP_DEFAULT_REQID 40 SNMP_DEFAULT_RETRIES 41 SNMP_DEFAULT_TIME 42 SNMP_DEFAULT_TIMEOUT 43 SNMP_DEFAULT_VERSION 44 TIMED_OUT 45 snmp_get 46 snmp_getnext 47 snmp_set 48 snmp_trap 49 SNMP_API_TRADITIONAL 50 SNMP_API_SINGLE 51); 52 53sub AUTOLOAD { 54 no strict; 55 # This AUTOLOAD is used to 'autoload' constants from the constant() 56 # XS function. If a constant is not found then control is passed 57 # to the AUTOLOAD in AutoLoader. 58 my($val,$pack,$file,$line); 59 my $constname; 60 ($constname = $AUTOLOAD) =~ s/.*:://; 61 # croak "&$module::constant not defined" if $constname eq 'constant'; 62 ($!, $val) = constant($constname, @_ ? $_[0] : 0); 63 if ($! != 0) { 64 if ($! =~ /Invalid/) { 65 $AutoLoader::AUTOLOAD = $AUTOLOAD; 66 goto &AutoLoader::AUTOLOAD; 67 } 68 else { 69 ($pack,$file,$line) = caller; 70 die "Your vendor has not defined SNMP macro $constname, used at $file line $line. 71"; 72 } 73 } 74 eval "sub $AUTOLOAD { $val }"; 75 goto &$AUTOLOAD; 76} 77 78bootstrap SNMP; 79 80# Preloaded methods go here. 81 82# Package variables 83tie $SNMP::debugging, 'SNMP::DEBUGGING'; 84tie $SNMP::debug_internals, 'SNMP::DEBUG_INTERNALS'; 85tie $SNMP::dump_packet, 'SNMP::DUMP_PACKET'; 86tie %SNMP::MIB, 'SNMP::MIB'; 87tie $SNMP::save_descriptions, 'SNMP::MIB::SAVE_DESCR'; 88tie $SNMP::replace_newer, 'SNMP::MIB::REPLACE_NEWER'; 89tie $SNMP::mib_options, 'SNMP::MIB::MIB_OPTIONS'; 90 91%SNMP::V3_SEC_LEVEL_MAP = (noAuthNoPriv => 1, authNoPriv => 2, authPriv =>3); 92 93use vars qw( 94 $auto_init_mib $use_long_names $use_sprint_value $use_enums 95 $use_numeric %MIB $verbose $debugging $dump_packet $save_descriptions 96 $best_guess $non_increasing $replace_newer %session_params 97 $debug_internals $mib_options 98); 99 100$auto_init_mib = 1; # enable automatic MIB loading at session creation time 101$use_long_names = 0; # non-zero to prefer longer mib textual identifiers rather 102 # than just leaf indentifiers (see translateObj) 103 # may also be set on a per session basis(see UseLongNames) 104$use_sprint_value = 0; # non-zero to enable formatting of response values 105 # using the snmp libraries "snprint_value" 106 # may also be set on a per session basis(see UseSprintValue) 107 # note: returned values not suitable for 'set' operations 108$use_enums = 0; # non-zero to return integers as enums and allow sets 109 # using enums where appropriate - integer data will 110 # still be accepted for set operations 111 # may also be set on a per session basis (see UseEnums) 112$use_numeric = 0; # non-zero to return object tags as numeric OID's instead 113 # of converting to textual representations. use_long_names, 114 # if non-zero, returns the entire OID, otherwise, return just 115 # the label portion. use_long_names is also set if the 116 # use_numeric variable is set. 117%MIB = (); # tied hash to access libraries internal mib tree structure 118 # parsed in from mib files 119$verbose = 0; # controls warning/info output of SNMP module, 120 # 0 => no output, 1 => enables warning and info 121 # output from SNMP module itself (is also controlled 122 # by SNMP::debugging) 123$debugging = 0; # non-zero to globally enable libsnmp do_debugging output 124 # set to >= 2 to enabling packet dumping (see below) 125$dump_packet = 0; # non-zero to globally enable libsnmp dump_packet output. 126 # is also enabled when $debugging >= 2 127$save_descriptions = 0; #tied scalar to control saving descriptions during 128 # mib parsing - must be set prior to mib loading 129$best_guess = 0; # determine whether or not to enable best-guess regular 130 # expression object name translation. 1 = Regex (-Ib), 131 # 2 = random (-IR) 132$non_increasing = 0; # stop polling with an "OID not increasing"-error 133 # when an OID does not increases in bulkwalk. 134$replace_newer = 0; # determine whether or not to tell the parser to replace 135 # older MIB modules with newer ones when loading MIBs. 136 # WARNING: This can cause an incorrect hierarchy. 137 138sub register_debug_tokens { 139 my $tokens = shift; 140 141 SNMP::_register_debug_tokens($tokens); 142} 143 144sub getenv { 145 my $name = shift; 146 147 return SNMP::_getenv($name); 148} 149 150sub setenv { 151 my $envname = shift; 152 my $envval = shift; 153 my $overwrite = shift; 154 155 return SNMP::_setenv($envname, $envval, $overwrite); 156} 157 158sub setMib { 159# loads mib from file name provided 160# setting second arg to true causes currently loaded mib to be replaced 161# otherwise mib file will be added to existing loaded mib database 162# NOTE: now deprecated in favor of addMibFiles and new module based funcs 163 my $file = shift; 164 my $force = shift || '0'; 165 return 0 if $file and not (-r $file); 166 SNMP::_read_mib($file,$force); 167} 168 169sub initMib { 170# equivalent to calling the snmp library init_mib if Mib is NULL 171# if Mib is already loaded this function does nothing 172# Pass a zero valued argument to get minimal mib tree initialization 173# If non zero argument or no argument then full mib initialization 174 175 SNMP::init_snmp("perl"); 176 return; 177 178 179 if (defined $_[0] and $_[0] == 0) { 180 SNMP::_init_mib_internals(); 181 } else { 182 SNMP::_read_mib(""); 183 } 184} 185 186sub addMibDirs { 187# adds directories to search path when a module is requested to be loaded 188 SNMP::init_snmp("perl"); 189 foreach (@_) { 190 SNMP::_add_mib_dir($_) or return undef; 191 } 192 return 1; 193} 194 195sub addMibFiles { 196# adds mib definitions to currently loaded mib database from 197# file(s) supplied 198 SNMP::init_snmp("perl"); 199 foreach (@_) { 200 SNMP::_read_mib($_) or return undef; 201 } 202 return 1; 203} 204 205sub loadModules { 206# adds mib module definitions to currently loaded mib database. 207# Modules will be searched from previously defined mib search dirs 208# Passing and arg of 'ALL' will cause all known modules to be loaded 209 SNMP::init_snmp("perl"); 210 foreach (@_) { 211 SNMP::_read_module($_) or return undef; 212 } 213 return 1; 214} 215 216sub unloadModules { 217# causes modules to be unloaded from mib database 218# Passing and arg of 'ALL' will cause all known modules to be unloaded 219 warn("SNMP::unloadModules not implemented! (yet)"); 220} 221 222sub translateObj { 223# Translate object identifier(tag or numeric) into alternate representation 224# (i.e., sysDescr => '.1.3.6.1.2.1.1.1' and '.1.3.6.1.2.1.1.1' => sysDescr) 225# when $SNMP::use_long_names or second arg is non-zero the translation will 226# return longer textual identifiers (e.g., system.sysDescr). An optional 227# third argument of non-zero will cause the module name to be prepended 228# to the text name (e.g. 'SNMPv2-MIB::sysDescr'). If no Mib is loaded 229# when called and $SNMP::auto_init_mib is enabled then the Mib will be 230# loaded. Will return 'undef' upon failure. 231 SNMP::init_snmp("perl"); 232 my $obj = shift; 233 my $temp = shift; 234 my $include_module_name = shift || "0"; 235 my $long_names = $temp || $SNMP::use_long_names; 236 237 return undef if not defined $obj; 238 my $res; 239 if ($obj =~ /^\.?(\d+\.)*\d+$/) { 240 $res = SNMP::_translate_obj($obj,1,$long_names,$SNMP::auto_init_mib,0,$include_module_name); 241 } elsif ($obj =~ /(\.\d+)*$/ && $SNMP::best_guess == 0) { 242 $res = SNMP::_translate_obj($`,0,$long_names,$SNMP::auto_init_mib,0,$include_module_name); 243 $res .= $& if defined $res and defined $&; 244 } elsif ($SNMP::best_guess) { 245 $res = SNMP::_translate_obj($obj,0,$long_names,$SNMP::auto_init_mib,$SNMP::best_guess,$include_module_name); 246 } 247 248 return($res); 249} 250 251sub getType { 252# return SNMP data type for given textual identifier 253# OBJECTID, OCTETSTR, INTEGER, NETADDR, IPADDR, COUNTER 254# GAUGE, TIMETICKS, OPAQUE, or undef 255 my $tag = shift; 256 SNMP::_get_type($tag, $SNMP::best_guess); 257} 258 259sub mapEnum { 260# return the corresponding integer value *or* tag for a given MIB attribute 261# and value. The function will sense which direction to perform the conversion 262# various arg formats are supported 263# $val = SNMP::mapEnum($varbind); # note: will update $varbind 264# $val = SNMP::mapEnum('ipForwarding', 'forwarding'); 265# $val = SNMP::mapEnum('ipForwarding', 1); 266# 267 my $var = shift; 268 my ($tag, $val, $update); 269 if (ref($var) =~ /ARRAY/ or ref($var) =~ /Varbind/) { 270 $tag = SNMP::Varbind::tag($var); 271 $val = SNMP::Varbind::val($var); 272 $update = 1; 273 } else { 274 $tag = $var; 275 $val = shift; 276 } 277 my $iflag = $val =~ /^\d+$/; 278 my $res = SNMP::_map_enum($tag, $val, $iflag, $SNMP::best_guess); 279 if ($update and defined $res) { SNMP::Varbind::val($var) = $res; } 280 return($res); 281} 282 283%session_params = (DestHost => 1, 284 Community => 1, 285 Version => 1, 286 Timeout => 1, 287 Retries => 1, 288 RemotePort => 1, 289 LocalPort => 1); 290 291sub strip_session_params { 292 my @params; 293 my @args; 294 my $param; 295 while ($param = shift) { 296 push(@params,$param, shift), next 297 if $session_params{$param}; 298 push(@args,$param); 299 } 300 @_ = @args; 301 @params; 302} 303 304 305sub snmp_get { 306# procedural form of 'get' method. sometimes quicker to code 307# but is less efficient since the Session is created and destroyed 308# with each call. Takes all the parameters of both SNMP::Session::new and 309# SNMP::Session::get (*NOTE*: this api does not support async callbacks) 310 311 my @sess_params = &strip_session_params; 312 my $sess = new SNMP::Session(@sess_params); 313 314 $sess->get(@_); 315} 316 317sub snmp_getnext { 318# procedural form of 'getnext' method. sometimes quicker to code 319# but is less efficient since the Session is created and destroyed 320# with each call. Takes all the parameters of both SNMP::Session::new and 321# SNMP::Session::getnext (*NOTE*: this api does not support async callbacks) 322 323 my @sess_params = &strip_session_params; 324 my $sess = new SNMP::Session(@sess_params); 325 326 $sess->getnext(@_); 327} 328 329sub snmp_set { 330# procedural form of 'set' method. sometimes quicker to code 331# but is less efficient since the Session is created and destroyed 332# with each call. Takes all the parameters of both SNMP::Session::new and 333# SNMP::Session::set (*NOTE*: this api does not support async callbacks) 334 335 my @sess_params = &strip_session_params; 336 my $sess = new SNMP::Session(@sess_params); 337 338 $sess->set(@_); 339} 340 341sub snmp_trap { 342# procedural form of 'trap' method. sometimes quicker to code 343# but is less efficient since the Session is created and destroyed 344# with each call. Takes all the parameters of both SNMP::TrapSession::new and 345# SNMP::TrapSession::trap 346 347 my @sess_params = &strip_session_params; 348 my $sess = new SNMP::TrapSession(@sess_params); 349 350 $sess->trap(@_); 351} 352 353#--------------------------------------------------------------------- 354# Preserves the ability to call MainLoop() with no args so we don't 355# break old code 356# 357# Alternately, MainLoop() could be called as an object method, 358# ( $sess->MainLoop() ) , so that $self winds up in @_. Then it would 359# be more like : 360# my $self = shift; 361# .... 362# SNMP::_main_loop(......, $self->{SessPtr}); 363#--------------------------------------------------------------------- 364sub MainLoop { 365 my $ss = shift if(&SNMP::_api_mode() == SNMP::SNMP_API_SINGLE()); 366 my $time = shift; 367 my $callback = shift; 368 my $time_sec = ($time ? int $time : 0); 369 my $time_usec = ($time ? int(($time-$time_sec)*1000000) : 0); 370 SNMP::_main_loop($time_sec,$time_usec,$callback,(defined($ss) ? $ss->{SessPtr} : ())); 371} 372 373sub finish { 374 SNMP::_mainloop_finish(); 375} 376 377sub reply_cb { 378 # callback function for async snmp calls 379 # when triggered, will do a SNMP read on the 380 # given fd 381 my $fd = shift; 382 SNMP::_read_on_fd($fd); 383} 384 385sub select_info { 386 # retrieves SNMP used fd's and timeout info 387 # calculates timeout in fractional seconds 388 # ( easy to use with select statement ) 389 my($block, $to_sec, $to_usec, @fd_set)=SNMP::_get_select_info(); 390 my $time_sec_dec = ($block? 0 : $to_sec + $to_usec * 1e-6); 391 #print "fd's for snmp -> ", @fd_set, "\n"; 392 #print "block -> ", $block, "\n"; 393 #print "timeout_sec -> ", $to_sec, "\n"; 394 #print "timeout_usec -> ", $to_usec, "\n"; 395 #print "timeout dec -> ", $time_sec_dec, "\n"; 396 return ($time_sec_dec,@fd_set); 397} 398 399sub check_timeout { 400 # check to see if a snmp session 401 # timed out, and if so triggers 402 # the callback function 403 SNMP::_check_timeout(); 404 # check to see when have to check again 405 my($block, $to_sec, $to_usec, @fd_set)=SNMP::_get_select_info(); 406 my $time_sec_dec = ($block? 0 : $to_sec + $to_usec * 1e-6); 407 #print "fd's for snmp -> ", @fd_set, "\n"; 408 #print "block -> ", $block, "\n"; 409 #print "timeout_sec -> ", $to_sec, "\n"; 410 #print "timeout_usec -> ", $to_usec, "\n"; 411 #print "timeout dec -> ", $time_sec_dec, "\n"; 412 return ($time_sec_dec); 413} 414 415sub _tie { 416# this is a little implementation hack so ActiveState can access pp_tie 417# thru perl code. All other environments allow the calling of pp_tie from 418# XS code but AS was not exporting it when PERL_OBJECT was used. 419# 420# short term solution was call this perl func which calls 'tie' 421# 422# longterm fix is to supply a patch which allows AS to export pp_tie in 423# such a way that it can be called from XS code. gsarathy says: 424# a patch to util.c is needed to provide access to PL_paddr 425# so it is possible to call PL_paddr[OP_TIE] as the compiler does 426 tie($_[0],$_[1],$_[2],$_[3]); 427} 428 429sub split_vars { 430 # This sub holds the regex that is used throughout this module 431 # to parse the base part of an OID from the IID. 432 # eg: portName.9.30 -> ['portName','9.30'] 433 my $vars = shift; 434 435 # The regex was changed to this simple form by patch 722075 for some reason. 436 # Testing shows now (2/05) that it is not needed, and that the long expression 437 # works fine. AB 438 # my ($tag, $iid) = ($vars =~ /^(.*?)\.?(\d+)+$/); 439 440 # These following two are the same. Broken down for easier maintenance 441 # my ($tag, $iid) = ($vars =~ /^((?:\.\d+)+|(?:\w+(?:\-*\w+)+))\.?(.*)$/); 442 my ($tag, $iid) = 443 ($vars =~ /^( # Capture $1 444 # 1. either this 5.5.5.5 445 (?:\.\d+)+ # for grouping, won't increment $1 446 | 447 # 2. or asdf-asdf-asdf-asdf 448 (?: # grouping again 449 \w+ # needs some letters followed by 450 (?:\-*\w+)+ # zero or more dashes, one or more letters 451 ) 452 ) 453 \.? # optionally match a dot 454 (.*) # whatever is left in the string is our iid ($2) 455 $/x 456 ); 457 return [$tag,$iid]; 458} 459 460package SNMP::Session; 461 462sub new { 463 my $type = shift; 464 my $this = {}; 465 my ($name, $aliases, $host_type, $len, $thisaddr); 466 467 SNMP::init_snmp("perl"); 468 469 %$this = @_; 470 471 $this->{ErrorStr} = ''; # if methods return undef check for expln. 472 $this->{ErrorNum} = 0; # contains SNMP error return 473 474 $this->{Version} ||= 475 NetSNMP::default_store::netsnmp_ds_get_int(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID, 476 NetSNMP::default_store::NETSNMP_DS_LIB_SNMPVERSION) || 477 SNMP::SNMP_DEFAULT_VERSION(); 478 479 if ($this->{Version} eq 128) { 480 # special handling of the bogus v1 definition. 481 $this->{Version} = 1; 482 } 483 484 # allow override of local SNMP port 485 $this->{LocalPort} ||= 0; 486 487 # destination host defaults to localhost 488 $this->{DestHost} ||= 'localhost'; 489 490 # community defaults to public 491 $this->{Community} ||= NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(), 492 NetSNMP::default_store::NETSNMP_DS_LIB_COMMUNITY()) || 'public'; 493 494 # number of retries before giving up, defaults to SNMP_DEFAULT_RETRIES 495 $this->{Retries} = SNMP::SNMP_DEFAULT_RETRIES() unless defined($this->{Retries}); 496 497 # timeout before retry, defaults to SNMP_DEFAULT_TIMEOUT 498 $this->{Timeout} = SNMP::SNMP_DEFAULT_TIMEOUT() unless defined($this->{Timeout}); 499 # flag to enable fixing pdu and retrying with a NoSuch error 500 $this->{RetryNoSuch} ||= 0; 501 502 # backwards compatibility. Make host = host:port 503 if ($this->{RemotePort} && $this->{DestHost} !~ /:/) { 504 $this->{DestHost} = $this->{DestHost} . ":" . $this->{RemotePort}; 505 } 506 507 if ($this->{DestHost} =~ /^(dtls|tls|ssh)/) { 508 # only works with version 3 509 $this->{Version} = 3; 510 } 511 512 if ($this->{Version} eq '1' or $this->{Version} eq '2' 513 or $this->{Version} eq '2c') { 514 $this->{SessPtr} = SNMP::_new_session($this->{Version}, 515 $this->{Community}, 516 $this->{DestHost}, 517 $this->{LocalPort}, 518 $this->{Retries}, 519 $this->{Timeout}, 520 ); 521 } elsif ($this->{Version} eq '3' ) { 522 $this->{SecName} ||= 523 NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(), 524 NetSNMP::default_store::NETSNMP_DS_LIB_SECNAME()) || 525 'initial'; 526 if (!$this->{SecLevel}) { 527 $this->{SecLevel} = 528 NetSNMP::default_store::netsnmp_ds_get_int(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(), 529 NetSNMP::default_store::NETSNMP_DS_LIB_SECLEVEL()) || 530 $SNMP::V3_SEC_LEVEL_MAP{'noAuthNoPriv'}; 531 } elsif ($this->{SecLevel} !~ /^\d+$/) { 532 $this->{SecLevel} = $SNMP::V3_SEC_LEVEL_MAP{$this->{SecLevel}}; 533 } 534 $this->{SecEngineId} ||= ''; 535 $this->{ContextEngineId} ||= $this->{SecEngineId}; 536 $this->{Context} ||= 537 NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(), 538 NetSNMP::default_store::NETSNMP_DS_LIB_CONTEXT()) || ''; 539 540 if ($this->{DestHost} =~ /^(dtls|tls|ssh)/) { 541 # this is a tunneled protocol 542 543 $this->{'OurIdentity'} ||= ''; 544 $this->{'TheirIdentity'} ||= ''; 545 $this->{'TheirHostname'} ||= ''; 546 $this->{'TrustCert'} ||= ''; 547 548 $this->{'SecLevel'} = $SNMP::V3_SEC_LEVEL_MAP{'authPriv'}; 549 550 $this->{SessPtr} = 551 SNMP::_new_tunneled_session($this->{Version}, 552 $this->{DestHost}, 553 $this->{Retries}, 554 $this->{Timeout}, 555 $this->{SecName}, 556 $this->{SecLevel}, 557 $this->{ContextEngineId}, 558 $this->{Context}, 559 $this->{'OurIdentity'}, 560 $this->{'TheirIdentity'}, 561 $this->{'TheirHostname'}, 562 $this->{'TrustCert'}, 563 ); 564 565 566 } else { 567 # USM or some other internal security protocol 568 569 # USM specific parameters: 570 $this->{AuthProto} ||= 'DEFAULT'; # use the library's default 571 $this->{AuthPass} ||= 572 NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(), 573 NetSNMP::default_store::NETSNMP_DS_LIB_AUTHPASSPHRASE()) || 574 NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(), 575 NetSNMP::default_store::NETSNMP_DS_LIB_PASSPHRASE()) || ''; 576 577 $this->{AuthMasterKey} ||= ''; 578 $this->{PrivMasterKey} ||= ''; 579 $this->{AuthLocalizedKey} ||= ''; 580 $this->{PrivLocalizedKey} ||= ''; 581 582 $this->{PrivProto} ||= 'DEFAULT'; # use the library's default 583 $this->{PrivPass} ||= 584 NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(), 585 NetSNMP::default_store::NETSNMP_DS_LIB_PRIVPASSPHRASE()) || 586 NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(), 587 NetSNMP::default_store::NETSNMP_DS_LIB_PASSPHRASE()) || ''; 588 $this->{EngineBoots} = 0 if not defined $this->{EngineBoots}; 589 $this->{EngineTime} = 0 if not defined $this->{EngineTime}; 590 591 $this->{SessPtr} = 592 SNMP::_new_v3_session($this->{Version}, 593 $this->{DestHost}, 594 $this->{Retries}, 595 $this->{Timeout}, 596 $this->{SecName}, 597 $this->{SecLevel}, 598 $this->{SecEngineId}, 599 $this->{ContextEngineId}, 600 $this->{Context}, 601 $this->{AuthProto}, 602 $this->{AuthPass}, 603 $this->{PrivProto}, 604 $this->{PrivPass}, 605 $this->{EngineBoots}, 606 $this->{EngineTime}, 607 $this->{AuthMasterKey}, 608 length($this->{AuthMasterKey}), 609 $this->{PrivMasterKey}, 610 length($this->{PrivMasterKey}), 611 $this->{AuthLocalizedKey}, 612 length($this->{AuthLocalizedKey}), 613 $this->{PrivLocalizedKey}, 614 length($this->{PrivLocalizedKey}), 615 ); 616 } 617 } 618 unless ($this->{SessPtr}) { 619 warn("unable to create session") if $SNMP::verbose; 620 return undef; 621 } 622 623 SNMP::initMib($SNMP::auto_init_mib); # ensures that *some* mib is loaded 624 625 $this->{UseLongNames} = $SNMP::use_long_names 626 unless exists $this->{UseLongNames}; 627 $this->{UseSprintValue} = $SNMP::use_sprint_value 628 unless exists $this->{UseSprintValue}; 629 $this->{BestGuess} = $SNMP::best_guess unless exists $this->{BestGuess}; 630 $this->{NonIncreasing} ||= $SNMP::non_increasing; 631 $this->{UseEnums} = $SNMP::use_enums unless exists $this->{UseEnums}; 632 $this->{UseNumeric} = $SNMP::use_numeric unless exists $this->{UseNumeric}; 633 634 # Force UseLongNames if UseNumeric is in use. 635 $this->{UseLongNames}++ if $this->{UseNumeric}; 636 637 bless $this, $type; 638} 639 640sub update { 641# *Not Implemented* 642# designed to update the fields of session to allow retargetting to different 643# host, community name change, timeout, retry changes etc. Unfortunately not 644# working yet because some updates (the address in particular) need to be 645# done on the internal session pointer which cannot be fetched w/o touching 646# globals at this point which breaks win32. A patch to the net-snmp toolkit 647# is needed 648 my $this = shift; 649 my ($name, $aliases, $host_type, $len, $thisaddr); 650 my %new_fields = @_; 651 652 @$this{keys %new_fields} = values %new_fields; 653 654 $this->{UseLongNames} = $SNMP::use_long_names 655 unless exists $this->{UseLongNames}; 656 $this->{UseSprintValue} = $SNMP::use_sprint_value 657 unless exists $this->{UseSprintValue}; 658 $this->{BestGuess} = $SNMP::best_guess unless exists $this->{BestGuess}; 659 $this->{NonIncreasing} ||= $SNMP::non_increasing; 660 $this->{UseEnums} = $SNMP::use_enums unless exists $this->{UseEnums}; 661 $this->{UseNumeric} = $SNMP::use_numeric unless exists $this->{UseNumeric}; 662 663 # Force UseLongNames if UseNumeric is in use. 664 $this->{UseLongNames}++ if $this->{UseNumeric}; 665 666 SNMP::_update_session($this->{Version}, 667 $this->{Community}, 668 $this->{DestHost}, 669 $this->{RemotePort}, 670 $this->{LocalPort}, 671 $this->{Retries}, 672 $this->{Timeout}, 673 ); 674 675 676} 677 678sub set { 679 my $this = shift; 680 my $vars = shift; 681 my $varbind_list_ref; 682 my $res = 0; 683 684 if (ref($vars) =~ /SNMP::VarList/) { 685 $varbind_list_ref = $vars; 686 } elsif (ref($vars) =~ /SNMP::Varbind/) { 687 $varbind_list_ref = [$vars]; 688 } elsif (ref($vars) =~ /ARRAY/) { 689 $varbind_list_ref = [$vars]; 690 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 691 } else { 692 #$varbind_list_ref = [[$tag, $iid, $val]]; 693 my $split_vars = SNMP::split_vars($vars); 694 my $val = shift; 695 push @$split_vars,$val; 696 $varbind_list_ref = [$split_vars]; 697 } 698 my $cb = shift; 699 700 $res = SNMP::_set($this, $varbind_list_ref, $cb); 701} 702 703sub get { 704 my $this = shift; 705 my $vars = shift; 706 my ($varbind_list_ref, @res); 707 708 if (ref($vars) =~ /SNMP::VarList/) { 709 $varbind_list_ref = $vars; 710 } elsif (ref($vars) =~ /SNMP::Varbind/) { 711 $varbind_list_ref = [$vars]; 712 } elsif (ref($vars) =~ /ARRAY/) { 713 $varbind_list_ref = [$vars]; 714 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 715 } else { 716 $varbind_list_ref = [SNMP::split_vars($vars)]; 717 } 718 719 my $cb = shift; 720 721 @res = SNMP::_get($this, $this->{RetryNoSuch}, $varbind_list_ref, $cb); 722 723 return(wantarray() ? @res : $res[0]); 724} 725 726 727my $have_netsnmp_oid = eval { require NetSNMP::OID; }; 728sub gettable { 729 730 # 731 # getTable 732 # -------- 733 # 734 # Get OIDs starting at $table_oid, and continue down the tree 735 # until we get to an OID which does not start with $table_oid, 736 # i.e. we have reached the end of this table. 737 # 738 739 my $state; 740 741 my ($this, $root_oid, @options) = @_; 742 $state->{'options'} = {@options}; 743 my ($textnode, $varbinds, $vbl, $res, $repeat); 744 745 # translate the OID into numeric form if its not 746 if ($root_oid !~ /^[\.0-9]+$/) { 747 $textnode = $root_oid; 748 $root_oid = SNMP::translateObj($root_oid); 749 } else { 750 $textnode = SNMP::translateObj($root_oid); 751 } 752 753 # bail if we don't have a valid oid. 754 return if (!$root_oid); 755 756 # deficed if we're going to parse indexes 757 my $parse_indexes = (defined($state->{'options'}{'noindexes'})) ? 758 0 : $have_netsnmp_oid; 759 760 # get the list of columns we should look at. 761 my @columns; 762 if (!$state->{'options'}{'columns'}) { 763 if ($textnode) { 764 my %indexes; 765 766 if ($parse_indexes) { 767 # get indexes 768 my @indexes = 769 @{$SNMP::MIB{$textnode}{'children'}[0]{'indexes'} || []}; 770 # quick translate into a hash 771 map { $indexes{$_} = 1; } @indexes; 772 } 773 774 # calculate the list of accessible columns that aren't indexes 775 my $children = $SNMP::MIB{$textnode}{'children'}[0]{'children'}; 776 foreach my $c (@$children) { 777 push @{$state->{'columns'}}, 778 $root_oid . ".1." . $c->{'subID'} 779 if (!$indexes{$c->{'label'}}); 780 } 781 if ($#{$state->{'columns'}} == -1) { 782 # some tables are only indexes, and we need to walk at 783 # least one column. We pick the last. 784 push @{$state->{'columns'}}, $root_oid . ".1." . 785 $children->[$#$children]{'subID'} 786 if ref($state) eq 'HASH' and ref($children) eq 'ARRAY'; 787 } 788 } 789 } else { 790 # XXX: requires specification in numeric OID... ack.! 791 @{$state->{'columns'}} = @{$state->{'options'}{'columns'}}; 792 793 # if the columns aren't numeric, we need to turn them into 794 # numeric columns... 795 map { 796 if ($_ !~ /\.1\.3/) { 797 $_ = $SNMP::MIB{$_}{'objectID'}; 798 } 799 } @{$state->{'columns'}}; 800 } 801 802 # create the initial walking info. 803 foreach my $c (@{$state->{'columns'}}) { 804 push @{$state->{'varbinds'}}, [$c]; 805 push @{$state->{'stopconds'}}, $c; 806 } 807 808 if ($#{$state->{'varbinds'}} == -1) { 809 print STDERR "ack: gettable failed to find any columns to look for.\n"; 810 return; 811 } 812 813 $vbl = $state->{'varbinds'}; 814 815 my $repeatcount; 816 if ($this->{Version} eq '1' || $state->{'options'}{nogetbulk}) { 817 $state->{'repeatcount'} = 1; 818 } elsif ($state->{'options'}{'repeat'}) { 819 $state->{'repeatcount'} = $state->{'options'}{'repeat'}; 820 } elsif ($#{$state->{'varbinds'}} == -1) { 821 $state->{'repeatcount'} = 1; 822 } else { 823 # experimentally determined maybe guess at a best repeat value 824 # 1000 bytes max (safe), 30 bytes average for encoding of the 825 # varbind (experimentally determined to be closer to 826 # 26. Again, being safe. Then devide by the number of 827 # varbinds. 828 $state->{'repeatcount'} = int(1000 / 36 / ($#{$state->{'varbinds'}} + 1)); 829 } 830 # Make sure we run at least once 831 if ($state->{'repeatcount'} < 1) { 832 $state->{'repeatcount'} = 1; 833 } 834 835 # 836 # if we've been configured with a callback, then call the 837 # sub-functions with a callback to our own "next" processing 838 # function (_gettable_do_it). or else call the blocking method and 839 # call the next processing function ourself. 840 # 841 if ($state->{'options'}{'callback'}) { 842 if ($this->{Version} ne '1' && !$state->{'options'}{'nogetbulk'}) { 843 $res = $this->getbulk(0, $state->{'repeatcount'}, $vbl, 844 [\&_gettable_do_it, $this, $vbl, 845 $parse_indexes, $textnode, $state]); 846 } else { 847 $res = $this->getnext($vbl, 848 [\&_gettable_do_it, $this, $vbl, 849 $parse_indexes, $textnode, $state]); 850 } 851 } else { 852 if ($this->{Version} ne '1' && !$state->{'options'}{'nogetbulk'}) { 853 $res = $this->getbulk(0, $state->{'repeatcount'}, $vbl); 854 } else { 855 $res = $this->getnext($vbl); 856 } 857 return $this->_gettable_do_it($vbl, $parse_indexes, $textnode, $state); 858 } 859 return 0; 860} 861 862sub _gettable_do_it() { 863 my ($this, $vbl, $parse_indexes, $textnode, $state) = @_; 864 865 my ($res); 866 867 $vbl = $_[$#_] if ($state->{'options'}{'callback'}); 868 869 while ($#$vbl > -1 && !$this->{ErrorNum}) { 870 if (($#$vbl + 1) % ($#{$state->{'stopconds'}} + 1) != 0) { 871 if ($vbl->[$#$vbl][2] ne 'ENDOFMIBVIEW') { 872 # unless it's an end of mib view we didn't get the 873 # proper number of results back. 874 print STDERR "ack: gettable results not appropriate\n"; 875 } 876 my @k = keys(%{$state->{'result_hash'}}); 877 last if ($#k > -1); # bail with what we have 878 return; 879 } 880 881 $state->{'varbinds'} = []; 882 my $newstopconds; 883 884 my $lastsetstart = ($state->{'repeatcount'}-1) * ($#{$state->{'stopconds'}}+1); 885 886 for (my $i = 0; $i <= $#$vbl; $i++) { 887 my $row_oid = SNMP::translateObj($vbl->[$i][0]); 888 my $row_text = $vbl->[$i][0]; 889 my $row_index = $vbl->[$i][1]; 890 my $row_value = $vbl->[$i][2]; 891 my $row_type = $vbl->[$i][3]; 892 893 if ($row_oid =~ 894 /^$state->{'stopconds'}[$i % ($#{$state->{'stopconds'}}+1)]/ && 895 $row_value ne 'ENDOFMIBVIEW' ){ 896 897 if ($row_type eq "OBJECTID") { 898 899 # If the value returned is an OID, translate this 900 # back in to a textual OID 901 902 $row_value = SNMP::translateObj($row_value); 903 904 } 905 906 # Place the results in a hash 907 908 $state->{'result_hash'}{$row_index}{$row_text} = $row_value; 909 910 # continue past this next time 911 if ($i >= $lastsetstart) { 912 push @$newstopconds, 913 $state->{'stopconds'}->[$i%($#{$state->{'stopconds'}}+1)]; 914 push @{$state->{'varbinds'}},[$vbl->[$i][0],$vbl->[$i][1]]; 915 } 916 } 917 } 918 if ($#$newstopconds == -1) { 919 last; 920 } 921 if ($#{$state->{'varbinds'}} == -1) { 922 print "gettable ack. shouldn't get here\n"; 923 } 924 $vbl = $state->{'varbinds'}; 925 $state->{'stopconds'} = $newstopconds; 926 927 # 928 # if we've been configured with a callback, then call the 929 # sub-functions with a callback to our own "next" processing 930 # function (_gettable_do_it). or else call the blocking method and 931 # call the next processing function ourself. 932 # 933 if ($state->{'options'}{'callback'}) { 934 if ($this->{Version} ne '1' && !$state->{'options'}{'nogetbulk'}) { 935 $res = $this->getbulk(0, $state->{'repeatcount'}, $vbl, 936 [\&_gettable_do_it, $this, $vbl, 937 $parse_indexes, $textnode, $state]); 938 } else { 939 $res = $this->getnext($vbl, 940 [\&_gettable_do_it, $this, $vbl, 941 $parse_indexes, $textnode, $state]); 942 } 943 return; 944 } else { 945 if ($this->{Version} ne '1' && !$state->{'options'}{'nogetbulk'}) { 946 $res = $this->getbulk(0, $state->{'repeatcount'}, $vbl); 947 } else { 948 $res = $this->getnext($vbl); 949 } 950 } 951 } 952 953 # finish up 954 _gettable_end_routine($state, $parse_indexes, $textnode); 955 956 # return the hash if no callback was specified 957 if (!$state->{'options'}{'callback'}) { 958 return($state->{'result_hash'}); 959 } 960 961 # 962 # if they provided a callback, call it 963 # (if an array pass the args as well) 964 # 965 if (ref($state->{'options'}{'callback'}) eq 'ARRAY') { 966 my $code = shift @{$state->{'options'}{'callback'}}; 967 $code->(@{$state->{'options'}{'callback'}}, $state->{'result_hash'}); 968 } else { 969 $state->{'options'}{'callback'}->($state->{'result_hash'}); 970 } 971} 972 973sub _gettable_end_routine { 974 my ($state, $parse_indexes, $textnode) = @_; 975 if ($parse_indexes) { 976 my @indexes = @{$SNMP::MIB{$textnode}{'children'}[0]{'indexes'}}; 977 my $i; 978 foreach my $trow (keys(%{$state->{'result_hash'}})) { 979 my $noid = new NetSNMP::OID($state->{'columns'}[0] . "." . $trow); 980 if (!$noid) { 981 print STDERR "***** ERROR parsing $state->{'columns'}[0].$trow MIB OID\n"; 982 next; 983 } 984 my $nindexes = $noid->get_indexes(); 985 if (!$nindexes || ref($nindexes) ne 'ARRAY' || 986 $#indexes != $#$nindexes) { 987 print STDERR "***** ERROR parsing $state->{'columns'}[0].$trow MIB indexes:\n $noid => " . ref($nindexes) . "\n [should be an ARRAY]\n expended # indexes = $#indexes\n"; 988 if (ref($nindexes) eq 'ARRAY') { 989 print STDERR "***** ERROR parsing $state->{'columns'}[0].$trow MIB indexes: " . ref($nindexes) . " $#indexes $#$nindexes\n"; 990 } 991 next; 992 } 993 994 for ($i = 0; $i <= $#indexes; $i++) { 995 $state->{'result_hash'}{$trow}{$indexes[$i]} = $nindexes->[$i]; 996 } 997 } 998 } 999} 1000 1001 1002sub fget { 1003 my $this = shift; 1004 my $vars = shift; 1005 my ($varbind_list_ref, @res); 1006 1007 if (ref($vars) =~ /SNMP::VarList/) { 1008 $varbind_list_ref = $vars; 1009 } elsif (ref($vars) =~ /SNMP::Varbind/) { 1010 $varbind_list_ref = [$vars]; 1011 } elsif (ref($vars) =~ /ARRAY/) { 1012 $varbind_list_ref = [$vars]; 1013 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 1014 } else { 1015 $varbind_list_ref = [SNMP::split_vars($vars)]; 1016 } 1017 1018 my $cb = shift; 1019 1020 SNMP::_get($this, $this->{RetryNoSuch}, $varbind_list_ref, $cb); 1021 1022 foreach my $varbind (@$varbind_list_ref) { 1023 my $sub = $this->{VarFormats}{SNMP::Varbind::tag($varbind)} || 1024 $this->{TypeFormats}{SNMP::Varbind::type($varbind)}; 1025 &$sub($varbind) if defined $sub; 1026 push(@res, SNMP::Varbind::val($varbind)); 1027 } 1028 1029 return(wantarray() ? @res : $res[0]); 1030} 1031 1032sub getnext { 1033 my $this = shift; 1034 my $vars = shift; 1035 my ($varbind_list_ref, @res); 1036 1037 if (ref($vars) =~ /SNMP::VarList/) { 1038 $varbind_list_ref = $vars; 1039 } elsif (ref($vars) =~ /SNMP::Varbind/) { 1040 $varbind_list_ref = [$vars]; 1041 } elsif (ref($vars) =~ /ARRAY/) { 1042 $varbind_list_ref = [$vars]; 1043 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 1044 } else { 1045 $varbind_list_ref = [SNMP::split_vars($vars)]; 1046 } 1047 1048 my $cb = shift; 1049 1050 @res = SNMP::_getnext($this, $varbind_list_ref, $cb); 1051 1052 return(wantarray() ? @res : $res[0]); 1053} 1054 1055sub fgetnext { 1056 my $this = shift; 1057 my $vars = shift; 1058 my ($varbind_list_ref, @res); 1059 1060 if (ref($vars) =~ /SNMP::VarList/) { 1061 $varbind_list_ref = $vars; 1062 } elsif (ref($vars) =~ /SNMP::Varbind/) { 1063 $varbind_list_ref = [$vars]; 1064 } elsif (ref($vars) =~ /ARRAY/) { 1065 $varbind_list_ref = [$vars]; 1066 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 1067 } else { 1068 $varbind_list_ref = [SNMP::split_vars($vars)]; 1069 } 1070 1071 my $cb = shift; 1072 1073 SNMP::_getnext($this, $varbind_list_ref, $cb); 1074 1075 foreach my $varbind (@$varbind_list_ref) { 1076 my $sub = $this->{VarFormats}{SNMP::Varbind::tag($varbind)} || 1077 $this->{TypeFormats}{SNMP::Varbind::type($varbind)}; 1078 &$sub($varbind) if defined $sub; 1079 push(@res, SNMP::Varbind::val($varbind)); 1080 } 1081 1082 return(wantarray() ? @res : $res[0]); 1083} 1084 1085sub getbulk { 1086 my $this = shift; 1087 my $nonrepeaters = shift; 1088 my $maxrepetitions = shift; 1089 my $vars = shift; 1090 my ($varbind_list_ref, @res); 1091 1092 if (ref($vars) =~ /SNMP::VarList/) { 1093 $varbind_list_ref = $vars; 1094 } elsif (ref($vars) =~ /SNMP::Varbind/) { 1095 $varbind_list_ref = [$vars]; 1096 } elsif (ref($vars) =~ /ARRAY/) { 1097 $varbind_list_ref = [$vars]; 1098 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 1099 } else { 1100 $varbind_list_ref = [SNMP::split_vars($vars)]; 1101 } 1102 1103 my $cb = shift; 1104 1105 @res = SNMP::_getbulk($this, $nonrepeaters, $maxrepetitions, $varbind_list_ref, $cb); 1106 1107 return(wantarray() ? @res : $res[0]); 1108} 1109 1110sub bulkwalk { 1111 my $this = shift; 1112 my $nonrepeaters = shift; 1113 my $maxrepetitions = shift; 1114 my $vars = shift; 1115 my ($varbind_list_ref, @res); 1116 1117 if (ref($vars) =~ /SNMP::VarList/) { 1118 $varbind_list_ref = $vars; 1119 } elsif (ref($vars) =~ /SNMP::Varbind/) { 1120 $varbind_list_ref = [$vars]; 1121 } elsif (ref($vars) =~ /ARRAY/) { 1122 $varbind_list_ref = [$vars]; 1123 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 1124 } else { 1125 # my ($tag, $iid) = ($vars =~ /^((?:\.\d+)+|\w+)\.?(.*)$/); 1126 my ($tag, $iid) = ($vars =~ /^(.*?)\.?(\d+)+$/); 1127 $varbind_list_ref = [[$tag, $iid]]; 1128 } 1129 1130 if (scalar @$varbind_list_ref == 0) { 1131 $this->{ErrorNum} = SNMP::constant("SNMPERR_GENERR", 0); 1132 $this->{ErrorStr} = "cannot bulkwalk() empty variable list"; 1133 return undef; 1134 } 1135 if (scalar @$varbind_list_ref < $nonrepeaters) { 1136 $this->{ErrorNum} = SNMP::constant("SNMPERR_GENERR", 0); 1137 $this->{ErrorStr} = "bulkwalk() needs at least $nonrepeaters varbinds"; 1138 return undef; 1139 } 1140 1141 my $cb = shift; 1142 @res = SNMP::_bulkwalk($this, $nonrepeaters, $maxrepetitions, 1143 $varbind_list_ref, $cb); 1144 1145 # Return, in list context, a copy of the array of arrays of Varbind refs. 1146 # In scalar context, return either a reference to the array of arrays of 1147 # Varbind refs, or the request ID for an asynchronous bulkwalk. This is 1148 # a compromise between the getbulk()-ish return, and the more useful array 1149 # of arrays of Varbinds return from the synchronous bulkwalk(). 1150 # 1151 return @res if (wantarray()); 1152 return defined($cb) ? $res[0] : \@res; 1153} 1154 1155my %trap_type = (coldStart => 0, warmStart => 1, linkDown => 2, linkUp => 3, 1156 authFailure => 4, egpNeighborLoss => 5, specific => 6 ); 1157sub trap { 1158# (v1) enterprise, agent, generic, specific, uptime, <vars> 1159# $sess->trap(enterprise=>'.1.3.6.1.4.1.2021', # or 'ucdavis' [default] 1160# agent => '127.0.0.1', # or 'localhost',[default 1st intf on host] 1161# generic => specific, # can be omitted if 'specific' supplied 1162# specific => 5, # can be omitted if 'generic' supplied 1163# uptime => 1234, # default to localhost uptime (0 on win32) 1164# [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars 1165# # always last 1166# (v2) oid, uptime, <vars> 1167# $sess->trap(uptime => 1234, 1168# oid => 'snmpRisingAlarm', 1169# [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars 1170# # always last 1171# # always last 1172 1173 1174 my $this = shift; 1175 my $vars = pop if ref($_[$#_]); # last arg may be varbind or varlist 1176 my %param = @_; 1177 my ($varbind_list_ref, @res); 1178 1179 if (ref($vars) =~ /SNMP::VarList/) { 1180 $varbind_list_ref = $vars; 1181 } elsif (ref($vars) =~ /SNMP::Varbind/) { 1182 $varbind_list_ref = [$vars]; 1183 } elsif (ref($vars) =~ /ARRAY/) { 1184 $varbind_list_ref = [$vars]; 1185 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 1186 } 1187 1188 if ($this->{Version} =~ '^1') { 1189 my $enterprise = $param{enterprise} || 'ucdavis'; 1190 $enterprise = SNMP::translateObj($enterprise) 1191 unless $enterprise =~ /^[\.\d]+$/; 1192 my $agent = $param{agent} || ''; 1193 my $generic = $param{generic} || 'specific'; 1194 $generic = $trap_type{$generic} || $generic; 1195 my $uptime = $param{uptime} || SNMP::_sys_uptime(); 1196 my $specific = $param{specific} || 0; 1197 @res = SNMP::_trapV1($this, $enterprise, $agent, $generic, $specific, 1198 $uptime, $varbind_list_ref); 1199 } elsif ($this->{Version} =~ '^[23]') { 1200 my $trap_oid = $param{oid} || $param{trapoid} || '.0.0'; 1201 my $uptime = $param{uptime} || SNMP::_sys_uptime(); 1202 @res = SNMP::_trapV2($this, $uptime, $trap_oid, $varbind_list_ref); 1203 } else { 1204 warn("error:trap: Unsupported SNMP version " . $this->{Version} . "\n"); 1205 } 1206 1207 return(wantarray() ? @res : $res[0]); 1208} 1209 1210sub inform { 1211# (v3) oid, uptime, <vars> 1212# $sess->inform(uptime => 1234, 1213# oid => 'coldStart', 1214# [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars 1215# # then callback 1216 # always last 1217 1218 1219 my $this = shift; 1220 my $vars; 1221 my $cb; 1222 $cb = pop if ref($_[$#_]) eq 'CODE'; # last arg may be code 1223 $vars = pop if ref($_[$#_]); # varbind or varlist 1224 my %param = @_; 1225 my ($varbind_list_ref, @res); 1226 1227 if (ref($vars) =~ /SNMP::VarList/) { 1228 $varbind_list_ref = $vars; 1229 } elsif (ref($vars) =~ /SNMP::Varbind/) { 1230 $varbind_list_ref = [$vars]; 1231 } elsif (ref($vars) =~ /ARRAY/) { 1232 $varbind_list_ref = [$vars]; 1233 $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/; 1234 } 1235 1236 my $trap_oid = $param{oid} || $param{trapoid}; 1237 my $uptime = $param{uptime} || SNMP::_sys_uptime(); 1238 1239 if ($this->{Version} =~ '^[23]') { 1240 @res = SNMP::_inform($this, $uptime, $trap_oid, $varbind_list_ref, $cb); 1241 } else { 1242 warn("error:inform: This version doesn't support the command\n"); 1243 } 1244 1245 return(wantarray() ? @res : $res[0]); 1246} 1247 1248package SNMP::TrapSession; 1249@SNMP::TrapSession::ISA = ('SNMP::Session'); 1250 1251sub new { 1252 my $type = shift; 1253 1254 # allow override of remote SNMP trap port 1255 unless (grep(/RemotePort/, @_)) { 1256 push(@_, 'RemotePort', 162); # push on new default for trap session 1257 } 1258 1259 SNMP::Session::new($type, @_); 1260} 1261 1262package SNMP::Varbind; 1263 1264$SNMP::Varbind::tag_f = 0; 1265$SNMP::Varbind::iid_f = 1; 1266$SNMP::Varbind::val_f = 2; 1267$SNMP::Varbind::type_f = 3; 1268$SNMP::Varbind::time_f = 4; 1269 1270sub new { 1271 my $type = shift; 1272 my $this = shift; 1273 $this ||= []; 1274 bless $this; 1275} 1276 1277sub tag { 1278 $_[0]->[$SNMP::Varbind::tag_f]; 1279} 1280 1281sub iid { 1282 $_[0]->[$SNMP::Varbind::iid_f]; 1283} 1284 1285sub val { 1286 $_[0]->[$SNMP::Varbind::val_f]; 1287} 1288 1289sub type { 1290 $_[0]->[$SNMP::Varbind::type_f]; 1291} 1292 1293sub name { 1294 if (defined($_[0]->[$SNMP::Varbind::iid_f]) && ($_[0]->[$SNMP::Varbind::iid_f] =~ m/^[0-9]+$/)) { 1295 return $_[0]->[$SNMP::Varbind::tag_f] . "." . $_[0]->[$SNMP::Varbind::iid_f]; 1296 } 1297 1298 return $_[0]->[$SNMP::Varbind::tag_f]; 1299} 1300 1301sub fmt { 1302 my $self = shift; 1303 return $self->name . " = \"" . $self->val . "\" (" . $self->type . ")"; 1304} 1305 1306 1307#sub DESTROY { 1308# print "SNMP::Varbind::DESTROY($_[0])\n"; 1309#} 1310 1311package SNMP::VarList; 1312 1313sub new { 1314 my $type = shift; 1315 my $this = []; 1316 my $varb; 1317 foreach $varb (@_) { 1318 $varb = new SNMP::Varbind($varb) unless ref($varb) =~ /SNMP::Varbind/; 1319 push(@{$this}, $varb); 1320 } 1321 1322 bless $this; 1323} 1324 1325#sub DESTROY { 1326# print "SNMP::VarList::DESTROY($_[0])\n"; 1327#} 1328 1329package SNMP::DEBUGGING; 1330# controls info/debugging output from SNMP module and libsnmp 1331# $SNMP::debugging == 1 => enables general info and warning output 1332# (eqiv. to setting $SNMP::verbose) 1333# $SNMP::debugging == 2 => enables do_debugging from libsnmp as well 1334# $SNMP::debugging == 3 => enables packet_dump from libsnmp as well 1335sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; } 1336 1337sub FETCH { ${$_[0]}; } 1338 1339sub STORE { 1340 $SNMP::verbose = $_[1]; 1341 SNMP::_set_debugging($_[1]>1); 1342 $SNMP::dump_packet = ($_[1]>2); 1343 ${$_[0]} = $_[1]; 1344} 1345 1346sub DELETE { 1347 $SNMP::verbose = 0; 1348 SNMP::_set_debugging(0); 1349 $SNMP::dump_packet = 0; 1350 ${$_[0]} = undef; 1351} 1352 1353package SNMP::DEBUG_INTERNALS; # Controls SNMP.xs debugging. 1354sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; } 1355 1356sub FETCH { ${$_[0]}; } 1357 1358sub STORE { 1359 SNMP::_debug_internals($_[1]); 1360 ${$_[0]} = $_[1]; 1361} 1362 1363sub DELETE { 1364 SNMP::_debug_internals(0); 1365 ${$_[0]} = undef; 1366} 1367 1368package SNMP::DUMP_PACKET; 1369# controls packet dump output from libsnmp 1370 1371sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; } 1372 1373sub FETCH { ${$_[0]}; } 1374 1375sub STORE { SNMP::_dump_packet($_[1]); ${$_[0]} = $_[1]; } 1376 1377sub DELETE { SNMP::_dump_packet(0); ${$_[0]} = 0; } 1378 1379package SNMP::MIB; 1380 1381sub TIEHASH { 1382 bless {}; 1383} 1384 1385sub FETCH { 1386 my $this = shift; 1387 my $key = shift; 1388 1389 if (!defined $this->{$key}) { 1390 tie(%{$this->{$key}}, 'SNMP::MIB::NODE', $key) or return undef; 1391 } 1392 $this->{$key}; 1393} 1394 1395sub STORE { 1396 warn "STORE(@_) : write access to the MIB not implemented\n"; 1397} 1398 1399sub DELETE { 1400 delete $_[0]->{$_[1]}; # just delete cache entry 1401} 1402 1403sub FIRSTKEY { return '.1'; } # this should actually start at .0 but 1404 # because nodes are not stored in lexico 1405 # order in ucd-snmp node tree walk will 1406 # miss most of the tree 1407sub NEXTKEY { # this could be sped up by using an XS __get_next_oid maybe 1408 my $node = $_[0]->FETCH($_[1])->{nextNode}; 1409 $node->{objectID}; 1410} 1411sub EXISTS { exists $_[0]->{$_[1]} || $_[0]->FETCH($_[1]); } 1412sub CLEAR { undef %{$_[0]}; } # clear the cache 1413 1414package SNMP::MIB::NODE; 1415my %node_elements = 1416 ( 1417 objectID => 0, # dotted decimal fully qualified OID 1418 label => 0, # leaf textual identifier (e.g., 'sysDescr') 1419 subID => 0, # leaf numeric OID component of objectID (e.g., '1') 1420 moduleID => 0, # textual identifier for module (e.g., 'RFC1213-MIB') 1421 parent => 0, # parent node 1422 children => 0, # array reference of children nodes 1423 indexes => 0, # returns array of column labels 1424 implied => 0, # boolean: is the last index IMPLIED 1425 varbinds => 0, # returns array of trap/notification varbinds 1426 nextNode => 0, # next lexico node (BUG! does not return in lexico order) 1427 type => 0, # returns simple type (see getType for values) 1428 access => 0, # returns ACCESS (ReadOnly, ReadWrite, WriteOnly, 1429 # NoAccess, Notify, Create) 1430 status => 0, # returns STATUS (Mandatory, Optional, Obsolete, 1431 # Deprecated) 1432 syntax => 0, # returns 'textualConvention' if defined else 'type' 1433 textualConvention => 0, # returns TEXTUAL-CONVENTION 1434 units => 0, # returns UNITS 1435 hint => 0, # returns HINT 1436 enums => 0, # returns hash ref {tag => num, ...} 1437 ranges => 0, # returns array ref of hash ref [{low => num, high => num}] 1438 defaultValue => 0, # returns default value 1439 description => 0, # returns DESCRIPTION ($SNMP::save_descriptions must 1440 # be set prior to MIB initialization/parsing 1441 augments => 0, # textual identifier of augmented object 1442 ); 1443 1444# sub TIEHASH - implemented in SNMP.xs 1445 1446# sub FETCH - implemented in SNMP.xs 1447 1448sub STORE { 1449 warn "STORE(@_): write access to MIB node not implemented\n"; 1450} 1451 1452sub DELETE { 1453 warn "DELETE(@_): write access to MIB node not implemented\n"; 1454} 1455 1456sub FIRSTKEY { my $k = keys %node_elements; (each(%node_elements))[0]; } 1457sub NEXTKEY { (each(%node_elements))[0]; } 1458sub EXISTS { exists($node_elements{$_[1]}); } 1459sub CLEAR { 1460 warn "CLEAR(@_): write access to MIB node not implemented\n"; 1461} 1462 1463#sub DESTROY { 1464# warn "DESTROY(@_): write access to MIB node not implemented\n"; 1465# # print "SNMP::MIB::NODE::DESTROY : $_[0]->{label} ($_[0])\n"; 1466#} 1467package SNMP::MIB::SAVE_DESCR; 1468 1469sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; } 1470 1471sub FETCH { ${$_[0]}; } 1472 1473sub STORE { SNMP::_set_save_descriptions($_[1]); ${$_[0]} = $_[1]; } 1474 1475sub DELETE { SNMP::_set_save_descriptions(0); ${$_[0]} = 0; } 1476 1477package SNMP::MIB::REPLACE_NEWER; # Controls MIB parsing 1478 1479sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; } 1480 1481sub FETCH { ${$_[0]}; } 1482 1483sub STORE { 1484 SNMP::_set_replace_newer($_[1]); 1485 ${$_[0]} = $_[1]; 1486} 1487 1488sub DELETE { 1489 SNMP::_set_replace_newer(0); 1490 ${$_[0]} = 0; 1491} 1492 1493package SNMP::MIB::MIB_OPTIONS; 1494 1495sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; } 1496 1497sub FETCH { ${$_[0]}; } 1498 1499sub STORE { SNMP::_mib_toggle_options($_[1]); ${$_[0]} = $_[1]; } 1500 1501sub DELETE { SNMP::_mib_toggle_options(0); ${$_[0]} = ''; } 1502 1503package SNMP; 1504END{SNMP::_sock_cleanup() if defined &SNMP::_sock_cleanup;} 1505# Autoload methods go after __END__, and are processed by the autosplit prog. 1506 15071; 1508__END__ 1509 1510=head1 NAME 1511 1512SNMP - The Perl5 'SNMP' Extension Module for the Net-SNMP SNMP package. 1513 1514=head1 SYNOPSIS 1515 1516 use SNMP; 1517 ... 1518 $sess = new SNMP::Session(DestHost => localhost, Community => public); 1519 $val = $sess->get('sysDescr.0'); 1520 ... 1521 $vars = new SNMP::VarList([sysDescr,0], [sysContact,0], [sysLocation,0]); 1522 @vals = $sess->get($vars); 1523 ... 1524 $vb = new SNMP::Varbind(); 1525 do { 1526 $val = $sess->getnext($vb); 1527 print "@{$vb}\n"; 1528 } until ($sess->{ErrorNum}); 1529 ... 1530 $SNMP::save_descriptions = 1; 1531 SNMP::initMib(); # assuming mib is not already loaded 1532 print "$SNMP::MIB{sysDescr}{description}\n"; 1533 1534=head1 DESCRIPTION 1535 1536 1537Note: The perl SNMP 5.0 module which comes with net-snmp 5.0 and 1538higher is different than previous versions in a number of ways. Most 1539importantly, it behaves like a proper net-snmp application and calls 1540init_snmp properly, which means it will read configuration files and 1541use those defaults where appropriate automatically parse MIB files, 1542etc. This will likely affect your perl applications if you have, for 1543instance, default values set up in your snmp.conf file (as the perl 1544module will now make use of those defaults). The documentation, 1545however, has sadly not been updated yet (aside from this note), nor is 1546the read_config default usage implementation fully complete. 1547 1548The basic operations of the SNMP protocol are provided by this module 1549through an object oriented interface for modularity and ease of use. 1550The primary class is SNMP::Session which encapsulates the persistent 1551aspects of a connection between the management application and the 1552managed agent. Internally the class is implemented as a blessed hash 1553reference. This class supplies 'get', 'getnext', 'set', 'fget', and 1554'fgetnext' method calls. The methods take a variety of input argument 1555formats and support both synchronous and asynchronous operation through 1556a polymorphic API (i.e., method behaviour varies dependent on args 1557passed - see below). 1558 1559=head1 SNMP::Session 1560 1561$sess = new SNMP::Session(DestHost => 'host', ...) 1562 1563The following arguments may be passed to new as a hash. 1564 1565=head2 Basic Options 1566 1567=over 4 1568 1569=item DestHost 1570 1571Hostname or IP address of the SNMP agent you want to talk to. 1572Specified in Net-SNMP formatted agent addresses. These addresses 1573typically look like one of the following: 1574 1575 localhost 1576 tcp:localhost 1577 tls:localhost 1578 tls:localhost:9876 1579 udp6:[::1]:9876 1580 unix:/some/path/to/file/socket 1581 1582Defaults to 'localhost'. 1583 1584=item Version 1585 1586SNMP version to use. 1587 1588The default is taken from library configuration - probably 3 [1, 2 1589(same as 2c), 2c, 3]. 1590 1591=item Timeout 1592 1593The number of micro-seconds to wait before resending a request. 1594 1595The default is '1000000' 1596 1597=item Retries 1598 1599The number of times to retry a request. 1600 1601The default is '5' 1602 1603=item RetryNoSuch 1604 1605If enabled NOSUCH errors in 'get' pdus will 1606be repaired, removing the varbind in error, and resent - 1607undef will be returned for all NOSUCH varbinds, when set 1608to '0' this feature is disabled and the entire get request 1609will fail on any NOSUCH error (applies to v1 only) 1610 1611The default is '0'. 1612 1613=back 1614 1615=head2 SNMPv3/TLS Options 1616 1617=over 1618 1619=item OurIdentity 1620 1621Our X.509 identity to use, which should either be a fingerprint or the 1622filename that holds the certificate. 1623 1624=item TheirIdentity 1625 1626The remote server's identity to connect to, specified as either a 1627fingerprint or a file name. Either this must be specified, or the 1628hostname below along with a trust anchor. 1629 1630=item TheirHostname 1631 1632The remote server's hostname that is expected. If their certificate 1633was signed by a CA then their hostname presented in the certificate 1634must match this value or the connection fails to be established (to 1635avoid man-in-the-middle attacks). 1636 1637=item TrustCert 1638 1639A trusted certificate to use as trust anchor (like a CA certificate) 1640for verifying a remote server's certificate. If a CA certificate is 1641used to validate a certificate then the TheirHostname parameter must 1642also be specified to ensure their presented hostname in the certificate 1643matches. 1644 1645=back 1646 1647=head2 SNMPv3/USM Options 1648 1649=over 1650 1651=item SecName 1652 1653The SNMPv3 security name to use (most for SNMPv3 with USM). 1654 1655The default is 'initial'. 1656 1657=item SecLevel 1658 1659The SNMPv3 security level to use [noAuthNoPriv, authNoPriv, authPriv] (v3) 1660 1661The default is 'noAuthNoPriv'. 1662 1663=item SecEngineId 1664 1665The SNMPv3 security engineID to use (if the snmpv3 security model 1666needs it; for example USM). The format is as a string without the leading '0x'. 1667So if snmptrapd.conf has C<-e 0x8000000001020304>, use C<< SecEngineId => 1668'8000000001020304' >>. 1669 1670The default is <none>, security engineID and it will be probed if not 1671supplied (v3) 1672 1673=item ContextEngineId 1674 1675The SNMPv3 context engineID to use. 1676 1677The default is the <none> and will be set either to the SecEngineId 1678value if set or discovered or will be discovered in other ways if 1679using TLS (RFC5343 based discovery). 1680 1681=item Context 1682 1683The SNMPv3 context name to use. 1684 1685The default is '' (an empty string) 1686 1687=item AuthProto 1688 1689The SNMPv3/USM authentication protocol to use [MD5, SHA]. 1690 1691The default is 'MD5'. 1692 1693=item AuthPass 1694 1695The SNMPv3/USM authentication passphrase to use. 1696 1697default <none>, authentication passphrase 1698 1699=item PrivProto 1700 1701The SNMPv3/USM privacy protocol to use [DES, AES]. 1702 1703The default is 'DES'. 1704 1705=item PrivPass 1706 1707The SNMPv3/USM privacy passphrase to use. 1708 1709default <none>, privacy passphrase (v3) 1710 1711=item AuthMasterKey 1712 1713=item PrivMasterKey 1714 1715=item AuthLocalizedKey 1716 1717=item PrivLocalizedKey 1718 1719Directly specified SNMPv3 USM user keys (used if you want to specify 1720the keys instead of deriving them from a password as above). 1721 1722=back 1723 1724=head2 SNMPv1 and SNMPv2c Options 1725 1726=over 1727 1728=item Community 1729 1730For SNMPv1 and SNMPv2c, the clear-text community name to use. 1731 1732The default is 'public'. 1733 1734=back 1735 1736=head2 Other Configuration Options 1737 1738=over 1739 1740=item VarFormats 1741 1742default 'undef', used by 'fget[next]', holds an hash 1743reference of output value formatters, (e.g., {<obj> => 1744<sub-ref>, ... }, <obj> must match the <obj> and format 1745used in the get operation. A special <obj>, '*', may be 1746used to apply all <obj>s, the supplied sub is called to 1747translate the value to a new format. The sub is called 1748passing the Varbind as the arg 1749 1750=item TypeFormats 1751 1752default 'undef', used by 'fget[next]', holds an hash 1753reference of output value formatters, (e.g., {<type> => 1754<sub-ref>, ... }, the supplied sub is called to translate 1755the value to a new format, unless a VarFormat mathces first 1756(e.g., $sess->{TypeFormats}{INTEGER} = \&mapEnum(); 1757although this can be done more efficiently by enabling 1758$SNMP::use_enums or session creation param 'UseEnums') 1759 1760=item UseLongNames 1761 1762defaults to the value of SNMP::use_long_names at time 1763of session creation. set to non-zero to have <tags> 1764for 'getnext' methods generated preferring longer Mib name 1765convention (e.g., system.sysDescr vs just sysDescr) 1766 1767=item UseSprintValue 1768 1769defaults to the value of SNMP::use_sprint_value at time 1770of session creation. set to non-zero to have return values 1771for 'get' and 'getnext' methods formatted with the libraries 1772snprint_value function. This will result in certain data types 1773being returned in non-canonical format Note: values returned 1774with this option set may not be appropriate for 'set' operations 1775(see discussion of value formats in <vars> description section) 1776 1777=item UseEnums 1778 1779defaults to the value of SNMP::use_enums at time of session 1780creation. set to non-zero to have integer return values 1781converted to enumeration identifiers if possible, these values 1782will also be acceptable when supplied to 'set' operations 1783 1784=item UseNumeric 1785 1786defaults to the value of SNMP::use_numeric at time of session 1787creation. set to non-zero to have <tags> for get methods returned 1788as numeric OID's rather than descriptions. UseLongNames will be 1789set so that the full OID is returned to the caller. 1790 1791=item BestGuess 1792 1793defaults to the value of SNMP::best_guess at time of session 1794creation. this setting controls how <tags> are parsed. setting to 17950 causes a regular lookup. setting to 1 causes a regular expression 1796match (defined as -Ib in snmpcmd) and setting to 2 causes a random 1797access lookup (defined as -IR in snmpcmd). 1798 1799=item NonIncreasing 1800 1801defaults to the value of SNMP::non_increasing at time of session 1802creation. this setting controls if a non-increasing OID during 1803bulkwalk will causes an error. setting to 0 causes the default 1804behaviour (which may, in very badly performing agents, result in a never-ending loop). 1805setting to 1 causes an error (OID not increasing) when this error occur. 1806 1807=item ErrorStr 1808 1809read-only, holds the error message assoc. w/ last request 1810 1811=item ErrorNum 1812 1813read-only, holds the snmp_err or staus of last request 1814 1815=item ErrorInd 1816 1817read-only, holds the snmp_err_index when appropriate 1818 1819=back 1820 1821Private variables: 1822 1823=over 1824 1825=item DestAddr 1826 1827internal field used to hold the translated DestHost field 1828 1829=item SessPtr 1830 1831internal field used to cache a created session structure 1832 1833=item RemotePort 1834 1835Obsolete. Please use the DestHost specifier to indicate the hostname 1836and port combination instead of this paramet. 1837 1838=back 1839 1840=head2 SNMP::Session methods 1841 1842=over 1843 1844=item $sess->update(E<lt>fieldsE<gt>) 1845 1846Updates the SNMP::Session object with the values fields 1847passed in as a hash list (similar to new(E<lt>fieldsE<gt>)) 1848B<(WARNING! not fully implemented)> 1849 1850=item $sess->get(E<lt>varsE<gt> [,E<lt>callbackE<gt>]) 1851 1852do SNMP GET, multiple <vars> formats accepted. 1853for syncronous operation <vars> will be updated 1854with value(s) and type(s) and will also return 1855retrieved value(s). If <callback> supplied method 1856will operate asynchronously 1857 1858=item $sess->fget(E<lt>varsE<gt> [,E<lt>callbackE<gt>]) 1859 1860do SNMP GET like 'get' and format the values according 1861the handlers specified in $sess->{VarFormats} and 1862$sess->{TypeFormats} 1863 1864=item $sess->getnext(E<lt>varsE<gt> [,E<lt>callbackE<gt>]) 1865 1866do SNMP GETNEXT, multiple <vars> formats accepted, 1867returns retrieved value(s), <vars> passed as arguments are 1868updated to indicate next lexicographical <obj>,<iid>,<val>, 1869and <type> 1870 1871Note: simple string <vars>,(e.g., 'sysDescr.0') 1872form is not updated. If <callback> supplied method 1873will operate asynchronously 1874 1875=item $sess->fgetnext(E<lt>varsE<gt> [,E<lt>callbackE<gt>]) 1876 1877do SNMP GETNEXT like getnext and format the values according 1878the handlers specified in $sess->{VarFormats} and 1879$sess->{TypeFormats} 1880 1881=item $sess->set(E<lt>varsE<gt> [,E<lt>callbackE<gt>]) 1882 1883do SNMP SET, multiple <vars> formats accepted. 1884the value field in all <vars> formats must be in a canonical 1885format (i.e., well known format) to ensure unambiguous 1886translation to SNMP MIB data value (see discussion of 1887canonical value format <vars> description section), 1888returns snmp_errno. If <callback> supplied method 1889will operate asynchronously 1890 1891=item $sess->getbulk(E<lt>non-repeatersE<gt>, E<lt>max-repeatersE<gt>, E<lt>varsE<gt>) 1892 1893do an SNMP GETBULK, from the list of Varbinds, the single 1894next lexico instance is fetched for the first n Varbinds 1895as defined by <non-repeaters>. For remaining Varbinds, 1896the m lexico instances are retrieved each of the remaining 1897Varbinds, where m is <max-repeaters>. 1898 1899=item $sess->bulkwalk(E<lt>non-repeatersE<gt>, E<lt>max-repeatersE<gt>, E<lt>varsE<gt> [,E<lt>callbackE<gt>]) 1900 1901Do a "bulkwalk" of the list of Varbinds. This is done by 1902sending a GETBULK request (see getbulk() above) for the 1903Varbinds. For each requested variable, the response is 1904examined to see if the next lexico instance has left the 1905requested sub-tree. Any further instances returned for 1906this variable are ignored, and the walk for that sub-tree 1907is considered complete. 1908 1909If any sub-trees were not completed when the end of the 1910responses is reached, another request is composed, consisting 1911of the remaining variables. This process is repeated until 1912all sub-trees have been completed, or too many packets have 1913been exchanged (to avoid loops). 1914 1915The bulkwalk() method returns an array containing an array of 1916Varbinds, one for each requested variable, in the order of the 1917variable requests. Upon error, bulkwalk() returns undef and 1918sets $sess->ErrorStr and $sess->ErrorNum. If a callback is 1919supplied, bulkwalk() returns the SNMP request id, and returns 1920immediately. The callback will be called with the supplied 1921argument list and the returned variables list. 1922 1923Note: Because the client must "discover" that the tree is 1924complete by comparing the returned variables with those that 1925were requested, there is a potential "gotcha" when using the 1926max-repeaters value. Consider the following code to print a 1927list of interfaces and byte counts: 1928 1929 $numInts = $sess->get('ifNumber.0'); 1930 ($desc, $in, $out) = $sess->bulkwalk(0, $numInts, 1931 [['ifDescr'], ['ifInOctets'], ['ifOutOctets']]); 1932 1933 for $i (0..($numInts - 1)) { 1934 printf "Interface %4s: %s inOctets, %s outOctets\n", 1935 $$desc[$i]->val, $$in[$i]->val, $$out[$i]->val; 1936 } 1937 1938This code will produce *two* requests to the agent -- the first 1939to get the interface values, and the second to discover that all 1940the information was in the first packet. To get around this, 1941use '$numInts + 1' for the max_repeaters value. This asks the 1942agent to include one additional (unrelated) variable that signals 1943the end of the sub-tree, allowing bulkwalk() to determine that 1944the request is complete. 1945 1946=item $results = $sess->gettable(E<lt>TABLE OIDE<gt>, E<lt>OPTIONSE<gt>) 1947 1948This will retrieve an entire table of data and return a hash reference 1949to that data. The returned hash reference will have indexes of the 1950OID suffixes for the index data as the key. The value for each entry 1951will be another hash containing the data for a given row. The keys to 1952that hash will be the column names, and the values will be the data. 1953 1954Example: 1955 1956 #!/usr/bin/perl 1957 1958 use SNMP; 1959 use Data::Dumper; 1960 1961 my $s = new SNMP::Session(DestHost => 'localhost'); 1962 1963 print Dumper($s->gettable('ifTable')); 1964 1965On my machine produces: 1966 1967 $VAR1 = { 1968 '6' => { 1969 'ifMtu' => '1500', 1970 'ifPhysAddress' => 'PV', 1971 # ... 1972 'ifInUnknownProtos' => '0' 1973 }, 1974 '4' => { 1975 'ifMtu' => '1480', 1976 'ifPhysAddress' => '', 1977 # ... 1978 'ifInUnknownProtos' => '0' 1979 }, 1980 # ... 1981 }; 1982 1983By default, it will try to do as optimized retrieval as possible. 1984It'll request multiple columns at once, and use GETBULK if possible. 1985A few options may be specified by passing in an I<OPTIONS> hash 1986containing various parameters: 1987 1988=over 1989 1990=item noindexes => 1 1991 1992Instructs the code not to parse the indexes and place the results in 1993the second hash. If you don't need the index data, this will be 1994faster. 1995 1996=item columns => [ colname1, ... ] 1997 1998This specifies which columns to collect. By default, it will try to 1999collect all the columns defined in the MIB table. 2000 2001=item repeat => I<COUNT> 2002 2003Specifies a GETBULK repeat I<COUNT>. IE, it will request this many 2004varbinds back per column when using the GETBULK operation. Shortening 2005this will mean smaller packets which may help going through some 2006systems. By default, this value is calculated and attempts to guess 2007at what will fit all the results into 1000 bytes. This calculation is 2008fairly safe, hopefully, but you can either raise or lower the number 2009using this option if desired. In lossy networks, you want to make 2010sure that the packets don't get fragmented and lowering this value is 2011one way to help that. 2012 2013=item nogetbulk => 1 2014 2015Force the use of GETNEXT rather than GETBULK. (always true for 2016SNMPv1, as it doesn't have GETBULK anyway). Some agents are great 2017implementers of GETBULK and this allows you to force the use of 2018GETNEXT operations instead. 2019 2020=item callback => \&subroutine 2021 2022=item callback => [\&subroutine, optarg1, optarg2, ...] 2023 2024If a callback is specified, gettable will return quickly without 2025returning results. When the results are finally retrieved the 2026callback subroutine will be called (see the other sections defining 2027callback behaviour and how to make use of SNMP::MainLoop which is 2028required for this to work). An additional argument of the normal hash 2029result will be added to the callback subroutine arguments. 2030 2031Note 1: internally, the gettable function uses it's own callbacks 2032which are passed to getnext/getbulk as appropriate. 2033 2034Note 2: callback support is only available in the SNMP module version 20355.04 and above. To test for this in code intending to support both 2036versions prior to 5.04 and 5.04 and up, the following should work: 2037 2038 if ($response = $sess->gettable('ifTable', callback => \&my_sub)) { 2039 # got a response, gettable doesn't support callback 2040 my_sub($response); 2041 $no_mainloop = 1; 2042 } 2043 2044Deciding on whether to use SNMP::MainLoop is left as an exercise to 2045the reader since it depends on whether your code uses other callbacks 2046as well. 2047 2048=back 2049 2050=back 2051 2052=head1 SNMP::TrapSession 2053 2054$sess = new SNMP::Session(DestHost => 'host', ...) 2055 2056supports all applicable fields from SNMP::Session 2057(see above) 2058 2059=head2 SNMP::TrapSession methods 2060 2061=over 2062 2063=item $sess->trap(enterprise, agent, generic, specific, uptime, <vars>) 2064 2065 $sess->trap(enterprise=>'.1.3.6.1.4.1.2021', # or 'ucdavis' [default] 2066 agent => '127.0.0.1', # or 'localhost',[dflt 1st intf on host] 2067 generic => specific, # can be omitted if 'specific' supplied 2068 specific => 5, # can be omitted if 'generic' supplied 2069 uptime => 1234, # dflt to localhost uptime (0 on win32) 2070 [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars 2071 # always last 2072 2073=item trap(oid, uptime, <vars>) - v2 format 2074 2075 $sess->trap(oid => 'snmpRisingAlarm', 2076 uptime => 1234, 2077 [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars 2078 # always last 2079 2080=back 2081 2082=head1 Acceptable variable formats: 2083 2084<vars> may be one of the following forms: 2085 2086=over 2087 2088=item SNMP::VarList 2089 2090represents an array of MIB objects to get or set, 2091implemented as a blessed reference to an array of 2092SNMP::Varbinds, (e.g., [<varbind1>, <varbind2>, ...]) 2093 2094=item SNMP::Varbind 2095 2096represents a single MIB object to get or set, implemented as 2097a blessed reference to a 4 element array; 2098[<obj>, <iid>, <val>, <type>]. 2099 2100=over 2101 2102=item <obj> 2103 2104one of the following forms: 2105 2106=over 2107 2108=item 1) 2109 2110leaf identifier (e.g., 'sysDescr') assumed to be 2111unique for practical purposes 2112 2113=item 2) 2114 2115fully qualified identifier (e.g., 2116'.iso.org.dod.internet.mgmt.mib-2.system.sysDescr') 2117 2118=item 3) 2119 2120fully qualified, dotted-decimal, numeric OID (e.g., 2121'.1.3.6.1.2.1.1.1') 2122 2123=back 2124 2125=item <iid> 2126 2127the dotted-decimal, instance identifier. for 2128scalar MIB objects use '0' 2129 2130=item <val> 2131 2132the SNMP data value retrieved from or being set 2133to the agents MIB. for (f)get(next) operations 2134<val> may have a variety of formats as determined by 2135session and package settings. However for set 2136operations the <val> format must be canonical to 2137ensure unambiguous translation. The canonical forms 2138are as follows: 2139 2140=over 2141 2142=item OBJECTID 2143 2144dotted-decimal (e.g., .1.3.6.1.2.1.1.1) 2145 2146=item OCTETSTR 2147 2148perl scalar containing octets 2149 2150=item INTEGER 2151 2152decimal signed integer (or enum) 2153 2154=item NETADDR 2155 2156dotted-decimal 2157 2158=item IPADDR 2159 2160dotted-decimal 2161 2162=item COUNTER 2163 2164decimal unsigned integer 2165 2166=item COUNTER64 2167 2168decimal unsigned integer 2169 2170=item GAUGE 2171 2172decimal unsigned integer 2173 2174=item UINTEGER 2175 2176decimal unsigned integer 2177 2178=item TICKS 2179 2180decimal unsigned integer 2181 2182=item OPAQUE 2183 2184perl scalar containing octets 2185 2186=item NULL 2187 2188perl scalar containing nothing 2189 2190=back 2191 2192=item <type> 2193 2194SNMP data type (see list above), this field is 2195populated by 'get' and 'getnext' operations. In 2196some cases the programmer needs to populate this 2197field when passing to a 'set' operation. this 2198field need not be supplied when the attribute 2199indicated by <tag> is already described by loaded 2200Mib modules. for 'set's, if a numeric OID is used 2201and the object is not currently in the loaded Mib, 2202the <type> field must be supplied 2203 2204=back 2205 2206=item simple string 2207 2208light weight form of <var> used to 'set' or 'get' a 2209single attribute without constructing an SNMP::Varbind. 2210stored in a perl scalar, has the form '<tag>.<iid>', 2211(e.g., 'sysDescr.0'). for 'set' operations the value 2212is passed as a second arg. Note: This argument form is 2213not updated in get[next] operations as are the other forms. 2214 2215=back 2216 2217=head1 Acceptable callback formats 2218 2219<callback> may be one of the following forms: 2220 2221=over 2222 2223=item without arguments 2224 2225=over 2226 2227=item \&subname 2228 2229=item sub { ... } 2230 2231=back 2232 2233=item or with arguments 2234 2235=over 2236 2237=item [ \&subname, $arg1, ... ] 2238 2239=item [ sub { ... }, $arg1, ... ] 2240 2241=item [ "method", $obj, $arg1, ... ] 2242 2243=back 2244 2245=back 2246 2247callback will be called when response is received or timeout 2248occurs. the last argument passed to callback will be a 2249SNMP::VarList reference. In case of timeout the last argument 2250will be undef. 2251 2252=over 2253 2254=item &SNMP::MainLoop([<timeout>, [<callback>]]) 2255 2256to be used with async SNMP::Session 2257calls. MainLoop must be called after initial async calls 2258so return packets from the agent will be processed. 2259If no args supplied this function enters an infinite loop 2260so program must be exited in a callback or externally 2261interrupted. If <timeout(sic) 2262 2263=item &SNMP::finish() 2264 2265This function, when called from an SNMP::MainLoop() callback 2266function, will cause the current SNMP::MainLoop() to return 2267after the callback is completed. finish() can be used to 2268terminate an otherwise-infinite MainLoop. A new MainLoop() 2269instance can then be started to handle further requests. 2270 2271=back 2272 2273=head1 SNMP package variables and functions 2274 2275=over 2276 2277=item $SNMP::VERSION 2278 2279the current version specifier (e.g., 3.1.0) 2280 2281=item $SNMP::auto_init_mib 2282 2283default '1', set to 0 to disable automatic reading 2284of the MIB upon session creation. set to non-zero 2285to call initMib at session creation which will result 2286in MIB loading according to Net-SNMP env. variables (see 2287man mib_api) 2288 2289=item $SNMP::verbose 2290 2291default '0', controls warning/info output of 2292SNMP module, 0 => no output, 1 => enables warning/info 2293output from SNMP module itself (is also controlled 2294by SNMP::debugging - see below) 2295 2296=item $SNMP::use_long_names 2297 2298default '0', set to non-zero to enable the use of 2299longer Mib identifiers. see translateObj. will also 2300influence the formatting of <tag> in varbinds returned 2301from 'getnext' operations. Can be set on a per session 2302basis (UseLongNames) 2303 2304=item $SNMP::use_sprint_value 2305 2306default '0', set to non-zero to enable formatting of 2307response values using the snmp libraries snprint_value 2308function. can also be set on a per session basis (see 2309UseSprintValue) Note: returned values may not be 2310suitable for 'set' operations 2311 2312=item $SNMP::use_enums 2313 2314default '0',set non-zero to return values as enums and 2315allow sets using enums where appropriate. integer data 2316will still be accepted for set operations. can also be 2317set on a per session basis (see UseEnums) 2318 2319=item $SNMP::use_numeric 2320 2321default to '0',set to non-zero to have <tags> for 'get' 2322methods returned as numeric OID's rather than descriptions. 2323UseLongNames will be set so that the entire OID will be 2324returned. Set on a per-session basis (see UseNumeric). 2325 2326=item $SNMP::best_guess 2327 2328default '0'. This setting controls how <tags> are 2329parsed. Setting to 0 causes a regular lookup. Setting 2330to 1 causes a regular expression match (defined as -Ib 2331in snmpcmd) and setting to 2 causes a random access 2332lookup (defined as -IR in snmpcmd). Can also be set 2333on a per session basis (see BestGuess) 2334 2335=item $SNMP::save_descriptions 2336 2337default '0',set non-zero to have mib parser save 2338attribute descriptions. must be set prior to mib 2339initialization 2340 2341=item $SNMP::debugging 2342 2343default '0', controls debugging output level 2344within SNMP module and libsnmp 2345 2346=over 2347 2348=item 1 2349 2350enables 'SNMP::verbose' (see above) 2351 2352=item 2 2353 2354level 1 plus snmp_set_do_debugging(1) 2355 2356=item 3 2357 2358level 2 plus snmp_set_dump_packet(1) 2359 2360=back 2361 2362=item $SNMP::dump_packet 2363 2364default '0', set [non-]zero to independently set 2365snmp_set_dump_packet() 2366 2367=item SNMP::register_debug_tokens() 2368 2369Allows to register one or more debug tokens, just like the -D option of snmpd. 2370Each debug token enables a group of debug statements. An example: 2371SNMP::register_debug_tokens("tdomain,netsnmp_unix"); 2372 2373=back 2374 2375=head1 %SNMP::MIB 2376 2377a tied hash to access parsed MIB information. After 2378the MIB has been loaded this hash allows access to 2379to the parsed in MIB meta-data(the structure of the 2380MIB (i.e., schema)). The hash returns blessed 2381references to SNMP::MIB::NODE objects which represent 2382a single MIB attribute. The nodes can be fetched with 2383multiple 'key' formats - the leaf name (e.g.,sysDescr) 2384or fully/partially qualified name (e.g., 2385system.sysDescr) or fully qualified numeric OID. The 2386returned node object supports the following fields: 2387 2388=over 2389 2390=item objectID 2391 2392dotted decimal fully qualified OID 2393 2394=item label 2395 2396leaf textual identifier (e.g., 'sysDescr') 2397 2398=item subID 2399 2400leaf numeric OID component of objectID (e.g., '1') 2401 2402=item moduleID 2403 2404textual identifier for module (e.g., 'RFC1213-MIB') 2405 2406=item parent 2407 2408parent node 2409 2410=item children 2411 2412array reference of children nodes 2413 2414=item nextNode 2415 2416next lexico node B<(BUG!does not return in lexico order)> 2417 2418=item type 2419 2420returns application type (see getType for values) 2421 2422=item access 2423 2424returns ACCESS (ReadOnly, ReadWrite, WriteOnly, 2425NoAccess, Notify, Create) 2426 2427=item status 2428 2429returns STATUS (Mandatory, Optional, Obsolete, 2430Deprecated) 2431 2432=item syntax 2433 2434returns 'textualConvention' if defined else 'type' 2435 2436=item textualConvention 2437 2438returns TEXTUAL-CONVENTION 2439 2440=item TCDescription 2441 2442returns the TEXTUAL-CONVENTION's DESCRIPTION field. 2443 2444=item units 2445 2446returns UNITS 2447 2448=item hint 2449 2450returns HINT 2451 2452=item enums 2453 2454returns hash ref {tag => num, ...} 2455 2456=item ranges 2457 2458returns array ref of hash ref [{low => num, high => num}, ...] 2459 2460=item description 2461 2462returns DESCRIPTION ($SNMP::save_descriptions must 2463be set prior to MIB initialization/parsing) 2464 2465=item reference 2466 2467returns the REFERENCE clause 2468 2469=item indexes 2470 2471returns the objects in the INDEX clause 2472 2473=item implied 2474 2475returns true if the last object in the INDEX is IMPLIED 2476 2477=back 2478 2479=head1 MIB Functions 2480 2481=over 2482 2483=item &SNMP::setMib(<file>) 2484 2485allows dynamic parsing of the mib and explicit 2486specification of mib file independent of environment 2487variables. called with no args acts like initMib, 2488loading MIBs indicated by environment variables (see 2489Net-SNMP mib_api docs). passing non-zero second arg 2490forces previous mib to be freed and replaced 2491B<(Note: second arg not working since freeing previous 2492Mib is more involved than before)>. 2493 2494=item &SNMP::initMib() 2495 2496calls library init_mib function if Mib not already 2497loaded - does nothing if Mib already loaded. will 2498parse directories and load modules according to 2499environment variables described in Net-SNMP documentations. 2500(see man mib_api, MIBDIRS, MIBS, MIBFILE(S), etc.) 2501 2502=item &SNMP::addMibDirs(<dir>,...) 2503 2504calls library add_mibdir for each directory 2505supplied. will cause directory(s) to be added to 2506internal list and made available for searching in 2507subsequent loadModules calls 2508 2509=item &SNMP::addMibFiles(<file>,...) 2510 2511calls library read_mib function. The file(s) 2512supplied will be read and all Mib module definitions 2513contained therein will be added to internal mib tree 2514structure 2515 2516=item &SNMP::loadModules(<mod>,...) 2517 2518calls library read_module function. The 2519module(s) supplied will be searched for in the 2520current mibdirs and and added to internal mib tree 2521structure. Passing special <mod>, 'ALL', will cause 2522all known modules to be loaded. 2523 2524=item &SNMP::unloadModules(<mod>,...) 2525 2526B<*Not Implemented*> 2527 2528=item &SNMP::translateObj(<var>[,arg,[arg]]) 2529 2530will convert a text obj tag to an OID and vice-versa. 2531Any iid suffix is retained numerically. Default 2532behaviour when converting a numeric OID to text 2533form is to return leaf identifier only 2534(e.g.,'sysDescr') but when $SNMP::use_long_names 2535is non-zero or a non-zero second arg is supplied it 2536will return a longer textual identifier. An optional 2537third argument of non-zero will cause the module name 2538to be prepended to the text name (e.g. 2539'SNMPv2-MIB::sysDescr'). When converting a text obj, 2540the $SNMP::best_guess option is used. If no Mib is 2541loaded when called and $SNMP::auto_init_mib is enabled 2542then the Mib will be loaded. Will return 'undef' upon 2543failure. 2544 2545=item &SNMP::getType(<var>) 2546 2547return SNMP data type for given textual identifier 2548OBJECTID, OCTETSTR, INTEGER, NETADDR, IPADDR, COUNTER 2549GAUGE, TIMETICKS, OPAQUE, or undef 2550 2551=item &SNMP::mapEnum(<var>) 2552 2553converts integer value to enumertion tag defined 2554in Mib or converts tag to integer depending on 2555input. the function will return the corresponding 2556integer value *or* tag for a given MIB attribute 2557and value. The function will sense which direction 2558to perform the conversion. Various arg formats are 2559supported 2560 2561=over 2562 2563=item $val = SNMP::mapEnum($varbind); 2564 2565where $varbind is SNMP::Varbind or equiv. 2566note: $varbind will be updated 2567 2568=item $val = SNMP::mapEnum('ipForwarding', 'forwarding'); 2569 2570=item $val = SNMP::mapEnum('ipForwarding', 1); 2571 2572=back 2573 2574=back 2575 2576=head1 Exported SNMP utility functions 2577 2578Note: utility functions do not support async operation yet. 2579 2580=over 2581 2582=item &snmp_get() 2583 2584takes args of SNMP::Session::new followed by those of 2585SNMP::Session::get 2586 2587=item &snmp_getnext() 2588 2589takes args of SNMP::Session::new followed by those of 2590SNMP::Session::getnext 2591 2592=item &snmp_set() 2593 2594takes args of SNMP::Session::new followed by those of 2595SNMP::Session::set 2596 2597=item &snmp_trap() 2598 2599takes args of SNMP::TrapSession::new followed by those of 2600SNMP::TrapSession::trap 2601 2602=back 2603 2604=head1 Trouble Shooting 2605 2606If problems occur there are number areas to look at to narrow down the 2607possibilities. 2608 2609The first step should be to test the Net-SNMP installation 2610independently from the Perl5 SNMP interface. 2611 2612Try running the apps from the Net-SNMP distribution. 2613 2614Make sure your agent (snmpd) is running and properly configured with 2615read-write access for the community you are using. 2616 2617Ensure that your MIBs are installed and enviroment variables are set 2618appropriately (see man mib_api) 2619 2620Be sure to remove old net-snmp installations and ensure headers and 2621libraries from old CMU installations are not being used by mistake. 2622 2623If the problem occurs during compilation/linking check that the snmp 2624library being linked is actually the Net-SNMP library (there have been 2625name conflicts with existing snmp libs). 2626 2627Also check that the header files are correct and up to date. 2628 2629Sometimes compiling the Net-SNMP library with 2630'position-independent-code' enabled is required (HPUX specifically). 2631 2632If you cannot resolve the problem you can post to 2633comp.lang.perl.modules or 2634net-snmp-users@net-snmp-users@lists.sourceforge.net 2635 2636please give sufficient information to analyze the problem (OS type, 2637versions for OS/Perl/Net-SNMP/compiler, complete error output, etc.) 2638 2639=head1 Acknowledgements 2640 2641Many thanks to all those who supplied patches, suggestions and 2642feedback. 2643 2644 Joe Marzot (the original author) 2645 Wes Hardaker and the net-snmp-coders 2646 Dave Perkins 2647 Marcel Wiget 2648 David Blackburn 2649 John Stofell 2650 Gary Hayward 2651 Claire Harrison 2652 Achim Bohnet 2653 Doug Kingston 2654 Jacques Vidrine 2655 Carl Jacobsen 2656 Wayne Marquette 2657 Scott Schumate 2658 Michael Slifcak 2659 Srivathsan Srinivasagopalan 2660 Bill Fenner 2661 Jef Peeraer 2662 Daniel Hagerty 2663 Karl "Rat" Schilke and Electric Lightwave, Inc. 2664 Perl5 Porters 2665 Alex Burger 2666 2667Apologies to any/all who's patch/feature/request was not mentioned or 2668included - most likely it was lost when paying work intruded on my 2669fun. Please try again if you do not see a desired feature. This may 2670actually turn out to be a decent package with such excellent help and 2671the fact that I have more time to work on it than in the past. 2672 2673=head1 AUTHOR 2674 2675bugs, comments, questions to net-snmp-users@lists.sourceforge.net 2676 2677=head1 Copyright 2678 2679 Copyright (c) 1995-2000 G. S. Marzot. All rights reserved. 2680 This program is free software; you can redistribute it and/or 2681 modify it under the same terms as Perl itself. 2682 2683 Copyright (c) 2001-2002 Networks Associates Technology, Inc. All 2684 Rights Reserved. This program is free software; you can 2685 redistribute it and/or modify it under the same terms as Perl 2686 itself. 2687 2688=cut 2689