Add a couple of tests for handling of tcp connections.
authormartijn <martijn@openbsd.org>
Mon, 20 Nov 2023 10:34:21 +0000 (10:34 +0000)
committermartijn <martijn@openbsd.org>
Mon, 20 Nov 2023 10:34:21 +0000 (10:34 +0000)
regress/usr.sbin/snmpd/Makefile
regress/usr.sbin/snmpd/regress.h
regress/usr.sbin/snmpd/snmp.c
regress/usr.sbin/snmpd/snmpd_regress.c
regress/usr.sbin/snmpd/transport.c [new file with mode: 0644]

index 9f34037..63b0fc0 100644 (file)
@@ -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
index cd05eb5..b63a587 100644 (file)
@@ -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);
index 3339095..d2e105e 100644 (file)
@@ -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");
index 36714ce..044f843 100644 (file)
@@ -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 (file)
index 0000000..cfda5ba
--- /dev/null
@@ -0,0 +1,150 @@
+#include <sys/socket.h>
+
+#include <ber.h>
+#include <err.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#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);
+}