summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/BER.pm158
-rw-r--r--lib/SNMP_Session.pm100
-rw-r--r--lib/SNMP_util.pm484
3 files changed, 438 insertions, 304 deletions
diff --git a/lib/BER.pm b/lib/BER.pm
index 1a3ad89..1206feb 100644
--- a/lib/BER.pm
+++ b/lib/BER.pm
@@ -2,10 +2,11 @@
######################################################################
### BER (Basic Encoding Rules) encoding and decoding.
######################################################################
-### Copyright (c) 1995-2002, Simon Leinen.
+### Copyright (c) 1995-2008, Simon Leinen.
###
### This program is free software; you can redistribute it under the
-### "Artistic License" included in this distribution (file "Artistic").
+### "Artistic License 2.0" included in this distribution
+### (file "Artistic").
######################################################################
### This module implements encoding and decoding of ASN.1-based data
### structures using the Basic Encoding Rules (BER). Only the subset
@@ -20,13 +21,14 @@
### Dave Rand <dlr@Bungi.com>: Added SysUpTime decode
### Philippe Simonet <sip00@vg.swissptt.ch>: Support larger subids
### Yufang HU <yhu@casc.com>: Support even larger subids
-### Mike Mitchell <mcm@unx.sas.com>: New generalized encode_int()
+### Mike Mitchell <Mike.Mitchell@sas.com>: New generalized encode_int()
### Mike Diehn <mdiehn@mindspring.net>: encode_ip_address()
### Rik Hoorelbeke <rik.hoorelbeke@pandora.be>: encode_oid() fix
### Brett T Warden <wardenb@eluminant.com>: pretty UInteger32
### Bert Driehuis <driehuis@playbeing.org>: Handle SNMPv2 exception codes
### Jakob Ilves (/IlvJa) <jakob.ilves@oracle.com>: PDU decoding
### Jan Kasprzak <kas@informatics.muni.cz>: Fix for PDU syntax check
+### Milen Pavlov <milen@batmbg.com>: Recognize variant length for ints
######################################################################
package BER;
@@ -34,10 +36,11 @@ package BER;
require 5.002;
use strict;
-use vars qw(@ISA @EXPORT $VERSION $pretty_print_timeticks $errmsg);
+use vars qw(@ISA @EXPORT $VERSION $pretty_print_timeticks
+ %pretty_printer %default_printer $errmsg);
use Exporter;
-$VERSION = '0.95';
+$VERSION = '1.05';
@ISA = qw(Exporter);
@@ -50,7 +53,8 @@ $VERSION = '0.95';
decode_sequence decode_by_template
pretty_print pretty_print_timeticks
hex_string hex_string_of_type
- encoded_oid_prefix_p errmsg);
+ encoded_oid_prefix_p errmsg
+ register_pretty_printer unregister_pretty_printer);
### Variables
@@ -84,6 +88,8 @@ sub pretty_uptime ($);
sub pretty_uptime_value ($);
sub pretty_ip_address ($);
sub pretty_generic_sequence ($);
+sub register_pretty_printer ($);
+sub unregister_pretty_printer ($);
sub hex_string ($);
sub hex_string_of_type ($$);
sub decode_oid ($);
@@ -95,7 +101,7 @@ sub decode_intlike ($);
sub decode_unsignedlike ($);
sub decode_intlike_s ($$);
sub decode_string ($);
-sub decode_length ($);
+sub decode_length ($@);
sub encoded_oid_prefix_p ($$);
sub decode_subid ($$$);
sub decode_generic_tlv ($);
@@ -147,6 +153,22 @@ sub snmp_nosuchobject { context_flag () | 0x00 }
sub snmp_nosuchinstance { context_flag () | 0x01 }
sub snmp_endofmibview { context_flag () | 0x02 }
+### pretty-printer initialization code. Create a hash with
+### the most common types of pretty-printer routines.
+
+BEGIN {
+ $default_printer{int_tag()} = \&pretty_intlike;
+ $default_printer{snmp_counter32_tag()} = \&pretty_unsignedlike;
+ $default_printer{snmp_gauge32_tag()} = \&pretty_unsignedlike;
+ $default_printer{snmp_counter64_tag()} = \&pretty_unsignedlike;
+ $default_printer{snmp_uinteger32_tag()} = \&pretty_unsignedlike;
+ $default_printer{octet_string_tag()} = \&pretty_string;
+ $default_printer{object_id_tag()} = \&pretty_oid;
+ $default_printer{snmp_ip_address_tag()} = \&pretty_ip_address;
+
+ %pretty_printer = %default_printer;
+}
+
#### Encoding
sub encode_header ($$) {
@@ -187,12 +209,11 @@ sub encode_intlike ($$) {
$sign = ($int >= 0) ? 0 : 0xff;
if (ref $int && $int->isa ("Math::BigInt")) {
for(;;) {
- $val = $int->bmod (256);
+ $val = $int->copy()->bmod (256);
unshift(@vals, $val);
return encode_header ($tag, $#vals + 1).pack ("C*", @vals)
if ($int >= -128 && $int < 128);
- $int = $int - $sign;
- $int = $int / 256;
+ $int->bsub ($sign)->bdiv (256);
}
} else {
for(;;) {
@@ -200,8 +221,7 @@ sub encode_intlike ($$) {
unshift(@vals, $val);
return encode_header ($tag, $#vals + 1).pack ("C*", @vals)
if ($int >= -128 && $int < 128);
- $int -= $sign;
- $int = int($int / 256);
+ $int -= $sign, $int = int($int / 256);
}
}
}
@@ -304,23 +324,16 @@ sub encode_timeticks ($) {
sub pretty_print ($) {
my ($packet) = @_;
- my ($type,$rest);
return undef unless defined $packet;
my $result = ord (substr ($packet, 0, 1));
- return pretty_intlike ($packet)
- if $result == int_tag;
- return pretty_unsignedlike ($packet)
- if $result == snmp_counter32_tag
- || $result == snmp_gauge32_tag
- || $result == snmp_counter64_tag
- || $result == snmp_uinteger32_tag;
- return pretty_string ($packet) if $result == octet_string_tag;
- return pretty_oid ($packet) if $result == object_id_tag;
+ if (exists ($pretty_printer{$result})) {
+ my $c_ref = $pretty_printer{$result};
+ return &$c_ref ($packet);
+ }
return ($pretty_print_timeticks
? pretty_uptime ($packet)
: pretty_unsignedlike ($packet))
if $result == uptime_tag;
- return pretty_ip_address ($packet) if $result == snmp_ip_address_tag;
return "(null)" if $result == null_tag;
return error ("Exception code: noSuchObject") if $result == snmp_nosuchobject;
return error ("Exception code: noSuchInstance") if $result == snmp_nosuchinstance;
@@ -334,7 +347,7 @@ sub pretty_print ($) {
if($result == (&constructor_flag | &sequence_tag) # sequence
|| $result == (0 | $ctx_cons_flags) #get_request
|| $result == (1 | $ctx_cons_flags) #getnext_request
- || $result == (2 | $ctx_cons_flags) #get_response
+ || $result == (2 | $ctx_cons_flags) #response
|| $result == (3 | $ctx_cons_flags) #set_request
|| $result == (4 | $ctx_cons_flags) #trap_request
|| $result == (5 | $ctx_cons_flags) #getbulk_request
@@ -350,12 +363,13 @@ sub pretty_print ($) {
(constructor_flag | sequence_tag) => "Sequence",
(0 | $ctx_cons_flags) => "GetRequest",
(1 | $ctx_cons_flags) => "GetNextRequest",
- (2 | $ctx_cons_flags) => "GetResponse",
+ (2 | $ctx_cons_flags) => "Response",
(3 | $ctx_cons_flags) => "SetRequest",
- (4 | $ctx_cons_flags) => "TrapRequest",
- (5 | $ctx_cons_flags) => "GetbulkRequest",
+ (4 | $ctx_cons_flags) => "Trap",
+ (5 | $ctx_cons_flags) => "GetBulkRequest",
(6 | $ctx_cons_flags) => "InformRequest",
- (7 | $ctx_cons_flags) => "Trap2Request",
+ (7 | $ctx_cons_flags) => "SNMPv2-Trap",
+ (8 | $ctx_cons_flags) => "Report",
}->{($result)};
return $seq_type_desc . "{\n" . $pretty_result . "\n}";
@@ -391,7 +405,7 @@ sub pretty_oid ($) {
my (@oid);
$result = ord (substr ($oid, 0, 1));
return error ("Object ID expected") unless $result == object_id_tag;
- ($result, $oid) = decode_length (substr ($oid, 1));
+ ($result, $oid) = decode_length ($oid, 1);
return error ("inconsistent length in OID") unless $result == length $oid;
@oid = ();
$subid = ord (substr ($oid, 0, 1));
@@ -460,8 +474,7 @@ sub pretty_ip_address ($) {
my ($length, $rest);
return error ("IP Address tag (".snmp_ip_address_tag.") expected")
unless ord (substr ($pdu, 0, 1)) == snmp_ip_address_tag;
- $pdu = substr ($pdu, 1);
- ($length,$pdu) = decode_length ($pdu);
+ ($length,$pdu) = decode_length ($pdu, 1);
return error ("Length of IP address should be four")
unless $length == 4;
sprintf "%d.%d.%d.%d", unpack ("CCCC", $pdu);
@@ -482,7 +495,7 @@ sub pretty_generic_sequence ($) {
unless ($type == (&constructor_flag | &sequence_tag) # sequence
|| $type == (0 | $flags) #get_request
|| $type == (1 | $flags) #getnext_request
- || $type == (2 | $flags) #get_response
+ || $type == (2 | $flags) #response
|| $type == (3 | $flags) #set_request
|| $type == (4 | $flags) #trap_request
|| $type == (5 | $flags) #getbulk_request
@@ -497,7 +510,7 @@ sub pretty_generic_sequence ($) {
# Cut away the first Tag and Length from $packet and then
# init $rest with that.
- (undef, $rest) = decode_length(substr $pdu, 1);
+ (undef, $rest) = decode_length ($pdu, 1);
while($rest)
{
($curelem,$rest) = decode_generic_tlv($rest);
@@ -522,8 +535,7 @@ sub hex_string_of_type ($$) {
my ($length);
return error ("BER tag ".$wanted_type." expected")
unless ord (substr ($pdu, 0, 1)) == $wanted_type;
- $pdu = substr ($pdu, 1);
- ($length,$pdu) = decode_length ($pdu);
+ ($length,$pdu) = decode_length ($pdu, 1);
hex_string_aux ($pdu);
}
@@ -543,7 +555,7 @@ sub decode_oid ($) {
my (@result);
$result = ord (substr ($pdu, 0, 1));
return error ("Object ID expected") unless $result == object_id_tag;
- ($result, $pdu_rest) = decode_length (substr ($pdu, 1));
+ ($result, $pdu_rest) = decode_length ($pdu, 1);
return error ("Short PDU")
if $result > length $pdu_rest;
@result = (substr ($pdu, 0, $result + (length ($pdu) - length ($pdu_rest))),
@@ -558,7 +570,7 @@ sub decode_oid ($) {
sub decode_generic_tlv ($) {
my ($pdu) = @_;
my (@result);
- my ($elemlength,$pdu_rest) = decode_length (substr($pdu,1));
+ my ($elemlength,$pdu_rest) = decode_length ($pdu, 1);
@result = (# Extract the first element.
substr ($pdu, 0, $elemlength + (length ($pdu)
- length ($pdu_rest)
@@ -610,8 +622,7 @@ sub decode_by_template_2 {
$template,
$template_index)
unless (ord (substr ($pdu, 0, 1)) == $expected);
- $pdu = substr ($pdu,1);
- (($length,$pdu) = decode_length ($pdu))
+ (($length,$pdu) = decode_length ($pdu, 1))
|| return template_error ("cannot read length",
$template, $template_index);
return template_error ("Expected length $length, got ".length $pdu ,
@@ -641,7 +652,7 @@ sub decode_by_template_2 {
$tag = ord (substr ($pdu, 0, 1));
return error ("Expected IP address, got tag ".$tag)
unless $tag == snmp_ip_address_tag;
- ($length, $pdu) = decode_length (substr ($pdu, 1));
+ ($length, $pdu) = decode_length ($pdu, 1);
return error ("Inconsistent length of InetAddress encoding")
if $length > length $pdu;
return template_error ("IP address must be four bytes long",
@@ -723,7 +734,7 @@ sub decode_sequence ($) {
$result = ord (substr ($pdu, 0, 1));
return error ("Sequence expected")
unless $result == (sequence_tag | constructor_flag);
- ($result, $pdu) = decode_length (substr ($pdu, 1));
+ ($result, $pdu) = decode_length ($pdu, 1);
return error ("Short PDU")
if $result > length $pdu;
@result = (substr ($pdu, 0, $result), substr ($pdu, $result));
@@ -751,8 +762,8 @@ my $have_math_bigint_p = 0;
sub decode_intlike_s ($$) {
my ($pdu, $signedp) = @_;
my ($length,$result);
- $length = ord (substr ($pdu, 1, 1));
- my $ptr = 2;
+ ($length,$pdu) = decode_length ($pdu, 1);
+ my $ptr = 0;
$result = unpack ($signedp ? "c" : "C", substr ($pdu, $ptr++, 1));
if ($length > 5 || ($length == 5 && $result > 0)) {
require 'Math/BigInt.pm' unless $have_math_bigint_p++;
@@ -771,32 +782,75 @@ sub decode_string ($) {
$result = ord (substr ($pdu, 0, 1));
return error ("Expected octet string, got tag ".$result)
unless $result == octet_string_tag;
- ($result, $pdu) = decode_length (substr ($pdu, 1));
+ ($result, $pdu) = decode_length ($pdu, 1);
return error ("Short PDU")
if $result > length $pdu;
return (substr ($pdu, 0, $result), substr ($pdu, $result));
}
-sub decode_length ($) {
+sub decode_length ($@) {
my ($pdu) = shift;
+ my $index = shift || 0;
my ($result);
my (@result);
- $result = ord (substr ($pdu, 0, 1));
+ $result = ord (substr ($pdu, $index, 1));
if ($result & long_length) {
if ($result == (long_length | 1)) {
- @result = (ord (substr ($pdu, 1, 1)), substr ($pdu, 2));
+ @result = (ord (substr ($pdu, $index+1, 1)), substr ($pdu, $index+2));
} elsif ($result == (long_length | 2)) {
- @result = ((ord (substr ($pdu, 1, 1)) << 8)
- + ord (substr ($pdu, 2, 1)), substr ($pdu, 3));
+ @result = ((ord (substr ($pdu, $index+1, 1)) << 8)
+ + ord (substr ($pdu, $index+2, 1)), substr ($pdu, $index+3));
} else {
return error ("Unsupported length");
}
} else {
- @result = ($result, substr ($pdu, 1));
+ @result = ($result, substr ($pdu, $index+1));
}
@result;
}
+# This takes a hashref that specifies functions to call when
+# the specified value type is being printed. It returns the
+# number of functions that were registered.
+sub register_pretty_printer($)
+{
+ my ($h_ref) = shift;
+ my ($type, $val, $cnt);
+
+ $cnt = 0;
+ while(($type, $val) = each %$h_ref) {
+ if (ref $val eq "CODE") {
+ $pretty_printer{$type} = $val;
+ $cnt++;
+ }
+ }
+ return($cnt);
+}
+
+# This takes a hashref that specifies functions to call when
+# the specified value type is being printed. It removes the
+# functions from the list for the types specified.
+# It returns the number of functions that were unregistered.
+sub unregister_pretty_printer($)
+{
+ my ($h_ref) = shift;
+ my ($type, $val, $cnt);
+
+ $cnt = 0;
+ while(($type, $val) = each %$h_ref) {
+ if ((exists ($pretty_printer{$type}))
+ && ($pretty_printer{$type} == $val)) {
+ if (exists($default_printer{$type})) {
+ $pretty_printer{$type} = $default_printer{$type};
+ } else {
+ delete $pretty_printer{$type};
+ }
+ $cnt++;
+ }
+ }
+ return($cnt);
+}
+
#### OID prefix check
### encoded_oid_prefix_p OID1 OID2
@@ -813,8 +867,8 @@ sub encoded_oid_prefix_p ($$) {
my ($subid1, $subid2);
return error ("OID tag expected") unless ord (substr ($oid1, 0, 1)) == object_id_tag;
return error ("OID tag expected") unless ord (substr ($oid2, 0, 1)) == object_id_tag;
- ($l1,$oid1) = decode_length (substr ($oid1, 1));
- ($l2,$oid2) = decode_length (substr ($oid2, 1));
+ ($l1,$oid1) = decode_length ($oid1, 1);
+ ($l2,$oid2) = decode_length ($oid2, 1);
for ($i1 = 0, $i2 = 0;
$i1 < $l1 && $i2 < $l2;
++$i1, ++$i2) {
diff --git a/lib/SNMP_Session.pm b/lib/SNMP_Session.pm
index 34bde10..8521a52 100644
--- a/lib/SNMP_Session.pm
+++ b/lib/SNMP_Session.pm
@@ -2,10 +2,11 @@
######################################################################
### SNMP Request/Response Handling
######################################################################
-### Copyright (c) 1995-2002, Simon Leinen.
+### Copyright (c) 1995-2008, Simon Leinen.
###
### This program is free software; you can redistribute it under the
-### "Artistic License" included in this distribution (file "Artistic").
+### "Artistic License 2.0" included in this distribution
+### (file "Artistic").
######################################################################
### The abstract class SNMP_Session defines objects that can be used
### to communicate with SNMP entities. It has methods to send
@@ -20,7 +21,7 @@
### Contributions and fixes by:
###
### Matthew Trunnell <matter@media.mit.edu>
-### Tobias Oetiker <oetiker@ee.ethz.ch>
+### Tobias Oetiker <tobi@oetiker.ch>
### Heine Peters <peters@dkrz.de>
### Daniel L. Needles <dan_needles@INS.COM>
### Mike Mitchell <mcm@unx.sas.com>
@@ -35,6 +36,10 @@
### Valerio Bontempi <v.bontempi@inwind.it>: IPv6 support
### Lorenzo Colitti <lorenzo@colitti.com>: IPv6 support
### Philippe Simonet <Philippe.Simonet@swisscom.com>: Export avoid...
+### Luc Pauwels <Luc.Pauwels@xalasys.com>: use_16bit_request_ids
+### Andrew Cornford-Matheson <andrew.matheson@corenetworks.com>: inform
+### Gerry Dalton <gerry.dalton@consolidated.com>: strict subs bug
+### Mike Fischer <mlf2@tampabay.rr.com>: pass MSG_DONTWAIT to recv()
######################################################################
package SNMP_Session;
@@ -45,9 +50,10 @@ use strict;
use Exporter;
use vars qw(@ISA $VERSION @EXPORT $errmsg
$suppress_warnings
- $default_avoid_negative_request_ids);
+ $default_avoid_negative_request_ids
+ $default_use_16bit_request_ids);
use Socket;
-use BER '0.95';
+use BER '1.05';
use Carp;
sub map_table ($$$ );
@@ -56,7 +62,7 @@ sub map_table_start_end ($$$$$$);
sub index_compare ($$);
sub oid_diff ($$);
-$VERSION = '0.98';
+$VERSION = '1.12';
@ISA = qw(Exporter);
@@ -107,6 +113,13 @@ my $default_max_repetitions = 12;
###
$SNMP_Session::default_avoid_negative_request_ids = 0;
+### Default value for "use_16bit_request_ids".
+###
+### Set this to non-zero if you have agents that use 16bit request IDs,
+### and don't forget to complain to your agent vendor.
+###
+$SNMP_Session::default_use_16bit_request_ids = 0;
+
### Whether all SNMP_Session objects should share a single UDP socket.
###
$SNMP_Session::recycle_socket = 0;
@@ -120,16 +133,24 @@ $SNMP_Session::recycle_socket = 0;
### but this function is only available in recent versions of Socket.pm.
my $ipv6_addr_len;
+### Flags to be passed to recv() when non-blocking behavior is
+### desired. On most POSIX-like systems this will be set to
+### MSG_DONTWAIT, on other systems we leave it at zero.
+###
+my $dont_wait_flags;
+
BEGIN {
$ipv6_addr_len = undef;
$SNMP_Session::ipv6available = 0;
+ $dont_wait_flags = 0;
- if (eval {require Socket6;} &&
- eval {require IO::Socket::INET6; IO::Socket::INET6->VERSION("1.26");}) {
+ if (eval {local $SIG{__DIE__};require Socket6;} &&
+ eval {local $SIG{__DIE__};require IO::Socket::INET6; IO::Socket::INET6->VERSION("1.26");}) {
import Socket6;
$ipv6_addr_len = length(pack_sockaddr_in6(161, inet_pton(AF_INET6(), "::1")));
$SNMP_Session::ipv6available = 1;
}
+ eval 'local $SIG{__DIE__};local $SIG{__WARN__};$dont_wait_flags = MSG_DONTWAIT();';
}
my $the_socket;
@@ -137,14 +158,14 @@ my $the_socket;
$SNMP_Session::errmsg = '';
$SNMP_Session::suppress_warnings = 0;
-sub get_request { 0 | context_flag };
-sub getnext_request { 1 | context_flag };
-sub get_response { 2 | context_flag };
-sub set_request { 3 | context_flag };
-sub trap_request { 4 | context_flag };
-sub getbulk_request { 5 | context_flag };
-sub inform_request { 6 | context_flag };
-sub trap2_request { 7 | context_flag };
+sub get_request { 0 | context_flag () };
+sub getnext_request { 1 | context_flag () };
+sub get_response { 2 | context_flag () };
+sub set_request { 3 | context_flag () };
+sub trap_request { 4 | context_flag () };
+sub getbulk_request { 5 | context_flag () };
+sub inform_request { 6 | context_flag () };
+sub trap2_request { 7 | context_flag () };
sub standard_udp_port { 161 };
@@ -180,10 +201,11 @@ sub encode_request_3 ($$$@) {
local($_);
$this->{request_id} = ($this->{request_id} == 0x7fffffff)
- ? ($this->{avoid_negative_request_ids}
- ? 0x00000000
- : -0x80000000)
- : $this->{request_id}+1;
+ ? -0x80000000 : $this->{request_id}+1;
+ $this->{request_id} += 0x80000000
+ if ($this->{avoid_negative_request_ids} && $this->{request_id} < 0);
+ $this->{request_id} &= 0x0000ffff
+ if ($this->{use_16bit_request_ids});
foreach $_ (@{$encoded_oids_or_pairs}) {
if (ref ($_) eq 'ARRAY') {
$_ = &encode_sequence ($_->[0], $_->[1])
@@ -267,14 +289,18 @@ sub decode_trap_request ($$) {
$bindings)
= decode_by_template ($trap, "%{%i%s%*{%O%A%i%i%u%{%@",
trap_request);
- if (! defined ($snmp_version)) {
+ if (!defined $snmp_version) {
($snmp_version, $community,
$request_id, $error_status, $error_index,
$bindings)
= decode_by_template ($trap, "%{%i%s%*{%i%i%i%{%@",
trap2_request);
- return $this->error_return ("v2 trap request contained errorStatus/errorIndex "
- .$error_status."/".$error_index)
+ if (!defined $snmp_version) {
+ ($snmp_version, $community,$request_id, $error_status, $error_index, $bindings)
+ = decode_by_template ($trap, "%{%i%s%*{%i%i%i%{%@", inform_request);
+ }
+ return $this->error_return ("v2 trap/inform request contained errorStatus/errorIndex "
+ .$error_status."/".$error_index)
if defined $error_status && defined $error_index
&& ($error_status != 0 || $error_index != 0);
}
@@ -367,14 +393,13 @@ sub request_response_5 ($$$$$) {
if (defined $this->{'capture_buffer'}
and ref $this->{'capture_buffer'} eq 'ARRAY');
#
-
wait_for_response:
($nfound, $timeleft) = $this->wait_for_response($timeleft);
if ($nfound > 0) {
my($response_length);
$response_length
- = $this->receive_response_3 ($response_tag, $oids, $errorp);
+ = $this->receive_response_3 ($response_tag, $oids, $errorp, 1);
if ($response_length) {
# IlvJa
# Add response pdu to capture_buffer
@@ -384,8 +409,6 @@ sub request_response_5 ($$$$$) {
if (defined $this->{'capture_buffer'}
and ref $this->{'capture_buffer'} eq 'ARRAY');
#
-
-
return $response_length;
} elsif (defined ($response_length)) {
goto wait_for_response;
@@ -407,7 +430,6 @@ sub request_response_5 ($$$$$) {
if (defined $this->{'capture_buffer'}
and ref $this->{'capture_buffer'} eq 'ARRAY');
#
-
$this->error ("no response received");
}
@@ -667,11 +689,8 @@ sub open {
'sockfamily' => $sockfamily,
'max_pdu_len' => $max_pdu_len,
'pdu_buffer' => '\0' x $max_pdu_len,
- 'request_id' =>
- $SNMP_Session::default_avoid_negative_request_ids
- ? (int (rand 0x8000) << 16) + int (rand 0x10000)
- : (int (rand 0x10000) << 16) + int (rand 0x10000)
- - 0x80000000,
+ 'request_id' => (int (rand 0x10000) << 16)
+ + int (rand 0x10000) - 0x80000000,
'timeout' => $default_timeout,
'retries' => $default_retries,
'backoff' => $default_backoff,
@@ -683,6 +702,7 @@ sub open {
'lenient_source_address_matching' => 1,
'lenient_source_port_matching' => 1,
'avoid_negative_request_ids' => $SNMP_Session::default_avoid_negative_request_ids,
+ 'use_16bit_request_ids' => $SNMP_Session::default_use_16bit_request_ids,
'capture_buffer' => undef,
};
}
@@ -817,9 +837,11 @@ sub sa_equal_p ($$$) {
}
sub receive_response_3 {
- my ($this, $response_tag, $oids, $errorp) = @_;
+ my ($this, $response_tag, $oids, $errorp, $dont_block_p) = @_;
my ($remote_addr);
- $remote_addr = recv ($this->sock,$this->{'pdu_buffer'},$this->max_pdu_len,0);
+ my $flags = 0;
+ $flags = $dont_wait_flags if defined $dont_block_p and $dont_block_p;
+ $remote_addr = recv ($this->sock,$this->{'pdu_buffer'},$this->max_pdu_len,$flags);
return $this->error ("receiving response PDU: $!")
unless defined $remote_addr;
return $this->error ("short (".length $this->{'pdu_buffer'}
@@ -1075,7 +1097,9 @@ sub map_table_start_end ($$$$$$) {
}
($base_index = undef), last
if !defined $min_index;
- last if defined $end && index_compare ($min_index, $end) >= 0;
+ last
+ if defined $end
+ and SNMP_Session::index_compare ($min_index, $end) >= 0;
&$mapfn ($min_index, @collected_values);
++$call_counter;
$base_index = $min_index;
@@ -1084,7 +1108,9 @@ sub map_table_start_end ($$$$$$) {
return undef;
}
last if !defined $base_index;
- last if defined $end and index_compare ($base_index, $end) >= 0;
+ last
+ if defined $end
+ and SNMP_Session::index_compare ($base_index, $end) >= 0;
}
$call_counter;
}
diff --git a/lib/SNMP_util.pm b/lib/SNMP_util.pm
index d103dbc..c3ea43e 100644
--- a/lib/SNMP_util.pm
+++ b/lib/SNMP_util.pm
@@ -2,30 +2,33 @@
######################################################################
### SNMP_util -- SNMP utilities using SNMP_Session.pm and BER.pm
######################################################################
-### Copyright (c) 1998-2002, Mike Mitchell.
+### Copyright (c) 1998-2007, Mike Mitchell.
###
### This program is free software; you can redistribute it under the
-### "Artistic License" included in this distribution (file "Artistic").
+### "Artistic License 2.0" included in this distribution
+### (file "Artistic").
######################################################################
### Created by: Mike Mitchell <Mike.Mitchell@sas.com>
###
### Contributions and fixes by:
###
-### Tobias Oetiker <oetiker@ee.ethz.ch>: Basic layout
+### Tobias Oetiker <tobi@oetiker.ch>: Basic layout
### Simon Leinen <simon@switch.ch>: SNMP_session.pm/BER.pm
### Jeff Allen <jeff.allen@acm.org>: length() of undefined value
### Johannes Demel <demel@zid.tuwien.ac.at>: MIB file parse problem
### Simon Leinen <simon@switch.ch>: more OIDs from Interface MIB
### Jacques Supcik <supcik@ip-plus.net>: Specify local IP, port
-### Tobias Oetiker <oetiker@ee.ethz.ch>: HASH as first OID to set SNMP options
+### Tobias Oetiker <tobi@oetiker.ch>: HASH as first OID to set SNMP options
### Simon Leinen <simon@switch.ch>: 'undefined port' bug
### Daniel McDonald <dmcdonald@digicontech.com>: request for getbulk support
-### Laurent Girod <girod.laurent@pmintl.ch>: code for snmpwalkhash
+### Laurent Girod <it.fb@net2000.ch>: code for snmpwalkhash
### Ian Duplisse <i.duplisse@cablelabs.com>: MIB parsing suggestions
### Jakob Ilves <jakob.ilves@oracle.com>: return_array_refs for snmpwalk()
### Valerio Bontempi <v.bontempi@inwind.it>: IPv6 support
### Lorenzo Colitti <lorenzo@colitti.com>: IPv6 support
### Joerg Kummer <JOERG.KUMMER@Roche.COM>: TimeTicks support in snmpset()
+### Christopher J. Tengi <tengi@CS.Princeton.EDU>: Gauge32 support in snmpset()
+### Nicolai Petri <nicolai@catpipe.net>: hashref passing for snmpwalkhash()
######################################################################
package SNMP_util;
@@ -37,11 +40,11 @@ use vars qw(@ISA @EXPORT $VERSION);
use Exporter;
use Carp;
-use BER "0.95";
-use SNMP_Session "0.97";
+use BER "1.02";
+use SNMP_Session "1.00";
use Socket;
-$VERSION = '0.98';
+$VERSION = '1.12';
@ISA = qw(Exporter);
@@ -339,6 +342,7 @@ $SNMP_util::Debug = 0;
$SNMP_util::CacheFile = "OID_cache.txt";
$SNMP_util::CacheLoaded = 0;
$SNMP_util::Return_array_refs = 0;
+$SNMP_util::Return_hash_refs = 0;
srand(time + $$);
@@ -361,6 +365,7 @@ sub encode_oid_with_errmsg ($);
sub Check_OID ($);
sub snmpLoad_OID_Cache ($);
sub snmpQueue_MIB_File (@);
+sub MIB_fill_OID ($);
sub version () { $VERSION; }
@@ -382,7 +387,7 @@ sub snmpopen ($$$) {
# We can't split on the : character because a numeric IPv6
# address contains a variable number of :'s
my $opts;
- if( ($host =~ /^(\[.*\]):(.*)$/) || ($host =~ /^(\[.*\])$/) ) {
+ if( ($host =~ /^(\[.*\]):(.*)$/) or ($host =~ /^(\[.*\])$/) ) {
# Numeric IPv6 address between []
($host, $opts) = ($1, $2);
} else {
@@ -390,28 +395,28 @@ sub snmpopen ($$$) {
($host, $opts) = split(':', $host, 2);
}
($port, $timeout, $retries, $backoff, $version, $v4onlystr) = split(':', $opts, 6)
- if(defined($opts) && (length $opts > 0) );
+ if(defined($opts) and (length $opts > 0) );
- undef($version) if (defined($version) && length($version) <= 0);
+ undef($version) if (defined($version) and length($version) <= 0);
$v4onlystr = "" unless defined $v4onlystr;
$version = '1' unless defined $version;
- if (defined($port) && ($port =~ /^([^!]*)!(.*)$/)) {
+ if (defined($port) and ($port =~ /^([^!]*)!(.*)$/)) {
($port, $lhost) = ($1, $2);
$nlhost = $lhost;
($lhost, $lport) = ($1, $2) if ($lhost =~ /^(.*)!(.*)$/);
- undef($lhost) if (defined($lhost) && (length($lhost) <= 0));
- undef($lport) if (defined($lport) && (length($lport) <= 0));
+ undef($lhost) if (defined($lhost) and (length($lhost) <= 0));
+ undef($lport) if (defined($lport) and (length($lport) <= 0));
}
- undef($port) if (defined($port) && length($port) <= 0);
- $port = 162 if ($type == 1 && !defined($port));
+ undef($port) if (defined($port) and length($port) <= 0);
+ $port = 162 if ($type == 1 and !defined($port));
$nhost = "$community\@$host";
$nhost .= ":" . $port if (defined($port));
if ((!defined($SNMP_util::Session))
- || ($SNMP_util::Host ne $nhost)
- || ($SNMP_util::Version ne $version)
- || ($SNMP_util::LHost ne $nlhost)
- || ($SNMP_util::IPv4only ne $v4onlystr)) {
+ or ($SNMP_util::Host ne $nhost)
+ or ($SNMP_util::Version ne $version)
+ or ($SNMP_util::LHost ne $nlhost)
+ or ($SNMP_util::IPv4only ne $v4onlystr)) {
if (defined($SNMP_util::Session)) {
$SNMP_util::Session->close();
undef $SNMP_util::Session;
@@ -435,8 +440,9 @@ sub snmpopen ($$$) {
foreach $type (keys %$opts) {
if ($type eq 'return_array_refs') {
$SNMP_util::Return_array_refs = $opts->{$type};
- }
- else {
+ } elsif ($type eq 'return_hash_refs') {
+ $SNMP_util::Return_hash_refs = $opts->{$type};
+ } else {
if (exists $SNMP_util::Session->{$type}) {
if ($type eq 'timeout') {
$SNMP_util::Session->set_timeout($opts->{$type});
@@ -455,11 +461,11 @@ sub snmpopen ($$$) {
}
}
$SNMP_util::Session->set_timeout($timeout)
- if (defined($timeout) && (length($timeout) > 0));
+ if (defined($timeout) and (length($timeout) > 0));
$SNMP_util::Session->set_retries($retries)
- if (defined($retries) && (length($retries) > 0));
+ if (defined($retries) and (length($retries) > 0));
$SNMP_util::Session->set_backoff($backoff)
- if (defined($backoff) && (length($backoff) > 0));
+ if (defined($backoff) and (length($backoff) > 0));
}
return $SNMP_util::Session;
}
@@ -492,7 +498,7 @@ sub snmpget ($@) {
my $tempo = pretty_print($value);
push @retvals, $tempo;
}
- return(@retvals);
+ return wantarray ? @retvals : $retvals[0];
}
$var = join(' ', @vars);
carp "SNMPGET Problem for $var on $host\n"
@@ -536,7 +542,7 @@ sub snmpgetnext ($@) {
my $tempv = pretty_print($value);
push @retvals, "$tempo:$tempv";
}
- return (@retvals);
+ return wantarray ? @retvals : $retvals[0];
} else {
$var = join(' ', @vars);
carp "SNMPGETNEXT Problem for $var on $host\n"
@@ -568,7 +574,7 @@ sub snmpwalk_flg ($$@) {
my($got, @nnoid, $noid, $ok, $ix, @avars);
my $session;
my(%soid);
- my(%done, %rethash);
+ my(%done, %rethash, $h_ref);
$session = &snmpopen($host, 0, \@vars);
if (!defined($session)) {
@@ -577,6 +583,8 @@ sub snmpwalk_flg ($$@) {
return undef;
}
+ $h_ref = (ref $vars[$#vars] eq "HASH") ? pop(@vars) : \%rethash;
+
@enoid = toOID(@vars);
return undef unless defined $enoid[0];
@@ -584,9 +592,9 @@ sub snmpwalk_flg ($$@) {
#
# Create/Refresh a reversed hash with oid -> name
#
- if (defined($hash_sub) && $RevNeeded) {
- %revOIDS = reverse %SNMP_util::OIDS;
- $RevNeeded = 0;
+ if (defined($hash_sub) and ($RevNeeded)) {
+ %revOIDS = reverse %SNMP_util::OIDS;
+ $RevNeeded = 0;
}
$got = 0;
@@ -618,7 +626,7 @@ sub snmpwalk_flg ($$@) {
}
- while(($SNMP_util::Version ne '1' && $session->{'use_getbulk'})
+ while(($SNMP_util::Version ne '1' and $session->{'use_getbulk'})
? $session->getbulk_request_response(0,
$session->default_max_repetitions(),
@nnoid)
@@ -638,13 +646,13 @@ sub snmpwalk_flg ($$@) {
$ok = 0;
my $tempo = pretty_print($oid);
$noid = $avars[$ix]; # IlvJa
- if ($tempo =~ /^$noid\./ || $tempo eq $noid ) {
+ if ($tempo =~ /^$noid\./ or $tempo eq $noid ) {
$ok = 1;
$upoid = $noid;
} else {
# IlvJa
#
- # The walk for variable $var[$ix] has been finished as
+ # The walk for variable $vars[$ix] has been finished as
# $nnoid[$ix] no longer is in the $avar[$ix] OID tree.
# So we exclude this variable from further requests.
@@ -655,7 +663,16 @@ sub snmpwalk_flg ($$@) {
if ($ok) {
my $tmp = encode_oid_with_errmsg ($tempo);
return undef unless defined $tmp;
- next if (exists($done{$tmp})); # GIL
+ if (exists($done{$tmp})) { # GIL, Ilvja
+ #
+ # We've detected a loop for $nnoid[$ix], so mark it as finished.
+ # Exclude this variable from further requests.
+ #
+ $avars[$ix] = "";
+ $nnoid[$ix] = "";
+ $retvaltmprefs[$ix] = undef if $SNMP_util::Return_array_refs;
+ next;
+ }
$nnoid[$ix] = $tmp; # Keep on walking. (IlvJa)
my $tempv = pretty_print($value);
if (defined($hash_sub)) {
@@ -664,40 +681,40 @@ sub snmpwalk_flg ($$@) {
#
my $inst = "";
my $upo = $upoid;
- while (!exists($revOIDS{$upo}) && length($upo)) {
+ while (!exists($revOIDS{$upo}) and length($upo)) {
$upo =~ s/(\.\d+?)$//;
- if (defined($1) && length($1)) {
+ if (defined($1) and length($1)) {
$inst = $1 . $inst;
} else {
$upo = "";
last;
}
}
- if (length($upo) && exists($revOIDS{$upo})) {
+ if (length($upo) and exists($revOIDS{$upo})) {
$upo = $revOIDS{$upo} . $inst;
} else {
$upo = $upoid;
}
$inst = "";
- while (!exists($revOIDS{$tempo}) && length($tempo)) {
+ while (!exists($revOIDS{$tempo}) and length($tempo)) {
$tempo =~ s/(\.\d+?)$//;
- if (defined($1) && length($1)) {
+ if (defined($1) and length($1)) {
$inst = $1 . $inst;
} else {
$tempo = "";
last;
}
}
- if (length($tempo) && exists($revOIDS{$tempo})) {
- $tempo = $revOIDS{$tempo} . $inst;
+ if (length($tempo) and exists($revOIDS{$tempo})) {
+ $var = $revOIDS{$tempo};
} else {
- $tempo = pretty_print($oid);
+ $var = pretty_print($oid);
}
#
# call hash_sub
#
- &$hash_sub(\%rethash, $host, $revOIDS{$tempo}, $tempo, $inst,
+ &$hash_sub($h_ref, $host, $var, $tempo, $inst,
$tempv, $upo);
} else {
if ($SNMP_util::Return_array_refs) {
@@ -728,7 +745,8 @@ sub snmpwalk_flg ($$@) {
}
if ($got) {
if (defined($hash_sub)) {
- return (%rethash)
+ return ($h_ref) if ($SNMP_util::Return_hash_refs);
+ return (%$h_ref);
} else {
return (@retvals);
}
@@ -746,7 +764,7 @@ sub snmpwalk_flg ($$@) {
sub snmpset($@) {
my($host, @vars) = @_;
my(@enoid, $response, $bindings, $binding);
- my($oid, @retvals, $type, $value);
+ my($oid, @retvals, $type, $value, $val);
my $session;
$session = &snmpopen($host, 0, \@vars);
@@ -760,27 +778,62 @@ sub snmpset($@) {
($oid) = toOID((shift @vars));
$type = shift @vars;
$value = shift @vars;
- if ($type =~ /string/i) {
- $value = encode_string($value);
- push @enoid, [$oid,$value];
- } elsif ($type =~ /ipaddr/i) {
- $value = encode_ip_address($value);
- push @enoid, [$oid,$value];
- } elsif ($type =~ /int/i) {
- $value = encode_int($value);
- push @enoid, [$oid,$value];
- } elsif ($type =~ /oid/i) {
- my $tmp = encode_oid_with_errmsg($value);
- return undef unless defined $tmp;
- push @enoid, [$oid,$tmp];
- } elsif ($type =~ /timeticks/i) {
- $value = encode_timeticks($value);
- push @enoid, [$oid,$value];
+ $type =~ tr/A-Z/a-z/;
+ if ($type eq "int") {
+ $val = encode_int($value);
+ } elsif ($type eq "integer") {
+ $val = encode_int($value);
+ } elsif ($type eq "string") {
+ $val = encode_string($value);
+ } elsif ($type eq "octetstring") {
+ $val = encode_string($value);
+ } elsif ($type eq "octet string") {
+ $val = encode_string($value);
+ } elsif ($type eq "oid") {
+ $val = encode_oid_with_errmsg($value);
+ } elsif ($type eq "object id") {
+ $val = encode_oid_with_errmsg($value);
+ } elsif ($type eq "object identifier") {
+ $val = encode_oid_with_errmsg($value);
+ } elsif ($type eq "ipaddr") {
+ $val = encode_ip_address($value);
+ } elsif ($type eq "ip address") {
+ $val = encode_ip_address($value);
+ } elsif ($type eq "timeticks") {
+ $val = encode_timeticks($value);
+ } elsif ($type eq "uint") {
+ $val = encode_uinteger32($value);
+ } elsif ($type eq "uinteger") {
+ $val = encode_uinteger32($value);
+ } elsif ($type eq "uinteger32") {
+ $val = encode_uinteger32($value);
+ } elsif ($type eq "unsigned int") {
+ $val = encode_uinteger32($value);
+ } elsif ($type eq "unsigned integer") {
+ $val = encode_uinteger32($value);
+ } elsif ($type eq "unsigned integer32") {
+ $val = encode_uinteger32($value);
+ } elsif ($type eq "counter") {
+ $val = encode_counter32($value);
+ } elsif ($type eq "counter32") {
+ $val = encode_counter32($value);
+ } elsif ($type eq "counter64") {
+ $val = encode_counter64($value);
+ } elsif ($type eq "gauge") {
+ $val = encode_gauge32($value);
+ } elsif ($type eq "gauge32") {
+ $val = encode_gauge32($value);
} else {
carp "unknown SNMP type: $type\n"
unless ($SNMP_Session::suppress_warnings > 1);
return undef;
}
+ if (!defined($val)) {
+ carp "SNMP type $type value $value didn't encode properly\n"
+ unless ($SNMP_Session::suppress_warnings > 1);
+ return undef;
+ }
+ push @enoid, [$oid,$val];
}
return undef unless defined $enoid[0];
if ($session->set_request_response(@enoid)) {
@@ -792,7 +845,7 @@ sub snmpset($@) {
my $tempo = pretty_print($value);
push @retvals, $tempo;
}
- return (@retvals);
+ return wantarray ? @retvals : $retvals[0];
}
return undef;
}
@@ -945,7 +998,7 @@ sub toOID(@) {
undef @retvar;
foreach $var (@vars) {
($oid, $tmp) = &Check_OID($var);
- if (!$oid && $SNMP_util::CacheLoaded == 0) {
+ if (!$oid and $SNMP_util::CacheLoaded == 0) {
$tmp = $SNMP_Session::suppress_warnings;
$SNMP_Session::suppress_warnings = 1000;
@@ -956,7 +1009,7 @@ sub toOID(@) {
($oid, $tmp) = &Check_OID($var);
}
- while (!$oid && $#SNMP_util::MIB_Files >= 0) {
+ while (!$oid and $#SNMP_util::MIB_Files >= 0) {
$tmp = $SNMP_Session::suppress_warnings;
$SNMP_Session::suppress_warnings = 1000;
@@ -996,15 +1049,14 @@ sub toOID(@) {
sub snmpmapOID(@)
{
my(@vars) = @_;
- my($oid, $txt, $ind);
+ my($oid, $txt);
- $ind = 0;
- while($ind <= $#vars) {
- $txt = $vars[$ind++];
- next unless($txt =~ /^(([a-zA-Z][a-zA-Z\d\-]*\.)*([a-zA-Z][a-zA-Z\d\-]*))$/);
+ while($#vars >= 0) {
+ $txt = shift @vars;
+ $oid = shift @vars;
- $oid = $vars[$ind++];
- next unless($oid =~ /^((\d+.)*\d+)$/);
+ next unless($txt =~ /^[a-zA-Z][\w\-]*(\.[a-zA-Z][\w\-])*$/);
+ next unless($oid =~ /^\d+(\.\d+)*$/);
$SNMP_util::OIDS{$txt} = $oid;
$RevNeeded = 1;
@@ -1033,13 +1085,23 @@ sub snmpLoad_OID_Cache ($) {
}
while(<CACHE>) {
- s/#.*//;
- s/--.*--//g;
- s/--.*//;
+ s/#.*//; # '#' starts a comment
+ s/--.*--//g; # comment delimited by '--', like MIBs
+ s/--.*//; # comment started by '--'
next if (/^$/);
- next unless (/\s/);
- chop;
+ next unless (/\s/); # must have whitespace as separator
+ chomp;
($txt, $oid) = split(' ', $_, 2);
+ $txt = $1 if ($txt =~ /^[\'\"](.*)[\'\"]/);
+ $oid = $1 if ($oid =~ /^[\'\"](.*)[\'\"]/);
+ if (($txt =~ /^\.?\d+(\.\d+)*\.?$/)
+ and ($oid !~ /^\.?\d+(\.\d+)*\.?$/)) {
+ my($a) = $oid;
+ $oid = $txt;
+ $txt = $a;
+ }
+ $oid =~ s/^\.//;
+ $oid =~ s/\.$//;
&snmpmapOID($txt, $oid);
}
close(CACHE);
@@ -1055,12 +1117,12 @@ sub Check_OID ($) {
my($var) = @_;
my($tmp, $tmpv, $oid);
- if ($var =~ /^(([a-zA-Z][a-zA-Z\d\-]*\.)*([a-zA-Z][a-zA-Z\d\-]*))/)
+ if ($var =~ /^[a-zA-Z][\w\-]*(\.[a-zA-Z][\w\-]*)*/)
{
$tmp = $&;
$tmpv = $tmp;
for (;;) {
- last if defined($SNMP_util::OIDS{$tmpv});
+ last if exists($SNMP_util::OIDS{$tmpv});
last if !($tmpv =~ s/^[^\.]*\.//);
}
$oid = $SNMP_util::OIDS{$tmpv};
@@ -1093,19 +1155,8 @@ sub snmpQueue_MIB_File (@) {
#
sub snmpMIB_to_OID ($) {
my($arg) = @_;
- my($quote, $buf, $var, $code, $val, $tmp, $tmpv, $strt);
- my($ret, $pass, $pos, $need2pass, $cnt, %prev);
- my(%Link) = (
- 'org' => 'iso',
- 'dod' => 'org',
- 'internet' => 'dod',
- 'directory' => 'internet',
- 'mgmt' => 'internet',
- 'mib-2' => 'mgmt',
- 'experimental' => 'internet',
- 'private' => 'internet',
- 'enterprises' => 'private',
- );
+ my($cnt, $quote, $buf, %tOIDs, $tgot);
+ my($var, @parts, $strt, $indx, $ind, $val);
if (!open(MIB, $arg)) {
carp "snmpMIB_to_OID: Can't open $arg: $!"
@@ -1113,145 +1164,148 @@ sub snmpMIB_to_OID ($) {
return -1;
}
print "snmpMIB_to_OID: loading $arg\n" if $SNMP_util::Debug;
- $ret = 0;
- $pass = 0;
- $need2pass = 1;
$cnt = 0;
- $pos = tell(MIB);
- while($need2pass) {
- while(<MIB>) {
- s/--.*--//g; # throw away comments (-- anything --)
- s/--.*//; # throw away comments (-- anything EOL)
- if ($quote) {
- next unless /"/;
- $quote = 0;
- }
- chop;
-#
-# $buf = "$buf $_";
-# Previous line removed (and following replacement)
-# suggested by Brian Reichert, reichert@numachi.com
-#
- $buf .= ' ' . $_;
- $buf =~ s/\s+/ /g;
-
- if ($buf =~ / DEFINITIONS ::= BEGIN/) {
- if ($pass == 0 && $need2pass) {
- seek(MIB, $pos, 0);
- $buf = "";
- $pass = 1;
- $need2pass = 0;
- $cnt = 0;
- next;
- }
- $need2pass = 0;
- $pass = 0;
- $pos = tell(MIB);
- undef %Link;
- undef %prev;
- %Link = (
- 'org' => 'iso',
- 'dod' => 'org',
- 'internet' => 'dod',
- 'directory' => 'internet',
- 'mgmt' => 'internet',
- 'mib-2' => 'mgmt',
- 'experimental' => 'internet',
- 'private' => 'internet',
- 'enterprises' => 'private',
- );
- $buf = "";
- next;
- }
+ $quote = 0;
+ $tgot = 0;
+ $buf = '';
+ while(<MIB>) {
+ if ($quote) {
+ next unless /"/;
+ $quote = 0;
+ } else {
+ s/--.*--//g; # throw away comments (-- anything --)
+ s/^\s*--.*//; # throw away comments at start of line
+ }
+ chomp;
+
+ $buf .= ' ' . $_;
- $buf =~ s/OBJECT-TYPE/OBJECT IDENTIFIER/;
- $buf =~ s/OBJECT-IDENTITY/OBJECT IDENTIFIER/;
- $buf =~ s/OBJECT-GROUP/OBJECT IDENTIFIER/;
- $buf =~ s/MODULE-IDENTITY/OBJECT IDENTIFIER/;
- $buf =~ s/ IMPORTS .*\;//;
- $buf =~ s/ SEQUENCE {.*}//;
- $buf =~ s/ SYNTAX .*//;
- $buf =~ s/ [\w-]+ ::= OBJECT IDENTIFIER//;
- $buf =~ s/ OBJECT IDENTIFIER .* ::= {/ OBJECT IDENTIFIER ::= {/;
- $buf =~ s/".*"//;
- if ($buf =~ /"/) {
- $quote = 1;
+ $buf =~ s/"[^"]*"//g;
+ if ($buf =~ /"/) {
+ $quote = 1;
+ next;
+ }
+ $buf =~ s/--.*--//g; # throw away comments (-- anything --)
+ $buf =~ s/--.*//; # throw away comments (-- anything EOL)
+ $buf =~ s/\s+/ /g;
+ if ($buf =~ /DEFINITIONS *::= *BEGIN/) {
+ $cnt += MIB_fill_OID(\%tOIDs) if ($tgot);
+ $buf = '';
+ %tOIDs = ();
+ $tgot = 0;
+ next;
+ }
+ $buf =~ s/OBJECT-TYPE/OBJECT IDENTIFIER/;
+ $buf =~ s/OBJECT-IDENTITY/OBJECT IDENTIFIER/;
+ $buf =~ s/OBJECT-GROUP/OBJECT IDENTIFIER/;
+ $buf =~ s/MODULE-IDENTITY/OBJECT IDENTIFIER/;
+ $buf =~ s/ IMPORTS .*\;//;
+ $buf =~ s/ SEQUENCE *{.*}//;
+ $buf =~ s/ SYNTAX .*//;
+ $buf =~ s/ [\w\-]+ *::= *OBJECT IDENTIFIER//;
+ $buf =~ s/ OBJECT IDENTIFIER.*::= *{/ OBJECT IDENTIFIER ::= {/;
+
+ if ($buf =~ / ([\w\-]+) OBJECT IDENTIFIER *::= *{([^}]+)}/) {
+ $var = $1;
+ $buf = $2;
+ $buf =~ s/ +$//;
+ $buf =~ s/\s+\(/\(/g; # remove spacing around '('
+ $buf =~ s/\(\s+/\(/g;
+ $buf =~ s/\s+\)/\)/g; # remove spacing before ')'
+ @parts = split(' ', $buf);
+ $strt = '';
+ foreach $indx (@parts) {
+ if ($indx =~ /([\w\-]+)\((\d+)\)/) {
+ $ind = $1;
+ $val = $2;
+ if (exists($tOIDs{$strt})) {
+ $tOIDs{$ind} = $tOIDs{$strt} . '.' . $val;
+ } elsif ($strt ne '') {
+ $tOIDs{$ind} = "${strt}.${val}";
+ } else {
+ $tOIDs{$ind} = $val;
+ }
+ $strt = $ind;
+ $tgot = 1;
+ } elsif ($indx =~ /^\d+$/) {
+ if (exists($tOIDs{$strt})) {
+ $tOIDs{$var} = $tOIDs{$strt} . '.' . $indx;
+ } else {
+ $tOIDs{$var} = "${strt}.${indx}";
+ }
+ $tgot = 1;
+ } else {
+ $strt = $indx;
+ }
}
+ $buf = '';
+ }
+ }
+ $cnt += MIB_fill_OID(\%tOIDs) if ($tgot);
+ $RevNeeded = 1 if ($cnt > 0);
+ return $cnt;
+}
- if ($buf =~ / ([\w\-]+) OBJECT IDENTIFIER ::= {([^}]+)}/) {
- $var = $1;
- $buf = $2;
- undef $val;
- $buf =~ s/ +$//;
- ($code, $val) = split(' ', $buf, 2);
+#
+# Fill the OIDS hash with results from the MIB parsing
+#
+sub MIB_fill_OID ($)
+{
+ my($href) = @_;
+ my($cnt, $changed, @del, $var, $val, @parts, $indx);
+ my(%seen);
- if (!defined($val) || (length($val) <= 0)) {
- $SNMP_util::OIDS{$var} = $code;
- $cnt++;
- print "'$var' => '$code'\n" if $SNMP_util::Debug;
+ $cnt = 0;
+ do {
+ $changed = 0;
+ @del = ();
+ foreach $var (keys %$href) {
+ $val = $href->{$var};
+ @parts = split('\.', $val);
+ $val = '';
+ foreach $indx (@parts) {
+ if ($indx =~ /^\d+$/) {
+ $val .= '.' . $indx;
} else {
- $strt = $code;
- while($val =~ / /) {
- ($tmp, $val) = split(' ', $val, 2);
- if ($tmp =~ /([\w\-]+)\((\d+)\)/) {
- $tmp = $1;
- $tmpv = "$SNMP_util::OIDS{$strt}.$2";
- $Link{$tmp} = $strt;
- if (!defined($prev{$tmp}) && defined($SNMP_util::OIDS{$tmp})) {
- if ($tmpv ne $SNMP_util::OIDS{$tmp}) {
- $strt = "$strt.$tmp";
- $SNMP_util::OIDS{$strt} = $tmpv;
- $cnt++;
- }
- } else {
- $prev{$tmp} = 1;
- $SNMP_util::OIDS{$tmp} = $tmpv;
- $cnt++;
- $strt = $tmp;
- }
- }
- }
-
- if (!defined($SNMP_util::OIDS{$strt})) {
- if ($pass) {
- carp "snmpMIB_to_OID: $arg: \"$strt\" prefix unknown, load the parent MIB first.\n"
- unless ($SNMP_Session::suppress_warnings > 1);
- } else {
- $need2pass = 1;
- }
- }
- $Link{$var} = $strt;
- $val = "$SNMP_util::OIDS{$strt}.$val";
- if (!defined($prev{$var}) && defined($SNMP_util::OIDS{$var})) {
- if ($val ne $SNMP_util::OIDS{$var}) {
- $var = "$strt.$var";
- }
+ if (exists($SNMP_util::OIDS{$indx})) {
+ $val = $SNMP_util::OIDS{$indx};
+ } else {
+ $val .= '.' . $indx;
}
-
+ }
+ }
+ if ($val =~ /^[\d\.]+$/) {
+ $val =~ s/^\.//;
+ if (!exists($SNMP_util::OIDS{$var})
+ || (length($val) > length($SNMP_util::OIDS{$var}))) {
$SNMP_util::OIDS{$var} = $val;
- $prev{$var} = 1;
- $cnt++;
-
print "'$var' => '$val'\n" if $SNMP_util::Debug;
+ $changed = 1;
+ $cnt++;
}
- undef $buf;
+ push @del, $var;
}
}
- if ($pass == 0 && $need2pass) {
- seek(MIB, $pos, 0);
- $buf = "";
- $pass = 1;
- $cnt = 0;
- } else {
- $ret += $cnt;
- $need2pass = 0;
+ foreach $var (@del) {
+ delete $href->{$var};
}
+ } while($changed);
+
+ $Carp::CarpLevel++;
+ foreach $var (sort keys %$href) {
+ $val = $href->{$var};
+ $val =~ s/\..*//;
+ next if (exists($seen{$val}));
+ $seen{$val} = 1;
+ $seen{$var} = 1;
+ carp "snmpMIB_to_OID: prefix \"$val\" unknown, load the parent MIB first.\n"
+ unless ($SNMP_Session::suppress_warnings > 1);
}
- close(MIB);
- $RevNeeded = 1;
- return $ret;
+ $Carp::CarpLevel--;
+ return $cnt;
}
+
sub encode_oid_with_errmsg ($) {
my ($oid) = @_;
my $tmp = encode_oid(split(/\./, $oid));