As the original comment said: /* * This should probably go into parsevarbinds, but that's for a * next refactor */
This moves the pdu parsing of traps into parsevarbinds. Added bonus, we can now see the packets in debugging mode: startup snmpe: listening on udp 127.0.0.1:162 ktable_new: new ktable for rtableid 0 snmpe_parse: 127.0.0.1:162: SNMPv2 'public' pdutype SNMPv2-Trap request 1329591927 snmpe_parse: 127.0.0.1:162: SNMPv1 'public' pdutype Trap request 0 OK? martijn@ Index: snmpd.h =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v retrieving revision 1.95 diff -u -p -r1.95 snmpd.h --- snmpd.h 20 May 2021 08:53:12 -0000 1.95 +++ snmpd.h 28 May 2021 06:17:16 -0000 @@ -776,6 +776,7 @@ int proc_flush_imsg(struct privsep *, e /* traphandler.c */ int traphandler_parse(struct snmp_message *); +int traphandler_v1translate(struct snmp_message *, int); int traphandler_priv_recvmsg(struct privsep_proc *, struct imsg *); void trapcmd_free(struct trapcmd *); int trapcmd_add(struct trapcmd *); Index: snmpe.c =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v retrieving revision 1.71 diff -u -p -r1.71 snmpe.c --- snmpe.c 20 May 2021 08:53:12 -0000 1.71 +++ snmpe.c 28 May 2021 06:17:16 -0000 @@ -368,6 +368,10 @@ snmpe_parse(struct snmp_message *msg) msg->sm_errstr = "trapv1 request on !SNMPv1 message"; goto parsefail; } + /* Internally we work with SNMPv2-Traps */ + if (traphandler_v1translate(msg, 0) == -1) + goto fail; + a = msg->sm_pdu->be_sub; case SNMP_C_TRAPV2: if (msg->sm_pdutype == SNMP_C_TRAPV2 && !(msg->sm_version == SNMP_V2 || @@ -390,16 +394,9 @@ snmpe_parse(struct snmp_message *msg) goto fail; } stats->snmp_intraps++; - /* - * This should probably go into parsevarbinds, but that's for a - * next refactor - */ - if (traphandler_parse(msg) == -1) - goto fail; - /* Shortcircuit */ - return 0; + break; default: - msg->sm_errstr = "invalid context"; + msg->sm_errstr = "invalid pdutype"; goto parsefail; } @@ -450,7 +447,14 @@ snmpe_parsevarbinds(struct snmp_message struct ber_element *pvarbind = NULL, *end; char buf[BUFSIZ]; struct ber_oid o; - int i; + int i = 1; + + if (msg->sm_pdutype == SNMP_C_TRAP || + msg->sm_pdutype == SNMP_C_TRAPV2) { + if (traphandler_parse(msg) == -1) + goto varfail; + return 0; + } msg->sm_errstr = "invalid varbind element"; @@ -458,7 +462,7 @@ snmpe_parsevarbinds(struct snmp_message msg->sm_varbindresp = NULL; end = NULL; - for (i = 1; varbind != NULL && i < SNMPD_MAXVARBIND; + for (; varbind != NULL && i < SNMPD_MAXVARBIND; varbind = varbind->be_next, i++) { if (ober_scanf_elements(varbind, "{oeS$}", &o, &value) == -1) { stats->snmp_inasnparseerrs++; @@ -543,7 +547,7 @@ snmpe_parsevarbinds(struct snmp_message msg->sm_errorindex = 0; return 0; - varfail: +varfail: log_debug("%s: %s:%hd: %s, error index %d", __func__, msg->sm_host, msg->sm_port, msg->sm_errstr, i); if (msg->sm_error == 0) @@ -790,18 +794,18 @@ snmpe_recvmsg(int fd, short sig, void *a void snmpe_dispatchmsg(struct snmp_message *msg) { - if (msg->sm_pdutype == SNMP_C_TRAP || - msg->sm_pdutype == SNMP_C_TRAPV2) { - snmp_msgfree(msg); - return; - } /* dispatched to subagent */ /* XXX Do proper error handling */ (void) snmpe_parsevarbinds(msg); - /* respond directly */ - msg->sm_pdutype = SNMP_C_GETRESP; - snmpe_response(msg); + if (msg->sm_pdutype == SNMP_C_TRAP || + msg->sm_pdutype == SNMP_C_TRAPV2) + snmp_msgfree(msg); + else { + /* respond directly */ + msg->sm_pdutype = SNMP_C_GETRESP; + snmpe_response(msg); + } } void Index: traphandler.c =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/traphandler.c,v retrieving revision 1.21 diff -u -p -r1.21 traphandler.c --- traphandler.c 22 Feb 2021 11:31:09 -0000 1.21 +++ traphandler.c 28 May 2021 06:17:16 -0000 @@ -45,8 +45,6 @@ int traphandler_priv_recvmsg(struct privsep_proc *, struct imsg *); int traphandler_fork_handler(struct privsep_proc *, struct imsg *); -struct ber_element * - traphandler_v1translate(struct snmp_message *, int); int trapcmd_cmp(struct trapcmd *, struct trapcmd *); void trapcmd_exec(struct trapcmd *, struct sockaddr *, struct ber_element *); @@ -76,25 +74,17 @@ traphandler_parse(struct snmp_message *m ssize_t buflen; int ret = -1; - switch (msg->sm_pdu->be_type) { - case SNMP_C_TRAP: - if ((vblist = traphandler_v1translate(msg, 0)) == NULL) - goto done; - break; - case SNMP_C_TRAPV2: - if (ober_scanf_elements(msg->sm_pdu, "{SSe}$", &elm) == -1) { - stats->snmp_inasnparseerrs++; - goto done; - } - if (elm->be_type != BER_TYPE_INTEGER) { - stats->snmp_inasnparseerrs++; - goto done; - } - vblist = ober_unlink_elements(elm); - break; - default: - fatalx("%s called without proper context", __func__); + if (ober_scanf_elements(msg->sm_pdu, "{SSe}$", &elm) == -1) { + stats->snmp_inasnparseerrs++; + msg->sm_errstr = "invalid pdu"; + goto done; + } + if (elm->be_type != BER_TYPE_INTEGER) { + stats->snmp_inasnparseerrs++; + msg->sm_errstr = "invalid pdu"; + goto done; } + vblist = ober_unlink_elements(elm); (void)ober_string2oid("1.3.6.1.2.1.1.3.0", &sysUpTimeOID); (void)ober_string2oid("1.3.6.1.6.3.1.1.4.1.0", &snmpTrapOIDOID); @@ -103,11 +93,13 @@ traphandler_parse(struct snmp_message *m ober_oid_cmp(&o1, &sysUpTimeOID) != 0 || ober_oid_cmp(&o2, &snmpTrapOIDOID) != 0) { stats->snmp_inasnparseerrs++; + msg->sm_errstr = "invalid pdu"; goto done; } (void)ober_scanf_elements(vblist, "{Se", &elm); for (elm = elm->be_next; elm != NULL; elm = elm->be_next) { if (ober_scanf_elements(elm, "{oS$}", &o1) == -1) { + msg->sm_errstr = "invalid pdu"; stats->snmp_inasnparseerrs++; goto done; } @@ -140,7 +132,7 @@ done: return ret; } -struct ber_element * +int traphandler_v1translate(struct snmp_message *msg, int proxy) { struct snmp_stats *stats = &snmpd_env->sc_stats; @@ -158,7 +150,8 @@ traphandler_v1translate(struct snmp_mess agent_addrlen != 4 || vblist->be_type != BER_TYPE_SEQUENCE) { stats->snmp_inasnparseerrs++; - return NULL; + msg->sm_errstr = "invalid pdu"; + return -1; } switch (generic_trap) { case 0: @@ -184,33 +177,33 @@ traphandler_v1translate(struct snmp_mess /* Officially this should be 128, but BER_MAX_OID_LEN is 64 */ if (trapoid.bo_n + 2 > BER_MAX_OID_LEN) { stats->snmp_inasnparseerrs++; - return NULL; + msg->sm_errstr = "enterprise too large"; + return -1; } trapoid.bo_id[trapoid.bo_n++] = 0; trapoid.bo_id[trapoid.bo_n++] = specific_trap; break; default: stats->snmp_inasnparseerrs++; - return NULL; + msg->sm_errstr = "invalid generic-trap"; + return -1; } /* work aronud net-snmp's snmptrap: It adds an EOC element in vblist */ if (vblist->be_len != 0) vb0 = ober_unlink_elements(vblist); + vblist = ober_unlink_elements(msg->sm_pdu); + ober_free_elements(vblist); - if ((vblist = ober_add_sequence(NULL)) == NULL) { - msg->sm_errstr = strerror(errno); - if (vb0 != NULL) - ober_free_elements(vb0); - return NULL; - } - if (ober_printf_elements(vblist, "{od}{oO}e", "1.3.6.1.2.1.1.3.0", - time_stamp, "1.3.6.1.6.3.1.1.4.1.0", &trapoid, vb0) == NULL) { + if (ober_printf_elements(msg->sm_pdu, "ddd{{od}{oO}e}", 0, 0, 0, + "1.3.6.1.2.1.1.3.0", time_stamp, "1.3.6.1.6.3.1.1.4.1.0", &trapoid, + vb0) == NULL) { msg->sm_errstr = strerror(errno); if (vb0 != 0) ober_free_elements(vb0); ober_free_elements(vblist); - return NULL; + msg->sm_errstr = strerror(errno); + return -1; } if (proxy) { @@ -220,11 +213,12 @@ traphandler_v1translate(struct snmp_mess &snmpTrapCommunityOid); (void)ober_string2oid("1.3.6.1.6.3.1.1.4.3.0", &snmpTrapEnterpriseOid); - for (elm = vblist->be_sub; elm != NULL; elm = elm->be_next) { + ober_scanf_elements(msg->sm_pdu, "{SSS{e", &elm); + for (; elm != NULL; elm = elm->be_next) { if (ober_get_oid(elm->be_sub, &oid) == -1) { msg->sm_errstr = "failed to read oid"; ober_free_elements(vblist); - return NULL; + return -1; } if (ober_oid_cmp(&oid, &snmpTrapAddressOid) == 0) hasaddress = 1; @@ -243,11 +237,11 @@ traphandler_v1translate(struct snmp_mess &snmpTrapEnterpriseOid, &enterprise) == NULL) { msg->sm_errstr = strerror(errno); ober_free_elements(vblist); - return NULL; + return -1; } } } - return vblist; + return 0; } int