--- snmpdx 2003/09/02 12:39:20 1.5
+++ snmpdx 2003/09/02 15:36:18 1.6
@@ -476,7 +476,7 @@
package main;
# find path to ourself
-my $myroot = "$FindBin::Bin";
+my $myroot = "$FindBin::Bin";
# parameters (defaults)
my $opt = {
@@ -493,6 +493,7 @@
'mibname' => "snmpdx",
'logfile' => "$myroot/snmpdx.log",
'loglevel' => 9,
+ 'strict' => 0,
};
# command line parsing
@@ -510,6 +511,7 @@
'm|mibname=s' => \$opt->{'mibname'},
'l|logfile=s' => \$opt->{'logfile'},
'L|loglevel=i' => \$opt->{'loglevel'},
+ 's|strict' => \$opt->{'strict'},
);
Getopt::Long::Configure("bundling");
my $result = GetOptions(%options) || die "option parsing failed";
@@ -528,7 +530,8 @@
" -M,--mibdir=PATH path to MIB directory\n" .
" -m,--mibname=MIB the name of the MIB to act under\n" .
" -l,--logfile=PATH path to daemon logfile\n" .
- " -L,--loglevel=NUM logging level (0...9)\n";
+ " -L,--loglevel=NUM logging level (0...9)\n" .
+ " -s,--strict strict processing of unknown values\n";
exit(0);
}
if ($opt->{'version'}) {
@@ -604,6 +607,7 @@
# load probes and determine their handled OIDs
my $oidtable = [];
my $oidhandler = {};
+my $oidprobe = {};
my $oidtype = {
'DisplayString' => [ 'string', 'N.A.' ],
'Integer32' => [ 'integer', '-1' ],
@@ -630,12 +634,13 @@
die if ($@);
};
if ($@) {
- die "invalid probe \"$probe\"";
+ die "invalid probe \"$probe\": $@";
}
$ctx->{-log}->printf(2, "Probe: \"%s\"", $probe);
foreach my $oid (sort(@{$p->oids()})) {
push(@{$oidtable}, $oid);
$oidhandler->{$oid} = $p;
+ $oidprobe->{$oid} = $probe;
$ctx->{-log}->printf(1, "MIB OID: %s [%s] ::= %s (%s)",
$oid, $ctx->{-mib}->oid2name($oid),
$ctx->{-mib}->oid2type($oid),
@@ -665,111 +670,219 @@
$ctx->{-log}->printf(4, "IO: recv: << \"%s\\n\"", $cmd);
if ($cmd =~ m/^PING$/i) {
+ #
# the PING/PONG protocol part
+ #
$ctx->{-log}->printf(4, "IO: send: >> \"PONG\\n\"");
$stdout->printf("PONG\n");
}
+
elsif ($cmd =~ m/^GET$/i or $cmd =~ m/^GETNEXT$/i) {
+ #
# the GET/GETNEXT protocol part
+ #
+
+ # read requested OID
my $error = 1;
- my $oid = $stdin->getline;
- if (not defined($oid)) {
+ my $oid_request = $stdin->getline;
+ if (not defined($oid_request)) {
$ctx->{-log}->printf(1, "ERROR: EOF instead of OID");
goto ERROR;
}
- $oid =~ s|\n?$||s;
- $ctx->{-log}->printf(4, "IO: recv: << \"%s\\n\"", $oid);
- if ($oid !~ m/^(\.\d+)+$/) {
- $ctx->{-log}->printf(1, "ERROR: invalid query OID \"%s\"", $oid);
+ $oid_request =~ s|\n?$||s;
+ $ctx->{-log}->printf(4, "IO: recv: << \"%s\\n\"", $oid_request);
+ if ($oid_request !~ m/^(\.\d+)+$/) {
+ $ctx->{-log}->printf(1, "ERROR: invalid query OID \"%s\"", $oid_request);
goto ERROR;
}
- my $oid_table = undef;
- if ($cmd =~ m/^GETNEXT$/i) {
- my $oid_parent = $oid;
- $oid_parent =~ s|(\.\d+)$||s;
+
+ # re-entry point for OID processing
+ my $oid_search = $oid_request;
+ RETRY:
+
+ # determine acted/handled OID
+ my $oid_action = undef;
+ my $oid_handled = undef;
+ my $oid_handler = undef;
+ my $oid_next = undef;
+ if ($cmd =~ m/^GET$/i) {
+ # search for explicitly handled OID
for (my $i = 0; defined($oidtable->[$i]); $i++) {
- if ($oidtable->[$i] =~ m|^\Q$oid\E(\.\d+)+$|) {
- # OID start with requested OID prefix, so use this OID
- $oid = $oidtable->[$i];
+ if ($oidtable->[$i] eq $oid_search) {
+ $oid_action = $oidtable->[$i];
+ $oid_handled = $oidtable->[$i];
last;
}
- elsif ($oidtable->[$i] eq $oid) {
+ }
+ # search for implicitly handled OID (sequence element)
+ if (not defined($oid_handled)) {
+ my $oid_parent = $oid_search;
+ $oid_parent =~ s|(\.\d+)$||s;
+ for (my $i = 0; defined($oidtable->[$i]); $i++) {
+ if ($oidtable->[$i] =~ m|^\Q$oid_parent\E\.#$|) {
+ $oid_action = $oid_search;
+ $oid_handled = $oidtable->[$i];
+ last;
+ }
+ }
+ }
+ }
+ elsif ($cmd =~ m/^GETNEXT$/i) {
+ # search for explicitly handled OID
+ for (my $i = 0; defined($oidtable->[$i]); $i++) {
+ if ($oidtable->[$i] =~ m|^\Q$oid_search\E(\.\d+)+$|) {
+ # OID starts with requested OID prefix, so use this OID
+ $oid_action = $oidtable->[$i];
+ $oid_handled = $oidtable->[$i];
+ $oid_next = $oidtable->[$i+1];
+ last;
+ }
+ elsif ($oidtable->[$i] eq $oid_search) {
# OID is the requested OID exactly, so use next OID
if (defined($oidtable->[$i+1])) {
- $oid = $oidtable->[$i+1];
+ $oid_action = $oidtable->[$i+1];
+ $oid_action =~ s|\.#$|.1|s;
+ $oid_handled = $oidtable->[$i+1];
+ $oid_next = $oidtable->[$i+2];
last;
}
else {
- goto ERROR; # end-of-MIB case
+ goto ERROR; # end-of-MIB
}
}
- elsif ($oidtable->[$i] =~ m|^\Q$oid\E(\.\d+)*(\.#)$|) {
- # OID start with requested OID prefix, so use this OID (special case of table)
- $oid = $oidtable->[$i];
- $oid =~ s|\.#$|.1|s;
- last;
- }
- elsif ($oidtable->[$i] =~ m|^\Q$oid_parent\E\.#$|) {
- # OID is the a requested OID of a table, so use next OID in table
- $oid = s|\.(\d+)$|".".($1+1)|se;
- $oid_table = $oidtable->[$i+1];
- $oid =~ s|\.#$|.1|s;
- last;
+ }
+ # search for implicitly handled OID (sequence element)
+ if (not defined($oid_handled)) {
+ my $oid_parent = $oid_search;
+ $oid_parent =~ s|(\.\d+)$||s;
+ for (my $i = 0; defined($oidtable->[$i]); $i++) {
+ # search for implicitly handled OID (sequence element)
+ if ($oidtable->[$i] =~ m|^\Q$oid_search\E(\.\d+)*\.#$|) {
+ # OID start with requested OID prefix, so use first OID in sequence
+ $oid_action = $oidtable->[$i];
+ $oid_action =~ s|\.#$|.1|s;
+ $oid_handled = $oidtable->[$i];
+ $oid_next = $oidtable->[$i+1];
+ last;
+ }
+ elsif ($oidtable->[$i] =~ m|^\Q$oid_parent\E\.#$|) {
+ # OID is the requested OID of a sequence exactly, so use next OID in sequence
+ $oid_action = $oid_search;
+ $oid_action =~ s|\.(\d+)$|".".($1+1)|se;
+ $oid_handled = $oidtable->[$i];
+ $oid_next = $oidtable->[$i+1];
+ last;
+ }
}
}
}
- TABLE_NEXT:
- my $oid_wild = $oid;
- my $handler = $oidhandler->{$oid};
- if (not defined($handler)) {
- $oid_wild =~ s|(\.\d+)$|.#|s;
- $handler = $oidhandler->{$oid_wild};
+ if (defined($oid_handled)) {
+ $oid_handler = $oidhandler->{$oid_handled};
}
- if (not defined($handler)) {
- $ctx->{-log}->printf(1, "ERROR: no handler found for OID \"%s\"", $oid);
- goto ERROR;
+ else {
+ $ctx->{-log}->printf(1, "ERROR: no handler found for OID \"%s\"", $oid_request);
+ goto ERROR; # end-of-MIB
}
+
+ # prepare probe request object
my $obj = {
- -oid => $oid,
- -name => $ctx->{-mib}->oid2name($oid_wild),
- -type => $ctx->{-mib}->oid2type($oid_wild),
+ -oid => $oid_action,
+ -name => $ctx->{-mib}->oid2name($oid_handled),
+ -type => $ctx->{-mib}->oid2type($oid_handled),
-value => undef
};
- $handler->probe($obj);
+
+ # provide mixed name/OID for sequence index
+ if ($obj->{-name} =~ m|\.#$|) {
+ my ($idx) = ($obj->{-oid} =~ m|\.(\d+)$|);
+ $obj->{-name} =~ s|\.#$|.$idx|;
+ }
+
+ # probe value of OID
+ $ctx->{-log}->printf(2, "probing \"%s\" for OID \"%s\"", $oidprobe->{$oid_handled}, $oid_action);
+ $oid_handler->probe($obj);
+
+ # handle special "end of sequence" situation
+ #if (not defined($obj->{-value}) and $oid_handled =~ m|\.#$|) {
+ # if (defined($oid_next)) {
+ # $oid_search = $oid_next;
+ # $oid_search =~ s|\.#$||s;
+ # goto RETRY;
+ # }
+ # else {
+ # goto ERROR; # end-of-MIB
+ # }
+ #}
+
+ # handle special "unknown OID value" situation
if (not defined($obj->{-value})) {
- if (defined($oid_table)) {
- # end of table entry
- $oid = $oid_table;
- goto TABLE_NEXT;
+ $ctx->{-log}->printf(1, "WARNING: handler was unable to provide probe value for OID \"%s\"", $oid_request);
+ if ($opt->{'strict'}) {
+ # strict processing: return ERROR on unknown value
+ # for GET request and skip unknown OIDs on GETNEXT.
+ if ($cmd =~ m/^GET$/i) {
+ goto ERROR; # no-value
+ }
+ else { # GETNEXT
+ if (defined($oid_next)) {
+ $oid_search = $oid_next;
+ $oid_search =~ s|\.#$||s;
+ goto RETRY;
+ }
+ else {
+ goto ERROR; # no-value
+ }
+ }
+ }
+ else {
+ # non-strict processing: return a reasonable default value
+ if ($oid_handled =~ m|\.#$|) {
+ if ($oid_action =~ m|\.1$|) {
+ $obj->{-value} = $oidtype->{$obj->{-type}}->[1];
+ }
+ else {
+ if (defined($oid_next)) {
+ $oid_search = $oid_next;
+ $oid_search =~ s|\.#$||s;
+ goto RETRY;
+ }
+ else {
+ goto ERROR; # end-of-MIB
+ }
+ }
+ }
+ else {
+ $obj->{-value} = $oidtype->{$obj->{-type}}->[1];
+ }
}
- #$ctx->{-log}->printf(1, "ERROR: handler was unable to provide probe value for OID \"%s\"", $oid);
- #goto ERROR;
- $ctx->{-log}->printf(1, "WARNING: handler was unable to provide probe value for OID \"%s\"", $oid);
- $obj->{-value} = $oidtype->{$obj->{-type}}->[1];
}
+
+ # optionally encode value to conform to snmpd(8) protocol
if ($oidtype->{$obj->{-type}}->[0] =~ m/^(octet|opaque)$/) {
$obj->{-value} = $ctx->{-enc}->octet_encode($obj->{-value});
}
+
+ # return result
$ctx->{-log}->printf(1, "QUERY: %s [%s] ::= %s \"%s\"",
$obj->{-name}, $obj->{-oid}, $obj->{-type}, $obj->{-value});
$stdout->printf("%s\n%s\n%s\n",
$obj->{-oid}, $oidtype->{$obj->{-type}}->[0], $obj->{-value});
$ctx->{-log}->printf(4, "IO: send: >> \"%s\\n%s\\n%s\\n\"",
$obj->{-oid}, $oidtype->{$obj->{-type}}->[0], $obj->{-value});
- $error = 0;
+ # end-of-MIB or no-value handling
+ $error = 0;
if ($error) {
- # end-of-MIB or error
ERROR:
$ctx->{-log}->printf(4, "IO: send: >> \"NONE\\n\"");
$stdout->printf("NONE\n");
}
}
else {
- # for anything else (not expected) just send
- # something in case snmpd expects something.
- $ctx->{-log}->printf(4, "IO: send: >> \"\"");
- $stdout->printf("\n");
+ # for anything else (not expected) just send at least
+ # "NONE" in case snmpd(8) expects something.
+ $ctx->{-log}->printf(4, "IO: send: >> \"NONE\\n\"");
+ $stdout->printf("NONE\n");
}
}
|