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