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