addrmerge_test.c revision 302676
1/*-
2 * Copyright (c) 2014 Spectra Logic Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions, and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    substantially similar to the "NO WARRANTY" disclaimer below
13 *    ("Disclaimer") and any redistribution must be conditioned upon
14 *    including a substantially similar Disclaimer requirement for further
15 *    binary redistribution.
16 *
17 * NO WARRANTY
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGES.
29 *
30 * $FreeBSD: stable/10/usr.sbin/rpcbind/tests/addrmerge_test.c 302676 2016-07-12 21:49:08Z asomers $
31 */
32
33#include <rpc/rpc.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36
37#include <net/if.h>
38#include <netinet/in.h>
39#include <arpa/inet.h>
40
41#include <ifaddrs.h>
42#include <stdlib.h>
43#include <stdio.h>
44
45#include <atf-c.h>
46
47#include "rpcbind.h"
48
49#define MAX_IFADDRS 16
50
51int debugging = false;
52
53/* Data for mocking getifaddrs */
54struct ifaddr_storage {
55	struct ifaddrs ifaddr;
56	struct sockaddr_storage addr;
57	struct sockaddr_storage mask;
58	struct sockaddr_storage bcast;
59} mock_ifaddr_storage[MAX_IFADDRS];
60struct ifaddrs *mock_ifaddrs = NULL;
61int ifaddr_count = 0;
62
63/* Data for mocking listen_addr */
64int bind_address_count = 0;
65struct sockaddr* bind_addresses[MAX_IFADDRS];
66
67/* Stub library functions */
68void
69freeifaddrs(struct ifaddrs *ifp __unused)
70{
71	return ;
72}
73
74int
75getifaddrs(struct ifaddrs **ifap)
76{
77	*ifap = mock_ifaddrs;
78	return (0);
79}
80
81static void
82mock_ifaddr4(const char* name, const char* addr, const char* mask,
83    const char* bcast, unsigned int flags, bool bind)
84{
85	struct ifaddrs *ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
86	struct sockaddr_in *in = (struct sockaddr_in*)
87	    			&mock_ifaddr_storage[ifaddr_count].addr;
88	struct sockaddr_in *mask_in = (struct sockaddr_in*)
89	    			&mock_ifaddr_storage[ifaddr_count].mask;
90	struct sockaddr_in *bcast_in = (struct sockaddr_in*)
91	    			&mock_ifaddr_storage[ifaddr_count].bcast;
92
93	in->sin_family = AF_INET;
94	in->sin_port = 0;
95	in->sin_len = sizeof(*in);
96	in->sin_addr.s_addr = inet_addr(addr);
97	mask_in->sin_family = AF_INET;
98	mask_in->sin_port = 0;
99	mask_in->sin_len = sizeof(*mask_in);
100	mask_in->sin_addr.s_addr = inet_addr(mask);
101	bcast_in->sin_family = AF_INET;
102	bcast_in->sin_port = 0;
103	bcast_in->sin_len = sizeof(*bcast_in);
104	bcast_in->sin_addr.s_addr = inet_addr(bcast);
105	*ifaddr = (struct ifaddrs) {
106		.ifa_next = NULL,
107		.ifa_name = (char*) name,
108		.ifa_flags = flags,
109		.ifa_addr = (struct sockaddr*) in,
110		.ifa_netmask = (struct sockaddr*) mask_in,
111		.ifa_broadaddr = (struct sockaddr*) bcast_in,
112		.ifa_data = NULL,	/* addrmerge doesn't care*/
113	};
114
115	if (ifaddr_count > 0)
116		mock_ifaddr_storage[ifaddr_count - 1].ifaddr.ifa_next = ifaddr;
117	ifaddr_count++;
118	mock_ifaddrs = &mock_ifaddr_storage[0].ifaddr;
119
120	/* Optionally simulate binding an ip ala "rpcbind -h foo" */
121	if (bind) {
122		bind_addresses[bind_address_count] = (struct sockaddr*)in;
123		bind_address_count++;
124	}
125}
126
127#ifdef INET6
128static void
129mock_ifaddr6(const char* name, const char* addr, const char* mask,
130    const char* bcast, unsigned int flags, uint32_t scope_id, bool bind)
131{
132	struct ifaddrs *ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
133	struct sockaddr_in6 *in6 = (struct sockaddr_in6*)
134	    			&mock_ifaddr_storage[ifaddr_count].addr;
135	struct sockaddr_in6 *mask_in6 = (struct sockaddr_in6*)
136	    			&mock_ifaddr_storage[ifaddr_count].mask;
137	struct sockaddr_in6 *bcast_in6 = (struct sockaddr_in6*)
138	    			&mock_ifaddr_storage[ifaddr_count].bcast;
139
140	in6->sin6_family = AF_INET6;
141	in6->sin6_port = 0;
142	in6->sin6_len = sizeof(*in6);
143	in6->sin6_scope_id = scope_id;
144	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, addr, (void*)&in6->sin6_addr));
145	mask_in6->sin6_family = AF_INET6;
146	mask_in6->sin6_port = 0;
147	mask_in6->sin6_len = sizeof(*mask_in6);
148	mask_in6->sin6_scope_id = scope_id;
149	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, mask,
150	    (void*)&mask_in6->sin6_addr));
151	bcast_in6->sin6_family = AF_INET6;
152	bcast_in6->sin6_port = 0;
153	bcast_in6->sin6_len = sizeof(*bcast_in6);
154	bcast_in6->sin6_scope_id = scope_id;
155	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, bcast,
156	    (void*)&bcast_in6->sin6_addr));
157	*ifaddr = (struct ifaddrs) {
158		.ifa_next = NULL,
159		.ifa_name = (char*) name,
160		.ifa_flags = flags,
161		.ifa_addr = (struct sockaddr*) in6,
162		.ifa_netmask = (struct sockaddr*) mask_in6,
163		.ifa_broadaddr = (struct sockaddr*) bcast_in6,
164		.ifa_data = NULL,	/* addrmerge doesn't care*/
165	};
166
167	if (ifaddr_count > 0)
168		mock_ifaddr_storage[ifaddr_count - 1].ifaddr.ifa_next = ifaddr;
169	ifaddr_count++;
170	mock_ifaddrs = &mock_ifaddr_storage[0].ifaddr;
171
172	/* Optionally simulate binding an ip ala "rpcbind -h foo" */
173	if (bind) {
174		bind_addresses[bind_address_count] = (struct sockaddr*)in6;
175		bind_address_count++;
176	}
177}
178#else
179static void
180mock_ifaddr6(const char* name __unused, const char* addr __unused,
181    const char* mask __unused, const char* bcast __unused,
182    unsigned int flags __unused, uint32_t scope_id __unused, bool bind __unused)
183{
184}
185#endif /*INET6 */
186
187static void
188mock_lo0(void)
189{
190	/*
191	 * This broadcast address looks wrong, but it's what getifaddrs(2)
192	 * actually returns.  It's invalid because IFF_BROADCAST is not set
193	 */
194	mock_ifaddr4("lo0", "127.0.0.1", "255.0.0.0", "127.0.0.1",
195	    IFF_LOOPBACK | IFF_UP | IFF_RUNNING | IFF_MULTICAST, false);
196	mock_ifaddr6("lo0", "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
197	    "::1",
198	    IFF_LOOPBACK | IFF_UP | IFF_RUNNING | IFF_MULTICAST, 0, false);
199}
200
201static void
202mock_igb0(void)
203{
204	mock_ifaddr4("igb0", "192.0.2.2", "255.255.255.128", "192.0.2.127",
205	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
206	    false);
207	mock_ifaddr6("igb0", "2001:db8::2", "ffff:ffff:ffff:ffff::",
208	    "2001:db8::ffff:ffff:ffff:ffff",
209	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
210	    0, false);
211	/* Link local address */
212	mock_ifaddr6("igb0", "fe80::2", "ffff:ffff:ffff:ffff::",
213	    "fe80::ffff:ffff:ffff:ffff",
214	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
215	    2, false);
216}
217
218/* On the same subnet as igb0 */
219static void
220mock_igb1(bool bind)
221{
222	mock_ifaddr4("igb1", "192.0.2.3", "255.255.255.128", "192.0.2.127",
223	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
224	    bind);
225	mock_ifaddr6("igb1", "2001:db8::3", "ffff:ffff:ffff:ffff::",
226	    "2001:db8::ffff:ffff:ffff:ffff",
227	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
228	    0, bind);
229	/* Link local address */
230	mock_ifaddr6("igb1", "fe80::3", "ffff:ffff:ffff:ffff::",
231	    "fe80::ffff:ffff:ffff:ffff",
232	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
233	    3, bind);
234}
235
236/* igb2 is on a different subnet than igb0 */
237static void
238mock_igb2(void)
239{
240	mock_ifaddr4("igb2", "192.0.2.130", "255.255.255.128", "192.0.2.255",
241	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
242	    false);
243	mock_ifaddr6("igb2", "2001:db8:1::2", "ffff:ffff:ffff:ffff::",
244	    "2001:db8:1:0:ffff:ffff:ffff:ffff",
245	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
246	    0, false);
247}
248
249/* tun0 is a P2P interface */
250static void
251mock_tun0(void)
252{
253	mock_ifaddr4("tun0", "192.0.2.5", "255.255.255.255", "192.0.2.6",
254	    IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_MULTICAST, false);
255	mock_ifaddr6("tun0", "2001:db8::5",
256	    "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
257	    "2001:db8::6",
258	    IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_MULTICAST, 0, false);
259}
260
261
262/* Stub rpcbind functions */
263int
264listen_addr(const struct sockaddr *sa)
265{
266	int i;
267
268	if (bind_address_count == 0)
269		return (1);
270
271	for (i = 0; i < bind_address_count; i++) {
272		if (bind_addresses[i]->sa_family != sa->sa_family)
273			continue;
274
275		if (0 == memcmp(bind_addresses[i]->sa_data, sa->sa_data,
276		    sa->sa_len))
277			return (1);
278	}
279	return (0);
280}
281
282struct netconfig*
283rpcbind_get_conf(const char* netid __unused)
284{
285	/* Use static variables so we can return pointers to them */
286	static char* lookups = NULL;
287	static struct netconfig nconf_udp;
288#ifdef INET6
289	static struct netconfig nconf_udp6;
290#endif /* INET6 */
291
292	nconf_udp.nc_netid = "udp"; //netid_storage;
293	nconf_udp.nc_semantics = NC_TPI_CLTS;
294	nconf_udp.nc_flag = NC_VISIBLE;
295	nconf_udp.nc_protofmly = (char*)"inet";
296	nconf_udp.nc_proto = (char*)"udp";
297	nconf_udp.nc_device = (char*)"-";
298	nconf_udp.nc_nlookups = 0;
299	nconf_udp.nc_lookups = &lookups;
300
301#ifdef INET6
302	nconf_udp6.nc_netid = "udp6"; //netid_storage;
303	nconf_udp6.nc_semantics = NC_TPI_CLTS;
304	nconf_udp6.nc_flag = NC_VISIBLE;
305	nconf_udp6.nc_protofmly = (char*)"inet6";
306	nconf_udp6.nc_proto = (char*)"udp6";
307	nconf_udp6.nc_device = (char*)"-";
308	nconf_udp6.nc_nlookups = 0;
309	nconf_udp6.nc_lookups = &lookups;
310#endif /* INET6 */
311
312	if (0 == strncmp("udp", netid, sizeof("udp")))
313		return (&nconf_udp);
314#ifdef INET6
315	else if (0 == strncmp("udp6", netid, sizeof("udp6")))
316		return (&nconf_udp6);
317#endif /* INET6 */
318	else
319		return (NULL);
320}
321
322/*
323 * Helper function used by most test cases
324 * param recvdstaddr	If non-null, the uaddr on which the request was received
325 */
326static char*
327do_addrmerge4(const char* recvdstaddr)
328{
329	struct netbuf caller;
330	struct sockaddr_in caller_in;
331	const char *serv_uaddr, *clnt_uaddr, *netid;
332
333	/* caller contains the client's IP address */
334	caller.maxlen = sizeof(struct sockaddr_storage);
335	caller.len = sizeof(caller_in);
336	caller_in.sin_family = AF_INET;
337	caller_in.sin_len = sizeof(caller_in);
338	caller_in.sin_port = 1234;
339	caller_in.sin_addr.s_addr = inet_addr("192.0.2.1");
340	caller.buf = (void*)&caller_in;
341	if (recvdstaddr != NULL)
342		clnt_uaddr = recvdstaddr;
343	else
344		clnt_uaddr = "192.0.2.1.3.46";
345
346	/* assume server is bound in INADDR_ANY port 814 */
347	serv_uaddr = "0.0.0.0.3.46";
348
349	netid = "udp";
350	return (addrmerge(&caller, serv_uaddr, clnt_uaddr, netid));
351}
352
353#ifdef INET6
354/*
355 * Variant of do_addrmerge4 where the caller has an IPv6 address
356 * param recvdstaddr	If non-null, the uaddr on which the request was received
357 */
358static char*
359do_addrmerge6(const char* recvdstaddr)
360{
361	struct netbuf caller;
362	struct sockaddr_in6 caller_in6;
363	const char *serv_uaddr, *clnt_uaddr, *netid;
364
365	/* caller contains the client's IP address */
366	caller.maxlen = sizeof(struct sockaddr_storage);
367	caller.len = sizeof(caller_in6);
368	caller_in6.sin6_family = AF_INET6;
369	caller_in6.sin6_len = sizeof(caller_in6);
370	caller_in6.sin6_port = 1234;
371	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, "2001:db8::1",
372	    (void*)&caller_in6.sin6_addr));
373	caller.buf = (void*)&caller_in6;
374	if (recvdstaddr != NULL)
375		clnt_uaddr = recvdstaddr;
376	else
377		clnt_uaddr = "2001:db8::1.3.46";
378
379	/* assume server is bound in INADDR_ANY port 814 */
380	serv_uaddr = "::1.3.46";
381
382	netid = "udp6";
383	return (addrmerge(&caller, serv_uaddr, clnt_uaddr, netid));
384}
385
386/* Variant of do_addrmerge6 where the caller uses a link local address */
387static char*
388do_addrmerge6_ll(void)
389{
390	struct netbuf caller;
391	struct sockaddr_in6 caller_in6;
392	const char *serv_uaddr, *clnt_uaddr, *netid;
393
394	/* caller contains the client's IP address */
395	caller.maxlen = sizeof(struct sockaddr_storage);
396	caller.len = sizeof(caller_in6);
397	caller_in6.sin6_family = AF_INET6;
398	caller_in6.sin6_len = sizeof(caller_in6);
399	caller_in6.sin6_port = 1234;
400	caller_in6.sin6_scope_id = 2; /* same as igb0 */
401	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, "fe80::beef",
402	    (void*)&caller_in6.sin6_addr));
403	caller.buf = (void*)&caller_in6;
404	clnt_uaddr = "fe80::beef.3.46";
405
406	/* assume server is bound in INADDR_ANY port 814 */
407	serv_uaddr = "::1.3.46";
408
409	netid = "udp6";
410	return (addrmerge(&caller, serv_uaddr, clnt_uaddr, netid));
411}
412#endif /* INET6 */
413
414ATF_TC_WITHOUT_HEAD(addrmerge_noifaddrs);
415ATF_TC_BODY(addrmerge_noifaddrs, tc)
416{
417	char* maddr;
418
419	maddr = do_addrmerge4(NULL);
420
421	/* Since getifaddrs returns null, addrmerge must too */
422	ATF_CHECK_EQ(NULL, maddr);
423}
424
425ATF_TC_WITHOUT_HEAD(addrmerge_localhost_only);
426ATF_TC_BODY(addrmerge_localhost_only, tc)
427{
428	char *maddr;
429
430	/* getifaddrs will return localhost only */
431	mock_lo0();
432
433	maddr = do_addrmerge4(NULL);
434
435	/* We must return localhost if there is nothing better */
436	ATF_REQUIRE(maddr != NULL);
437	ATF_CHECK_STREQ("127.0.0.1.3.46", maddr);
438	free(maddr);
439}
440
441ATF_TC_WITHOUT_HEAD(addrmerge_singlehomed);
442ATF_TC_BODY(addrmerge_singlehomed, tc)
443{
444	char *maddr;
445
446	/* getifaddrs will return one public address */
447	mock_lo0();
448	mock_igb0();
449
450	maddr = do_addrmerge4(NULL);
451
452	ATF_REQUIRE(maddr != NULL);
453	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
454	free(maddr);
455}
456
457ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet);
458ATF_TC_BODY(addrmerge_one_addr_on_each_subnet, tc)
459{
460	char *maddr;
461
462	mock_lo0();
463	mock_igb0();
464	mock_igb2();
465
466	maddr = do_addrmerge4(NULL);
467
468	/* We must return the address on the caller's subnet */
469	ATF_REQUIRE(maddr != NULL);
470	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
471	free(maddr);
472}
473
474
475/*
476 * Like addrmerge_one_addr_on_each_subnet, but getifaddrs returns a different
477 * order
478 */
479ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet_rev);
480ATF_TC_BODY(addrmerge_one_addr_on_each_subnet_rev, tc)
481{
482	char *maddr;
483
484	/* getifaddrs will return one public address on each of two subnets */
485	mock_igb2();
486	mock_igb0();
487	mock_lo0();
488
489	maddr = do_addrmerge4(NULL);
490
491	/* We must return the address on the caller's subnet */
492	ATF_REQUIRE(maddr != NULL);
493	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
494	free(maddr);
495}
496
497ATF_TC_WITHOUT_HEAD(addrmerge_point2point);
498ATF_TC_BODY(addrmerge_point2point, tc)
499{
500	char *maddr;
501
502	/* getifaddrs will return one normal and one p2p address */
503	mock_lo0();
504	mock_igb2();
505	mock_tun0();
506
507	maddr = do_addrmerge4(NULL);
508
509	/* addrmerge should disprefer P2P interfaces */
510	ATF_REQUIRE(maddr != NULL);
511	ATF_CHECK_STREQ("192.0.2.130.3.46", maddr);
512	free(maddr);
513}
514
515/* Like addrerge_point2point, but getifaddrs returns a different order */
516ATF_TC_WITHOUT_HEAD(addrmerge_point2point_rev);
517ATF_TC_BODY(addrmerge_point2point_rev, tc)
518{
519	char *maddr;
520
521	/* getifaddrs will return one normal and one p2p address */
522	mock_tun0();
523	mock_igb2();
524	mock_lo0();
525
526	maddr = do_addrmerge4(NULL);
527
528	/* addrmerge should disprefer P2P interfaces */
529	ATF_REQUIRE(maddr != NULL);
530	ATF_CHECK_STREQ("192.0.2.130.3.46", maddr);
531	free(maddr);
532}
533
534/*
535 * Simulate using rpcbind -h to select just one ip when the subnet has
536 * multiple
537 */
538ATF_TC_WITHOUT_HEAD(addrmerge_bindip);
539ATF_TC_BODY(addrmerge_bindip, tc)
540{
541	char *maddr;
542
543	/* getifaddrs will return one public address on each of two subnets */
544	mock_lo0();
545	mock_igb0();
546	mock_igb1(true);
547
548	maddr = do_addrmerge4(NULL);
549
550	/* We must return the address to which we are bound */
551	ATF_REQUIRE(maddr != NULL);
552	ATF_CHECK_STREQ("192.0.2.3.3.46", maddr);
553	free(maddr);
554}
555
556/* Like addrmerge_bindip, but getifaddrs returns a different order */
557ATF_TC_WITHOUT_HEAD(addrmerge_bindip_rev);
558ATF_TC_BODY(addrmerge_bindip_rev, tc)
559{
560	char *maddr;
561
562	/* getifaddrs will return one public address on each of two subnets */
563	mock_igb1(true);
564	mock_igb0();
565	mock_lo0();
566
567	maddr = do_addrmerge4(NULL);
568
569	/* We must return the address to which we are bound */
570	ATF_REQUIRE(maddr != NULL);
571	ATF_CHECK_STREQ("192.0.2.3.3.46", maddr);
572	free(maddr);
573}
574
575/*
576 * The address on which the request was received is known, and is provided as
577 * the hint.
578 */
579ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr);
580ATF_TC_BODY(addrmerge_recvdstaddr, tc)
581{
582	char *maddr;
583
584	mock_lo0();
585	mock_igb0();
586	mock_igb1(false);
587
588	maddr = do_addrmerge4("192.0.2.2.3.46");
589
590	/* We must return the address on which the request was received */
591	ATF_REQUIRE(maddr != NULL);
592	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
593	free(maddr);
594}
595
596ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr_rev);
597ATF_TC_BODY(addrmerge_recvdstaddr_rev, tc)
598{
599	char *maddr;
600
601	mock_igb1(false);
602	mock_igb0();
603	mock_lo0();
604
605	maddr = do_addrmerge4("192.0.2.2.3.46");
606
607	/* We must return the address on which the request was received */
608	ATF_REQUIRE(maddr != NULL);
609	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
610	free(maddr);
611}
612
613#ifdef INET6
614ATF_TC_WITHOUT_HEAD(addrmerge_localhost_only6);
615ATF_TC_BODY(addrmerge_localhost_only6, tc)
616{
617	char *maddr;
618
619	/* getifaddrs will return localhost only */
620	mock_lo0();
621
622	maddr = do_addrmerge6(NULL);
623
624	/* We must return localhost if there is nothing better */
625	ATF_REQUIRE(maddr != NULL);
626	ATF_CHECK_STREQ("::1.3.46", maddr);
627	free(maddr);
628}
629
630ATF_TC_WITHOUT_HEAD(addrmerge_singlehomed6);
631ATF_TC_BODY(addrmerge_singlehomed6, tc)
632{
633	char *maddr;
634
635	/* getifaddrs will return one public address */
636	mock_lo0();
637	mock_igb0();
638
639	maddr = do_addrmerge6(NULL);
640
641	ATF_REQUIRE(maddr != NULL);
642	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
643	free(maddr);
644}
645
646ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet6);
647ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6, tc)
648{
649	char *maddr;
650
651	mock_lo0();
652	mock_igb0();
653	mock_igb2();
654
655	maddr = do_addrmerge6(NULL);
656
657	/* We must return the address on the caller's subnet */
658	ATF_REQUIRE(maddr != NULL);
659	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
660	free(maddr);
661}
662
663
664/*
665 * Like addrmerge_one_addr_on_each_subnet6, but getifaddrs returns a different
666 * order
667 */
668ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet6_rev);
669ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6_rev, tc)
670{
671	char *maddr;
672
673	/* getifaddrs will return one public address on each of two subnets */
674	mock_igb2();
675	mock_igb0();
676	mock_lo0();
677
678	maddr = do_addrmerge6(NULL);
679
680	/* We must return the address on the caller's subnet */
681	ATF_REQUIRE(maddr != NULL);
682	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
683	free(maddr);
684}
685
686ATF_TC_WITHOUT_HEAD(addrmerge_point2point6);
687ATF_TC_BODY(addrmerge_point2point6, tc)
688{
689	char *maddr;
690
691	/* getifaddrs will return one normal and one p2p address */
692	mock_lo0();
693	mock_igb2();
694	mock_tun0();
695
696	maddr = do_addrmerge6(NULL);
697
698	/* addrmerge should disprefer P2P interfaces */
699	ATF_REQUIRE(maddr != NULL);
700	ATF_CHECK_STREQ("2001:db8:1::2.3.46", maddr);
701	free(maddr);
702}
703
704/* Like addrerge_point2point, but getifaddrs returns a different order */
705ATF_TC_WITHOUT_HEAD(addrmerge_point2point6_rev);
706ATF_TC_BODY(addrmerge_point2point6_rev, tc)
707{
708	char *maddr;
709
710	/* getifaddrs will return one normal and one p2p address */
711	mock_tun0();
712	mock_igb2();
713	mock_lo0();
714
715	maddr = do_addrmerge6(NULL);
716
717	/* addrmerge should disprefer P2P interfaces */
718	ATF_REQUIRE(maddr != NULL);
719	ATF_CHECK_STREQ("2001:db8:1::2.3.46", maddr);
720	free(maddr);
721}
722
723ATF_TC_WITHOUT_HEAD(addrmerge_bindip6);
724ATF_TC_BODY(addrmerge_bindip6, tc)
725{
726	char *maddr;
727
728	/* getifaddrs will return one public address on each of two subnets */
729	mock_lo0();
730	mock_igb0();
731	mock_igb1(true);
732
733	maddr = do_addrmerge6(NULL);
734
735	/* We must return the address to which we are bound */
736	ATF_REQUIRE(maddr != NULL);
737	ATF_CHECK_STREQ("2001:db8::3.3.46", maddr);
738	free(maddr);
739}
740
741/* Like addrerge_bindip, but getifaddrs returns a different order */
742ATF_TC_WITHOUT_HEAD(addrmerge_bindip6_rev);
743ATF_TC_BODY(addrmerge_bindip6_rev, tc)
744{
745	char *maddr;
746
747	/* getifaddrs will return one public address on each of two subnets */
748	mock_igb1(true);
749	mock_igb0();
750	mock_lo0();
751
752	maddr = do_addrmerge6(NULL);
753
754	/* We must return the address to which we are bound */
755	ATF_REQUIRE(maddr != NULL);
756	ATF_CHECK_STREQ("2001:db8::3.3.46", maddr);
757	free(maddr);
758}
759
760/*
761 * IPv6 Link Local addresses with the same scope id as the caller, if the caller
762 * is also a link local address, should be preferred
763 */
764ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_linklocal);
765ATF_TC_BODY(addrmerge_ipv6_linklocal, tc)
766{
767	char *maddr;
768
769	/*
770	 * getifaddrs will return two link local addresses with the same netmask
771	 * and prefix but different scope IDs
772	 */
773	mock_igb1(false);
774	mock_igb0();
775	mock_lo0();
776
777	maddr = do_addrmerge6_ll();
778
779	/* We must return the address to which we are bound */
780	ATF_REQUIRE(maddr != NULL);
781	ATF_CHECK_STREQ("fe80::2.3.46", maddr);
782	free(maddr);
783}
784
785ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_linklocal_rev);
786ATF_TC_BODY(addrmerge_ipv6_linklocal_rev, tc)
787{
788	char *maddr;
789
790	/*
791	 * getifaddrs will return two link local addresses with the same netmask
792	 * and prefix but different scope IDs
793	 */
794	mock_lo0();
795	mock_igb0();
796	mock_igb1(false);
797
798	maddr = do_addrmerge6_ll();
799
800	/* We must return the address to which we are bound */
801	ATF_REQUIRE(maddr != NULL);
802	ATF_CHECK_STREQ("fe80::2.3.46", maddr);
803	free(maddr);
804}
805
806ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr6);
807ATF_TC_BODY(addrmerge_recvdstaddr6, tc)
808{
809	char *maddr;
810
811	mock_lo0();
812	mock_igb0();
813	mock_igb1(false);
814
815	maddr = do_addrmerge6("2001:db8::2.3.46");
816
817	/* We must return the address on which the request was received */
818	ATF_REQUIRE(maddr != NULL);
819	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
820	free(maddr);
821}
822
823ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr6_rev);
824ATF_TC_BODY(addrmerge_recvdstaddr6_rev, tc)
825{
826	char *maddr;
827
828	mock_igb1(false);
829	mock_igb0();
830	mock_lo0();
831
832	maddr = do_addrmerge6("2001:db8::2.3.46");
833
834	/* We must return the address on which the request was received */
835	ATF_REQUIRE(maddr != NULL);
836	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
837	free(maddr);
838}
839#endif /* INET6 */
840
841
842ATF_TP_ADD_TCS(tp)
843{
844	ATF_TP_ADD_TC(tp, addrmerge_noifaddrs);
845	ATF_TP_ADD_TC(tp, addrmerge_localhost_only);
846	ATF_TP_ADD_TC(tp, addrmerge_singlehomed);
847	ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet);
848	ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet_rev);
849	ATF_TP_ADD_TC(tp, addrmerge_point2point);
850	ATF_TP_ADD_TC(tp, addrmerge_point2point_rev);
851	ATF_TP_ADD_TC(tp, addrmerge_bindip);
852	ATF_TP_ADD_TC(tp, addrmerge_bindip_rev);
853	ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr);
854	ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr_rev);
855#ifdef INET6
856	ATF_TP_ADD_TC(tp, addrmerge_localhost_only6);
857	ATF_TP_ADD_TC(tp, addrmerge_singlehomed6);
858	ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet6);
859	ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet6_rev);
860	ATF_TP_ADD_TC(tp, addrmerge_point2point6);
861	ATF_TP_ADD_TC(tp, addrmerge_point2point6_rev);
862	ATF_TP_ADD_TC(tp, addrmerge_bindip6);
863	ATF_TP_ADD_TC(tp, addrmerge_bindip6_rev);
864	ATF_TP_ADD_TC(tp, addrmerge_ipv6_linklocal);
865	ATF_TP_ADD_TC(tp, addrmerge_ipv6_linklocal_rev);
866	ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr6);
867	ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr6_rev);
868#endif
869
870	return (atf_no_error());
871}
872