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
freeifaddrs(struct ifaddrs * ifp __unused)66 freeifaddrs(struct ifaddrs *ifp __unused)
67 {
68 return ;
69 }
70
71 int
getifaddrs(struct ifaddrs ** ifap)72 getifaddrs(struct ifaddrs **ifap)
73 {
74 *ifap = mock_ifaddrs;
75 return (0);
76 }
77
78 static void
mock_ifaddr4(const char * name,const char * addr,const char * mask,const char * bcast,unsigned int flags,bool bind)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
mock_ifaddr6(const char * name,const char * addr,const char * mask,const char * bcast,unsigned int flags,uint32_t scope_id,bool bind)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
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)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
mock_lo0(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
mock_igb0(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
mock_igb1(bool bind)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
mock_igb2(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
mock_tun0(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
mock_mlxen0(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
listen_addr(const struct sockaddr * sa)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*
rpcbind_get_conf(const char * netid __unused)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*
do_addrmerge4(const char * recvdstaddr)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*
do_addrmerge6(const char * recvdstaddr)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*
do_addrmerge6_ll(void)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);
ATF_TC_BODY(addrmerge_noifaddrs,tc)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);
ATF_TC_BODY(addrmerge_localhost_only,tc)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);
ATF_TC_BODY(addrmerge_singlehomed,tc)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);
ATF_TC_BODY(addrmerge_one_addr_on_each_subnet,tc)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);
ATF_TC_BODY(addrmerge_one_addr_on_each_subnet_rev,tc)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);
ATF_TC_BODY(addrmerge_point2point,tc)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);
ATF_TC_BODY(addrmerge_point2point_rev,tc)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);
ATF_TC_BODY(addrmerge_bindip,tc)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);
ATF_TC_BODY(addrmerge_bindip_rev,tc)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);
ATF_TC_BODY(addrmerge_recvdstaddr,tc)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);
ATF_TC_BODY(addrmerge_recvdstaddr_rev,tc)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);
ATF_TC_BODY(addrmerge_localhost_only6,tc)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);
ATF_TC_BODY(addrmerge_singlehomed6,tc)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);
ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6,tc)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);
ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6_rev,tc)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);
ATF_TC_BODY(addrmerge_point2point6,tc)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);
ATF_TC_BODY(addrmerge_point2point6_rev,tc)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);
ATF_TC_BODY(addrmerge_bindip6,tc)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);
ATF_TC_BODY(addrmerge_bindip6_rev,tc)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);
ATF_TC_BODY(addrmerge_ipv6_linklocal,tc)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);
ATF_TC_BODY(addrmerge_ipv6_linklocal_rev,tc)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);
ATF_TC_BODY(addrmerge_recvdstaddr6,tc)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);
ATF_TC_BODY(addrmerge_recvdstaddr6_rev,tc)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);
ATF_TC_BODY(addrmerge_ipv6_other_subnet,tc)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
ATF_TP_ADD_TCS(tp)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