So I got puzzled because of a behavioural difference between snmpwalk
and snmpctl walk.
snmp returns the next element after the requested element for a
getNextRequest. So for a leaf-element this can be it's closest
neighbour. e.g.
$ make && snmpctl snmp walk host oid 1.3.6.1.4.1.9.9.273.1.1.2.1.1
1.1=1
1.2=5
icinga2$ make && snmpctl snmp walk host oid 1.3.6.1.4.1.9.9.273.1.1.2.1.1.1
2=5
icinga2$ make && snmpctl snmp walk host oid 1.3.6.1.4.1.9.9.273.1.1.2.1.1.2
1=0
snmpwalk returns the requested leaf if no subelements can be found:
$ snmpwalk -v2c -c public host 1.3.6.1.4.1.9.9.273.1.1.2.1.1.1
SNMPv2-SMI::enterprises.9.9.273.1.1.2.1.1.1 = Gauge32: 1
$ snmpwalk -v2c -c public host 1.3.6.1.4.1.9.9.273.1.1.2.1.1.2
SNMPv2-SMI::enterprises.9.9.273.1.1.2.1.1.2 = Gauge32: 5
The problem for snmpctl is that we always return the first match, even
if even if it's not in our scope. The diff below removes that
requirement and also makes sure we also match itself, so to keep
"snmp get" working.
Note that this diff doesn't include the value of the leaf itself, unlike
snmpwalk, since that would require extra wiring and isn't exactly what's
being asked. If people would like this it could probably be added.
$ ./snmpctl snmp walk host oid 1.3.6.1.4.1.9.9.273.1.1.2.1.1.1
$ ./snmpctl snmp get 10.17.11.27 oid 1.3.6.1.4.1.9.9.273.1.1.2.1.1.1
1=1
$
OK?
martijn@
Index: snmpclient.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpctl/snmpclient.c,v
retrieving revision 1.18
diff -u -p -r1.18 snmpclient.c
--- snmpclient.c 25 Nov 2018 14:58:28 -0000 1.18
+++ snmpclient.c 11 Dec 2018 12:05:46 -0000
@@ -56,7 +56,6 @@ struct snmpc {
int sc_retry_max;
const char *sc_community;
int sc_version;
- int sc_nresp;
};
#define SNMPC_RETRY_MAX 3
@@ -180,8 +179,6 @@ snmpc_run(struct snmpc *sc, enum actions
if (sc->sc_oid.bo_n > 2)
sc->sc_root_len = sc->sc_oid.bo_n - 1;
- sc->sc_nresp = 0;
-
if (action == GET)
snmpc_request(sc, SNMP_C_GETREQ);
else if (action == BULKWALK)
@@ -235,7 +232,7 @@ snmpc_response(struct snmpc *sc)
char buf[BUFSIZ];
struct ber_element *resp = NULL, *s, *e;
char *value = NULL, *p;
- int ret = 0;
+ int ret = 0, bercmp;
/* Receive response */
if (snmpc_recvresp(sc->sc_fd, sc->sc_version,
@@ -250,10 +247,10 @@ snmpc_response(struct snmpc *sc)
goto fail;
/* Break if the returned OID is not a child of the root. */
- if (sc->sc_nresp &&
- (ber_oid_cmp(&sc->sc_root_oid, &sc->sc_oid) != 2 ||
+ bercmp = ber_oid_cmp(&sc->sc_root_oid, &sc->sc_oid);
+ if ((bercmp != 0 && bercmp != 2) ||
e->be_class == BER_CLASS_CONTEXT ||
- e->be_type == BER_TYPE_NULL)) {
+ e->be_type == BER_TYPE_NULL) {
ret = 1;
break;
}
@@ -271,8 +268,6 @@ snmpc_response(struct snmpc *sc)
}
bcopy(&sc->sc_oid, &sc->sc_last_oid, sizeof(sc->sc_last_oid));
}
-
- sc->sc_nresp++;
ber_free_elements(resp);
return (ret);