The new code uses smi_print_element when debugging is enabled to trace
calls. Unfortunately the current smi_print_element lacks in quite a few
departments. This diff rewrites smi_print_element to be more concise
than what we currently have, without moving into the more complex
territory that snmp(1) has.
Unknown types are printed in a similar fashion to what tcpdump(8)'s
snmp output does.
This change helps mostly with exceptions (NOSUCH{OBJECT,INSTANCE} and
ENDOFMIBVIEW) and distinguishing between different integer types.
I kept the current implementation under smi_print_element_legacy, so
that we don't change the output of trap handlers. We should probably
revisit that one at some point, but I don't think to go into that
territory right now.
OK?
martijn@
p.s. I'm not particularly thrilled about the type hinting, but it's
the cleanest that I could come up with without being too much of an
eyesore or filling the screen up even further.
Index: smi.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
retrieving revision 1.30
diff -u -p -r1.30 smi.c
--- smi.c 21 Oct 2021 15:08:15 -0000 1.30
+++ smi.c 19 Jan 2022 15:21:20 -0000
@@ -46,6 +46,7 @@
#include "snmpd.h"
#include "mib.h"
+#include "application.h"
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
@@ -461,8 +462,9 @@ smi_debug_elements(struct ber_element *r
}
#endif
+/* Keep around so trap handle scripts don't break */
char *
-smi_print_element(struct ber_element *root)
+smi_print_element_legacy(struct ber_element *root)
{
char *str = NULL, *buf, *p;
size_t len, i;
@@ -520,6 +522,139 @@ smi_print_element(struct ber_element *ro
case BER_TYPE_SET:
default:
str = strdup("");
+ break;
+ }
+
+ return (str);
+
+ fail:
+ free(str);
+ return (NULL);
+}
+
+char *
+smi_print_element(struct ber_element *root)
+{
+ char *str = NULL, *buf, *p;
+ long long v;
+ struct ber_oid o;
+ char strbuf[BUFSIZ];
+
+ switch (root->be_class) {
+ case BER_CLASS_UNIVERSAL:
+ switch (root->be_type) {
+ case BER_TYPE_INTEGER:
+ if (ober_get_integer(root, &v) == -1)
+ goto fail;
+ if (asprintf(&str, "%lld", v) == -1)
+ goto fail;
+ break;
+ case BER_TYPE_OBJECT:
+ if (ober_get_oid(root, &o) == -1)
+ goto fail;
+ if (asprintf(&str, "%s", smi_oid2string(&o, strbuf,
+ sizeof(strbuf), 0)) == -1)
+ goto fail;
+ break;
+ case BER_TYPE_OCTETSTRING:
+ if (ober_get_string(root, &buf) == -1)
+ goto fail;
+ p = reallocarray(NULL, 4, root->be_len + 1);
+ if (p == NULL)
+ goto fail;
+ strvisx(p, buf, root->be_len, VIS_NL);
+ if (asprintf(&str, "\"%s\"", p) == -1) {
+ free(p);
+ goto fail;
+ }
+ free(p);
+ break;
+ case BER_TYPE_NULL:
+ if (asprintf(&str, "null") == -1)
+ goto fail;
+ default:
+ /* Should not happen in a valid SNMP packet */
+ if (asprintf(&str, "[U/%u]", root->be_type) == -1)
+ goto fail;
+ break;
+ }
+ break;
+ case BER_CLASS_APPLICATION:
+ switch (root->be_type) {
+ case SNMP_T_IPADDR:
+ if (ober_get_string(root, &buf) == -1)
+ goto fail;
+ if (asprintf(&str, "%s",
+ inet_ntoa(*(struct in_addr *)buf)) == -1)
+ goto fail;
+ break;
+ case SNMP_T_COUNTER32:
+ if (ober_get_integer(root, &v) == -1)
+ goto fail;
+ if (asprintf(&str, "%lld(c32)", v) == -1)
+ goto fail;
+ break;
+ case SNMP_T_GAUGE32:
+ if (ober_get_integer(root, &v) == -1)
+ goto fail;
+ if (asprintf(&str, "%lld(g32)", v) == -1)
+ goto fail;
+ break;
+ case SNMP_T_TIMETICKS:
+ if (ober_get_integer(root, &v) == -1)
+ goto fail;
+ if (asprintf(&str, "%lld.%llds", v/100, v%100) == -1)
+ goto fail;
+ break;
+ case SNMP_T_OPAQUE:
+ if (ober_get_string(root, &buf) == -1)
+ goto fail;
+ p = reallocarray(NULL, 4, root->be_len + 1);
+ if (p == NULL)
+ goto fail;
+ strvisx(p, buf, root->be_len, VIS_NL);
+ if (asprintf(&str, "\"%s\"(opaque)", p) == -1) {
+ free(p);
+ goto fail;
+ }
+ free(p);
+ break;
+ case SNMP_T_COUNTER64:
+ if (ober_get_integer(root, &v) == -1)
+ goto fail;
+ if (asprintf(&str, "%lld(c64)", v) == -1)
+ goto fail;
+ break;
+ default:
+ /* Should not happen in a valid SNMP packet */
+ if (asprintf(&str, "[A/%u]", root->be_type) == -1)
+ goto fail;
+ break;
+ }
+ break;
+ case BER_CLASS_CONTEXT:
+ switch (root->be_type) {
+ case SNMP_V_NOSUCHOBJECT:
+ str = strdup("noSuchObject");
+ break;
+ case SNMP_V_NOSUCHINSTANCE:
+ str = strdup("noSuchInstance");
+ break;
+ case SNMP_V_ENDOFMIBVIEW:
+ str = strdup("endOfMibView");
+ break;
+ default:
+ /* Should not happen in a valid SNMP packet */
+ if (asprintf(&str, "[C/%u]", root->be_type) == -1)
+ goto fail;
+ break;
+ }
+ break;
+ default:
+ /* Should not happen in a valid SNMP packet */
+ if (asprintf(&str, "[%hhu/%u]", root->be_class,
+ root->be_type) == -1)
+ goto fail;
break;
}
Index: smi.h
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/smi.h,v
retrieving revision 1.1
diff -u -p -r1.1 smi.h
--- smi.h 19 Jan 2022 10:25:04 -0000 1.1
+++ smi.h 19 Jan 2022 15:21:20 -0000
@@ -25,3 +25,4 @@
char *smi_oid2string(struct ber_oid *, char *, size_t, size_t);
u_long smi_getticks(void);
char *smi_print_element(struct ber_element *);
+char *smi_print_element_legacy(struct ber_element *);
Index: snmp.h
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmp.h,v
retrieving revision 1.18
diff -u -p -r1.18 snmp.h
--- snmp.h 21 Oct 2021 14:33:13 -0000 1.18
+++ snmp.h 19 Jan 2022 15:21:20 -0000
@@ -91,6 +91,12 @@ enum snmp_pdutype {
SNMP_C_REPORT = 8
};
+enum snmp_varbindtype {
+ SNMP_V_NOSUCHOBJECT = 0,
+ SNMP_V_NOSUCHINSTANCE = 1,
+ SNMP_V_ENDOFMIBVIEW = 2
+};
+
enum snmp_application {
SNMP_T_IPADDR = 0,
SNMP_T_COUNTER32 = 1,
Index: traphandler.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/traphandler.c,v
retrieving revision 1.22
diff -u -p -r1.22 traphandler.c
--- traphandler.c 21 Oct 2021 08:17:34 -0000 1.22
+++ traphandler.c 19 Jan 2022 15:21:20 -0000
@@ -380,7 +380,7 @@ trapcmd_exec(struct trapcmd *cmd, struct
for (; vb != NULL; vb = vb->be_next) {
if (ober_scanf_elements(vb, "{oeS$}", &oid, &elm) == -1)
goto out;
- if ((value = smi_print_element(elm)) == NULL)
+ if ((value = smi_print_element_legacy(elm)) == NULL)
goto out;
smi_oid2string(&oid, oidbuf, sizeof(oidbuf), 0);
n = dprintf(s[0], "%s %s\n", oidbuf, value);