Skip to content

fix(snmp): probe with GETBULK, which is what every device answers - #28

Merged
Gerrrt merged 1 commit into
mainfrom
fix/snmp-verify-getbulk
Aug 19, 2026
Merged

fix(snmp): probe with GETBULK, which is what every device answers#28
Gerrrt merged 1 commit into
mainfrom
fix/snmp-verify-getbulk

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Makes scripts/snmp-verify.sh pass against all four devices, and closes a correctness hole in --old.

What changed

probe() sends one GETBULK (-Cn0 -Cr1) instead of one GET.

Why

snmp-verify has always reported FAIL for neo while snmp-exporter scraped
it fine. The difference is the PDU type — the exporter bulk-walks, this script
sent a GET:

GETBULK   OK   .1.3.6.1.2.1.1.1.0 "53 77 69 74 63 68 00"
GETNEXT   no response
GET       no response

The MokerLink switch answers GETBULK and silently drops GET and GETNEXT. No
GET-based probe could ever have succeeded against it.

This is a correctness fix, not a cosmetic one. --old infers "rejected"
from a timeout. A probe the device never answers therefore reports every
community as refused — including one that still works. Against neo the
old-community check was capable only of agreeing with the operator. The only
thing preventing that wrong answer from being printed was that neo was being
SKIPped for an unrelated reason.

Design notes

  • One GETBULK with non-repeaters 0 and max-repetitions 1 is a single round trip
    returning a single varbind — the same cost as the GET it replaces. That
    matters here: this switch has been bricked by a full walk before.
  • Aimed at the sysDescr node, not sysDescr.0, because GETBULK is
    GETNEXT-shaped — asking for 1.3.6.1.2.1.1.1 returns 1.3.6.1.2.1.1.1.0.
  • The returned OID is asserted. Unlike GET, a GETBULK against a device with no
    sysDescr does not raise an error, it returns whatever comes next — which
    would otherwise be reported as a pass carrying the wrong value. That case is
    classified as nosuchobject, exactly as before.

Blast radius

One script. No config, no service, no credential, no segmentation change.

  • No change to network segmentation or firewall rules
  • No new port published to a VLAN that could not already reach the service
  • No credential added outside secrets/*.sops.yaml

Verification

$ ./scripts/snmp-verify.sh

Current community
  PASS morpheus   10.0.99.1    "pfSense morpheus.matrix.elysium 2.8.1-RELEASE FreeBSD 15.0-
  PASS mjolnir    10.0.99.10   "APC Web/SNMP Management Card (MB:v4.2.9 PF:v2.0.0.6 PN:apc_
  PASS neo        10.7.7.2     "53 77 69 74 63 68 00 "
  PASS shiva      10.0.30.10   "Integrated Lights-Out 4 2.82 Feb 06 2023"

all SNMP targets verified

GETBULK confirmed working against all four devices individually before the
change was made. shellcheck clean, ./scripts/validate.sh passes.

  • make validate passes
  • Deployed to the lab and confirmed working
  • Docs updated — see below

Follow-up, not fixed here

--old prompts for a single previous community and tests it against every
device. That was right when one string was shared across all four; it is no
longer. neo now has a different previous community from the other three, so
proving it needs its own --old run. Worth a runbook note or a per-device
prompt, deliberately left out of this change.

Refs #9

snmp-verify has always reported FAIL for neo while snmp-exporter scraped it
successfully. The difference was the PDU type: the exporter bulk-walks, this
script sent a GET. The MokerLink switch answers GETBULK and silently drops both
GET and GETNEXT, so no GET-based probe could ever succeed against it.

That is not a cosmetic FAIL. --old infers "rejected" from a timeout, so a probe
the device never answers reports every community as refused — including one
that still works. Against neo the old-community check was capable only of
agreeing with the operator, which is the single thing this script exists not to
do. It was skipping neo for an unrelated reason, which is the only thing that
kept the wrong answer from being printed.

One GETBULK with non-repeaters 0 and max-repetitions 1 is a single round trip
returning one varbind — the same cost as the GET it replaces, which matters on
a switch that has been bricked by a full walk before. Verified against all four
devices.

Aimed at the sysDescr node rather than sysDescr.0, since GETBULK is
GETNEXT-shaped. The returned OID is asserted, because a GETBULK against a
device with no sysDescr returns the next varbind rather than an error, and that
would otherwise read as a pass carrying the wrong value.

All four now PASS.

Refs #9

Co-Authored-By: Claude Opus 5 <[email protected]>
@Gerrrt
Gerrrt merged commit 2dbb036 into main Aug 19, 2026
3 checks passed
@Gerrrt
Gerrrt deleted the fix/snmp-verify-getbulk branch August 19, 2026 03:12
Gerrrt added a commit that referenced this pull request Aug 19, 2026
fix(snmp): probe with GETBULK, which is what every device answers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant