Home | History | Annotate | Line # | Download | only in inpcb
inpcb_bind.c revision 1.1
      1 /* $OpenBSD: runtest.c,v 1.7 2022/04/10 14:08:35 claudio Exp $ */
      2 /*
      3  * Copyright (c) 2015 Vincent Gross <vincent.gross (at) kilob.yt>
      4  *
      5  * Permission to use, copy, modify, and distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  */
     17 
     18 #include <errno.h>
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 #include <unistd.h>
     22 #include <string.h>
     23 #include <err.h>
     24 #include <netdb.h>
     25 
     26 #include <sys/types.h>
     27 #include <sys/socket.h>
     28 #include <netinet/in.h>
     29 #include <net/if.h>
     30 #include <ifaddrs.h>
     31 
     32 int
     33 runtest(int *sockp, struct addrinfo *ai, int reuseaddr, int reuseport,
     34     void *mreq, int expected)
     35 {
     36 	int error, optval;
     37 	struct ip_mreq imr;
     38 
     39 	*sockp = socket(ai->ai_family, ai->ai_socktype, 0);
     40 	if (*sockp == -1) {
     41 		warn("%s : socket()", ai->ai_canonname);
     42 		return (3);
     43 	}
     44 
     45 	if (reuseaddr) {
     46 		optval = 1;
     47 		error = setsockopt(*sockp, SOL_SOCKET, SO_REUSEADDR,
     48 		    &optval, sizeof(int));
     49 		if (error) {
     50 			warn("%s : setsockopt(SO_REUSEADDR)", ai->ai_canonname);
     51 			return (2);
     52 		}
     53 	}
     54 
     55 	if (reuseport) {
     56 		optval = 1;
     57 		error = setsockopt(*sockp, SOL_SOCKET, SO_REUSEPORT,
     58 		    &optval, sizeof(int));
     59 		if (error) {
     60 			warn("%s : setsockopt(SO_REUSEPORT)", ai->ai_canonname);
     61 			return (2);
     62 		}
     63 	}
     64 
     65 	if (mreq) {
     66 		switch (ai->ai_family) {
     67 		case AF_INET6:
     68 			error = setsockopt(*sockp, IPPROTO_IPV6, IPV6_JOIN_GROUP,
     69 			    mreq, sizeof(struct ipv6_mreq));
     70 			if (error) {
     71 				warn("%s : setsockopt(IPV6_JOIN_GROUP)",
     72 				    ai->ai_canonname);
     73 				return (2);
     74 			}
     75 			break;
     76 		case AF_INET:
     77 			error = setsockopt(*sockp, IPPROTO_IP, IP_ADD_MEMBERSHIP,
     78 			    mreq, sizeof(struct ip_mreq));
     79 			if (error) {
     80 				warn("%s : setsockopt(IP_ADD_MEMBERSHIP)",
     81 				    ai->ai_canonname);
     82 				return (2);
     83 			}
     84 			break;
     85 		default:
     86 			warnx("%s : trying to join multicast group in unknown AF",
     87 			    ai->ai_canonname);
     88 			return (2);
     89 		}
     90 	}
     91 
     92 
     93 	error = bind(*sockp, ai->ai_addr, ai->ai_addrlen);
     94 	if (error && (expected == 0 || expected != errno)) {
     95 		warn("bind(%s,%s,%s)", ai->ai_canonname,
     96 		    reuseaddr ? "REUSEADDR" : "", reuseport ? "REUSEPORT" : "");
     97 		return (1);
     98 	}
     99 	if (error == 0 && expected != 0) {
    100 		warnx("bind(%s,%s,%s) succeeded, expected : %s", ai->ai_canonname,
    101 		    reuseaddr ? "REUSEADDR" : "", reuseport ? "REUSEPORT" : "",
    102 		    strerror(expected));
    103 		return (1);
    104 	}
    105 
    106 	return (0);
    107 }
    108 
    109 void
    110 cleanup(int *fds, int num_fds)
    111 {
    112 	while (num_fds-- > 0)
    113 		if (close(*fds++) && errno != EBADF)
    114 			err(2, "unable to clean up sockets, aborting");
    115 }
    116 
    117 int
    118 unicast_testsuite(struct addrinfo *local, struct addrinfo *any)
    119 {
    120 	int test_rc, rc, *s;
    121 	int sockets[4];
    122 
    123 	test_rc = 0;
    124 	rc = 0; s = sockets;
    125 	rc |= runtest(s++, local, 0, 0, NULL, 0);
    126 	rc |= runtest(s++, any,   0, 0, NULL, EADDRINUSE);
    127 	rc |= runtest(s++, any,   1, 0, NULL, 0);
    128 	cleanup(sockets, 3);
    129 	test_rc |= rc;
    130 	if (rc)
    131 		warnx("%s : test #%d failed", __func__, 1);
    132 
    133 	rc = 0; s = sockets;
    134 	rc |= runtest(s++, any,   0, 0, NULL, 0);
    135 	rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
    136 	rc |= runtest(s++, local, 1, 0, NULL, 0);
    137 	cleanup(sockets, 3);
    138 	test_rc |= rc;
    139 	if (rc)
    140 		warnx("%s : test #%d failed", __func__, 2);
    141 
    142 	rc = 0; s = sockets;
    143 	rc |= runtest(s++, local, 0, 1, NULL, 0);
    144 	rc |= runtest(s++, local, 0, 1, NULL, 0);
    145 	rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
    146 	rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
    147 	cleanup(sockets, 4);
    148 	test_rc |= rc;
    149 	if (rc)
    150 		warnx("%s : test #%d failed", __func__, 3);
    151 
    152 	rc = 0; s = sockets;
    153 	rc |= runtest(s++, any, 0, 1, NULL, 0);
    154 	rc |= runtest(s++, any, 0, 1, NULL, 0);
    155 	rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
    156 	rc |= runtest(s++, any, 0, 0, NULL, EADDRINUSE);
    157 	cleanup(sockets, 4);
    158 	test_rc |= rc;
    159 	if (rc)
    160 		warnx("%s : test #%d failed", __func__, 4);
    161 
    162 	rc = 0; s = sockets;
    163 	rc |= runtest(s++, local, 1, 0, NULL, 0);
    164 	rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
    165 	rc |= runtest(s++, local, 0, 1, NULL, EADDRINUSE);
    166 	cleanup(sockets, 3);
    167 	test_rc |= rc;
    168 	if (rc)
    169 		warnx("%s : test #%d failed", __func__, 5);
    170 
    171 	rc = 0; s = sockets;
    172 	rc |= runtest(s++, any, 1, 0, NULL, 0);
    173 	rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
    174 	rc |= runtest(s++, any, 0, 1, NULL, EADDRINUSE);
    175 	cleanup(sockets, 3);
    176 	test_rc |= rc;
    177 	if (rc)
    178 		warnx("%s : test #%d failed", __func__, 6);
    179 
    180 	return (test_rc);
    181 }
    182 
    183 int
    184 mcast_reuse_testsuite(struct addrinfo *local, void *mr)
    185 {
    186 	int test_rc, rc, *s;
    187 	int sockets[6];
    188 	int testnum = 1;
    189 
    190 	test_rc = 0;
    191 	rc = 0; s = sockets;
    192 	rc |= runtest(s++, local, 0, 0, mr, 0);
    193 	rc |= runtest(s++, local, 1, 0, mr, EADDRINUSE);
    194 	rc |= runtest(s++, local, 0, 1, mr, EADDRINUSE);
    195 	rc |= runtest(s++, local, 1, 1, mr, EADDRINUSE);
    196 	cleanup(sockets, 4);
    197 	test_rc |= rc;
    198 	if (rc)
    199 		warnx("%s : test #%d failed", __func__, 1);
    200 
    201 	rc = 0; s = sockets;
    202 	rc |= runtest(s++, local, 0, 1, mr, 0);
    203 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
    204 	rc |= runtest(s++, local, 0, 1, mr, 0);
    205 	rc |= runtest(s++, local, 1, 0, mr, 0);
    206 	rc |= runtest(s++, local, 1, 1, mr, 0);
    207 	cleanup(sockets, 5);
    208 	test_rc |= rc;
    209 	if (rc)
    210 		warnx("%s : test #%d failed", __func__, 2);
    211 
    212 	rc = 0; s = sockets;
    213 	rc |= runtest(s++, local, 1, 0, mr, 0);
    214 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
    215 	rc |= runtest(s++, local, 1, 0, mr, 0);
    216 	rc |= runtest(s++, local, 0, 1, mr, 0);
    217 	rc |= runtest(s++, local, 1, 1, mr, 0);
    218 	cleanup(sockets, 5);
    219 	test_rc |= rc;
    220 	if (rc)
    221 		warnx("%s : test #%d failed", __func__, 3);
    222 
    223 	rc = 0; s = sockets;
    224 	rc |= runtest(s++, local, 1, 1, mr, 0);
    225 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
    226 	rc |= runtest(s++, local, 0, 1, mr, 0);
    227 	rc |= runtest(s++, local, 1, 0, mr, 0);
    228 	rc |= runtest(s++, local, 1, 1, mr, 0);
    229 	cleanup(sockets, 5);
    230 	test_rc |= rc;
    231 	if (rc)
    232 		warnx("%s : test #%d failed", __func__, 4);
    233 
    234 #if 0
    235 	rc = 0; s = sockets;
    236 	rc |= runtest(s++, local, 1, 1, mr, 0);
    237 	rc |= runtest(s++, local, 1, 0, mr, 0);
    238 	rc |= runtest(s++, local, 0, 1, mr, 0);
    239 	cleanup(sockets, 3);
    240 	test_rc |= rc;
    241 	if (rc)
    242 		warnx("%s : test #%d failed", __func__, 5);
    243 
    244 	rc = 0; s = sockets;
    245 	rc |= runtest(s++, local, 1, 1, mr, 0);
    246 	rc |= runtest(s++, local, 1, 0, mr, 0);
    247 	rc |= runtest(s++, local, 1, 0, mr, 0);
    248 	rc |= runtest(s++, local, 1, 1, mr, 0);
    249 	rc |= runtest(s++, local, 0, 1, mr, 0);
    250 	cleanup(sockets, 5);
    251 	test_rc |= rc;
    252 	if (rc)
    253 		warnx("%s : test #%d failed", __func__, 6);
    254 
    255 	rc = 0; s = sockets;
    256 	rc |= runtest(s++, local, 1, 1, mr, 0);
    257 	rc |= runtest(s++, local, 1, 0, mr, 0);
    258 	rc |= runtest(s++, local, 1, 1, mr, 0);
    259 	rc |= runtest(s++, local, 1, 0, mr, 0);
    260 	rc |= runtest(s++, local, 0, 1, mr, 0);
    261 	cleanup(sockets, 5);
    262 	test_rc |= rc;
    263 	if (rc)
    264 		warnx("%s : test #%d failed", __func__, 7);
    265 #endif
    266 	return (test_rc);
    267 }
    268 
    269 int
    270 mcast6_testsuite(struct addrinfo *local, struct ipv6_mreq *local_mreq,
    271     struct addrinfo *any, struct ipv6_mreq *any_mreq)
    272 {
    273 	int test_rc, rc, *s;
    274 	int sockets[4];
    275 	int testnum = 1;
    276 
    277 	test_rc = 0;
    278 	rc = 0; s = sockets;
    279 	rc |= runtest(s++, local, 0, 0, local_mreq, 0);
    280 	rc |= runtest(s++, any,   0, 0, any_mreq,   EADDRINUSE);
    281 	rc |= runtest(s++, any,   1, 0, any_mreq,   0);
    282 	cleanup(sockets, 3);
    283 	test_rc |= rc;
    284 	if (rc)
    285 		warnx("%s : test #%d failed", __func__, 1);
    286 
    287 	rc = 0; s = sockets;
    288 	rc |= runtest(s++, any,   0, 0, any_mreq,   0);
    289 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
    290 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
    291 	cleanup(sockets, 3);
    292 	test_rc |= rc;
    293 	if (rc)
    294 		warnx("%s : test #%d failed", __func__, 2);
    295 
    296 	rc = 0; s = sockets;
    297 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
    298 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
    299 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
    300 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
    301 	cleanup(sockets, 4);
    302 	test_rc |= rc;
    303 	if (rc)
    304 		warnx("%s : test #%d failed", __func__, 3);
    305 
    306 	/*
    307 	 * :: is not a multicast address, SO_REUSEADDR and SO_REUSEPORT
    308 	 * keep their unicast semantics although we are binding on multicast
    309 	 */
    310 
    311 	rc = 0; s = sockets;
    312 	rc |= runtest(s++, any, 0, 1, any_mreq, 0);
    313 	rc |= runtest(s++, any, 0, 1, any_mreq, 0);
    314 	rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
    315 	rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
    316 	cleanup(sockets, 4);
    317 	test_rc |= rc;
    318 	if (rc)
    319 		warnx("%s : test #%d failed", __func__, 4);
    320 
    321 	rc = 0; s = sockets;
    322 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
    323 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
    324 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
    325 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
    326 	cleanup(sockets, 4);
    327 	test_rc |= rc;
    328 	if (rc)
    329 		warnx("%s : test #%d failed", __func__, 5);
    330 
    331 	/* See above */
    332 
    333 	rc = 0; s = sockets;
    334 	rc |= runtest(s++, any, 1, 0, any_mreq, 0);
    335 	rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
    336 	rc |= runtest(s++, any, 0, 1, any_mreq, EADDRINUSE);
    337 	rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
    338 	cleanup(sockets, 4);
    339 	test_rc |= rc;
    340 	if (rc)
    341 		warnx("%s : test #%d failed", __func__, 6);
    342 
    343 	return (test_rc);
    344 }
    345 
    346 int
    347 main(int argc, char *argv[])
    348 {
    349 	int error, rc;
    350 	char *baddr_s, *bport_s, *bmifa_s;
    351 	struct addrinfo hints, *baddr, *any, *mifa;
    352 	struct ifaddrs *ifap, *curifa;
    353 	struct ip_mreq local_imr, any_imr;
    354 	struct ipv6_mreq local_i6mr, any_i6mr;
    355 	struct sockaddr_in *sin;
    356 	struct sockaddr_in6 *sin6;
    357 	int *s;
    358 
    359 	memset(&hints, 0, sizeof(hints));
    360 	hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV | \
    361 	    AI_PASSIVE;
    362 	hints.ai_socktype = SOCK_DGRAM;
    363 
    364 	baddr_s = argv[1];
    365 	bport_s = argv[2];
    366 
    367 	if ((error = getaddrinfo(baddr_s, bport_s, &hints, &baddr)))
    368 		errx(2, "getaddrinfo(%s,%s): %s", baddr_s, bport_s,
    369 		    gai_strerror(error));
    370 	baddr->ai_canonname = baddr_s;
    371 
    372 	hints.ai_family = baddr->ai_family;
    373 	if ((error = getaddrinfo(NULL, bport_s, &hints, &any)))
    374 		errx(2, "getaddrinfo(NULL,%s): %s", bport_s,
    375 		    gai_strerror(error));
    376 	any->ai_canonname = "*";
    377 
    378 	switch (baddr->ai_family) {
    379 	case AF_INET:
    380 		sin = (struct sockaddr_in *)baddr->ai_addr;
    381 		if (!IN_MULTICAST( ntohl(sin->sin_addr.s_addr) )) {
    382 			puts("executing unicast testsuite");
    383 			return unicast_testsuite(baddr, any);
    384 		}
    385 		bmifa_s = argv[3];
    386 		hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
    387 
    388 		if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa)))
    389 			errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s,
    390 			    gai_strerror(error));
    391 
    392 		local_imr.imr_interface =
    393 		    ((struct sockaddr_in *)mifa->ai_addr)->sin_addr;
    394 		local_imr.imr_multiaddr =
    395 		    ((struct sockaddr_in *)baddr->ai_addr)->sin_addr;
    396 
    397 		puts("executing ipv4 multicast testsuite");
    398 
    399 		/* no 'any' mcast group in ipv4 */
    400 		return mcast_reuse_testsuite(baddr, &local_imr);
    401 	case AF_INET6:
    402 		sin6 = (struct sockaddr_in6 *)baddr->ai_addr;
    403 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
    404 			puts("executing unicast testsuite");
    405 			return unicast_testsuite(baddr, any);
    406 		}
    407 		bmifa_s = argv[3];
    408 		hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
    409 
    410 		if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa)))
    411 			errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s,
    412 			    gai_strerror(error));
    413 
    414 		if (getifaddrs(&ifap))
    415 			err(2, "getifaddrs()");
    416 		curifa = ifap;
    417 		while (curifa) {
    418 			if (curifa->ifa_addr != NULL &&
    419 			    memcmp(curifa->ifa_addr,
    420 			    mifa->ai_addr,
    421 			    mifa->ai_addrlen) == 0)
    422 				break;
    423 			curifa = curifa->ifa_next;
    424 		}
    425 		if (curifa == NULL)
    426 			errx(2, "no interface configured with %s", argv[4]);
    427 		local_i6mr.ipv6mr_interface =
    428 		    if_nametoindex(curifa->ifa_name);
    429 		if (local_i6mr.ipv6mr_interface == 0)
    430 			errx(2, "unable to get \"%s\" index",
    431 			    curifa->ifa_name);
    432 		freeifaddrs(ifap);
    433 
    434 		local_i6mr.ipv6mr_multiaddr =
    435 		    ((struct sockaddr_in6 *)baddr->ai_addr)->sin6_addr;
    436 
    437 		any_i6mr.ipv6mr_interface = local_i6mr.ipv6mr_interface;
    438 		any_i6mr.ipv6mr_multiaddr =
    439 		    ((struct sockaddr_in6 *)any->ai_addr)->sin6_addr;
    440 
    441 		puts("executing ipv6 multicast testsuite");
    442 
    443 		rc = 0;
    444 		rc |= mcast_reuse_testsuite(baddr, &local_i6mr);
    445 		if (geteuid() == 0)
    446 			rc |= mcast6_testsuite(baddr, &local_i6mr, any, &any_i6mr);
    447 		else
    448 			warnx("skipping mcast6_testsuite() due to insufficient privs, please run again as root");
    449 		return (rc);
    450 	default:
    451 		errx(2,"unknown AF");
    452 	}
    453 
    454 	return (2);
    455 }
    456