Index: ossp-pkg/snmpdx/snmpdx RCS File: /v/ossp/cvs/ossp-pkg/snmpdx/Attic/snmpdx,v rcsdiff -q -kk '-r1.5' '-r1.6' -u '/v/ossp/cvs/ossp-pkg/snmpdx/Attic/snmpdx,v' 2>/dev/null --- 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"); } }