Hi,

there's a bug in snmpd that breaks GETBULK requests for multiple OIDs.

Example:

   # OID1=1.3.6.1.2.1.1.1
   # OID2=1.3.6.1.2.1.31.1.1.1.1
   # snmpbulkget -Cr3 -c public -v2c localhost $OID1
   SNMPv2-MIB::sysDescr.0 = STRING: OpenBSD null 5.7 GENERIC#123 i386
   SNMPv2-MIB::sysObjectID.0 = OID: OPENBSD-BASE-MIB::openBSDDefaultObjectID
   SNMPv2-MIB::sysUpTime.0 = Timeticks: (68096) 0:11:20.96
   # snmpbulkget -Cr3 -c public -v2c localhost $OID2
   IF-MIB::ifName.1 = STRING: em0
   IF-MIB::ifName.2 = STRING: iwi0
   IF-MIB::ifName.3 = STRING: enc0
   # snmpbulkget -Cr3 -c public -v2c localhost $OID1 $OID2
   SNMPv2-MIB::sysDescr.0 = STRING: OpenBSD null 5.7 GENERIC#123 i386
   IF-MIB::ifName.1 = STRING: em0
   IF-MIB::ifName.2 = STRING: iwi0
   IF-MIB::ifName.3 = STRING: enc0


Each query for a single OID delivers three repetitions (as requested by
"-Cr3"). But the query for two OIDs skips the repetitions for the first
one. If we add more OIDs, only the last OID of the query will have
repetitions in the reply.

The reason is that we must link the result of each mps_getbulkreq()
to the end of the previous list and not the start of it.

With the patch below, we get the desired result:

   # snmpbulkget -Cr3 -c public -v2c localhost $OID1 $OID2
   SNMPv2-MIB::sysDescr.0 = STRING: OpenBSD null 5.7 GENERIC#123 i386
   SNMPv2-MIB::sysObjectID.0 = OID: OPENBSD-BASE-MIB::openBSDDefaultObjectID
   SNMPv2-MIB::sysUpTime.0 = Timeticks: (239) 0:00:02.39
   IF-MIB::ifName.1 = STRING: em0
   IF-MIB::ifName.2 = STRING: iwi0
   IF-MIB::ifName.3 = STRING: enc0


Gerhard



Index: mps.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/mps.c,v
retrieving revision 1.20
diff -u -p -u -p -r1.20 mps.c
--- mps.c       16 Jan 2015 00:05:13 -0000      1.20
+++ mps.c       3 Jun 2015 08:48:42 -0000
@@ -289,7 +289,7 @@ mps_getnextreq(struct snmp_message *msg,
 
 int
 mps_getbulkreq(struct snmp_message *msg, struct ber_element **root,
-    struct ber_oid *o, int max)
+    struct ber_element **end, struct ber_oid *o, int max)
 {
        struct ber_element *c, *d, *e;
        size_t len;
@@ -297,14 +297,17 @@ mps_getbulkreq(struct snmp_message *msg,
 
        j = max;
        c = *root;
+       *end = NULL;
 
        for (d = NULL, len = 0; j > 0; j--) {
                e = ber_add_sequence(NULL);
                if (c == NULL)
                        c = e;
                ret = mps_getnextreq(msg, e, o);
-               if (ret == 1)
+               if (ret == 1) {
+                       *root = c;
                        return (1);
+               }
                if (ret == -1) {
                        ber_free_elements(e);
                        if (d == NULL)
@@ -319,6 +322,7 @@ mps_getbulkreq(struct snmp_message *msg,
                if (d != NULL)
                        ber_link_elements(d, e);
                d = e;
+               *end = d;
        }
 
        *root = c;
Index: snmpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v
retrieving revision 1.59
diff -u -p -u -p -r1.59 snmpd.h
--- snmpd.h     16 Jan 2015 00:05:13 -0000      1.59
+++ snmpd.h     3 Jun 2015 09:02:38 -0000
@@ -396,6 +396,7 @@ struct snmp_message {
        struct ber_element      *sm_c;
        struct ber_element      *sm_next;
        struct ber_element      *sm_last;
+       struct ber_element      *sm_end;
 
        u_int8_t                 sm_data[READ_BUF_SIZE];
        size_t                   sm_datalen;
@@ -638,7 +639,7 @@ int          mps_getreq(struct snmp_message *, 
 int             mps_getnextreq(struct snmp_message *, struct ber_element *,
                    struct ber_oid *);
 int             mps_getbulkreq(struct snmp_message *, struct ber_element **,
-                   struct ber_oid *, int);
+                   struct ber_element **, struct ber_oid *, int);
 int             mps_setreq(struct snmp_message *, struct ber_element *,
                    struct ber_oid *);
 int             mps_set(struct ber_oid *, void *, long long);
Index: snmpe.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.40
diff -u -p -u -p -r1.40 snmpe.c
--- snmpe.c     16 Jan 2015 00:05:13 -0000      1.40
+++ snmpe.c     3 Jun 2015 09:06:31 -0000
@@ -374,6 +374,7 @@ snmpe_parsevarbinds(struct snmp_message 
                                break;
                        case 1:
                                msg->sm_c = NULL;
+                               msg->sm_end = NULL;
 
                                switch (msg->sm_context) {
 
@@ -409,7 +410,8 @@ snmpe_parsevarbinds(struct snmp_message 
 
                                case SNMP_C_GETBULKREQ:
                                        ret = mps_getbulkreq(msg, &msg->sm_c,
-                                           &o, msg->sm_maxrepetitions);
+                                           &msg->sm_end, &o,
+                                           msg->sm_maxrepetitions);
                                        if (ret == 0 || ret == 1)
                                                break;
                                        msg->sm_error = SNMP_ERROR_NOSUCHNAME;
@@ -420,11 +422,13 @@ snmpe_parsevarbinds(struct snmp_message 
                                }
                                if (msg->sm_c == NULL)
                                        break;
+                               if (msg->sm_end == NULL)
+                                       msg->sm_end = msg->sm_c;
                                if (msg->sm_last == NULL)
                                        msg->sm_varbindresp = msg->sm_c;
                                else
                                        ber_link_elements(msg->sm_last, 
msg->sm_c);
-                               msg->sm_last = msg->sm_c;
+                               msg->sm_last = msg->sm_end;
                                break;
                        }
                }


Index: mps.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/mps.c,v
retrieving revision 1.20
diff -u -p -u -p -r1.20 mps.c
--- mps.c       16 Jan 2015 00:05:13 -0000      1.20
+++ mps.c       3 Jun 2015 08:48:42 -0000
@@ -289,7 +289,7 @@ mps_getnextreq(struct snmp_message *msg,
 
 int
 mps_getbulkreq(struct snmp_message *msg, struct ber_element **root,
-    struct ber_oid *o, int max)
+    struct ber_element **end, struct ber_oid *o, int max)
 {
        struct ber_element *c, *d, *e;
        size_t len;
@@ -297,14 +297,17 @@ mps_getbulkreq(struct snmp_message *msg,
 
        j = max;
        c = *root;
+       *end = NULL;
 
        for (d = NULL, len = 0; j > 0; j--) {
                e = ber_add_sequence(NULL);
                if (c == NULL)
                        c = e;
                ret = mps_getnextreq(msg, e, o);
-               if (ret == 1)
+               if (ret == 1) {
+                       *root = c;
                        return (1);
+               }
                if (ret == -1) {
                        ber_free_elements(e);
                        if (d == NULL)
@@ -319,6 +322,7 @@ mps_getbulkreq(struct snmp_message *msg,
                if (d != NULL)
                        ber_link_elements(d, e);
                d = e;
+               *end = d;
        }
 
        *root = c;
Index: snmpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v
retrieving revision 1.59
diff -u -p -u -p -r1.59 snmpd.h
--- snmpd.h     16 Jan 2015 00:05:13 -0000      1.59
+++ snmpd.h     3 Jun 2015 09:02:38 -0000
@@ -396,6 +396,7 @@ struct snmp_message {
        struct ber_element      *sm_c;
        struct ber_element      *sm_next;
        struct ber_element      *sm_last;
+       struct ber_element      *sm_end;
 
        u_int8_t                 sm_data[READ_BUF_SIZE];
        size_t                   sm_datalen;
@@ -638,7 +639,7 @@ int          mps_getreq(struct snmp_message *, 
 int             mps_getnextreq(struct snmp_message *, struct ber_element *,
                    struct ber_oid *);
 int             mps_getbulkreq(struct snmp_message *, struct ber_element **,
-                   struct ber_oid *, int);
+                   struct ber_element **, struct ber_oid *, int);
 int             mps_setreq(struct snmp_message *, struct ber_element *,
                    struct ber_oid *);
 int             mps_set(struct ber_oid *, void *, long long);
Index: snmpe.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.40
diff -u -p -u -p -r1.40 snmpe.c
--- snmpe.c     16 Jan 2015 00:05:13 -0000      1.40
+++ snmpe.c     3 Jun 2015 09:06:31 -0000
@@ -374,6 +374,7 @@ snmpe_parsevarbinds(struct snmp_message 
                                break;
                        case 1:
                                msg->sm_c = NULL;
+                               msg->sm_end = NULL;
 
                                switch (msg->sm_context) {
 
@@ -409,7 +410,8 @@ snmpe_parsevarbinds(struct snmp_message 
 
                                case SNMP_C_GETBULKREQ:
                                        ret = mps_getbulkreq(msg, &msg->sm_c,
-                                           &o, msg->sm_maxrepetitions);
+                                           &msg->sm_end, &o,
+                                           msg->sm_maxrepetitions);
                                        if (ret == 0 || ret == 1)
                                                break;
                                        msg->sm_error = SNMP_ERROR_NOSUCHNAME;
@@ -420,11 +422,13 @@ snmpe_parsevarbinds(struct snmp_message 
                                }
                                if (msg->sm_c == NULL)
                                        break;
+                               if (msg->sm_end == NULL)
+                                       msg->sm_end = msg->sm_c;
                                if (msg->sm_last == NULL)
                                        msg->sm_varbindresp = msg->sm_c;
                                else
                                        ber_link_elements(msg->sm_last, 
msg->sm_c);
-                               msg->sm_last = msg->sm_c;
+                               msg->sm_last = msg->sm_end;
                                break;
                        }
                }

Reply via email to