Module Name:    src
Committed By:   ozaki-r
Date:           Thu Nov 17 08:38:08 UTC 2022

Added Files:
        src/tests/net/inpcb: inpcb_bind.c

Log Message:
tests: import in_pcbbind/runtest.c from OpenBSD as inpcb_bind.c

As of $OpenBSD: runtest.c,v 1.7 2022/04/10 14:08:35 claudio Exp $


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/tests/net/inpcb/inpcb_bind.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/tests/net/inpcb/inpcb_bind.c
diff -u /dev/null src/tests/net/inpcb/inpcb_bind.c:1.1
--- /dev/null	Thu Nov 17 08:38:08 2022
+++ src/tests/net/inpcb/inpcb_bind.c	Thu Nov 17 08:38:08 2022
@@ -0,0 +1,455 @@
+/* $OpenBSD: runtest.c,v 1.7 2022/04/10 14:08:35 claudio Exp $ */
+/*
+ * Copyright (c) 2015 Vincent Gross <vincent.gr...@kilob.yt>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+#include <netdb.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+
+int
+runtest(int *sockp, struct addrinfo *ai, int reuseaddr, int reuseport,
+    void *mreq, int expected)
+{
+	int error, optval;
+	struct ip_mreq imr;
+
+	*sockp = socket(ai->ai_family, ai->ai_socktype, 0);
+	if (*sockp == -1) {
+		warn("%s : socket()", ai->ai_canonname);
+		return (3);
+	}
+
+	if (reuseaddr) {
+		optval = 1;
+		error = setsockopt(*sockp, SOL_SOCKET, SO_REUSEADDR,
+		    &optval, sizeof(int));
+		if (error) {
+			warn("%s : setsockopt(SO_REUSEADDR)", ai->ai_canonname);
+			return (2);
+		}
+	}
+
+	if (reuseport) {
+		optval = 1;
+		error = setsockopt(*sockp, SOL_SOCKET, SO_REUSEPORT,
+		    &optval, sizeof(int));
+		if (error) {
+			warn("%s : setsockopt(SO_REUSEPORT)", ai->ai_canonname);
+			return (2);
+		}
+	}
+
+	if (mreq) {
+		switch (ai->ai_family) {
+		case AF_INET6:
+			error = setsockopt(*sockp, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+			    mreq, sizeof(struct ipv6_mreq));
+			if (error) {
+				warn("%s : setsockopt(IPV6_JOIN_GROUP)",
+				    ai->ai_canonname);
+				return (2);
+			}
+			break;
+		case AF_INET:
+			error = setsockopt(*sockp, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+			    mreq, sizeof(struct ip_mreq));
+			if (error) {
+				warn("%s : setsockopt(IP_ADD_MEMBERSHIP)",
+				    ai->ai_canonname);
+				return (2);
+			}
+			break;
+		default:
+			warnx("%s : trying to join multicast group in unknown AF",
+			    ai->ai_canonname);
+			return (2);
+		}
+	}
+
+
+	error = bind(*sockp, ai->ai_addr, ai->ai_addrlen);
+	if (error && (expected == 0 || expected != errno)) {
+		warn("bind(%s,%s,%s)", ai->ai_canonname,
+		    reuseaddr ? "REUSEADDR" : "", reuseport ? "REUSEPORT" : "");
+		return (1);
+	}
+	if (error == 0 && expected != 0) {
+		warnx("bind(%s,%s,%s) succeeded, expected : %s", ai->ai_canonname,
+		    reuseaddr ? "REUSEADDR" : "", reuseport ? "REUSEPORT" : "",
+		    strerror(expected));
+		return (1);
+	}
+
+	return (0);
+}
+
+void
+cleanup(int *fds, int num_fds)
+{
+	while (num_fds-- > 0)
+		if (close(*fds++) && errno != EBADF)
+			err(2, "unable to clean up sockets, aborting");
+}
+
+int
+unicast_testsuite(struct addrinfo *local, struct addrinfo *any)
+{
+	int test_rc, rc, *s;
+	int sockets[4];
+
+	test_rc = 0;
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 0, 0, NULL, 0);
+	rc |= runtest(s++, any,   0, 0, NULL, EADDRINUSE);
+	rc |= runtest(s++, any,   1, 0, NULL, 0);
+	cleanup(sockets, 3);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 1);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, any,   0, 0, NULL, 0);
+	rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
+	rc |= runtest(s++, local, 1, 0, NULL, 0);
+	cleanup(sockets, 3);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 2);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 0, 1, NULL, 0);
+	rc |= runtest(s++, local, 0, 1, NULL, 0);
+	rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
+	rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
+	cleanup(sockets, 4);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 3);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, any, 0, 1, NULL, 0);
+	rc |= runtest(s++, any, 0, 1, NULL, 0);
+	rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
+	rc |= runtest(s++, any, 0, 0, NULL, EADDRINUSE);
+	cleanup(sockets, 4);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 4);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 1, 0, NULL, 0);
+	rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
+	rc |= runtest(s++, local, 0, 1, NULL, EADDRINUSE);
+	cleanup(sockets, 3);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 5);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, any, 1, 0, NULL, 0);
+	rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
+	rc |= runtest(s++, any, 0, 1, NULL, EADDRINUSE);
+	cleanup(sockets, 3);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 6);
+
+	return (test_rc);
+}
+
+int
+mcast_reuse_testsuite(struct addrinfo *local, void *mr)
+{
+	int test_rc, rc, *s;
+	int sockets[6];
+	int testnum = 1;
+
+	test_rc = 0;
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 0, 0, mr, 0);
+	rc |= runtest(s++, local, 1, 0, mr, EADDRINUSE);
+	rc |= runtest(s++, local, 0, 1, mr, EADDRINUSE);
+	rc |= runtest(s++, local, 1, 1, mr, EADDRINUSE);
+	cleanup(sockets, 4);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 1);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 0, 1, mr, 0);
+	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
+	rc |= runtest(s++, local, 0, 1, mr, 0);
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	cleanup(sockets, 5);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 2);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 0, 1, mr, 0);
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	cleanup(sockets, 5);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 3);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
+	rc |= runtest(s++, local, 0, 1, mr, 0);
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	cleanup(sockets, 5);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 4);
+
+#if 0
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 0, 1, mr, 0);
+	cleanup(sockets, 3);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 5);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	rc |= runtest(s++, local, 0, 1, mr, 0);
+	cleanup(sockets, 5);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 6);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 1, 1, mr, 0);
+	rc |= runtest(s++, local, 1, 0, mr, 0);
+	rc |= runtest(s++, local, 0, 1, mr, 0);
+	cleanup(sockets, 5);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 7);
+#endif
+	return (test_rc);
+}
+
+int
+mcast6_testsuite(struct addrinfo *local, struct ipv6_mreq *local_mreq,
+    struct addrinfo *any, struct ipv6_mreq *any_mreq)
+{
+	int test_rc, rc, *s;
+	int sockets[4];
+	int testnum = 1;
+
+	test_rc = 0;
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 0, 0, local_mreq, 0);
+	rc |= runtest(s++, any,   0, 0, any_mreq,   EADDRINUSE);
+	rc |= runtest(s++, any,   1, 0, any_mreq,   0);
+	cleanup(sockets, 3);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 1);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, any,   0, 0, any_mreq,   0);
+	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
+	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
+	cleanup(sockets, 3);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 2);
+	
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
+	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
+	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
+	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
+	cleanup(sockets, 4);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 3);
+
+	/*
+	 * :: is not a multicast address, SO_REUSEADDR and SO_REUSEPORT
+	 * keep their unicast semantics although we are binding on multicast
+	 */
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, any, 0, 1, any_mreq, 0);
+	rc |= runtest(s++, any, 0, 1, any_mreq, 0);
+	rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
+	rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
+	cleanup(sockets, 4);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 4);
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
+	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
+	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
+	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
+	cleanup(sockets, 4);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 5);
+
+	/* See above */
+
+	rc = 0; s = sockets;
+	rc |= runtest(s++, any, 1, 0, any_mreq, 0);
+	rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
+	rc |= runtest(s++, any, 0, 1, any_mreq, EADDRINUSE);
+	rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
+	cleanup(sockets, 4);
+	test_rc |= rc;
+	if (rc)
+		warnx("%s : test #%d failed", __func__, 6);
+
+	return (test_rc);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int error, rc;
+	char *baddr_s, *bport_s, *bmifa_s;
+	struct addrinfo hints, *baddr, *any, *mifa;
+	struct ifaddrs *ifap, *curifa;
+	struct ip_mreq local_imr, any_imr;
+	struct ipv6_mreq local_i6mr, any_i6mr;
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
+	int *s;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV | \
+	    AI_PASSIVE;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	baddr_s = argv[1];
+	bport_s = argv[2];
+
+	if ((error = getaddrinfo(baddr_s, bport_s, &hints, &baddr)))
+		errx(2, "getaddrinfo(%s,%s): %s", baddr_s, bport_s,
+		    gai_strerror(error));
+	baddr->ai_canonname = baddr_s;
+
+	hints.ai_family = baddr->ai_family;
+	if ((error = getaddrinfo(NULL, bport_s, &hints, &any)))
+		errx(2, "getaddrinfo(NULL,%s): %s", bport_s,
+		    gai_strerror(error));
+	any->ai_canonname = "*";
+
+	switch (baddr->ai_family) {
+	case AF_INET:
+		sin = (struct sockaddr_in *)baddr->ai_addr;
+		if (!IN_MULTICAST( ntohl(sin->sin_addr.s_addr) )) {
+			puts("executing unicast testsuite");
+			return unicast_testsuite(baddr, any);
+		}
+		bmifa_s = argv[3];
+		hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
+
+		if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa)))
+			errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s,
+			    gai_strerror(error));
+
+		local_imr.imr_interface =
+		    ((struct sockaddr_in *)mifa->ai_addr)->sin_addr;
+		local_imr.imr_multiaddr =
+		    ((struct sockaddr_in *)baddr->ai_addr)->sin_addr;
+
+		puts("executing ipv4 multicast testsuite");
+
+		/* no 'any' mcast group in ipv4 */
+		return mcast_reuse_testsuite(baddr, &local_imr);
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)baddr->ai_addr;
+		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
+			puts("executing unicast testsuite");
+			return unicast_testsuite(baddr, any);
+		}
+		bmifa_s = argv[3];
+		hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
+
+		if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa)))
+			errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s,
+			    gai_strerror(error));
+
+		if (getifaddrs(&ifap))
+			err(2, "getifaddrs()");
+		curifa = ifap;
+		while (curifa) {
+			if (curifa->ifa_addr != NULL &&
+			    memcmp(curifa->ifa_addr,
+			    mifa->ai_addr,
+			    mifa->ai_addrlen) == 0)
+				break;
+			curifa = curifa->ifa_next;
+		}
+		if (curifa == NULL)
+			errx(2, "no interface configured with %s", argv[4]);
+		local_i6mr.ipv6mr_interface =
+		    if_nametoindex(curifa->ifa_name);
+		if (local_i6mr.ipv6mr_interface == 0)
+			errx(2, "unable to get \"%s\" index",
+			    curifa->ifa_name);
+		freeifaddrs(ifap);
+
+		local_i6mr.ipv6mr_multiaddr =
+		    ((struct sockaddr_in6 *)baddr->ai_addr)->sin6_addr;
+
+		any_i6mr.ipv6mr_interface = local_i6mr.ipv6mr_interface;
+		any_i6mr.ipv6mr_multiaddr =
+		    ((struct sockaddr_in6 *)any->ai_addr)->sin6_addr;
+
+		puts("executing ipv6 multicast testsuite");
+
+		rc = 0;
+		rc |= mcast_reuse_testsuite(baddr, &local_i6mr);
+		if (geteuid() == 0)
+			rc |= mcast6_testsuite(baddr, &local_i6mr, any, &any_i6mr);
+		else
+			warnx("skipping mcast6_testsuite() due to insufficient privs, please run again as root");
+		return (rc);
+	default:
+		errx(2,"unknown AF");
+	}
+
+	return (2);
+}

Reply via email to