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