xref: /openbsd-src/regress/sys/netinet/in_pcbbind/runtest.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: runtest.c,v 1.4 2016/09/05 10:15:24 vgross Exp $ */
2 /*
3  * Copyright (c) 2015 Vincent Gross <vincent.gross@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(errno));
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 	rc = 0; s = sockets;
124 	rc |= runtest(s++, local, 0, 0, NULL, 0);
125 	rc |= runtest(s++, any,   0, 0, NULL, EADDRINUSE);
126 	rc |= runtest(s++, any,   1, 0, NULL, 0);
127 	cleanup(sockets, 3);
128 	test_rc |= rc;
129 	if (rc)
130 		warnx("%s : test #%d failed", __func__, 1);
131 
132 	rc = 0; s = sockets;
133 	rc |= runtest(s++, any,   0, 0, NULL, 0);
134 	rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
135 	rc |= runtest(s++, local, 1, 0, NULL, 0);
136 	cleanup(sockets, 3);
137 	test_rc |= rc;
138 	if (rc)
139 		warnx("%s : test #%d failed", __func__, 2);
140 
141 	rc = 0; s = sockets;
142 	rc |= runtest(s++, local, 0, 1, NULL, 0);
143 	rc |= runtest(s++, local, 0, 1, NULL, 0);
144 	rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
145 	rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
146 	cleanup(sockets, 4);
147 	test_rc |= rc;
148 	if (rc)
149 		warnx("%s : test #%d failed", __func__, 3);
150 
151 	rc = 0; s = sockets;
152 	rc |= runtest(s++, any, 0, 1, NULL, 0);
153 	rc |= runtest(s++, any, 0, 1, NULL, 0);
154 	rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
155 	rc |= runtest(s++, any, 0, 0, NULL, EADDRINUSE);
156 	cleanup(sockets, 4);
157 	test_rc |= rc;
158 	if (rc)
159 		warnx("%s : test #%d failed", __func__, 4);
160 
161 	rc = 0; s = sockets;
162 	rc |= runtest(s++, local, 1, 0, NULL, 0);
163 	rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
164 	rc |= runtest(s++, local, 0, 1, NULL, EADDRINUSE);
165 	cleanup(sockets, 3);
166 	test_rc |= rc;
167 	if (rc)
168 		warnx("%s : test #%d failed", __func__, 5);
169 
170 	rc = 0; s = sockets;
171 	rc |= runtest(s++, any, 1, 0, NULL, 0);
172 	rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
173 	rc |= runtest(s++, any, 0, 1, NULL, EADDRINUSE);
174 	cleanup(sockets, 3);
175 	test_rc |= rc;
176 	if (rc)
177 		warnx("%s : test #%d failed", __func__, 6);
178 
179 	return (test_rc);
180 }
181 
182 int
183 mcast_reuse_testsuite(struct addrinfo *local, void *mr)
184 {
185 	int test_rc, rc, *s;
186 	int sockets[6];
187 	int testnum = 1;
188 
189 	rc = 0; s = sockets;
190 	rc |= runtest(s++, local, 0, 0, mr, 0);
191 	rc |= runtest(s++, local, 1, 0, mr, EADDRINUSE);
192 	rc |= runtest(s++, local, 0, 1, mr, EADDRINUSE);
193 	rc |= runtest(s++, local, 1, 1, mr, EADDRINUSE);
194 	cleanup(sockets, 4);
195 	test_rc |= rc;
196 	if (rc)
197 		warnx("%s : test #%d failed", __func__, 1);
198 
199 	rc = 0; s = sockets;
200 	rc |= runtest(s++, local, 0, 1, mr, 0);
201 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
202 	rc |= runtest(s++, local, 0, 1, mr, 0);
203 	rc |= runtest(s++, local, 1, 0, mr, 0);
204 	rc |= runtest(s++, local, 1, 1, mr, 0);
205 	cleanup(sockets, 5);
206 	test_rc |= rc;
207 	if (rc)
208 		warnx("%s : test #%d failed", __func__, 2);
209 
210 	rc = 0; s = sockets;
211 	rc |= runtest(s++, local, 1, 0, mr, 0);
212 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
213 	rc |= runtest(s++, local, 1, 0, mr, 0);
214 	rc |= runtest(s++, local, 0, 1, mr, 0);
215 	rc |= runtest(s++, local, 1, 1, mr, 0);
216 	cleanup(sockets, 5);
217 	test_rc |= rc;
218 	if (rc)
219 		warnx("%s : test #%d failed", __func__, 3);
220 
221 	rc = 0; s = sockets;
222 	rc |= runtest(s++, local, 1, 1, mr, 0);
223 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
224 	rc |= runtest(s++, local, 0, 1, mr, 0);
225 	rc |= runtest(s++, local, 1, 0, mr, 0);
226 	rc |= runtest(s++, local, 1, 1, mr, 0);
227 	cleanup(sockets, 5);
228 	test_rc |= rc;
229 	if (rc)
230 		warnx("%s : test #%d failed", __func__, 4);
231 
232 #if 0
233 	rc = 0; s = sockets;
234 	rc |= runtest(s++, local, 1, 1, mr, 0);
235 	rc |= runtest(s++, local, 1, 0, mr, 0);
236 	rc |= runtest(s++, local, 0, 1, mr, 0);
237 	cleanup(sockets, 3);
238 	test_rc |= rc;
239 	if (rc)
240 		warnx("%s : test #%d failed", __func__, 5);
241 
242 	rc = 0; s = sockets;
243 	rc |= runtest(s++, local, 1, 1, mr, 0);
244 	rc |= runtest(s++, local, 1, 0, mr, 0);
245 	rc |= runtest(s++, local, 1, 0, mr, 0);
246 	rc |= runtest(s++, local, 1, 1, mr, 0);
247 	rc |= runtest(s++, local, 0, 1, mr, 0);
248 	cleanup(sockets, 5);
249 	test_rc |= rc;
250 	if (rc)
251 		warnx("%s : test #%d failed", __func__, 6);
252 
253 	rc = 0; s = sockets;
254 	rc |= runtest(s++, local, 1, 1, mr, 0);
255 	rc |= runtest(s++, local, 1, 0, mr, 0);
256 	rc |= runtest(s++, local, 1, 1, mr, 0);
257 	rc |= runtest(s++, local, 1, 0, mr, 0);
258 	rc |= runtest(s++, local, 0, 1, mr, 0);
259 	cleanup(sockets, 5);
260 	test_rc |= rc;
261 	if (rc)
262 		warnx("%s : test #%d failed", __func__, 7);
263 #endif
264 	return (test_rc);
265 }
266 
267 int
268 mcast6_testsuite(struct addrinfo *local, struct ipv6_mreq *local_mreq,
269     struct addrinfo *any, struct ipv6_mreq *any_mreq)
270 {
271 	int test_rc, rc, *s;
272 	int sockets[4];
273 	int testnum = 1;
274 
275 	rc = 0; s = sockets;
276 	rc |= runtest(s++, local, 0, 0, local_mreq, 0);
277 	rc |= runtest(s++, any,   0, 0, any_mreq,   EADDRINUSE);
278 	rc |= runtest(s++, any,   1, 0, any_mreq,   0);
279 	cleanup(sockets, 3);
280 	test_rc |= rc;
281 	if (rc)
282 		warnx("%s : test #%d failed", __func__, 1);
283 
284 	rc = 0; s = sockets;
285 	rc |= runtest(s++, any,   0, 0, any_mreq,   0);
286 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
287 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
288 	cleanup(sockets, 3);
289 	test_rc |= rc;
290 	if (rc)
291 		warnx("%s : test #%d failed", __func__, 2);
292 
293 	rc = 0; s = sockets;
294 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
295 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
296 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
297 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
298 	cleanup(sockets, 4);
299 	test_rc |= rc;
300 	if (rc)
301 		warnx("%s : test #%d failed", __func__, 3);
302 
303 	/*
304 	 * :: is not a multicast address, SO_REUSEADDR and SO_REUSEPORT
305 	 * keep their unicast semantics although we are binding on multicast
306 	 */
307 
308 	rc = 0; s = sockets;
309 	rc |= runtest(s++, any, 0, 1, any_mreq, 0);
310 	rc |= runtest(s++, any, 0, 1, any_mreq, 0);
311 	rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
312 	rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
313 	cleanup(sockets, 4);
314 	test_rc |= rc;
315 	if (rc)
316 		warnx("%s : test #%d failed", __func__, 4);
317 
318 	rc = 0; s = sockets;
319 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
320 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
321 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
322 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
323 	cleanup(sockets, 4);
324 	test_rc |= rc;
325 	if (rc)
326 		warnx("%s : test #%d failed", __func__, 5);
327 
328 	/* See above */
329 
330 	rc = 0; s = sockets;
331 	rc |= runtest(s++, any, 1, 0, any_mreq, 0);
332 	rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
333 	rc |= runtest(s++, any, 0, 1, any_mreq, EADDRINUSE);
334 	rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
335 	cleanup(sockets, 4);
336 	test_rc |= rc;
337 	if (rc)
338 		warnx("%s : test #%d failed", __func__, 6);
339 
340 	return (test_rc);
341 }
342 
343 int
344 main(int argc, char *argv[])
345 {
346 	int error, rc;
347 	char *baddr_s, *bport_s, *bmifa_s;
348 	struct addrinfo hints, *baddr, *any, *mifa;
349 	struct ifaddrs *ifap, *curifa;
350 	struct ip_mreq local_imr, any_imr;
351 	struct ipv6_mreq local_i6mr, any_i6mr;
352 	struct sockaddr_in *sin;
353 	struct sockaddr_in6 *sin6;
354 	int *s;
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 = "*";
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 (memcmp(curifa->ifa_addr,
416 			    mifa->ai_addr,
417 			    mifa->ai_addrlen) == 0)
418 				break;
419 			curifa = curifa->ifa_next;
420 		}
421 		if (curifa == NULL)
422 			errx(2, "no interface configured with %s", argv[4]);
423 		local_i6mr.ipv6mr_interface =
424 		    if_nametoindex(curifa->ifa_name);
425 		if (local_i6mr.ipv6mr_interface == 0)
426 			errx(2, "unable to get \"%s\" index",
427 			    curifa->ifa_name);
428 		freeifaddrs(ifap);
429 
430 		local_i6mr.ipv6mr_multiaddr =
431 		    ((struct sockaddr_in6 *)baddr->ai_addr)->sin6_addr;
432 
433 		any_i6mr.ipv6mr_interface = local_i6mr.ipv6mr_interface;
434 		any_i6mr.ipv6mr_multiaddr =
435 		    ((struct sockaddr_in6 *)any->ai_addr)->sin6_addr;
436 
437 		puts("executing ipv6 multicast testsuite");
438 
439 		rc = 0;
440 		rc |= mcast_reuse_testsuite(baddr, &local_i6mr);
441 		if (geteuid() == 0)
442 			rc |= mcast6_testsuite(baddr, &local_i6mr, any, &any_i6mr);
443 		else
444 			warnx("skipping mcast6_testsuite() due to insufficient privs, please run again as root");
445 		return (rc);
446 	default:
447 		errx(2,"unknown AF");
448 	}
449 
450 	return (2);
451 }
452