1 /* $NetBSD: inpcb_bind.c,v 1.2 2022/11/17 08:38:58 ozaki-r Exp $ */ 2 /* $OpenBSD: runtest.c,v 1.7 2022/04/10 14:08:35 claudio Exp $ */ 3 /* 4 * Copyright (c) 2015 Vincent Gross <vincent.gross@kilob.yt> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <errno.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <unistd.h> 23 #include <string.h> 24 #include <err.h> 25 #include <netdb.h> 26 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <netinet/in.h> 30 #include <net/if.h> 31 #include <ifaddrs.h> 32 33 static int 34 runtest(int *sockp, struct addrinfo *ai, int reuseaddr, int reuseport, 35 void *mreq, int expected) 36 { 37 int error, optval; 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 static 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 static 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 static int 184 mcast_reuse_testsuite(struct addrinfo *local, void *mr) 185 { 186 int test_rc, rc, *s; 187 int sockets[6]; 188 189 test_rc = 0; 190 rc = 0; s = sockets; 191 rc |= runtest(s++, local, 0, 0, mr, 0); 192 rc |= runtest(s++, local, 1, 0, mr, EADDRINUSE); 193 rc |= runtest(s++, local, 0, 1, mr, EADDRINUSE); 194 rc |= runtest(s++, local, 1, 1, mr, EADDRINUSE); 195 cleanup(sockets, 4); 196 test_rc |= rc; 197 if (rc) 198 warnx("%s : test #%d failed", __func__, 1); 199 200 rc = 0; s = sockets; 201 rc |= runtest(s++, local, 0, 1, mr, 0); 202 rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE); 203 rc |= runtest(s++, local, 0, 1, mr, 0); 204 rc |= runtest(s++, local, 1, 0, mr, 0); 205 rc |= runtest(s++, local, 1, 1, mr, 0); 206 cleanup(sockets, 5); 207 test_rc |= rc; 208 if (rc) 209 warnx("%s : test #%d failed", __func__, 2); 210 211 rc = 0; s = sockets; 212 rc |= runtest(s++, local, 1, 0, mr, 0); 213 rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE); 214 rc |= runtest(s++, local, 1, 0, mr, 0); 215 rc |= runtest(s++, local, 0, 1, mr, 0); 216 rc |= runtest(s++, local, 1, 1, mr, 0); 217 cleanup(sockets, 5); 218 test_rc |= rc; 219 if (rc) 220 warnx("%s : test #%d failed", __func__, 3); 221 222 rc = 0; s = sockets; 223 rc |= runtest(s++, local, 1, 1, mr, 0); 224 rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE); 225 rc |= runtest(s++, local, 0, 1, mr, 0); 226 rc |= runtest(s++, local, 1, 0, mr, 0); 227 rc |= runtest(s++, local, 1, 1, mr, 0); 228 cleanup(sockets, 5); 229 test_rc |= rc; 230 if (rc) 231 warnx("%s : test #%d failed", __func__, 4); 232 233 #if 0 234 rc = 0; s = sockets; 235 rc |= runtest(s++, local, 1, 1, mr, 0); 236 rc |= runtest(s++, local, 1, 0, mr, 0); 237 rc |= runtest(s++, local, 0, 1, mr, 0); 238 cleanup(sockets, 3); 239 test_rc |= rc; 240 if (rc) 241 warnx("%s : test #%d failed", __func__, 5); 242 243 rc = 0; s = sockets; 244 rc |= runtest(s++, local, 1, 1, mr, 0); 245 rc |= runtest(s++, local, 1, 0, mr, 0); 246 rc |= runtest(s++, local, 1, 0, mr, 0); 247 rc |= runtest(s++, local, 1, 1, mr, 0); 248 rc |= runtest(s++, local, 0, 1, mr, 0); 249 cleanup(sockets, 5); 250 test_rc |= rc; 251 if (rc) 252 warnx("%s : test #%d failed", __func__, 6); 253 254 rc = 0; s = sockets; 255 rc |= runtest(s++, local, 1, 1, mr, 0); 256 rc |= runtest(s++, local, 1, 0, mr, 0); 257 rc |= runtest(s++, local, 1, 1, mr, 0); 258 rc |= runtest(s++, local, 1, 0, mr, 0); 259 rc |= runtest(s++, local, 0, 1, mr, 0); 260 cleanup(sockets, 5); 261 test_rc |= rc; 262 if (rc) 263 warnx("%s : test #%d failed", __func__, 7); 264 #endif 265 return (test_rc); 266 } 267 268 static int 269 mcast6_testsuite(struct addrinfo *local, struct ipv6_mreq *local_mreq, 270 struct addrinfo *any, struct ipv6_mreq *any_mreq) 271 { 272 int test_rc, rc, *s; 273 int sockets[4]; 274 275 test_rc = 0; 276 rc = 0; s = sockets; 277 rc |= runtest(s++, local, 0, 0, local_mreq, 0); 278 rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE); 279 rc |= runtest(s++, any, 1, 0, any_mreq, 0); 280 cleanup(sockets, 3); 281 test_rc |= rc; 282 if (rc) 283 warnx("%s : test #%d failed", __func__, 1); 284 285 rc = 0; s = sockets; 286 rc |= runtest(s++, any, 0, 0, any_mreq, 0); 287 rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE); 288 rc |= runtest(s++, local, 1, 0, local_mreq, 0); 289 cleanup(sockets, 3); 290 test_rc |= rc; 291 if (rc) 292 warnx("%s : test #%d failed", __func__, 2); 293 294 rc = 0; s = sockets; 295 rc |= runtest(s++, local, 0, 1, local_mreq, 0); 296 rc |= runtest(s++, local, 0, 1, local_mreq, 0); 297 rc |= runtest(s++, local, 1, 0, local_mreq, 0); 298 rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE); 299 cleanup(sockets, 4); 300 test_rc |= rc; 301 if (rc) 302 warnx("%s : test #%d failed", __func__, 3); 303 304 /* 305 * :: is not a multicast address, SO_REUSEADDR and SO_REUSEPORT 306 * keep their unicast semantics although we are binding on multicast 307 */ 308 309 rc = 0; s = sockets; 310 rc |= runtest(s++, any, 0, 1, any_mreq, 0); 311 rc |= runtest(s++, any, 0, 1, any_mreq, 0); 312 rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE); 313 rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE); 314 cleanup(sockets, 4); 315 test_rc |= rc; 316 if (rc) 317 warnx("%s : test #%d failed", __func__, 4); 318 319 rc = 0; s = sockets; 320 rc |= runtest(s++, local, 1, 0, local_mreq, 0); 321 rc |= runtest(s++, local, 1, 0, local_mreq, 0); 322 rc |= runtest(s++, local, 0, 1, local_mreq, 0); 323 rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE); 324 cleanup(sockets, 4); 325 test_rc |= rc; 326 if (rc) 327 warnx("%s : test #%d failed", __func__, 5); 328 329 /* See above */ 330 331 rc = 0; s = sockets; 332 rc |= runtest(s++, any, 1, 0, any_mreq, 0); 333 rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE); 334 rc |= runtest(s++, any, 0, 1, any_mreq, EADDRINUSE); 335 rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE); 336 cleanup(sockets, 4); 337 test_rc |= rc; 338 if (rc) 339 warnx("%s : test #%d failed", __func__, 6); 340 341 return (test_rc); 342 } 343 344 int 345 main(int argc, char *argv[]) 346 { 347 int error, rc; 348 char *baddr_s, *bport_s, *bmifa_s; 349 struct addrinfo hints, *baddr, *any, *mifa; 350 struct ifaddrs *ifap, *curifa; 351 struct ip_mreq local_imr; 352 struct ipv6_mreq local_i6mr, any_i6mr; 353 struct sockaddr_in *sin; 354 struct sockaddr_in6 *sin6; 355 356 memset(&hints, 0, sizeof(hints)); 357 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV | \ 358 AI_PASSIVE; 359 hints.ai_socktype = SOCK_DGRAM; 360 361 baddr_s = argv[1]; 362 bport_s = argv[2]; 363 364 if ((error = getaddrinfo(baddr_s, bport_s, &hints, &baddr))) 365 errx(2, "getaddrinfo(%s,%s): %s", baddr_s, bport_s, 366 gai_strerror(error)); 367 baddr->ai_canonname = baddr_s; 368 369 hints.ai_family = baddr->ai_family; 370 if ((error = getaddrinfo(NULL, bport_s, &hints, &any))) 371 errx(2, "getaddrinfo(NULL,%s): %s", bport_s, 372 gai_strerror(error)); 373 any->ai_canonname = strdup("*"); 374 375 switch (baddr->ai_family) { 376 case AF_INET: 377 sin = (struct sockaddr_in *)baddr->ai_addr; 378 if (!IN_MULTICAST( ntohl(sin->sin_addr.s_addr) )) { 379 puts("executing unicast testsuite"); 380 return unicast_testsuite(baddr, any); 381 } 382 bmifa_s = argv[3]; 383 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; 384 385 if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa))) 386 errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s, 387 gai_strerror(error)); 388 389 local_imr.imr_interface = 390 ((struct sockaddr_in *)mifa->ai_addr)->sin_addr; 391 local_imr.imr_multiaddr = 392 ((struct sockaddr_in *)baddr->ai_addr)->sin_addr; 393 394 puts("executing ipv4 multicast testsuite"); 395 396 /* no 'any' mcast group in ipv4 */ 397 return mcast_reuse_testsuite(baddr, &local_imr); 398 case AF_INET6: 399 sin6 = (struct sockaddr_in6 *)baddr->ai_addr; 400 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 401 puts("executing unicast testsuite"); 402 return unicast_testsuite(baddr, any); 403 } 404 bmifa_s = argv[3]; 405 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; 406 407 if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa))) 408 errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s, 409 gai_strerror(error)); 410 411 if (getifaddrs(&ifap)) 412 err(2, "getifaddrs()"); 413 curifa = ifap; 414 while (curifa) { 415 if (curifa->ifa_addr != NULL && 416 memcmp(curifa->ifa_addr, 417 mifa->ai_addr, 418 mifa->ai_addrlen) == 0) 419 break; 420 curifa = curifa->ifa_next; 421 } 422 if (curifa == NULL) 423 errx(2, "no interface configured with %s", argv[4]); 424 local_i6mr.ipv6mr_interface = 425 if_nametoindex(curifa->ifa_name); 426 if (local_i6mr.ipv6mr_interface == 0) 427 errx(2, "unable to get \"%s\" index", 428 curifa->ifa_name); 429 freeifaddrs(ifap); 430 431 local_i6mr.ipv6mr_multiaddr = 432 ((struct sockaddr_in6 *)baddr->ai_addr)->sin6_addr; 433 434 any_i6mr.ipv6mr_interface = local_i6mr.ipv6mr_interface; 435 any_i6mr.ipv6mr_multiaddr = 436 ((struct sockaddr_in6 *)any->ai_addr)->sin6_addr; 437 438 puts("executing ipv6 multicast testsuite"); 439 440 rc = 0; 441 rc |= mcast_reuse_testsuite(baddr, &local_i6mr); 442 if (geteuid() == 0) 443 rc |= mcast6_testsuite(baddr, &local_i6mr, any, &any_i6mr); 444 else 445 warnx("skipping mcast6_testsuite() due to insufficient privs, please run again as root"); 446 return (rc); 447 default: 448 errx(2,"unknown AF"); 449 } 450 451 return (2); 452 } 453