|
Packit |
667938 |
### -*- mode: Perl -*-
|
|
Packit |
667938 |
######################################################################
|
|
Packit |
667938 |
### SNMP Request/Response Handling
|
|
Packit |
667938 |
######################################################################
|
|
Packit |
667938 |
### Copyright (c) 1995-2008, Simon Leinen.
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
### This program is free software; you can redistribute it under the
|
|
Packit |
667938 |
### "Artistic License 2.0" included in this distribution
|
|
Packit |
667938 |
### (file "Artistic").
|
|
Packit |
667938 |
######################################################################
|
|
Packit |
667938 |
### The abstract class SNMP_Session defines objects that can be used
|
|
Packit |
667938 |
### to communicate with SNMP entities. It has methods to send
|
|
Packit |
667938 |
### requests to and receive responses from an agent.
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
### Two instantiable subclasses are defined:
|
|
Packit |
667938 |
### SNMPv1_Session implements SNMPv1 (RFC 1157) functionality
|
|
Packit |
667938 |
### SNMPv2c_Session implements community-based SNMPv2.
|
|
Packit |
667938 |
######################################################################
|
|
Packit |
667938 |
### Created by: Simon Leinen <simon@switch.ch>
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
### Contributions and fixes by:
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
### Matthew Trunnell <matter@media.mit.edu>
|
|
Packit |
667938 |
### Tobias Oetiker <tobi@oetiker.ch>
|
|
Packit |
667938 |
### Heine Peters <peters@dkrz.de>
|
|
Packit |
667938 |
### Daniel L. Needles <dan_needles@INS.COM>
|
|
Packit |
667938 |
### Mike Mitchell <mcm@unx.sas.com>
|
|
Packit |
667938 |
### Clinton Wong <clintdw@netcom.com>
|
|
Packit |
667938 |
### Alan Nichols <Alan.Nichols@Ebay.Sun.COM>
|
|
Packit |
667938 |
### Mike McCauley <mikem@open.com.au>
|
|
Packit |
667938 |
### Andrew W. Elble <elble@icculus.nsg.nwu.edu>
|
|
Packit |
667938 |
### Brett T Warden <wardenb@eluminant.com>: pretty UInteger32
|
|
Packit |
667938 |
### Michael Deegan <michael@cnspc18.murdoch.edu.au>
|
|
Packit |
667938 |
### Sergio Macedo <macedo@tmp.com.br>
|
|
Packit |
667938 |
### Jakob Ilves (/IlvJa) <jakob.ilves@oracle.com>: PDU capture
|
|
Packit |
667938 |
### Valerio Bontempi <v.bontempi@inwind.it>: IPv6 support
|
|
Packit |
667938 |
### Lorenzo Colitti <lorenzo@colitti.com>: IPv6 support
|
|
Packit |
667938 |
### Philippe Simonet <Philippe.Simonet@swisscom.com>: Export avoid...
|
|
Packit |
667938 |
### Luc Pauwels <Luc.Pauwels@xalasys.com>: use_16bit_request_ids
|
|
Packit |
667938 |
### Andrew Cornford-Matheson <andrew.matheson@corenetworks.com>: inform
|
|
Packit |
667938 |
### Gerry Dalton <gerry.dalton@consolidated.com>: strict subs bug
|
|
Packit |
667938 |
### Mike Fischer <mlf2@tampabay.rr.com>: pass MSG_DONTWAIT to recv()
|
|
Packit |
667938 |
######################################################################
|
|
Packit |
667938 |
|
|
Packit |
667938 |
package SNMP_Session;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
require 5.002;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
use strict;
|
|
Packit |
667938 |
use Exporter;
|
|
Packit |
667938 |
use vars qw(@ISA $VERSION @EXPORT $errmsg
|
|
Packit |
667938 |
$suppress_warnings
|
|
Packit |
667938 |
$default_avoid_negative_request_ids
|
|
Packit |
667938 |
$default_use_16bit_request_ids);
|
|
Packit |
667938 |
use Socket;
|
|
Packit |
667938 |
use BER '1.05';
|
|
Packit |
667938 |
use Carp;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub map_table ($$$ );
|
|
Packit |
667938 |
sub map_table_4 ($$$$);
|
|
Packit |
667938 |
sub map_table_start_end ($$$$$$);
|
|
Packit |
667938 |
sub index_compare ($$);
|
|
Packit |
667938 |
sub oid_diff ($$);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$VERSION = '1.12';
|
|
Packit |
667938 |
|
|
Packit |
667938 |
@ISA = qw(Exporter);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
@EXPORT = qw(errmsg suppress_warnings index_compare oid_diff recycle_socket ipv6available);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my $default_debug = 0;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### Default initial timeout (in seconds) waiting for a response PDU
|
|
Packit |
667938 |
### after a request is sent. Note that when a request is retried, the
|
|
Packit |
667938 |
### timeout is increased by BACKOFF (see below).
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
my $default_timeout = 2.0;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### Default number of attempts to get a reply for an SNMP request. If
|
|
Packit |
667938 |
### no response is received after TIMEOUT seconds, the request is
|
|
Packit |
667938 |
### resent and a new response awaited with a longer timeout (see the
|
|
Packit |
667938 |
### documentation on BACKOFF below). The "retries" value should be at
|
|
Packit |
667938 |
### least 1, because the first attempt counts, too (the name "retries"
|
|
Packit |
667938 |
### is confusing, sorry for that).
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
my $default_retries = 5;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### Default backoff factor for SNMP_Session objects. This factor is
|
|
Packit |
667938 |
### used to increase the TIMEOUT every time an SNMP request is
|
|
Packit |
667938 |
### retried.
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
my $default_backoff = 1.0;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### Default value for maxRepetitions. This specifies how many table
|
|
Packit |
667938 |
### rows are requested in getBulk requests. Used when walking tables
|
|
Packit |
667938 |
### using getBulk (only available in SNMPv2(c) and later). If this is
|
|
Packit |
667938 |
### too small, then a table walk will need unnecessarily many
|
|
Packit |
667938 |
### request/response exchanges. If it is too big, the agent may
|
|
Packit |
667938 |
### compute many variables after the end of the table. It is
|
|
Packit |
667938 |
### recommended to set this explicitly for each table walk by using
|
|
Packit |
667938 |
### map_table_4().
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
my $default_max_repetitions = 12;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### Default value for "avoid_negative_request_ids".
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
### Set this to non-zero if you have agents that have trouble with
|
|
Packit |
667938 |
### negative request IDs, and don't forget to complain to your agent
|
|
Packit |
667938 |
### vendor. According to the spec (RFC 1905), the request-id is an
|
|
Packit |
667938 |
### Integer32, i.e. its range is from -(2^31) to (2^31)-1. However,
|
|
Packit |
667938 |
### some agents erroneously encode the response ID as an unsigned,
|
|
Packit |
667938 |
### which prevents this code from matching such responses to requests.
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
$SNMP_Session::default_avoid_negative_request_ids = 0;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### Default value for "use_16bit_request_ids".
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
### Set this to non-zero if you have agents that use 16bit request IDs,
|
|
Packit |
667938 |
### and don't forget to complain to your agent vendor.
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
$SNMP_Session::default_use_16bit_request_ids = 0;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### Whether all SNMP_Session objects should share a single UDP socket.
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
$SNMP_Session::recycle_socket = 0;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### IPv6 initialization code: check that IPv6 libraries are available,
|
|
Packit |
667938 |
### and if so load them.
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### We store the length of an IPv6 socket address structure in the class
|
|
Packit |
667938 |
### so we can determine if a socket address is IPv4 or IPv6 just by checking
|
|
Packit |
667938 |
### its length. The proper way to do this would be to use sockaddr_family(),
|
|
Packit |
667938 |
### but this function is only available in recent versions of Socket.pm.
|
|
Packit |
667938 |
my $ipv6_addr_len;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### Flags to be passed to recv() when non-blocking behavior is
|
|
Packit |
667938 |
### desired. On most POSIX-like systems this will be set to
|
|
Packit |
667938 |
### MSG_DONTWAIT, on other systems we leave it at zero.
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
my $dont_wait_flags;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
BEGIN {
|
|
Packit |
667938 |
$ipv6_addr_len = undef;
|
|
Packit |
667938 |
$SNMP_Session::ipv6available = 0;
|
|
Packit |
667938 |
$dont_wait_flags = 0;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if (eval {local $SIG{__DIE__};require Socket6;} &&
|
|
Packit |
667938 |
eval {local $SIG{__DIE__};require IO::Socket::INET6; IO::Socket::INET6->VERSION("1.26");}) {
|
|
Packit Service |
41e76c |
Socket6->import(qw(pack_sockaddr_in6 inet_pton getaddrinfo));
|
|
Packit |
667938 |
$ipv6_addr_len = length(pack_sockaddr_in6(161, inet_pton(AF_INET6(), "::1")));
|
|
Packit |
667938 |
$SNMP_Session::ipv6available = 1;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
eval 'local $SIG{__DIE__};local $SIG{__WARN__};$dont_wait_flags = MSG_DONTWAIT();';
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my $the_socket;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$SNMP_Session::errmsg = '';
|
|
Packit |
667938 |
$SNMP_Session::suppress_warnings = 0;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub get_request { 0 | context_flag () };
|
|
Packit |
667938 |
sub getnext_request { 1 | context_flag () };
|
|
Packit |
667938 |
sub get_response { 2 | context_flag () };
|
|
Packit |
667938 |
sub set_request { 3 | context_flag () };
|
|
Packit |
667938 |
sub trap_request { 4 | context_flag () };
|
|
Packit |
667938 |
sub getbulk_request { 5 | context_flag () };
|
|
Packit |
667938 |
sub inform_request { 6 | context_flag () };
|
|
Packit |
667938 |
sub trap2_request { 7 | context_flag () };
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub standard_udp_port { 161 };
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub open
|
|
Packit |
667938 |
{
|
|
Packit |
667938 |
return SNMPv1_Session::open (@_);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub timeout { $_[0]->{timeout} }
|
|
Packit |
667938 |
sub retries { $_[0]->{retries} }
|
|
Packit |
667938 |
sub backoff { $_[0]->{backoff} }
|
|
Packit |
667938 |
sub set_timeout {
|
|
Packit |
667938 |
my ($session, $timeout) = @_;
|
|
Packit |
667938 |
croak ("timeout ($timeout) must be a positive number") unless $timeout > 0.0;
|
|
Packit |
667938 |
$session->{'timeout'} = $timeout;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
sub set_retries {
|
|
Packit |
667938 |
my ($session, $retries) = @_;
|
|
Packit |
667938 |
croak ("retries ($retries) must be a non-negative integer")
|
|
Packit |
667938 |
unless $retries == int ($retries) && $retries >= 0;
|
|
Packit |
667938 |
$session->{'retries'} = $retries;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
sub set_backoff {
|
|
Packit |
667938 |
my ($session, $backoff) = @_;
|
|
Packit |
667938 |
croak ("backoff ($backoff) must be a number >= 1.0")
|
|
Packit |
667938 |
unless $backoff == int ($backoff) && $backoff >= 1.0;
|
|
Packit |
667938 |
$session->{'backoff'} = $backoff;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub encode_request_3 ($$$@) {
|
|
Packit |
667938 |
my($this, $reqtype, $encoded_oids_or_pairs, $i1, $i2) = @_;
|
|
Packit |
667938 |
my($request);
|
|
Packit |
667938 |
local($_);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$this->{request_id} = ($this->{request_id} == 0x7fffffff)
|
|
Packit |
667938 |
? -0x80000000 : $this->{request_id}+1;
|
|
Packit |
667938 |
$this->{request_id} += 0x80000000
|
|
Packit |
667938 |
if ($this->{avoid_negative_request_ids} && $this->{request_id} < 0);
|
|
Packit |
667938 |
$this->{request_id} &= 0x0000ffff
|
|
Packit |
667938 |
if ($this->{use_16bit_request_ids});
|
|
Packit |
667938 |
foreach $_ (@{$encoded_oids_or_pairs}) {
|
|
Packit |
667938 |
if (ref ($_) eq 'ARRAY') {
|
|
Packit |
667938 |
$_ = &encode_sequence ($_->[0], $_->[1])
|
|
Packit |
667938 |
|| return $this->ber_error ("encoding pair");
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
$_ = &encode_sequence ($_, encode_null())
|
|
Packit |
667938 |
|| return $this->ber_error ("encoding value/null pair");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
$request = encode_tagged_sequence
|
|
Packit |
667938 |
($reqtype,
|
|
Packit |
667938 |
encode_int ($this->{request_id}),
|
|
Packit |
667938 |
defined $i1 ? encode_int ($i1) : encode_int_0 (),
|
|
Packit |
667938 |
defined $i2 ? encode_int ($i2) : encode_int_0 (),
|
|
Packit |
667938 |
encode_sequence (@{$encoded_oids_or_pairs}))
|
|
Packit |
667938 |
|| return $this->ber_error ("encoding request PDU");
|
|
Packit |
667938 |
return $this->wrap_request ($request);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub encode_get_request {
|
|
Packit |
667938 |
my($this, @oids) = @_;
|
|
Packit |
667938 |
return encode_request_3 ($this, get_request, \@oids);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub encode_getnext_request {
|
|
Packit |
667938 |
my($this, @oids) = @_;
|
|
Packit |
667938 |
return encode_request_3 ($this, getnext_request, \@oids);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub encode_getbulk_request {
|
|
Packit |
667938 |
my($this, $non_repeaters, $max_repetitions, @oids) = @_;
|
|
Packit |
667938 |
return encode_request_3 ($this, getbulk_request, \@oids,
|
|
Packit |
667938 |
$non_repeaters, $max_repetitions);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub encode_set_request {
|
|
Packit |
667938 |
my($this, @encoded_pairs) = @_;
|
|
Packit |
667938 |
return encode_request_3 ($this, set_request, \@encoded_pairs);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub encode_trap_request ($$$$$$@) {
|
|
Packit |
667938 |
my($this, $ent, $agent, $gen, $spec, $dt, @pairs) = @_;
|
|
Packit |
667938 |
my($request);
|
|
Packit |
667938 |
local($_);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
foreach $_ (@pairs) {
|
|
Packit |
667938 |
if (ref ($_) eq 'ARRAY') {
|
|
Packit |
667938 |
$_ = &encode_sequence ($_->[0], $_->[1])
|
|
Packit |
667938 |
|| return $this->ber_error ("encoding pair");
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
$_ = &encode_sequence ($_, encode_null())
|
|
Packit |
667938 |
|| return $this->ber_error ("encoding value/null pair");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
$request = encode_tagged_sequence
|
|
Packit |
667938 |
(trap_request, $ent, $agent, $gen, $spec, $dt, encode_sequence (@pairs))
|
|
Packit |
667938 |
|| return $this->ber_error ("encoding trap PDU");
|
|
Packit |
667938 |
return $this->wrap_request ($request);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub encode_v2_trap_request ($@) {
|
|
Packit |
667938 |
my($this, @pairs) = @_;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
return encode_request_3($this, trap2_request, \@pairs);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub decode_get_response {
|
|
Packit |
667938 |
my($this, $response) = @_;
|
|
Packit |
667938 |
my @rest;
|
|
Packit |
667938 |
@{$this->{'unwrapped'}};
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub decode_trap_request ($$) {
|
|
Packit |
667938 |
my ($this, $trap) = @_;
|
|
Packit |
667938 |
my ($snmp_version, $community, $ent, $agent, $gen, $spec, $dt,
|
|
Packit |
667938 |
$request_id, $error_status, $error_index,
|
|
Packit |
667938 |
$bindings);
|
|
Packit |
667938 |
($snmp_version, $community,
|
|
Packit |
667938 |
$ent, $agent,
|
|
Packit |
667938 |
$gen, $spec, $dt,
|
|
Packit |
667938 |
$bindings)
|
|
Packit |
667938 |
= decode_by_template ($trap, "%{%i%s%*{%O%A%i%i%u%{%@",
|
|
Packit |
667938 |
trap_request);
|
|
Packit |
667938 |
if (!defined $snmp_version) {
|
|
Packit |
667938 |
($snmp_version, $community,
|
|
Packit |
667938 |
$request_id, $error_status, $error_index,
|
|
Packit |
667938 |
$bindings)
|
|
Packit |
667938 |
= decode_by_template ($trap, "%{%i%s%*{%i%i%i%{%@",
|
|
Packit |
667938 |
trap2_request);
|
|
Packit |
667938 |
if (!defined $snmp_version) {
|
|
Packit |
667938 |
($snmp_version, $community,$request_id, $error_status, $error_index, $bindings)
|
|
Packit |
667938 |
= decode_by_template ($trap, "%{%i%s%*{%i%i%i%{%@", inform_request);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
return $this->error_return ("v2 trap/inform request contained errorStatus/errorIndex "
|
|
Packit |
667938 |
.$error_status."/".$error_index)
|
|
Packit |
667938 |
if defined $error_status && defined $error_index
|
|
Packit |
667938 |
&& ($error_status != 0 || $error_index != 0);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
if (!defined $snmp_version) {
|
|
Packit |
667938 |
return $this->error_return ("BER error decoding trap:\n ".$BER::errmsg);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
return ($community, $ent, $agent, $gen, $spec, $dt, $bindings);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub wait_for_response {
|
|
Packit |
667938 |
my($this) = shift;
|
|
Packit |
667938 |
my($timeout) = shift || 10.0;
|
|
Packit |
667938 |
my($rin,$win,$ein) = ('','','');
|
|
Packit |
667938 |
my($rout,$wout,$eout);
|
|
Packit |
667938 |
vec($rin,$this->sockfileno,1) = 1;
|
|
Packit |
667938 |
select($rout=$rin,$wout=$win,$eout=$ein,$timeout);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub get_request_response ($@) {
|
|
Packit |
667938 |
my($this, @oids) = @_;
|
|
Packit |
667938 |
return $this->request_response_5 ($this->encode_get_request (@oids),
|
|
Packit |
667938 |
get_response, \@oids, 1);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub set_request_response ($@) {
|
|
Packit |
667938 |
my($this, @pairs) = @_;
|
|
Packit |
667938 |
return $this->request_response_5 ($this->encode_set_request (@pairs),
|
|
Packit |
667938 |
get_response, \@pairs, 1);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub getnext_request_response ($@) {
|
|
Packit |
667938 |
my($this,@oids) = @_;
|
|
Packit |
667938 |
return $this->request_response_5 ($this->encode_getnext_request (@oids),
|
|
Packit |
667938 |
get_response, \@oids, 1);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub getbulk_request_response ($$$@) {
|
|
Packit |
667938 |
my($this,$non_repeaters,$max_repetitions,@oids) = @_;
|
|
Packit |
667938 |
return $this->request_response_5
|
|
Packit |
667938 |
($this->encode_getbulk_request ($non_repeaters,$max_repetitions,@oids),
|
|
Packit |
667938 |
get_response, \@oids, 1);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub trap_request_send ($$$$$$@) {
|
|
Packit |
667938 |
my($this, $ent, $agent, $gen, $spec, $dt, @pairs) = @_;
|
|
Packit |
667938 |
my($req);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$req = $this->encode_trap_request ($ent, $agent, $gen, $spec, $dt, @pairs);
|
|
Packit |
667938 |
## Encoding may have returned an error.
|
|
Packit |
667938 |
return undef unless defined $req;
|
|
Packit |
667938 |
$this->send_query($req)
|
|
Packit |
667938 |
|| return $this->error ("send_trap: $!");
|
|
Packit |
667938 |
return 1;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub v2_trap_request_send ($$$@) {
|
|
Packit |
667938 |
my($this, $trap_oid, $dt, @pairs) = @_;
|
|
Packit |
667938 |
my @sysUptime_OID = ( 1,3,6,1,2,1,1,3 );
|
|
Packit |
667938 |
my @snmpTrapOID_OID = ( 1,3,6,1,6,3,1,1,4,1 );
|
|
Packit |
667938 |
my($req);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
unshift @pairs, [encode_oid (@snmpTrapOID_OID,0),
|
|
Packit |
667938 |
encode_oid (@{$trap_oid})];
|
|
Packit |
667938 |
unshift @pairs, [encode_oid (@sysUptime_OID,0),
|
|
Packit |
667938 |
encode_timeticks ($dt)];
|
|
Packit |
667938 |
$req = $this->encode_v2_trap_request (@pairs);
|
|
Packit |
667938 |
## Encoding may have returned an error.
|
|
Packit |
667938 |
return undef unless defined $req;
|
|
Packit |
667938 |
$this->send_query($req)
|
|
Packit |
667938 |
|| return $this->error ("send_trap: $!");
|
|
Packit |
667938 |
return 1;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub request_response_5 ($$$$$) {
|
|
Packit |
667938 |
my ($this, $req, $response_tag, $oids, $errorp) = @_;
|
|
Packit |
667938 |
my $retries = $this->retries;
|
|
Packit |
667938 |
my $timeout = $this->timeout;
|
|
Packit |
667938 |
my ($nfound, $timeleft);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
## Encoding may have returned an error.
|
|
Packit |
667938 |
return undef unless defined $req;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$timeleft = $timeout;
|
|
Packit |
667938 |
while ($retries > 0) {
|
|
Packit |
667938 |
$this->send_query ($req)
|
|
Packit |
667938 |
|| return $this->error ("send_query: $!");
|
|
Packit |
667938 |
# IlvJa
|
|
Packit |
667938 |
# Add request pdu to capture_buffer
|
|
Packit |
667938 |
push @{$this->{'capture_buffer'}}, $req
|
|
Packit |
667938 |
if (defined $this->{'capture_buffer'}
|
|
Packit |
667938 |
and ref $this->{'capture_buffer'} eq 'ARRAY');
|
|
Packit |
667938 |
#
|
|
Packit |
667938 |
wait_for_response:
|
|
Packit |
667938 |
($nfound, $timeleft) = $this->wait_for_response($timeleft);
|
|
Packit |
667938 |
if ($nfound > 0) {
|
|
Packit |
667938 |
my($response_length);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$response_length
|
|
Packit |
667938 |
= $this->receive_response_3 ($response_tag, $oids, $errorp, 1);
|
|
Packit |
667938 |
if ($response_length) {
|
|
Packit |
667938 |
# IlvJa
|
|
Packit |
667938 |
# Add response pdu to capture_buffer
|
|
Packit |
667938 |
push (@{$this->{'capture_buffer'}},
|
|
Packit |
667938 |
substr($this->{'pdu_buffer'}, 0, $response_length)
|
|
Packit |
667938 |
)
|
|
Packit |
667938 |
if (defined $this->{'capture_buffer'}
|
|
Packit |
667938 |
and ref $this->{'capture_buffer'} eq 'ARRAY');
|
|
Packit |
667938 |
#
|
|
Packit |
667938 |
return $response_length;
|
|
Packit |
667938 |
} elsif (defined ($response_length)) {
|
|
Packit |
667938 |
goto wait_for_response;
|
|
Packit |
667938 |
# A response has been received, but for a different
|
|
Packit |
667938 |
# request ID or from a different IP address.
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
return undef;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
## No response received - retry
|
|
Packit |
667938 |
--$retries;
|
|
Packit |
667938 |
$timeout *= $this->backoff;
|
|
Packit |
667938 |
$timeleft = $timeout;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
# IlvJa
|
|
Packit |
667938 |
# Add empty packet to capture_buffer
|
|
Packit |
667938 |
push @{$this->{'capture_buffer'}}, ""
|
|
Packit |
667938 |
if (defined $this->{'capture_buffer'}
|
|
Packit |
667938 |
and ref $this->{'capture_buffer'} eq 'ARRAY');
|
|
Packit |
667938 |
#
|
|
Packit |
667938 |
$this->error ("no response received");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub map_table ($$$) {
|
|
Packit |
667938 |
my ($session, $columns, $mapfn) = @_;
|
|
Packit |
667938 |
return $session->map_table_4 ($columns, $mapfn,
|
|
Packit |
667938 |
$session->default_max_repetitions ());
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub map_table_4 ($$$$) {
|
|
Packit |
667938 |
my ($session, $columns, $mapfn, $max_repetitions) = @_;
|
|
Packit |
667938 |
return $session->map_table_start_end ($columns, $mapfn,
|
|
Packit |
667938 |
"", undef,
|
|
Packit |
667938 |
$max_repetitions);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub map_table_start_end ($$$$$$) {
|
|
Packit |
667938 |
my ($session, $columns, $mapfn, $start, $end, $max_repetitions) = @_;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my @encoded_oids;
|
|
Packit |
667938 |
my $call_counter = 0;
|
|
Packit |
667938 |
my $base_index = $start;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
do {
|
|
Packit |
667938 |
foreach (@encoded_oids = @{$columns}) {
|
|
Packit |
667938 |
$_=encode_oid (@{$_},split '\.',$base_index)
|
|
Packit |
667938 |
|| return $session->ber_error ("encoding OID $base_index");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
if ($session->getnext_request_response (@encoded_oids)) {
|
|
Packit |
667938 |
my $response = $session->pdu_buffer;
|
|
Packit |
667938 |
my ($bindings) = $session->decode_get_response ($response);
|
|
Packit |
667938 |
my $smallest_index = undef;
|
|
Packit |
667938 |
my @collected_values = ();
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my @bases = @{$columns};
|
|
Packit |
667938 |
while ($bindings ne '') {
|
|
Packit |
667938 |
my ($binding, $oid, $value);
|
|
Packit |
667938 |
my $base = shift @bases;
|
|
Packit |
667938 |
($binding, $bindings) = decode_sequence ($bindings);
|
|
Packit |
667938 |
($oid, $value) = decode_by_template ($binding, "%O%@");
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my $out_index;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$out_index = &oid_diff ($base, $oid);
|
|
Packit |
667938 |
my $cmp;
|
|
Packit |
667938 |
if (!defined $smallest_index
|
|
Packit |
667938 |
|| ($cmp = index_compare ($out_index,$smallest_index)) == -1) {
|
|
Packit |
667938 |
$smallest_index = $out_index;
|
|
Packit |
667938 |
grep ($_=undef, @collected_values);
|
|
Packit |
667938 |
push @collected_values, $value;
|
|
Packit |
667938 |
} elsif ($cmp == 1) {
|
|
Packit |
667938 |
push @collected_values, undef;
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
push @collected_values, $value;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
(++$call_counter,
|
|
Packit |
667938 |
&$mapfn ($smallest_index, @collected_values))
|
|
Packit |
667938 |
if defined $smallest_index;
|
|
Packit |
667938 |
$base_index = $smallest_index;
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
return undef;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
while (defined $base_index
|
|
Packit |
667938 |
&& (!defined $end || index_compare ($base_index, $end) < 0));
|
|
Packit |
667938 |
$call_counter;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub index_compare ($$) {
|
|
Packit |
667938 |
my ($i1, $i2) = @_;
|
|
Packit |
667938 |
$i1 = '' unless defined $i1;
|
|
Packit |
667938 |
$i2 = '' unless defined $i2;
|
|
Packit |
667938 |
if ($i1 eq '') {
|
|
Packit |
667938 |
return $i2 eq '' ? 0 : 1;
|
|
Packit |
667938 |
} elsif ($i2 eq '') {
|
|
Packit |
667938 |
return 1;
|
|
Packit |
667938 |
} elsif (!$i1) {
|
|
Packit |
667938 |
return $i2 eq '' ? 1 : !$i2 ? 0 : 1;
|
|
Packit |
667938 |
} elsif (!$i2) {
|
|
Packit |
667938 |
return -1;
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
my ($f1,$r1) = split('\.',$i1,2);
|
|
Packit |
667938 |
my ($f2,$r2) = split('\.',$i2,2);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if ($f1 < $f2) {
|
|
Packit |
667938 |
return -1;
|
|
Packit |
667938 |
} elsif ($f1 > $f2) {
|
|
Packit |
667938 |
return 1;
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
return index_compare ($r1,$r2);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub oid_diff ($$) {
|
|
Packit |
667938 |
my($base, $full) = @_;
|
|
Packit |
667938 |
my $base_dotnot = join ('.',@{$base});
|
|
Packit |
667938 |
my $full_dotnot = BER::pretty_oid ($full);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
return undef unless substr ($full_dotnot, 0, length $base_dotnot)
|
|
Packit |
667938 |
eq $base_dotnot
|
|
Packit |
667938 |
&& substr ($full_dotnot, length $base_dotnot, 1) eq '.';
|
|
Packit |
667938 |
substr ($full_dotnot, length ($base_dotnot)+1);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
# Pretty_address returns a human-readable representation of an IPv4 or IPv6 address.
|
|
Packit |
667938 |
sub pretty_address {
|
|
Packit |
667938 |
my($addr) = shift;
|
|
Packit |
667938 |
my($port, $addrunpack, $addrstr);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
# Disable strict subs to stop old versions of perl from
|
|
Packit |
667938 |
# complaining about AF_INET6 when Socket6 is not available
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if( (defined $ipv6_addr_len) && (length $addr == $ipv6_addr_len)) {
|
|
Packit |
667938 |
($port,$addrunpack) = Socket6::unpack_sockaddr_in6 ($addr);
|
|
Packit |
667938 |
$addrstr = inet_ntop (AF_INET6(), $addrunpack);
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
($port,$addrunpack) = unpack_sockaddr_in ($addr);
|
|
Packit |
667938 |
$addrstr = inet_ntoa ($addrunpack);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
return sprintf ("[%s].%d", $addrstr, $port);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub version { $VERSION; }
|
|
Packit |
667938 |
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub error_return ($$) {
|
|
Packit |
667938 |
my ($this,$message) = @_;
|
|
Packit |
667938 |
$SNMP_Session::errmsg = $message;
|
|
Packit |
667938 |
unless ($SNMP_Session::suppress_warnings) {
|
|
Packit |
667938 |
$message =~ s/^/ /mg;
|
|
Packit |
667938 |
carp ("Error:\n".$message."\n");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
return undef;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub error ($$) {
|
|
Packit |
667938 |
my ($this,$message) = @_;
|
|
Packit |
667938 |
my $session = $this->to_string;
|
|
Packit |
667938 |
$SNMP_Session::errmsg = $message."\n".$session;
|
|
Packit |
667938 |
unless ($SNMP_Session::suppress_warnings) {
|
|
Packit |
667938 |
$session =~ s/^/ /mg;
|
|
Packit |
667938 |
$message =~ s/^/ /mg;
|
|
Packit |
667938 |
carp ("SNMP Error:\n".$SNMP_Session::errmsg."\n");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
return undef;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub ber_error ($$) {
|
|
Packit |
667938 |
my ($this,$type) = @_;
|
|
Packit |
667938 |
my ($errmsg) = $BER::errmsg;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$errmsg =~ s/^/ /mg;
|
|
Packit |
667938 |
return $this->error ("$type:\n$errmsg");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
package SNMPv1_Session;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
use strict qw(vars subs); # see above
|
|
Packit |
667938 |
use vars qw(@ISA);
|
|
Packit |
667938 |
use SNMP_Session;
|
|
Packit |
667938 |
use Socket;
|
|
Packit |
667938 |
use BER;
|
|
Packit |
667938 |
use IO::Socket;
|
|
Packit |
667938 |
use Carp;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
BEGIN {
|
|
Packit |
667938 |
if($SNMP_Session::ipv6available) {
|
|
Packit |
667938 |
import IO::Socket::INET6;
|
|
Packit Service |
41e76c |
Socket6->import(qw(pack_sockaddr_in6 inet_pton getaddrinfo));
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
@ISA = qw(SNMP_Session);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub snmp_version { 0 }
|
|
Packit |
667938 |
|
|
Packit |
667938 |
# Supports both IPv4 and IPv6.
|
|
Packit |
667938 |
# Numeric IPv6 addresses must be passed between square brackets []
|
|
Packit |
667938 |
sub open {
|
|
Packit |
667938 |
my($this,
|
|
Packit |
667938 |
$remote_hostname,$community,$port,
|
|
Packit |
667938 |
$max_pdu_len,$local_port,$max_repetitions,
|
|
Packit |
667938 |
$local_hostname,$ipv4only) = @_;
|
|
Packit |
667938 |
my($remote_addr,$socket,$sockfamily);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$ipv4only = 1 unless defined $ipv4only;
|
|
Packit |
667938 |
$sockfamily = AF_INET;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$community = 'public' unless defined $community;
|
|
Packit |
667938 |
$port = SNMP_Session::standard_udp_port unless defined $port;
|
|
Packit |
667938 |
$max_pdu_len = 8000 unless defined $max_pdu_len;
|
|
Packit |
667938 |
$max_repetitions = $default_max_repetitions
|
|
Packit |
667938 |
unless defined $max_repetitions;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if ($ipv4only || ! $SNMP_Session::ipv6available) {
|
|
Packit |
667938 |
# IPv4-only code, uses only Socket and INET calls
|
|
Packit |
667938 |
if (defined $remote_hostname) {
|
|
Packit |
667938 |
$remote_addr = inet_aton ($remote_hostname)
|
|
Packit |
667938 |
or return $this->error_return ("can't resolve \"$remote_hostname\" to IP address");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
if ($SNMP_Session::recycle_socket && defined $the_socket) {
|
|
Packit |
667938 |
$socket = $the_socket;
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
$socket = IO::Socket::INET->new(Proto => 17,
|
|
Packit |
667938 |
Type => SOCK_DGRAM,
|
|
Packit |
667938 |
LocalAddr => $local_hostname,
|
|
Packit |
667938 |
LocalPort => $local_port)
|
|
Packit |
667938 |
|| return $this->error_return ("creating socket: $!");
|
|
Packit |
667938 |
$the_socket = $socket
|
|
Packit |
667938 |
if $SNMP_Session::recycle_socket;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
$remote_addr = pack_sockaddr_in ($port, $remote_addr)
|
|
Packit |
667938 |
if defined $remote_addr;
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
# IPv6-capable code. Will use IPv6 or IPv4 depending on the address.
|
|
Packit |
667938 |
# Uses Socket6 and INET6 calls.
|
|
Packit |
667938 |
|
|
Packit |
667938 |
# If it's a numeric IPv6 addresses, remove square brackets
|
|
Packit |
667938 |
if ($remote_hostname =~ /^\[(.*)\]$/) {
|
|
Packit |
667938 |
$remote_hostname = $1;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my (@res, $socktype_tmp, $proto_tmp, $canonname_tmp);
|
|
Packit |
667938 |
@res = getaddrinfo($remote_hostname, $port, AF_UNSPEC, SOCK_DGRAM);
|
|
Packit |
667938 |
($sockfamily, $socktype_tmp, $proto_tmp, $remote_addr, $canonname_tmp) = @res;
|
|
Packit |
667938 |
if (scalar(@res) < 5) {
|
|
Packit |
667938 |
return $this->error_return ("can't resolve \"$remote_hostname\" to IPv6 address");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if ($SNMP_Session::recycle_socket && defined $the_socket) {
|
|
Packit |
667938 |
$socket = $the_socket;
|
|
Packit |
667938 |
} elsif ($sockfamily == AF_INET) {
|
|
Packit |
667938 |
$socket = IO::Socket::INET->new(Proto => 17,
|
|
Packit |
667938 |
Type => SOCK_DGRAM,
|
|
Packit |
667938 |
LocalAddr => $local_hostname,
|
|
Packit |
667938 |
LocalPort => $local_port)
|
|
Packit |
667938 |
|| return $this->error_return ("creating socket: $!");
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
$socket = IO::Socket::INET6->new(Proto => 17,
|
|
Packit |
667938 |
Type => SOCK_DGRAM,
|
|
Packit |
667938 |
LocalAddr => $local_hostname,
|
|
Packit |
667938 |
LocalPort => $local_port)
|
|
Packit |
667938 |
|| return $this->error_return ("creating socket: $!");
|
|
Packit |
667938 |
$the_socket = $socket
|
|
Packit |
667938 |
if $SNMP_Session::recycle_socket;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
bless {
|
|
Packit |
667938 |
'sock' => $socket,
|
|
Packit |
667938 |
'sockfileno' => fileno ($socket),
|
|
Packit |
667938 |
'community' => $community,
|
|
Packit |
667938 |
'remote_hostname' => $remote_hostname,
|
|
Packit |
667938 |
'remote_addr' => $remote_addr,
|
|
Packit |
667938 |
'sockfamily' => $sockfamily,
|
|
Packit |
667938 |
'max_pdu_len' => $max_pdu_len,
|
|
Packit |
667938 |
'pdu_buffer' => '\0' x $max_pdu_len,
|
|
Packit |
667938 |
'request_id' => (int (rand 0x10000) << 16)
|
|
Packit |
667938 |
+ int (rand 0x10000) - 0x80000000,
|
|
Packit |
667938 |
'timeout' => $default_timeout,
|
|
Packit |
667938 |
'retries' => $default_retries,
|
|
Packit |
667938 |
'backoff' => $default_backoff,
|
|
Packit |
667938 |
'debug' => $default_debug,
|
|
Packit |
667938 |
'error_status' => 0,
|
|
Packit |
667938 |
'error_index' => 0,
|
|
Packit |
667938 |
'default_max_repetitions' => $max_repetitions,
|
|
Packit |
667938 |
'use_getbulk' => 1,
|
|
Packit |
667938 |
'lenient_source_address_matching' => 1,
|
|
Packit |
667938 |
'lenient_source_port_matching' => 1,
|
|
Packit |
667938 |
'avoid_negative_request_ids' => $SNMP_Session::default_avoid_negative_request_ids,
|
|
Packit |
667938 |
'use_16bit_request_ids' => $SNMP_Session::default_use_16bit_request_ids,
|
|
Packit |
667938 |
'capture_buffer' => undef,
|
|
Packit |
667938 |
};
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub open_trap_session (@) {
|
|
Packit |
667938 |
my ($this, $port) = @_;
|
|
Packit |
667938 |
$port = 162 unless defined $port;
|
|
Packit |
667938 |
return $this->open (undef, "", 161, undef, $port);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub sock { $_[0]->{sock} }
|
|
Packit |
667938 |
sub sockfileno { $_[0]->{sockfileno} }
|
|
Packit |
667938 |
sub remote_addr { $_[0]->{remote_addr} }
|
|
Packit |
667938 |
sub pdu_buffer { $_[0]->{pdu_buffer} }
|
|
Packit |
667938 |
sub max_pdu_len { $_[0]->{max_pdu_len} }
|
|
Packit |
667938 |
sub default_max_repetitions {
|
|
Packit |
667938 |
defined $_[1]
|
|
Packit |
667938 |
? $_[0]->{default_max_repetitions} = $_[1]
|
|
Packit |
667938 |
: $_[0]->{default_max_repetitions} }
|
|
Packit |
667938 |
sub debug { defined $_[1] ? $_[0]->{debug} = $_[1] : $_[0]->{debug} }
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub close {
|
|
Packit |
667938 |
my($this) = shift;
|
|
Packit |
667938 |
## Avoid closing the socket if it may be shared with other session
|
|
Packit |
667938 |
## objects.
|
|
Packit |
667938 |
if (! defined $the_socket || $this->sock ne $the_socket) {
|
|
Packit |
667938 |
close ($this->sock) || $this->error ("close: $!");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub wrap_request {
|
|
Packit |
667938 |
my($this) = shift;
|
|
Packit |
667938 |
my($request) = shift;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
encode_sequence (encode_int ($this->snmp_version),
|
|
Packit |
667938 |
encode_string ($this->{community}),
|
|
Packit |
667938 |
$request)
|
|
Packit |
667938 |
|| return $this->ber_error ("wrapping up request PDU");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my @error_status_code = qw(noError tooBig noSuchName badValue readOnly
|
|
Packit |
667938 |
genErr noAccess wrongType wrongLength
|
|
Packit |
667938 |
wrongEncoding wrongValue noCreation
|
|
Packit |
667938 |
inconsistentValue resourceUnavailable
|
|
Packit |
667938 |
commitFailed undoFailed authorizationError
|
|
Packit |
667938 |
notWritable inconsistentName);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub unwrap_response_5b {
|
|
Packit |
667938 |
my ($this,$response,$tag,$oids,$errorp) = @_;
|
|
Packit |
667938 |
my ($community,$request_id,@rest,$snmpver);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
($snmpver,$community,$request_id,
|
|
Packit |
667938 |
$this->{error_status},
|
|
Packit |
667938 |
$this->{error_index},
|
|
Packit |
667938 |
@rest)
|
|
Packit |
667938 |
= decode_by_template ($response, "%{%i%s%*{%i%i%i%{%@",
|
|
Packit |
667938 |
$tag);
|
|
Packit |
667938 |
return $this->ber_error ("Error decoding response PDU")
|
|
Packit |
667938 |
unless defined $snmpver;
|
|
Packit |
667938 |
return $this->error ("Received SNMP response with unknown snmp-version field $snmpver")
|
|
Packit |
667938 |
unless $snmpver == $this->snmp_version;
|
|
Packit |
667938 |
if ($this->{error_status} != 0) {
|
|
Packit |
667938 |
if ($errorp) {
|
|
Packit |
667938 |
my ($oid, $errmsg);
|
|
Packit |
667938 |
$errmsg = $error_status_code[$this->{error_status}] || $this->{error_status};
|
|
Packit |
667938 |
$oid = $oids->[$this->{error_index}-1]
|
|
Packit |
667938 |
if $this->{error_index} > 0 && $this->{error_index}-1 <= $#{$oids};
|
|
Packit |
667938 |
$oid = $oid->[0]
|
|
Packit |
667938 |
if ref($oid) eq 'ARRAY';
|
|
Packit |
667938 |
return ($community, $request_id,
|
|
Packit |
667938 |
$this->error ("Received SNMP response with error code\n"
|
|
Packit |
667938 |
." error status: $errmsg\n"
|
|
Packit |
667938 |
." index ".$this->{error_index}
|
|
Packit |
667938 |
.(defined $oid
|
|
Packit |
667938 |
? " (OID: ".&BER::pretty_oid($oid).")"
|
|
Packit |
667938 |
: "")));
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
if ($this->{error_index} == 1) {
|
|
Packit |
667938 |
@rest[$this->{error_index}-1..$this->{error_index}] = ();
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
($community, $request_id, @rest);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub send_query ($$) {
|
|
Packit |
667938 |
my ($this,$query) = @_;
|
|
Packit |
667938 |
send ($this->sock,$query,0,$this->remote_addr);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
## Compare two sockaddr_in structures for equality. This is used when
|
|
Packit |
667938 |
## matching incoming responses with outstanding requests. Previous
|
|
Packit |
667938 |
## versions of the code simply did a bytewise comparison ("eq") of the
|
|
Packit |
667938 |
## two sockaddr_in structures, but this didn't work on some systems
|
|
Packit |
667938 |
## where sockaddr_in contains other elements than just the IP address
|
|
Packit |
667938 |
## and port number, notably FreeBSD.
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
## We allow for varying degrees of leniency when checking the source
|
|
Packit |
667938 |
## address. By default we now ignore it altogether, because there are
|
|
Packit |
667938 |
## agents that don't respond from UDP port 161, and there are agents
|
|
Packit |
667938 |
## that don't respond from the IP address the query had been sent to.
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
## The address family is stored in the session object. We could use
|
|
Packit |
667938 |
## sockaddr_family() to determine it from the sockaddr, but this function
|
|
Packit |
667938 |
## is only available in recent versions of Socket.pm.
|
|
Packit |
667938 |
sub sa_equal_p ($$$) {
|
|
Packit |
667938 |
my ($this, $sa1, $sa2) = @_;
|
|
Packit |
667938 |
my ($p1,$a1,$p2,$a2);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
# Disable strict subs to stop old versions of perl from
|
|
Packit |
667938 |
# complaining about AF_INET6 when Socket6 is not available
|
|
Packit |
667938 |
if($this->{'sockfamily'} == AF_INET) {
|
|
Packit |
667938 |
# IPv4 addresses
|
|
Packit |
667938 |
($p1,$a1) = unpack_sockaddr_in ($sa1);
|
|
Packit |
667938 |
($p2,$a2) = unpack_sockaddr_in ($sa2);
|
|
Packit |
667938 |
} elsif($this->{'sockfamily'} == AF_INET6()) {
|
|
Packit |
667938 |
# IPv6 addresses
|
|
Packit |
667938 |
($p1,$a1) = Socket6::unpack_sockaddr_in6 ($sa1);
|
|
Packit |
667938 |
($p2,$a2) = Socket6::unpack_sockaddr_in6 ($sa2);
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
return 0;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
use strict "subs";
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if (! $this->{'lenient_source_address_matching'}) {
|
|
Packit |
667938 |
return 0 if $a1 ne $a2;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
if (! $this->{'lenient_source_port_matching'}) {
|
|
Packit |
667938 |
return 0 if $p1 != $p2;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
return 1;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub receive_response_3 {
|
|
Packit |
667938 |
my ($this, $response_tag, $oids, $errorp, $dont_block_p) = @_;
|
|
Packit |
667938 |
my ($remote_addr);
|
|
Packit |
667938 |
my $flags = 0;
|
|
Packit |
667938 |
$flags = $dont_wait_flags if defined $dont_block_p and $dont_block_p;
|
|
Packit |
667938 |
$remote_addr = recv ($this->sock,$this->{'pdu_buffer'},$this->max_pdu_len,$flags);
|
|
Packit |
667938 |
return $this->error ("receiving response PDU: $!")
|
|
Packit |
667938 |
unless defined $remote_addr;
|
|
Packit |
667938 |
return $this->error ("short (".length $this->{'pdu_buffer'}
|
|
Packit |
667938 |
." bytes) response PDU")
|
|
Packit |
667938 |
unless length $this->{'pdu_buffer'} > 2;
|
|
Packit |
667938 |
my $response = $this->{'pdu_buffer'};
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
## Check whether the response came from the address we've sent the
|
|
Packit |
667938 |
## request to. If this is not the case, we should probably ignore
|
|
Packit |
667938 |
## it, as it may relate to another request.
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
if (defined $this->{'remote_addr'}) {
|
|
Packit |
667938 |
if (! $this->sa_equal_p ($remote_addr, $this->{'remote_addr'})) {
|
|
Packit |
667938 |
if ($this->{'debug'} && !$SNMP_Session::recycle_socket) {
|
|
Packit |
667938 |
carp ("Response came from ".&SNMP_Session::pretty_address($remote_addr)
|
|
Packit |
667938 |
.", not ".&SNMP_Session::pretty_address($this->{'remote_addr'}))
|
|
Packit |
667938 |
unless $SNMP_Session::suppress_warnings;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
return 0;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
$this->{'last_sender_addr'} = $remote_addr;
|
|
Packit |
667938 |
my ($response_community, $response_id, @unwrapped)
|
|
Packit |
667938 |
= $this->unwrap_response_5b ($response, $response_tag,
|
|
Packit |
667938 |
$oids, $errorp);
|
|
Packit |
667938 |
if ($response_community ne $this->{community}
|
|
Packit |
667938 |
|| $response_id ne $this->{request_id}) {
|
|
Packit |
667938 |
if ($this->{'debug'}) {
|
|
Packit |
667938 |
carp ("$response_community != $this->{community}")
|
|
Packit |
667938 |
unless $SNMP_Session::suppress_warnings
|
|
Packit |
667938 |
|| $response_community eq $this->{community};
|
|
Packit |
667938 |
carp ("$response_id != $this->{request_id}")
|
|
Packit |
667938 |
unless $SNMP_Session::suppress_warnings
|
|
Packit |
667938 |
|| $response_id == $this->{request_id};
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
return 0;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
if (!defined $unwrapped[0]) {
|
|
Packit |
667938 |
$this->{'unwrapped'} = undef;
|
|
Packit |
667938 |
return undef;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
$this->{'unwrapped'} = \@unwrapped;
|
|
Packit |
667938 |
return length $this->pdu_buffer;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub receive_trap {
|
|
Packit |
667938 |
my ($this) = @_;
|
|
Packit |
667938 |
my ($remote_addr, $iaddr, $port, $trap);
|
|
Packit |
667938 |
$remote_addr = recv ($this->sock,$this->{'pdu_buffer'},$this->max_pdu_len,0);
|
|
Packit |
667938 |
return undef unless $remote_addr;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if( (defined $ipv6_addr_len) && (length $remote_addr == $ipv6_addr_len)) {
|
|
Packit |
667938 |
($port,$iaddr) = Socket6::unpack_sockaddr_in6($remote_addr);
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
($port,$iaddr) = unpack_sockaddr_in($remote_addr);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$trap = $this->{'pdu_buffer'};
|
|
Packit |
667938 |
return ($trap, $iaddr, $port);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub describe {
|
|
Packit |
667938 |
my($this) = shift;
|
|
Packit |
667938 |
print $this->to_string (),"\n";
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub to_string {
|
|
Packit |
667938 |
my($this) = shift;
|
|
Packit |
667938 |
my ($class,$prefix);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$class = ref($this);
|
|
Packit |
667938 |
$prefix = ' ' x (length ($class) + 2);
|
|
Packit |
667938 |
($class
|
|
Packit |
667938 |
.(defined $this->{remote_hostname}
|
|
Packit |
667938 |
? " (remote host: \"".$this->{remote_hostname}."\""
|
|
Packit |
667938 |
." ".&SNMP_Session::pretty_address ($this->remote_addr).")"
|
|
Packit |
667938 |
: " (no remote host specified)")
|
|
Packit |
667938 |
."\n"
|
|
Packit |
667938 |
.$prefix." community: \"".$this->{'community'}."\"\n"
|
|
Packit |
667938 |
.$prefix." request ID: ".$this->{'request_id'}."\n"
|
|
Packit |
667938 |
.$prefix."PDU bufsize: ".$this->{'max_pdu_len'}." bytes\n"
|
|
Packit |
667938 |
.$prefix." timeout: ".$this->{timeout}."s\n"
|
|
Packit |
667938 |
.$prefix." retries: ".$this->{retries}."\n"
|
|
Packit |
667938 |
.$prefix." backoff: ".$this->{backoff}.")");
|
|
Packit |
667938 |
## sprintf ("SNMP_Session: %s (size %d timeout %g)",
|
|
Packit |
667938 |
## &SNMP_Session::pretty_address ($this->remote_addr),$this->max_pdu_len,
|
|
Packit |
667938 |
## $this->timeout);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
### SNMP Agent support
|
|
Packit |
667938 |
### contributed by Mike McCauley <mikem@open.com.au>
|
|
Packit |
667938 |
###
|
|
Packit |
667938 |
sub receive_request {
|
|
Packit |
667938 |
my ($this) = @_;
|
|
Packit |
667938 |
my ($remote_addr, $iaddr, $port, $request);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$remote_addr = recv($this->sock, $this->{'pdu_buffer'},
|
|
Packit |
667938 |
$this->{'max_pdu_len'}, 0);
|
|
Packit |
667938 |
return undef unless $remote_addr;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if( (defined $ipv6_addr_len) && (length $remote_addr == $ipv6_addr_len)) {
|
|
Packit |
667938 |
($port,$iaddr) = Socket6::unpack_sockaddr_in6($remote_addr);
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
($port,$iaddr) = unpack_sockaddr_in($remote_addr);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
$request = $this->{'pdu_buffer'};
|
|
Packit |
667938 |
return ($request, $iaddr, $port);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub decode_request {
|
|
Packit |
667938 |
my ($this, $request) = @_;
|
|
Packit |
667938 |
my ($snmp_version, $community, $requestid, $errorstatus, $errorindex, $bindings);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
($snmp_version, $community, $requestid, $errorstatus, $errorindex, $bindings)
|
|
Packit |
667938 |
= decode_by_template ($request, "%{%i%s%*{%i%i%i%@", SNMP_Session::get_request);
|
|
Packit |
667938 |
if (defined $snmp_version)
|
|
Packit |
667938 |
{
|
|
Packit |
667938 |
# Its a valid get_request
|
|
Packit |
667938 |
return(SNMP_Session::get_request, $requestid, $bindings, $community);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
($snmp_version, $community, $requestid, $errorstatus, $errorindex, $bindings)
|
|
Packit |
667938 |
= decode_by_template ($request, "%{%i%s%*{%i%i%i%@", SNMP_Session::getnext_request);
|
|
Packit |
667938 |
if (defined $snmp_version)
|
|
Packit |
667938 |
{
|
|
Packit |
667938 |
# Its a valid getnext_request
|
|
Packit |
667938 |
return(SNMP_Session::getnext_request, $requestid, $bindings, $community);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
($snmp_version, $community, $requestid, $errorstatus, $errorindex, $bindings)
|
|
Packit |
667938 |
= decode_by_template ($request, "%{%i%s%*{%i%i%i%@", SNMP_Session::set_request);
|
|
Packit |
667938 |
if (defined $snmp_version)
|
|
Packit |
667938 |
{
|
|
Packit |
667938 |
# Its a valid set_request
|
|
Packit |
667938 |
return(SNMP_Session::set_request, $requestid, $bindings, $community);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
# Something wrong with this packet
|
|
Packit |
667938 |
# Decode failed
|
|
Packit |
667938 |
return undef;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
package SNMPv2c_Session;
|
|
Packit |
667938 |
use strict qw(vars subs); # see above
|
|
Packit |
667938 |
use vars qw(@ISA);
|
|
Packit |
667938 |
use SNMP_Session;
|
|
Packit |
667938 |
use BER;
|
|
Packit |
667938 |
use Carp;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
@ISA = qw(SNMPv1_Session);
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub snmp_version { 1 }
|
|
Packit |
667938 |
|
|
Packit |
667938 |
sub open {
|
|
Packit |
667938 |
my $session = SNMPv1_Session::open (@_);
|
|
Packit |
667938 |
return undef unless defined $session;
|
|
Packit |
667938 |
return bless $session;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
## map_table_start_end using get-bulk
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
sub map_table_start_end ($$$$$$) {
|
|
Packit |
667938 |
my ($session, $columns, $mapfn, $start, $end, $max_repetitions) = @_;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my @encoded_oids;
|
|
Packit |
667938 |
my $call_counter = 0;
|
|
Packit |
667938 |
my $base_index = $start;
|
|
Packit |
667938 |
my $ncols = @{$columns};
|
|
Packit |
667938 |
my @collected_values = ();
|
|
Packit |
667938 |
|
|
Packit |
667938 |
if (! $session->{'use_getbulk'}) {
|
|
Packit |
667938 |
return SNMP_Session::map_table_start_end
|
|
Packit |
667938 |
($session, $columns, $mapfn, $start, $end, $max_repetitions);
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
$max_repetitions = $session->default_max_repetitions
|
|
Packit |
667938 |
unless defined $max_repetitions;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
for (;;) {
|
|
Packit |
667938 |
foreach (@encoded_oids = @{$columns}) {
|
|
Packit |
667938 |
$_=encode_oid (@{$_},split '\.',$base_index)
|
|
Packit |
667938 |
|| return $session->ber_error ("encoding OID $base_index");
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
if ($session->getbulk_request_response (0, $max_repetitions,
|
|
Packit |
667938 |
@encoded_oids)) {
|
|
Packit |
667938 |
my $response = $session->pdu_buffer;
|
|
Packit |
667938 |
my ($bindings) = $session->decode_get_response ($response);
|
|
Packit |
667938 |
my @colstack = ();
|
|
Packit |
667938 |
my $k = 0;
|
|
Packit |
667938 |
my $j;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my $min_index = undef;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
my @bases = @{$columns};
|
|
Packit |
667938 |
my $n_bindings = 0;
|
|
Packit |
667938 |
my $binding;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
## Copy all bindings into the colstack.
|
|
Packit |
667938 |
## The colstack is a vector of vectors.
|
|
Packit |
667938 |
## It contains one vector for each "repeater" variable.
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
while ($bindings ne '') {
|
|
Packit |
667938 |
($binding, $bindings) = decode_sequence ($bindings);
|
|
Packit |
667938 |
my ($oid, $value) = decode_by_template ($binding, "%O%@");
|
|
Packit |
667938 |
|
|
Packit |
667938 |
push @{$colstack[$k]}, [$oid, $value];
|
|
Packit |
667938 |
++$k; $k = 0 if $k >= $ncols;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
## Now collect rows from the column stack:
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
## Iterate through the column stacks to find the smallest
|
|
Packit |
667938 |
## index, collecting the values for that index in
|
|
Packit |
667938 |
## @collected_values.
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
## As long as a row can be assembled, the map function is
|
|
Packit |
667938 |
## called on it and the iteration proceeds.
|
|
Packit |
667938 |
##
|
|
Packit |
667938 |
$base_index = undef;
|
|
Packit |
667938 |
walk_rows_from_pdu:
|
|
Packit |
667938 |
for (;;) {
|
|
Packit |
667938 |
my $min_index = undef;
|
|
Packit |
667938 |
|
|
Packit |
667938 |
for ($k = 0; $k < $ncols; ++$k) {
|
|
Packit |
667938 |
$collected_values[$k] = undef;
|
|
Packit |
667938 |
my $pair = $colstack[$k]->[0];
|
|
Packit |
667938 |
unless (defined $pair) {
|
|
Packit |
667938 |
$min_index = undef;
|
|
Packit |
667938 |
last walk_rows_from_pdu;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
my $this_index
|
|
Packit |
667938 |
= SNMP_Session::oid_diff ($columns->[$k], $pair->[0]);
|
|
Packit |
667938 |
if (defined $this_index) {
|
|
Packit |
667938 |
my $cmp
|
|
Packit |
667938 |
= !defined $min_index
|
|
Packit |
667938 |
? -1
|
|
Packit |
667938 |
: SNMP_Session::index_compare
|
|
Packit |
667938 |
($this_index, $min_index);
|
|
Packit |
667938 |
if ($cmp == -1) {
|
|
Packit |
667938 |
for ($j = 0; $j < $k; ++$j) {
|
|
Packit |
667938 |
unshift (@{$colstack[$j]},
|
|
Packit |
667938 |
[$min_index,
|
|
Packit |
667938 |
$collected_values[$j]]);
|
|
Packit |
667938 |
$collected_values[$j] = undef;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
$min_index = $this_index;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
if ($cmp <= 0) {
|
|
Packit |
667938 |
$collected_values[$k] = $pair->[1];
|
|
Packit |
667938 |
shift @{$colstack[$k]};
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
($base_index = undef), last
|
|
Packit |
667938 |
if !defined $min_index;
|
|
Packit |
667938 |
last
|
|
Packit |
667938 |
if defined $end
|
|
Packit |
667938 |
and SNMP_Session::index_compare ($min_index, $end) >= 0;
|
|
Packit |
667938 |
&$mapfn ($min_index, @collected_values);
|
|
Packit |
667938 |
++$call_counter;
|
|
Packit |
667938 |
$base_index = $min_index;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
} else {
|
|
Packit |
667938 |
return undef;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
last if !defined $base_index;
|
|
Packit |
667938 |
last
|
|
Packit |
667938 |
if defined $end
|
|
Packit |
667938 |
and SNMP_Session::index_compare ($base_index, $end) >= 0;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
$call_counter;
|
|
Packit |
667938 |
}
|
|
Packit |
667938 |
|
|
Packit |
667938 |
1;
|