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