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);

Reply via email to