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); +}