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
48int debugging = false;
49
50/* Data for mocking getifaddrs */
51struct 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];
57struct ifaddrs *mock_ifaddrs = NULL;
58int ifaddr_count = 0;
59
60/* Data for mocking listen_addr */
61int bind_address_count = 0;
62struct sockaddr* bind_addresses[MAX_IFADDRS];
63
64/* Stub library functions */
65void
66freeifaddrs(struct ifaddrs *ifp __unused)
67{
68	return ;
69}
70
71int
72getifaddrs(struct ifaddrs **ifap)
73{
74	*ifap = mock_ifaddrs;
75	return (0);
76}
77
78static void
79mock_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
125static void
126mock_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
176static void
177mock_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
184static void
185mock_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
198static void
199mock_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 */
216static void
217mock_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 */
234static void
235mock_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 */
247static void
248mock_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
258static void
259mock_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 */
276int
277listen_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
295struct netconfig*
296rpcbind_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 */
339static char*
340do_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 */
371static char*
372do_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 */
400static char*
401do_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
427ATF_TC_WITHOUT_HEAD(addrmerge_noifaddrs);
428ATF_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
438ATF_TC_WITHOUT_HEAD(addrmerge_localhost_only);
439ATF_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
454ATF_TC_WITHOUT_HEAD(addrmerge_singlehomed);
455ATF_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
470ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet);
471ATF_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 */
492ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet_rev);
493ATF_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
510ATF_TC_WITHOUT_HEAD(addrmerge_point2point);
511ATF_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 */
529ATF_TC_WITHOUT_HEAD(addrmerge_point2point_rev);
530ATF_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 */
551ATF_TC_WITHOUT_HEAD(addrmerge_bindip);
552ATF_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 */
570ATF_TC_WITHOUT_HEAD(addrmerge_bindip_rev);
571ATF_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 */
592ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr);
593ATF_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
609ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr_rev);
610ATF_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
627ATF_TC_WITHOUT_HEAD(addrmerge_localhost_only6);
628ATF_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
643ATF_TC_WITHOUT_HEAD(addrmerge_singlehomed6);
644ATF_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
659ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet6);
660ATF_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 */
681ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet6_rev);
682ATF_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
699ATF_TC_WITHOUT_HEAD(addrmerge_point2point6);
700ATF_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 */
718ATF_TC_WITHOUT_HEAD(addrmerge_point2point6_rev);
719ATF_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
736ATF_TC_WITHOUT_HEAD(addrmerge_bindip6);
737ATF_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 */
755ATF_TC_WITHOUT_HEAD(addrmerge_bindip6_rev);
756ATF_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 */
777ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_linklocal);
778ATF_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
798ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_linklocal_rev);
799ATF_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
819ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr6);
820ATF_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
836ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr6_rev);
837ATF_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
853ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_other_subnet);
854ATF_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
872ATF_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