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 #include <stdio.h>
44
45 #include <atf-c.h>
46
47 #include "rpcbind.h"
48
49 #define MAX_IFADDRS 16
50
51 int debugging = false;
52
53 /* Data for mocking getifaddrs */
54 struct 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];
60 struct ifaddrs *mock_ifaddrs = NULL;
61 int ifaddr_count = 0;
62
63 /* Data for mocking listen_addr */
64 int bind_address_count = 0;
65 struct sockaddr* bind_addresses[MAX_IFADDRS];
66
67 /* Stub library functions */
68 void
freeifaddrs(struct ifaddrs * ifp __unused)69 freeifaddrs(struct ifaddrs *ifp __unused)
70 {
71 return ;
72 }
73
74 int
getifaddrs(struct ifaddrs ** ifap)75 getifaddrs(struct ifaddrs **ifap)
76 {
77 *ifap = mock_ifaddrs;
78 return (0);
79 }
80
81 static void
mock_ifaddr4(const char * name,const char * addr,const char * mask,const char * bcast,unsigned int flags,bool bind)82 mock_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
128 static void
mock_ifaddr6(const char * name,const char * addr,const char * mask,const char * bcast,unsigned int flags,uint32_t scope_id,bool bind)129 mock_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
179 static void
mock_ifaddr6(const char * name __unused,const char * addr __unused,const char * mask __unused,const char * bcast __unused,unsigned int flags __unused,uint32_t scope_id __unused,bool bind __unused)180 mock_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
187 static void
mock_lo0(void)188 mock_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
201 static void
mock_igb0(void)202 mock_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 */
219 static void
mock_igb1(bool bind)220 mock_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 */
237 static void
mock_igb2(void)238 mock_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 */
250 static void
mock_tun0(void)251 mock_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 */
263 int
listen_addr(const struct sockaddr * sa)264 listen_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
282 struct netconfig*
rpcbind_get_conf(const char * netid __unused)283 rpcbind_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 */
326 static char*
do_addrmerge4(const char * recvdstaddr)327 do_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 */
358 static char*
do_addrmerge6(const char * recvdstaddr)359 do_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 */
387 static char*
do_addrmerge6_ll(void)388 do_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
414 ATF_TC_WITHOUT_HEAD(addrmerge_noifaddrs);
ATF_TC_BODY(addrmerge_noifaddrs,tc)415 ATF_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
425 ATF_TC_WITHOUT_HEAD(addrmerge_localhost_only);
ATF_TC_BODY(addrmerge_localhost_only,tc)426 ATF_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 }
439
440 ATF_TC_WITHOUT_HEAD(addrmerge_singlehomed);
ATF_TC_BODY(addrmerge_singlehomed,tc)441 ATF_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 }
454
455 ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet);
ATF_TC_BODY(addrmerge_one_addr_on_each_subnet,tc)456 ATF_TC_BODY(addrmerge_one_addr_on_each_subnet, tc)
457 {
458 char *maddr;
459
460 mock_lo0();
461 mock_igb0();
462 mock_igb2();
463
464 maddr = do_addrmerge4(NULL);
465
466 /* We must return the address on the caller's subnet */
467 ATF_REQUIRE(maddr != NULL);
468 ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
469 }
470
471
472 /*
473 * Like addrmerge_one_addr_on_each_subnet, but getifaddrs returns a different
474 * order
475 */
476 ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet_rev);
ATF_TC_BODY(addrmerge_one_addr_on_each_subnet_rev,tc)477 ATF_TC_BODY(addrmerge_one_addr_on_each_subnet_rev, tc)
478 {
479 char *maddr;
480
481 /* getifaddrs will return one public address on each of two subnets */
482 mock_igb2();
483 mock_igb0();
484 mock_lo0();
485
486 maddr = do_addrmerge4(NULL);
487
488 /* We must return the address on the caller's subnet */
489 ATF_REQUIRE(maddr != NULL);
490 ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
491 }
492
493 ATF_TC_WITHOUT_HEAD(addrmerge_point2point);
ATF_TC_BODY(addrmerge_point2point,tc)494 ATF_TC_BODY(addrmerge_point2point, tc)
495 {
496 char *maddr;
497
498 /* getifaddrs will return one normal and one p2p address */
499 mock_lo0();
500 mock_igb2();
501 mock_tun0();
502
503 maddr = do_addrmerge4(NULL);
504
505 /* addrmerge should disprefer P2P interfaces */
506 ATF_REQUIRE(maddr != NULL);
507 ATF_CHECK_STREQ("192.0.2.130.3.46", maddr);
508 }
509
510 /* Like addrerge_point2point, but getifaddrs returns a different order */
511 ATF_TC_WITHOUT_HEAD(addrmerge_point2point_rev);
ATF_TC_BODY(addrmerge_point2point_rev,tc)512 ATF_TC_BODY(addrmerge_point2point_rev, tc)
513 {
514 char *maddr;
515
516 /* getifaddrs will return one normal and one p2p address */
517 mock_tun0();
518 mock_igb2();
519 mock_lo0();
520
521 maddr = do_addrmerge4(NULL);
522
523 /* addrmerge should disprefer P2P interfaces */
524 ATF_REQUIRE(maddr != NULL);
525 ATF_CHECK_STREQ("192.0.2.130.3.46", maddr);
526 }
527
528 /*
529 * Simulate using rpcbind -h to select just one ip when the subnet has
530 * multiple
531 */
532 ATF_TC_WITHOUT_HEAD(addrmerge_bindip);
ATF_TC_BODY(addrmerge_bindip,tc)533 ATF_TC_BODY(addrmerge_bindip, tc)
534 {
535 char *maddr;
536
537 /* getifaddrs will return one public address on each of two subnets */
538 mock_lo0();
539 mock_igb0();
540 mock_igb1(true);
541
542 maddr = do_addrmerge4(NULL);
543
544 /* We must return the address to which we are bound */
545 ATF_REQUIRE(maddr != NULL);
546 ATF_CHECK_STREQ("192.0.2.3.3.46", maddr);
547 }
548
549 /* Like addrmerge_bindip, but getifaddrs returns a different order */
550 ATF_TC_WITHOUT_HEAD(addrmerge_bindip_rev);
ATF_TC_BODY(addrmerge_bindip_rev,tc)551 ATF_TC_BODY(addrmerge_bindip_rev, tc)
552 {
553 char *maddr;
554
555 /* getifaddrs will return one public address on each of two subnets */
556 mock_igb1(true);
557 mock_igb0();
558 mock_lo0();
559
560 maddr = do_addrmerge4(NULL);
561
562 /* We must return the address to which we are bound */
563 ATF_REQUIRE(maddr != NULL);
564 ATF_CHECK_STREQ("192.0.2.3.3.46", maddr);
565 }
566
567 /*
568 * The address on which the request was received is known, and is provided as
569 * the hint.
570 */
571 ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr);
ATF_TC_BODY(addrmerge_recvdstaddr,tc)572 ATF_TC_BODY(addrmerge_recvdstaddr, tc)
573 {
574 char *maddr;
575
576 mock_lo0();
577 mock_igb0();
578 mock_igb1(false);
579
580 maddr = do_addrmerge4("192.0.2.2.3.46");
581
582 /* We must return the address on which the request was received */
583 ATF_REQUIRE(maddr != NULL);
584 ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
585 }
586
587 ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr_rev);
ATF_TC_BODY(addrmerge_recvdstaddr_rev,tc)588 ATF_TC_BODY(addrmerge_recvdstaddr_rev, tc)
589 {
590 char *maddr;
591
592 mock_igb1(false);
593 mock_igb0();
594 mock_lo0();
595
596 maddr = do_addrmerge4("192.0.2.2.3.46");
597
598 /* We must return the address on which the request was received */
599 ATF_REQUIRE(maddr != NULL);
600 ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
601 }
602
603 #ifdef INET6
604 ATF_TC_WITHOUT_HEAD(addrmerge_localhost_only6);
ATF_TC_BODY(addrmerge_localhost_only6,tc)605 ATF_TC_BODY(addrmerge_localhost_only6, tc)
606 {
607 char *maddr;
608
609 /* getifaddrs will return localhost only */
610 mock_lo0();
611
612 maddr = do_addrmerge6(NULL);
613
614 /* We must return localhost if there is nothing better */
615 ATF_REQUIRE(maddr != NULL);
616 ATF_CHECK_STREQ("::1.3.46", maddr);
617 }
618
619 ATF_TC_WITHOUT_HEAD(addrmerge_singlehomed6);
ATF_TC_BODY(addrmerge_singlehomed6,tc)620 ATF_TC_BODY(addrmerge_singlehomed6, tc)
621 {
622 char *maddr;
623
624 /* getifaddrs will return one public address */
625 mock_lo0();
626 mock_igb0();
627
628 maddr = do_addrmerge6(NULL);
629
630 ATF_REQUIRE(maddr != NULL);
631 ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
632 }
633
634 ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet6);
ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6,tc)635 ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6, tc)
636 {
637 char *maddr;
638
639 mock_lo0();
640 mock_igb0();
641 mock_igb2();
642
643 maddr = do_addrmerge6(NULL);
644
645 /* We must return the address on the caller's subnet */
646 ATF_REQUIRE(maddr != NULL);
647 ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
648 }
649
650
651 /*
652 * Like addrmerge_one_addr_on_each_subnet6, but getifaddrs returns a different
653 * order
654 */
655 ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet6_rev);
ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6_rev,tc)656 ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6_rev, tc)
657 {
658 char *maddr;
659
660 /* getifaddrs will return one public address on each of two subnets */
661 mock_igb2();
662 mock_igb0();
663 mock_lo0();
664
665 maddr = do_addrmerge6(NULL);
666
667 /* We must return the address on the caller's subnet */
668 ATF_REQUIRE(maddr != NULL);
669 ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
670 }
671
672 ATF_TC_WITHOUT_HEAD(addrmerge_point2point6);
ATF_TC_BODY(addrmerge_point2point6,tc)673 ATF_TC_BODY(addrmerge_point2point6, tc)
674 {
675 char *maddr;
676
677 /* getifaddrs will return one normal and one p2p address */
678 mock_lo0();
679 mock_igb2();
680 mock_tun0();
681
682 maddr = do_addrmerge6(NULL);
683
684 /* addrmerge should disprefer P2P interfaces */
685 ATF_REQUIRE(maddr != NULL);
686 ATF_CHECK_STREQ("2001:db8:1::2.3.46", maddr);
687 }
688
689 /* Like addrerge_point2point, but getifaddrs returns a different order */
690 ATF_TC_WITHOUT_HEAD(addrmerge_point2point6_rev);
ATF_TC_BODY(addrmerge_point2point6_rev,tc)691 ATF_TC_BODY(addrmerge_point2point6_rev, tc)
692 {
693 char *maddr;
694
695 /* getifaddrs will return one normal and one p2p address */
696 mock_tun0();
697 mock_igb2();
698 mock_lo0();
699
700 maddr = do_addrmerge6(NULL);
701
702 /* addrmerge should disprefer P2P interfaces */
703 ATF_REQUIRE(maddr != NULL);
704 ATF_CHECK_STREQ("2001:db8:1::2.3.46", maddr);
705 }
706
707 ATF_TC_WITHOUT_HEAD(addrmerge_bindip6);
ATF_TC_BODY(addrmerge_bindip6,tc)708 ATF_TC_BODY(addrmerge_bindip6, tc)
709 {
710 char *maddr;
711
712 /* getifaddrs will return one public address on each of two subnets */
713 mock_lo0();
714 mock_igb0();
715 mock_igb1(true);
716
717 maddr = do_addrmerge6(NULL);
718
719 /* We must return the address to which we are bound */
720 ATF_REQUIRE(maddr != NULL);
721 ATF_CHECK_STREQ("2001:db8::3.3.46", maddr);
722 }
723
724 /* Like addrerge_bindip, but getifaddrs returns a different order */
725 ATF_TC_WITHOUT_HEAD(addrmerge_bindip6_rev);
ATF_TC_BODY(addrmerge_bindip6_rev,tc)726 ATF_TC_BODY(addrmerge_bindip6_rev, tc)
727 {
728 char *maddr;
729
730 /* getifaddrs will return one public address on each of two subnets */
731 mock_igb1(true);
732 mock_igb0();
733 mock_lo0();
734
735 maddr = do_addrmerge6(NULL);
736
737 /* We must return the address to which we are bound */
738 ATF_REQUIRE(maddr != NULL);
739 ATF_CHECK_STREQ("2001:db8::3.3.46", maddr);
740 }
741
742 /*
743 * IPv6 Link Local addresses with the same scope id as the caller, if the caller
744 * is also a link local address, should be preferred
745 */
746 ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_linklocal);
ATF_TC_BODY(addrmerge_ipv6_linklocal,tc)747 ATF_TC_BODY(addrmerge_ipv6_linklocal, tc)
748 {
749 char *maddr;
750
751 /*
752 * getifaddrs will return two link local addresses with the same netmask
753 * and prefix but different scope IDs
754 */
755 mock_igb1(false);
756 mock_igb0();
757 mock_lo0();
758
759 maddr = do_addrmerge6_ll();
760
761 /* We must return the address to which we are bound */
762 ATF_REQUIRE(maddr != NULL);
763 ATF_CHECK_STREQ("fe80::2.3.46", maddr);
764 }
765
766 ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_linklocal_rev);
ATF_TC_BODY(addrmerge_ipv6_linklocal_rev,tc)767 ATF_TC_BODY(addrmerge_ipv6_linklocal_rev, tc)
768 {
769 char *maddr;
770
771 /*
772 * getifaddrs will return two link local addresses with the same netmask
773 * and prefix but different scope IDs
774 */
775 mock_lo0();
776 mock_igb0();
777 mock_igb1(false);
778
779 maddr = do_addrmerge6_ll();
780
781 /* We must return the address to which we are bound */
782 ATF_REQUIRE(maddr != NULL);
783 ATF_CHECK_STREQ("fe80::2.3.46", maddr);
784 }
785
786 ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr6);
ATF_TC_BODY(addrmerge_recvdstaddr6,tc)787 ATF_TC_BODY(addrmerge_recvdstaddr6, tc)
788 {
789 char *maddr;
790
791 mock_lo0();
792 mock_igb0();
793 mock_igb1(false);
794
795 maddr = do_addrmerge6("2001:db8::2.3.46");
796
797 /* We must return the address on which the request was received */
798 ATF_REQUIRE(maddr != NULL);
799 ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
800 }
801
802 ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr6_rev);
ATF_TC_BODY(addrmerge_recvdstaddr6_rev,tc)803 ATF_TC_BODY(addrmerge_recvdstaddr6_rev, tc)
804 {
805 char *maddr;
806
807 mock_igb1(false);
808 mock_igb0();
809 mock_lo0();
810
811 maddr = do_addrmerge6("2001:db8::2.3.46");
812
813 /* We must return the address on which the request was received */
814 ATF_REQUIRE(maddr != NULL);
815 ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
816 }
817 #endif /* INET6 */
818
819
ATF_TP_ADD_TCS(tp)820 ATF_TP_ADD_TCS(tp)
821 {
822 ATF_TP_ADD_TC(tp, addrmerge_noifaddrs);
823 ATF_TP_ADD_TC(tp, addrmerge_localhost_only);
824 ATF_TP_ADD_TC(tp, addrmerge_singlehomed);
825 ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet);
826 ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet_rev);
827 ATF_TP_ADD_TC(tp, addrmerge_point2point);
828 ATF_TP_ADD_TC(tp, addrmerge_point2point_rev);
829 ATF_TP_ADD_TC(tp, addrmerge_bindip);
830 ATF_TP_ADD_TC(tp, addrmerge_bindip_rev);
831 ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr);
832 ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr_rev);
833 #ifdef INET6
834 ATF_TP_ADD_TC(tp, addrmerge_localhost_only6);
835 ATF_TP_ADD_TC(tp, addrmerge_singlehomed6);
836 ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet6);
837 ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet6_rev);
838 ATF_TP_ADD_TC(tp, addrmerge_point2point6);
839 ATF_TP_ADD_TC(tp, addrmerge_point2point6_rev);
840 ATF_TP_ADD_TC(tp, addrmerge_bindip6);
841 ATF_TP_ADD_TC(tp, addrmerge_bindip6_rev);
842 ATF_TP_ADD_TC(tp, addrmerge_ipv6_linklocal);
843 ATF_TP_ADD_TC(tp, addrmerge_ipv6_linklocal_rev);
844 ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr6);
845 ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr6_rev);
846 #endif
847
848 return (atf_no_error());
849 }
850