From 4e63e8f9957526d4ffa42e6da06b1274ae9e1088 Mon Sep 17 00:00:00 2001 From: martijn Date: Mon, 20 Nov 2023 10:34:21 +0000 Subject: [PATCH] Add a couple of tests for handling of tcp connections. --- regress/usr.sbin/snmpd/Makefile | 12 +- regress/usr.sbin/snmpd/regress.h | 21 ++++ regress/usr.sbin/snmpd/snmp.c | 39 +++---- regress/usr.sbin/snmpd/snmpd_regress.c | 5 +- regress/usr.sbin/snmpd/transport.c | 150 +++++++++++++++++++++++++ 5 files changed, 205 insertions(+), 22 deletions(-) create mode 100644 regress/usr.sbin/snmpd/transport.c diff --git a/regress/usr.sbin/snmpd/Makefile b/regress/usr.sbin/snmpd/Makefile index 9f3403736b8..63b0fc01711 100644 --- a/regress/usr.sbin/snmpd/Makefile +++ b/regress/usr.sbin/snmpd/Makefile @@ -1,8 +1,9 @@ -# $OpenBSD: Makefile,v 1.11 2023/11/16 13:26:45 martijn Exp $ +# $OpenBSD: Makefile,v 1.12 2023/11/20 10:34:21 martijn Exp $ # Regress tests for snmpd PROG = snmpd_regress SRCS = snmpd_regress.c agentx.c backend.c snmp.c +SRCS+= transport.c LDADD= -lutil DPADD= ${LIBUTIL} @@ -249,7 +250,14 @@ SNMP_TARGETS+= snmp_v3_usm_noauthpriv REGRESS_TARGETS+= ${SNMP_TARGETS} snmp: ${SNMP_TARGETS} -.PHONY: agentx backend +TRANSPORT_TARGETS+= transport_tcp_get +TRANSPORT_TARGETS+= transport_tcp_disconnect +TRANSPORT_TARGETS+= transport_tcp_double_get_disconnect + +REGRESS_TARGETS+= ${TRANSPORT_TARGETS} +transport: ${TRANSPORT_TARGETS} + +.PHONY: agentx backend snmp transport ${REGRESS_TARGETS}: snmpd_regress # Always start snmpd if it's not running diff --git a/regress/usr.sbin/snmpd/regress.h b/regress/usr.sbin/snmpd/regress.h index cd05eb51bf2..b63a58723d3 100644 --- a/regress/usr.sbin/snmpd/regress.h +++ b/regress/usr.sbin/snmpd/regress.h @@ -98,6 +98,19 @@ struct varbind { } data; }; +enum snmp_request { + REQUEST_GET = 0, + REQUEST_GETNEXT = 1, + REQUEST_RESPONSE = 2, + REQUEST_SET = 3, + REQUEST_TRAP = 4, + REQUEST_GETBULK = 5, + REQUEST_INFORM = 6, + REQUEST_TRAPV2 = 7, + REQUEST_REPORT = 8 +}; + + extern int verbose; extern char *axsocket; extern char *hostname; @@ -128,11 +141,13 @@ char *oid_print(struct oid *, char *, size_t); #define MIB_SUBAGENT_UNREGISTER MIB_SUBAGENTS, 4 #define MIB_SUBAGENT_BACKEND MIB_SUBAGENTS, 5 #define MIB_SUBAGENT_SNMP MIB_SUBAGENTS, 6 +#define MIB_SUBAGENT_TRANSPORT MIB_SUBAGENTS, 7 /* Region used for registration testing */ #define MIB_REGISTER MIB_OPENBSD_REGRESS, 2 #define MIB_UNREGISTER MIB_OPENBSD_REGRESS, 3 #define MIB_BACKEND MIB_OPENBSD_REGRESS, 4 #define MIB_SNMP MIB_OPENBSD_REGRESS, 5 +#define MIB_TRANSPORT MIB_OPENBSD_REGRESS, 6 #define SYSORTABLE 1, 3, 6, 1, 2, 1, 1, 9 @@ -234,9 +249,12 @@ int32_t snmpv2_get(int, const char *, int32_t, struct varbind *, size_t); int32_t snmpv2_getnext(int, const char *, int32_t, struct varbind *, size_t); int32_t snmpv2_getbulk(int, const char *, int32_t, int32_t, int32_t, struct varbind *, size_t); +struct ber_element *snmpv2_build(const char *, enum snmp_request, int32_t, + int32_t, int32_t, struct varbind *, size_t); void snmpv2_response_validate(int, int, const char *, int32_t, int32_t, int32_t, struct varbind *, size_t); void snmp_timeout(int, int); +void smi_debug_elements(struct ber_element *); void backend_get_integer(void); void backend_get_octetstring(void); @@ -370,3 +388,6 @@ void backend_error_getnext_nonstandard(void); void backend_error_getbulk_firstrepetition(void); void backend_error_getbulk_secondrepetition(void); void snmp_v3_usm_noauthpriv(void); +void transport_tcp_get(void); +void transport_tcp_disconnect(void); +void transport_tcp_double_get_disconnect(void); diff --git a/regress/usr.sbin/snmpd/snmp.c b/regress/usr.sbin/snmpd/snmp.c index 333909531f8..d2e105edff0 100644 --- a/regress/usr.sbin/snmpd/snmp.c +++ b/regress/usr.sbin/snmpd/snmp.c @@ -54,18 +54,6 @@ enum snmp_exception { EXCEPTION_ENDOFMIBVIEW = 2 }; -enum snmp_request { - REQUEST_GET = 0, - REQUEST_GETNEXT = 1, - REQUEST_RESPONSE = 2, - REQUEST_SET = 3, - REQUEST_TRAP = 4, - REQUEST_GETBULK = 5, - REQUEST_INFORM = 6, - REQUEST_TRAPV2 = 7, - REQUEST_REPORT = 8 -}; - enum security_model { SM_USM = 3, SM_TSM = 4 @@ -127,7 +115,6 @@ struct ber_element *snmp_data2ber_element(enum type, union data *); unsigned int smi_application(struct ber_element *); char *smi_oid2string(struct ber_oid *, char *, size_t); char *smi_print_element(struct ber_element *); -void smi_debug_elements(struct ber_element *); struct ber_element *v2cmps(struct ber_element *, const char *); void snmp_pdu_validate(struct ber_element *, enum snmp_request, int32_t, int32_t, int32_t, struct varbind *, size_t); @@ -243,6 +230,23 @@ snmpv2_getbulk(int s, const char *community, int32_t requestid, int32_t nonrep, maxrep, varbindlist, nvarbind); } +struct ber_element * +snmpv2_build(const char *community, enum snmp_request request, + int32_t requestid, int32_t error, int32_t index, + struct varbind *varbindlist, size_t nvarbind) +{ + struct ber_element *message; + + if (community == NULL) + community = SNMP_R_COMMUNITY; + message = ober_printf_elements(NULL, "{dse}", 1, community, + snmp_pdu(request, requestid, error, index, varbindlist, nvarbind)); + if (message == NULL) + err(1, NULL); + + return message; +} + int32_t snmpv2_send(int s, const char *community, enum snmp_request request, int32_t requestid, int32_t error, int32_t index, @@ -253,14 +257,11 @@ snmpv2_send(int s, const char *community, enum snmp_request request, void *buf; ssize_t buflen, writelen; - if (community == NULL) - community = SNMP_R_COMMUNITY; while (requestid == 0) requestid = arc4random(); - message = ober_printf_elements(NULL, "{dse}", 1, community, - snmp_pdu(request, requestid, error, index, varbindlist, nvarbind)); - if (message == NULL) - err(1, NULL); + + message = snmpv2_build(community, request, requestid, error, index, + varbindlist,nvarbind); if (ober_write_elements(&ber, message) == -1) err(1, "ober_write_elements"); diff --git a/regress/usr.sbin/snmpd/snmpd_regress.c b/regress/usr.sbin/snmpd/snmpd_regress.c index 36714ce3708..044f843e491 100644 --- a/regress/usr.sbin/snmpd/snmpd_regress.c +++ b/regress/usr.sbin/snmpd/snmpd_regress.c @@ -213,7 +213,10 @@ const struct { { "backend_error_getnext_nonstandard", backend_error_getnext_nonstandard }, { "backend_error_getbulk_firstrepetition", backend_error_getbulk_firstrepetition }, { "backend_error_getbulk_secondrepetition", backend_error_getbulk_secondrepetition }, - { "snmp_v3_usm_noauthpriv", snmp_v3_usm_noauthpriv}, + { "snmp_v3_usm_noauthpriv", snmp_v3_usm_noauthpriv }, + { "transport_tcp_get", transport_tcp_get }, + { "transport_tcp_disconnect", transport_tcp_disconnect }, + { "transport_tcp_double_get_disconnect", transport_tcp_double_get_disconnect }, { NULL, NULL } }; diff --git a/regress/usr.sbin/snmpd/transport.c b/regress/usr.sbin/snmpd/transport.c new file mode 100644 index 00000000000..cfda5ba4fd3 --- /dev/null +++ b/regress/usr.sbin/snmpd/transport.c @@ -0,0 +1,150 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "regress.h" + +#define MIB_SUBAGENT_TRANSPORT_TCP MIB_SUBAGENT_TRANSPORT, 1 +#define MIB_TRANSPORT_TCP MIB_TRANSPORT, 1 + +void +transport_tcp_get(void) +{ + struct sockaddr_storage ss; + struct sockaddr *sa = (struct sockaddr *)&ss; + socklen_t salen; + int snmp_s, ax_s; + uint32_t sessionid; + struct varbind varbind = { + .type = TYPE_NULL, + .name = OID_STRUCT(MIB_TRANSPORT_TCP, 1, 0), + .data.int32 = 1 + }; + int32_t requestid; + char buf[1024]; + size_t n; + + ax_s = agentx_connect(axsocket); + sessionid = agentx_open(ax_s, 0, 0, + OID_ARG(MIB_SUBAGENT_TRANSPORT_TCP, 1), __func__); + agentx_register(ax_s, sessionid, 0, 0, 127, 0, + OID_ARG(MIB_TRANSPORT_TCP, 1), 0); + + salen = snmp_resolve(SOCK_STREAM, hostname, servname, sa); + snmp_s = snmp_connect(SOCK_STREAM, sa, salen); + requestid = snmpv2_get(snmp_s, community, 0, &varbind, 1); + + n = agentx_read(ax_s, buf, sizeof(buf), 1000); + agentx_get_handle(__func__, buf, n, 0, sessionid, &varbind, 1); + + varbind.type = TYPE_INTEGER; + agentx_response(ax_s, buf, NOERROR, 0, &varbind, 1); + + snmpv2_response_validate(snmp_s, 1000, community, requestid, 0, 0, + &varbind, 1); +} + +void +transport_tcp_disconnect(void) +{ + struct sockaddr_storage ss; + struct sockaddr *sa = (struct sockaddr *)&ss; + socklen_t salen; + int snmp_s, ax_s; + uint32_t sessionid; + struct varbind varbind = { + .type = TYPE_NULL, + .name = OID_STRUCT(MIB_TRANSPORT_TCP, 2, 0), + .data.int32 = 1 + }; + int32_t requestid; + char buf[1024]; + size_t n; + + ax_s = agentx_connect(axsocket); + sessionid = agentx_open(ax_s, 0, 0, + OID_ARG(MIB_SUBAGENT_TRANSPORT_TCP, 2), __func__); + agentx_register(ax_s, sessionid, 0, 0, 127, 0, + OID_ARG(MIB_TRANSPORT_TCP, 2), 0); + + salen = snmp_resolve(SOCK_STREAM, hostname, servname, sa); + snmp_s = snmp_connect(SOCK_STREAM, sa, salen); + requestid = snmpv2_get(snmp_s, community, 0, &varbind, 1); + + close(snmp_s); + + n = agentx_read(ax_s, buf, sizeof(buf), 1000); + agentx_get_handle(__func__, buf, n, 0, sessionid, &varbind, 1); + + varbind.type = TYPE_INTEGER; + agentx_response(ax_s, buf, NOERROR, 0, &varbind, 1); +} + +void +transport_tcp_double_get_disconnect(void) +{ + struct sockaddr_storage ss; + struct sockaddr *sa = (struct sockaddr *)&ss; + socklen_t salen; + int snmp_s, ax_s; + uint32_t sessionid; + struct varbind varbind = { + .type = TYPE_NULL, + .name = OID_STRUCT(MIB_TRANSPORT_TCP, 2, 0), + .data.int32 = 1 + }; + struct ber_element *message; + struct ber ber = {}; + char buf[1024]; + ssize_t buflen, writelen; + void *ptr; + size_t n; + + ax_s = agentx_connect(axsocket); + sessionid = agentx_open(ax_s, 0, 0, + OID_ARG(MIB_SUBAGENT_TRANSPORT_TCP, 2), __func__); + agentx_register(ax_s, sessionid, 0, 0, 127, 0, + OID_ARG(MIB_TRANSPORT_TCP, 2), 0); + + salen = snmp_resolve(SOCK_STREAM, hostname, servname, sa); + snmp_s = snmp_connect(SOCK_STREAM, sa, salen); + + message = snmpv2_build(community, REQUEST_GET, 0, 0, 0, &varbind, 1); + + if (ober_write_elements(&ber, message) == -1) + err(1, "ober_write_elements"); + + buflen = ober_get_writebuf(&ber, &ptr); + /* send two copies in a single window */ + memcpy(buf, ptr, buflen); + memcpy(buf + buflen, ptr, buflen); + + if ((writelen = write(snmp_s, buf, buflen * 2)) == -1) + err(1, "write"); + if (writelen != buflen * 2) + errx(1, "write: short write"); + + if (verbose) { + printf("SNMP send(%d):\n", snmp_s); + smi_debug_elements(message); + } + ober_free_elements(message); + ober_free(&ber); + + close(snmp_s); + + n = agentx_read(ax_s, buf, sizeof(buf), 1000); + agentx_get_handle(__func__, buf, n, 0, sessionid, &varbind, 1); + + varbind.type = TYPE_INTEGER; + agentx_response(ax_s, buf, NOERROR, 0, &varbind, 1); + + n = agentx_read(ax_s, buf, sizeof(buf), 1000); + agentx_get_handle(__func__, buf, n, 0, sessionid, &varbind, 1); + agentx_response(ax_s, buf, NOERROR, 0, &varbind, 1); +} -- 2.20.1