1*93aefe23Sclaudio /* $OpenBSD: runtest.c,v 1.7 2022/04/10 14:08:35 claudio Exp $ */
292cb773aSvgross /*
392cb773aSvgross * Copyright (c) 2015 Vincent Gross <vincent.gross@kilob.yt>
492cb773aSvgross *
592cb773aSvgross * Permission to use, copy, modify, and distribute this software for any
692cb773aSvgross * purpose with or without fee is hereby granted, provided that the above
792cb773aSvgross * copyright notice and this permission notice appear in all copies.
892cb773aSvgross *
992cb773aSvgross * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1092cb773aSvgross * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1192cb773aSvgross * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1292cb773aSvgross * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1392cb773aSvgross * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1492cb773aSvgross * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1592cb773aSvgross * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1692cb773aSvgross */
1792cb773aSvgross
1892cb773aSvgross #include <errno.h>
1992cb773aSvgross #include <stdio.h>
2092cb773aSvgross #include <stdlib.h>
2192cb773aSvgross #include <unistd.h>
2292cb773aSvgross #include <string.h>
2392cb773aSvgross #include <err.h>
2492cb773aSvgross #include <netdb.h>
2592cb773aSvgross
2692cb773aSvgross #include <sys/types.h>
2792cb773aSvgross #include <sys/socket.h>
28f80fdc7eSvgross #include <netinet/in.h>
29f80fdc7eSvgross #include <net/if.h>
30f80fdc7eSvgross #include <ifaddrs.h>
3192cb773aSvgross
3292cb773aSvgross int
runtest(int * sockp,struct addrinfo * ai,int reuseaddr,int reuseport,void * mreq,int expected)3392cb773aSvgross runtest(int *sockp, struct addrinfo *ai, int reuseaddr, int reuseport,
34f80fdc7eSvgross void *mreq, int expected)
3592cb773aSvgross {
3692cb773aSvgross int error, optval;
37f80fdc7eSvgross struct ip_mreq imr;
3892cb773aSvgross
3992cb773aSvgross *sockp = socket(ai->ai_family, ai->ai_socktype, 0);
4092cb773aSvgross if (*sockp == -1) {
4192cb773aSvgross warn("%s : socket()", ai->ai_canonname);
4292cb773aSvgross return (3);
4392cb773aSvgross }
4492cb773aSvgross
4592cb773aSvgross if (reuseaddr) {
4692cb773aSvgross optval = 1;
4792cb773aSvgross error = setsockopt(*sockp, SOL_SOCKET, SO_REUSEADDR,
4892cb773aSvgross &optval, sizeof(int));
4992cb773aSvgross if (error) {
5092cb773aSvgross warn("%s : setsockopt(SO_REUSEADDR)", ai->ai_canonname);
5192cb773aSvgross return (2);
5292cb773aSvgross }
5392cb773aSvgross }
5492cb773aSvgross
5592cb773aSvgross if (reuseport) {
5692cb773aSvgross optval = 1;
5792cb773aSvgross error = setsockopt(*sockp, SOL_SOCKET, SO_REUSEPORT,
5892cb773aSvgross &optval, sizeof(int));
5992cb773aSvgross if (error) {
6092cb773aSvgross warn("%s : setsockopt(SO_REUSEPORT)", ai->ai_canonname);
6192cb773aSvgross return (2);
6292cb773aSvgross }
6392cb773aSvgross }
6492cb773aSvgross
65f80fdc7eSvgross if (mreq) {
66f80fdc7eSvgross switch (ai->ai_family) {
67f80fdc7eSvgross case AF_INET6:
68f80fdc7eSvgross error = setsockopt(*sockp, IPPROTO_IPV6, IPV6_JOIN_GROUP,
69f80fdc7eSvgross mreq, sizeof(struct ipv6_mreq));
70f80fdc7eSvgross if (error) {
71f80fdc7eSvgross warn("%s : setsockopt(IPV6_JOIN_GROUP)",
72f80fdc7eSvgross ai->ai_canonname);
73f80fdc7eSvgross return (2);
74f80fdc7eSvgross }
75f80fdc7eSvgross break;
76f80fdc7eSvgross case AF_INET:
77f80fdc7eSvgross error = setsockopt(*sockp, IPPROTO_IP, IP_ADD_MEMBERSHIP,
78f80fdc7eSvgross mreq, sizeof(struct ip_mreq));
79f80fdc7eSvgross if (error) {
80f80fdc7eSvgross warn("%s : setsockopt(IP_ADD_MEMBERSHIP)",
81f80fdc7eSvgross ai->ai_canonname);
82f80fdc7eSvgross return (2);
83f80fdc7eSvgross }
84f80fdc7eSvgross break;
85f80fdc7eSvgross default:
86f80fdc7eSvgross warnx("%s : trying to join multicast group in unknown AF",
87f80fdc7eSvgross ai->ai_canonname);
88f80fdc7eSvgross return (2);
89f80fdc7eSvgross }
90f80fdc7eSvgross }
91f80fdc7eSvgross
92f80fdc7eSvgross
9392cb773aSvgross error = bind(*sockp, ai->ai_addr, ai->ai_addrlen);
9492cb773aSvgross if (error && (expected == 0 || expected != errno)) {
9592cb773aSvgross warn("bind(%s,%s,%s)", ai->ai_canonname,
96f80fdc7eSvgross reuseaddr ? "REUSEADDR" : "", reuseport ? "REUSEPORT" : "");
9792cb773aSvgross return (1);
9892cb773aSvgross }
9992cb773aSvgross if (error == 0 && expected != 0) {
100f80fdc7eSvgross warnx("bind(%s,%s,%s) succeeded, expected : %s", ai->ai_canonname,
101f80fdc7eSvgross reuseaddr ? "REUSEADDR" : "", reuseport ? "REUSEPORT" : "",
102*93aefe23Sclaudio strerror(expected));
10392cb773aSvgross return (1);
10492cb773aSvgross }
10592cb773aSvgross
10692cb773aSvgross return (0);
10792cb773aSvgross }
10892cb773aSvgross
10992cb773aSvgross void
cleanup(int * fds,int num_fds)11092cb773aSvgross cleanup(int *fds, int num_fds)
11192cb773aSvgross {
11292cb773aSvgross while (num_fds-- > 0)
11392cb773aSvgross if (close(*fds++) && errno != EBADF)
11492cb773aSvgross err(2, "unable to clean up sockets, aborting");
11592cb773aSvgross }
11692cb773aSvgross
11792cb773aSvgross int
unicast_testsuite(struct addrinfo * local,struct addrinfo * any)118f80fdc7eSvgross unicast_testsuite(struct addrinfo *local, struct addrinfo *any)
119f80fdc7eSvgross {
120f80fdc7eSvgross int test_rc, rc, *s;
121f80fdc7eSvgross int sockets[4];
122f80fdc7eSvgross
123b12e34d8Sbluhm test_rc = 0;
124f80fdc7eSvgross rc = 0; s = sockets;
125f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, NULL, 0);
126f80fdc7eSvgross rc |= runtest(s++, any, 0, 0, NULL, EADDRINUSE);
127f80fdc7eSvgross rc |= runtest(s++, any, 1, 0, NULL, 0);
128f80fdc7eSvgross cleanup(sockets, 3);
129f80fdc7eSvgross test_rc |= rc;
130f80fdc7eSvgross if (rc)
131f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 1);
132f80fdc7eSvgross
133f80fdc7eSvgross rc = 0; s = sockets;
134f80fdc7eSvgross rc |= runtest(s++, any, 0, 0, NULL, 0);
135f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
136f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, NULL, 0);
137f80fdc7eSvgross cleanup(sockets, 3);
138f80fdc7eSvgross test_rc |= rc;
139f80fdc7eSvgross if (rc)
140f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 2);
141f80fdc7eSvgross
142f80fdc7eSvgross rc = 0; s = sockets;
143f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, NULL, 0);
144f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, NULL, 0);
145f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
146f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
147f80fdc7eSvgross cleanup(sockets, 4);
148f80fdc7eSvgross test_rc |= rc;
149f80fdc7eSvgross if (rc)
150f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 3);
151f80fdc7eSvgross
152f80fdc7eSvgross rc = 0; s = sockets;
153f80fdc7eSvgross rc |= runtest(s++, any, 0, 1, NULL, 0);
154f80fdc7eSvgross rc |= runtest(s++, any, 0, 1, NULL, 0);
155f80fdc7eSvgross rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
156f80fdc7eSvgross rc |= runtest(s++, any, 0, 0, NULL, EADDRINUSE);
157f80fdc7eSvgross cleanup(sockets, 4);
158f80fdc7eSvgross test_rc |= rc;
159f80fdc7eSvgross if (rc)
160f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 4);
161f80fdc7eSvgross
162f80fdc7eSvgross rc = 0; s = sockets;
163f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, NULL, 0);
164f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
165f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, NULL, EADDRINUSE);
166f80fdc7eSvgross cleanup(sockets, 3);
167f80fdc7eSvgross test_rc |= rc;
168f80fdc7eSvgross if (rc)
169f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 5);
170f80fdc7eSvgross
171f80fdc7eSvgross rc = 0; s = sockets;
172f80fdc7eSvgross rc |= runtest(s++, any, 1, 0, NULL, 0);
173f80fdc7eSvgross rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
174f80fdc7eSvgross rc |= runtest(s++, any, 0, 1, NULL, EADDRINUSE);
175f80fdc7eSvgross cleanup(sockets, 3);
176f80fdc7eSvgross test_rc |= rc;
177f80fdc7eSvgross if (rc)
178f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 6);
179f80fdc7eSvgross
180f80fdc7eSvgross return (test_rc);
181f80fdc7eSvgross }
182f80fdc7eSvgross
183f80fdc7eSvgross int
mcast_reuse_testsuite(struct addrinfo * local,void * mr)184f80fdc7eSvgross mcast_reuse_testsuite(struct addrinfo *local, void *mr)
185f80fdc7eSvgross {
186f80fdc7eSvgross int test_rc, rc, *s;
187f80fdc7eSvgross int sockets[6];
188f80fdc7eSvgross int testnum = 1;
189f80fdc7eSvgross
190b12e34d8Sbluhm test_rc = 0;
191f80fdc7eSvgross rc = 0; s = sockets;
192f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, mr, 0);
193f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, EADDRINUSE);
194f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, mr, EADDRINUSE);
195f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, EADDRINUSE);
196f80fdc7eSvgross cleanup(sockets, 4);
197f80fdc7eSvgross test_rc |= rc;
198f80fdc7eSvgross if (rc)
199f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 1);
200f80fdc7eSvgross
201f80fdc7eSvgross rc = 0; s = sockets;
202f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, mr, 0);
203f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
204f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, mr, 0);
205f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
206f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
207f80fdc7eSvgross cleanup(sockets, 5);
208f80fdc7eSvgross test_rc |= rc;
209f80fdc7eSvgross if (rc)
210f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 2);
211f80fdc7eSvgross
212f80fdc7eSvgross rc = 0; s = sockets;
213f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
214f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
215f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
216f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, mr, 0);
217f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
218f80fdc7eSvgross cleanup(sockets, 5);
219f80fdc7eSvgross test_rc |= rc;
220f80fdc7eSvgross if (rc)
221f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 3);
222f80fdc7eSvgross
223f80fdc7eSvgross rc = 0; s = sockets;
224f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
225f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
226f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, mr, 0);
227f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
228f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
229f80fdc7eSvgross cleanup(sockets, 5);
230f80fdc7eSvgross test_rc |= rc;
231f80fdc7eSvgross if (rc)
232f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 4);
233f80fdc7eSvgross
234bf308977Svgross #if 0
235f80fdc7eSvgross rc = 0; s = sockets;
236f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
237f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
238f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, mr, 0);
239f80fdc7eSvgross cleanup(sockets, 3);
240f80fdc7eSvgross test_rc |= rc;
241f80fdc7eSvgross if (rc)
242f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 5);
243f80fdc7eSvgross
244f80fdc7eSvgross rc = 0; s = sockets;
245f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
246f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
247f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
248f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
249f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, mr, 0);
250f80fdc7eSvgross cleanup(sockets, 5);
251f80fdc7eSvgross test_rc |= rc;
252f80fdc7eSvgross if (rc)
253f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 6);
254f80fdc7eSvgross
255f80fdc7eSvgross rc = 0; s = sockets;
256f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
257f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
258f80fdc7eSvgross rc |= runtest(s++, local, 1, 1, mr, 0);
259f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, mr, 0);
260bf308977Svgross rc |= runtest(s++, local, 0, 1, mr, 0);
261f80fdc7eSvgross cleanup(sockets, 5);
262f80fdc7eSvgross test_rc |= rc;
263f80fdc7eSvgross if (rc)
264f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 7);
265f80fdc7eSvgross #endif
266f80fdc7eSvgross return (test_rc);
267f80fdc7eSvgross }
268f80fdc7eSvgross
269f80fdc7eSvgross int
mcast6_testsuite(struct addrinfo * local,struct ipv6_mreq * local_mreq,struct addrinfo * any,struct ipv6_mreq * any_mreq)270f80fdc7eSvgross mcast6_testsuite(struct addrinfo *local, struct ipv6_mreq *local_mreq,
271f80fdc7eSvgross struct addrinfo *any, struct ipv6_mreq *any_mreq)
272f80fdc7eSvgross {
273f80fdc7eSvgross int test_rc, rc, *s;
274f80fdc7eSvgross int sockets[4];
275f80fdc7eSvgross int testnum = 1;
276f80fdc7eSvgross
277b12e34d8Sbluhm test_rc = 0;
278f80fdc7eSvgross rc = 0; s = sockets;
279f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, local_mreq, 0);
280f80fdc7eSvgross rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
281f80fdc7eSvgross rc |= runtest(s++, any, 1, 0, any_mreq, 0);
282f80fdc7eSvgross cleanup(sockets, 3);
283f80fdc7eSvgross test_rc |= rc;
284f80fdc7eSvgross if (rc)
285f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 1);
286f80fdc7eSvgross
287f80fdc7eSvgross rc = 0; s = sockets;
288f80fdc7eSvgross rc |= runtest(s++, any, 0, 0, any_mreq, 0);
289f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
290f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, local_mreq, 0);
291f80fdc7eSvgross cleanup(sockets, 3);
292f80fdc7eSvgross test_rc |= rc;
293f80fdc7eSvgross if (rc)
294f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 2);
295f80fdc7eSvgross
296f80fdc7eSvgross rc = 0; s = sockets;
297f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, local_mreq, 0);
298f80fdc7eSvgross rc |= runtest(s++, local, 0, 1, local_mreq, 0);
299f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, local_mreq, 0);
300f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
301f80fdc7eSvgross cleanup(sockets, 4);
302f80fdc7eSvgross test_rc |= rc;
303f80fdc7eSvgross if (rc)
304f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 3);
305f80fdc7eSvgross
306bf308977Svgross /*
307bf308977Svgross * :: is not a multicast address, SO_REUSEADDR and SO_REUSEPORT
308bf308977Svgross * keep their unicast semantics although we are binding on multicast
309bf308977Svgross */
310bf308977Svgross
311f80fdc7eSvgross rc = 0; s = sockets;
312f80fdc7eSvgross rc |= runtest(s++, any, 0, 1, any_mreq, 0);
313f80fdc7eSvgross rc |= runtest(s++, any, 0, 1, any_mreq, 0);
314bf308977Svgross rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
315f80fdc7eSvgross rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
316f80fdc7eSvgross cleanup(sockets, 4);
317f80fdc7eSvgross test_rc |= rc;
318f80fdc7eSvgross if (rc)
319f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 4);
320f80fdc7eSvgross
321f80fdc7eSvgross rc = 0; s = sockets;
322f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, local_mreq, 0);
323f80fdc7eSvgross rc |= runtest(s++, local, 1, 0, local_mreq, 0);
324bf308977Svgross rc |= runtest(s++, local, 0, 1, local_mreq, 0);
325f80fdc7eSvgross rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
326bf308977Svgross cleanup(sockets, 4);
327f80fdc7eSvgross test_rc |= rc;
328f80fdc7eSvgross if (rc)
329f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 5);
330f80fdc7eSvgross
331bf308977Svgross /* See above */
332bf308977Svgross
333f80fdc7eSvgross rc = 0; s = sockets;
334f80fdc7eSvgross rc |= runtest(s++, any, 1, 0, any_mreq, 0);
335bf308977Svgross rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
336bf308977Svgross rc |= runtest(s++, any, 0, 1, any_mreq, EADDRINUSE);
337f80fdc7eSvgross rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
338bf308977Svgross cleanup(sockets, 4);
339f80fdc7eSvgross test_rc |= rc;
340f80fdc7eSvgross if (rc)
341f80fdc7eSvgross warnx("%s : test #%d failed", __func__, 6);
342f80fdc7eSvgross
343f80fdc7eSvgross return (test_rc);
344f80fdc7eSvgross }
345f80fdc7eSvgross
346f80fdc7eSvgross int
main(int argc,char * argv[])34792cb773aSvgross main(int argc, char *argv[])
34892cb773aSvgross {
349f80fdc7eSvgross int error, rc;
350c214498eSvgross char *baddr_s, *bport_s, *bmifa_s;
351c214498eSvgross struct addrinfo hints, *baddr, *any, *mifa;
352f80fdc7eSvgross struct ifaddrs *ifap, *curifa;
353f80fdc7eSvgross struct ip_mreq local_imr, any_imr;
354f80fdc7eSvgross struct ipv6_mreq local_i6mr, any_i6mr;
355f80fdc7eSvgross struct sockaddr_in *sin;
356f80fdc7eSvgross struct sockaddr_in6 *sin6;
35792cb773aSvgross int *s;
35892cb773aSvgross
35992cb773aSvgross memset(&hints, 0, sizeof(hints));
36092cb773aSvgross hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV | \
36192cb773aSvgross AI_PASSIVE;
36292cb773aSvgross hints.ai_socktype = SOCK_DGRAM;
363f80fdc7eSvgross
364c214498eSvgross baddr_s = argv[1];
365c214498eSvgross bport_s = argv[2];
366c214498eSvgross
367c214498eSvgross if ((error = getaddrinfo(baddr_s, bport_s, &hints, &baddr)))
368c214498eSvgross errx(2, "getaddrinfo(%s,%s): %s", baddr_s, bport_s,
36992cb773aSvgross gai_strerror(error));
370c214498eSvgross baddr->ai_canonname = baddr_s;
37192cb773aSvgross
372c214498eSvgross hints.ai_family = baddr->ai_family;
373c214498eSvgross if ((error = getaddrinfo(NULL, bport_s, &hints, &any)))
374c214498eSvgross errx(2, "getaddrinfo(NULL,%s): %s", bport_s,
37592cb773aSvgross gai_strerror(error));
376c214498eSvgross any->ai_canonname = "*";
37792cb773aSvgross
378c214498eSvgross switch (baddr->ai_family) {
379f80fdc7eSvgross case AF_INET:
380c214498eSvgross sin = (struct sockaddr_in *)baddr->ai_addr;
381c214498eSvgross if (!IN_MULTICAST( ntohl(sin->sin_addr.s_addr) )) {
382c214498eSvgross puts("executing unicast testsuite");
383c214498eSvgross return unicast_testsuite(baddr, any);
384c214498eSvgross }
385c214498eSvgross bmifa_s = argv[3];
386c214498eSvgross hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
387c214498eSvgross
388c214498eSvgross if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa)))
389c214498eSvgross errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s,
390c214498eSvgross gai_strerror(error));
391c214498eSvgross
392c214498eSvgross local_imr.imr_interface =
393c214498eSvgross ((struct sockaddr_in *)mifa->ai_addr)->sin_addr;
394c214498eSvgross local_imr.imr_multiaddr =
395c214498eSvgross ((struct sockaddr_in *)baddr->ai_addr)->sin_addr;
396c214498eSvgross
397c214498eSvgross puts("executing ipv4 multicast testsuite");
39892cb773aSvgross
399f80fdc7eSvgross /* no 'any' mcast group in ipv4 */
400c214498eSvgross return mcast_reuse_testsuite(baddr, &local_imr);
401f80fdc7eSvgross case AF_INET6:
402c214498eSvgross sin6 = (struct sockaddr_in6 *)baddr->ai_addr;
403c214498eSvgross if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
404c214498eSvgross puts("executing unicast testsuite");
405c214498eSvgross return unicast_testsuite(baddr, any);
406c214498eSvgross }
407c214498eSvgross bmifa_s = argv[3];
408c214498eSvgross hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
409c214498eSvgross
410c214498eSvgross if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa)))
411c214498eSvgross errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s,
412c214498eSvgross gai_strerror(error));
413c214498eSvgross
414f80fdc7eSvgross if (getifaddrs(&ifap))
415f80fdc7eSvgross err(2, "getifaddrs()");
416f80fdc7eSvgross curifa = ifap;
417f80fdc7eSvgross while (curifa) {
418a3bb2ea1Sbenno if (curifa->ifa_addr != NULL &&
419a3bb2ea1Sbenno memcmp(curifa->ifa_addr,
420f80fdc7eSvgross mifa->ai_addr,
421f80fdc7eSvgross mifa->ai_addrlen) == 0)
422f80fdc7eSvgross break;
423f80fdc7eSvgross curifa = curifa->ifa_next;
424f80fdc7eSvgross }
425f80fdc7eSvgross if (curifa == NULL)
426f80fdc7eSvgross errx(2, "no interface configured with %s", argv[4]);
427f80fdc7eSvgross local_i6mr.ipv6mr_interface =
428f80fdc7eSvgross if_nametoindex(curifa->ifa_name);
429f80fdc7eSvgross if (local_i6mr.ipv6mr_interface == 0)
430f80fdc7eSvgross errx(2, "unable to get \"%s\" index",
431f80fdc7eSvgross curifa->ifa_name);
432f80fdc7eSvgross freeifaddrs(ifap);
433f80fdc7eSvgross
434c214498eSvgross local_i6mr.ipv6mr_multiaddr =
435c214498eSvgross ((struct sockaddr_in6 *)baddr->ai_addr)->sin6_addr;
436f80fdc7eSvgross
437f80fdc7eSvgross any_i6mr.ipv6mr_interface = local_i6mr.ipv6mr_interface;
438c214498eSvgross any_i6mr.ipv6mr_multiaddr =
439c214498eSvgross ((struct sockaddr_in6 *)any->ai_addr)->sin6_addr;
440c214498eSvgross
441c214498eSvgross puts("executing ipv6 multicast testsuite");
442f80fdc7eSvgross
443f80fdc7eSvgross rc = 0;
444c214498eSvgross rc |= mcast_reuse_testsuite(baddr, &local_i6mr);
445f80fdc7eSvgross if (geteuid() == 0)
446c214498eSvgross rc |= mcast6_testsuite(baddr, &local_i6mr, any, &any_i6mr);
447f80fdc7eSvgross else
448f80fdc7eSvgross warnx("skipping mcast6_testsuite() due to insufficient privs, please run again as root");
449f80fdc7eSvgross return (rc);
450f80fdc7eSvgross default:
451c214498eSvgross errx(2,"unknown AF");
452f80fdc7eSvgross }
453f80fdc7eSvgross
454f80fdc7eSvgross return (2);
45592cb773aSvgross }
456