xref: /netbsd/tests/net/inpcb/inpcb_bind.c (revision 614b568f)
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
runtest(int * sockp,struct addrinfo * ai,int reuseaddr,int reuseport,void * mreq,int expected)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
cleanup(int * fds,int num_fds)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
unicast_testsuite(struct addrinfo * local,struct addrinfo * any)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
mcast_reuse_testsuite(struct addrinfo * local,void * mr)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
mcast6_testsuite(struct addrinfo * local,struct ipv6_mreq * local_mreq,struct addrinfo * any,struct ipv6_mreq * any_mreq)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
main(int argc,char * argv[])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