1 /*
2 * Copyright (c) 2020-2022 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* -*- compile-command: "xcrun --sdk iphoneos.internal make sioc-if-addr-bounds" -*- */
30
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <sys/sockio.h>
34
35 #include <net/if.h>
36 #include <net/if_dl.h>
37
38 #include <netinet/in.h>
39 #include <netinet/in_var.h>
40
41 #include <string.h>
42 #include <unistd.h>
43
44 #include <arpa/inet.h>
45
46 #include <darwintest.h>
47 #include <darwintest_utils.h>
48
49 #include <uuid/uuid.h>
50
51 #include <ifaddrs.h>
52
53 #include <arpa/inet.h>
54
55 #include "ioc_str.h"
56
57 T_GLOBAL_META(T_META_NAMESPACE("xnu.net"));
58
59 #ifndef STRINGIFY
60 #define __STR(x) #x /* just a helper macro */
61 #define STRINGIFY(x) __STR(x)
62 #endif /* STRINGIFY */
63
64 #define IF_NAME "bridge"
65
66 /* On some platforms with DEBUG kernel, we need to wait a while */
67 #define SIFCREATE_RETRY 600
68
69 #define PATTERN_SIZE 8
70
71 static int
ifnet_destroy(int s,const char * ifname,bool fail_on_error)72 ifnet_destroy(int s, const char * ifname, bool fail_on_error)
73 {
74 int err;
75 struct ifreq ifr;
76
77 bzero(&ifr, sizeof(ifr));
78 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
79 err = ioctl(s, SIOCIFDESTROY, &ifr);
80 if (fail_on_error) {
81 T_QUIET;
82 T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name);
83 }
84 if (err < 0) {
85 T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name);
86 }
87 return err;
88 }
89
90 static int
ifnet_set_flags(int s,const char * ifname,uint16_t flags_set,uint16_t flags_clear)91 ifnet_set_flags(int s, const char * ifname,
92 uint16_t flags_set, uint16_t flags_clear)
93 {
94 uint16_t flags_after;
95 uint16_t flags_before;
96 struct ifreq ifr;
97 int ret;
98
99 bzero(&ifr, sizeof(ifr));
100 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
101 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
102 if (ret != 0) {
103 T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name);
104 return ret;
105 }
106 flags_before = (uint16_t)ifr.ifr_flags;
107 ifr.ifr_flags |= flags_set;
108 ifr.ifr_flags &= ~(flags_clear);
109 flags_after = (uint16_t)ifr.ifr_flags;
110 if (flags_before == flags_after) {
111 /* nothing to do */
112 ret = 0;
113 } else {
114 /* issue the ioctl */
115 T_QUIET;
116 T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr),
117 "SIOCSIFFLAGS %s 0x%x",
118 ifr.ifr_name, (uint16_t)ifr.ifr_flags);
119 }
120 return ret;
121 }
122
123 static int
ifnet_create(int s,char * ifname,size_t ifname_size)124 ifnet_create(int s, char * ifname, size_t ifname_size)
125 {
126 int error = 0;
127 struct ifreq ifr;
128
129 bzero(&ifr, sizeof(ifr));
130 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
131
132 for (int i = 0; i < SIFCREATE_RETRY; i++) {
133 if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
134 error = errno;
135 T_LOG("SIOCSIFCREATE %s: %s", ifname,
136 strerror(error));
137 if (error == EBUSY) {
138 /* interface is tearing down, try again */
139 usleep(10000);
140 } else if (error == EEXIST) {
141 /* interface exists, try destroying it */
142 (void)ifnet_destroy(s, ifname, false);
143 } else {
144 /* unexpected failure */
145 break;
146 }
147 } else {
148 error = 0;
149 break;
150 }
151 }
152 if (error == 0) {
153 /* Copy back the interface name with unit number */
154 strlcpy(ifname, ifr.ifr_name, ifname_size);
155 error = ifnet_set_flags(s, ifname, IFF_UP, 0);
156 }
157 return error;
158 }
159
160 #define MAXBUF 32
161
162 static void
HexDump(void * data,size_t len)163 HexDump(void *data, size_t len)
164 {
165 size_t i, j, k;
166 unsigned char *ptr = (unsigned char *)data;
167 unsigned char buf[3 * MAXBUF + 1];
168
169 for (i = 0; i < len; i += MAXBUF) {
170 for (j = i, k = 0; j < i + MAXBUF && j < len; j++) {
171 unsigned char msnbl = ptr[j] >> 4;
172 unsigned char lsnbl = ptr[j] & 0x0f;
173
174 buf[k++] = msnbl < 10 ? msnbl + '0' : msnbl + 'a' - 10;
175 buf[k++] = lsnbl < 10 ? lsnbl + '0' : lsnbl + 'a' - 10;
176 if ((j % 2) == 1) {
177 buf[k++] = ' ';
178 }
179 if ((j % MAXBUF) == MAXBUF - 1) {
180 buf[k++] = ' ';
181 }
182 }
183 buf[k] = 0;
184 T_LOG("%5zd: %s\n", i, buf);
185 }
186 }
187
188 static size_t
snprint_dottedhex(char * str,size_t strsize,const void * data,const size_t datasize)189 snprint_dottedhex(char *str, size_t strsize, const void *data, const size_t datasize)
190 {
191 size_t is = 0, ip = 0;
192 const unsigned char *ptr = (const unsigned char *)data;
193
194 for (is = 0, ip = 0; is + 3 < strsize - 1 && ip < datasize; ip++) {
195 unsigned char msnbl = ptr[ip] >> 4;
196 unsigned char lsnbl = ptr[ip] & 0x0f;
197
198 if (ip > 0) {
199 str[is++] = '.';
200 }
201 str[is++] = (char)(msnbl + (msnbl < 10 ? '0' : 'a' - 10));
202 str[is++] = (char)(lsnbl + (lsnbl < 10 ? '0' : 'a' - 10));
203 }
204 str[is] = 0;
205 return is;
206 }
207
208 static void
print_sockaddr_dl(const char * pre,const struct sockaddr * sa,const char * post)209 print_sockaddr_dl(const char *pre, const struct sockaddr *sa, const char *post)
210 {
211 char nbuffer[256];
212 char abuffer[256];
213 char sbuffer[256];
214 struct sockaddr_dl sdl = {};
215
216 if (sa == NULL) {
217 return;
218 }
219 memcpy(&sdl, sa, MIN(sizeof(sdl), sa->sa_len));
220 strlcpy(nbuffer, sdl.sdl_data, sdl.sdl_nlen);
221 snprint_dottedhex(abuffer, sizeof(abuffer), sdl.sdl_data + sdl.sdl_nlen, sdl.sdl_alen);
222 snprint_dottedhex(sbuffer, sizeof(sbuffer), sdl.sdl_data + sdl.sdl_nlen + sdl.sdl_alen, sdl.sdl_slen);
223
224 T_LOG("%ssdl_len %u sdl_family %u sdl_index %u sdl_type %u sdl_nlen %u (%s) sdl_alen %u (%s) sdl_slen %u (%s)%s",
225 pre != NULL ? pre : "",
226 sdl.sdl_len, sdl.sdl_family, sdl.sdl_index, sdl.sdl_type,
227 sdl.sdl_nlen, nbuffer, sdl.sdl_alen, abuffer, sdl.sdl_slen, sbuffer,
228 post != NULL ? post : "");
229 }
230
231 static void
print_sockaddr_in(const char * pre,const struct sockaddr * sa,const char * post)232 print_sockaddr_in(const char *pre, const struct sockaddr *sa, const char *post)
233 {
234 char abuffer[256];
235 char zbuffer[256];
236 struct sockaddr_in sin = {};
237
238 if (sa == NULL) {
239 return;
240 }
241
242 memcpy(&sin, sa, MIN(sizeof(sin), sa->sa_len));
243 inet_ntop(AF_INET, &sin.sin_addr, abuffer, sizeof(abuffer));
244 snprint_dottedhex(zbuffer, sizeof(zbuffer), sin.sin_zero, sizeof(sin.sin_zero));
245
246 T_LOG("%ssin_len %u sin_family %u sin_port %u sin_addr %s sin_zero %s%s",
247 pre != NULL ? pre : "",
248 sin.sin_len, sin.sin_family, htons(sin.sin_port), abuffer, zbuffer,
249 post != NULL ? post : "");
250 }
251
252 static void
print_sockaddr_in6(const char * pre,const struct sockaddr * sa,const char * post)253 print_sockaddr_in6(const char *pre, const struct sockaddr *sa, const char *post)
254 {
255 char abuffer[256];
256 struct sockaddr_in6 sin6 = {};
257
258 if (sa == NULL) {
259 return;
260 }
261
262 memcpy(&sin6, sa, MIN(sizeof(sin6), sa->sa_len));
263 inet_ntop(AF_INET6, &sin6.sin6_addr, abuffer, sizeof(abuffer));
264
265 T_LOG("%ssin6_len %u sin6_family %u sin6_port %u sin6_flowinfo %u sin6_addr %s sin6_scope_id %u%s",
266 pre != NULL ? pre : "",
267 sin6.sin6_len, sin6.sin6_family, htons(sin6.sin6_port), sin6.sin6_flowinfo, abuffer, sin6.sin6_scope_id,
268 post != NULL ? post : "");
269 }
270
271 static void
print_sockaddr(const char * pre,const struct sockaddr * sa,const char * post)272 print_sockaddr(const char *pre, const struct sockaddr *sa, const char *post)
273 {
274 char buffer[256];
275
276 if (sa == NULL) {
277 return;
278 }
279
280 snprint_dottedhex(buffer, sizeof(buffer), sa->sa_data, sa->sa_len - 2);
281
282 T_LOG("%ssa_len %u sa_family %u sa_data %s%s",
283 pre != NULL ? pre : "",
284 sa->sa_len, sa->sa_family, buffer,
285 post != NULL ? post : "");
286 }
287
288
289 #define ROUNDUP(a, size) (((a) & ((size) - 1)) ? (1 + ((a)|(size - 1))) : (a))
290
291 #define NEXT_SA(p) (struct sockaddr *) \
292 ((caddr_t)p + (p->sa_len ? ROUNDUP(p->sa_len, sizeof(u_int32_t)) : \
293 sizeof(u_long)))
294
295 static size_t
get_rti_info(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)296 get_rti_info(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
297 {
298 int i;
299 size_t len = 0;
300
301 for (i = 0; i < RTAX_MAX; i++) {
302 if (addrs & (1 << i)) {
303 rti_info[i] = sa;
304 if (sa->sa_len < sizeof(struct sockaddr)) {
305 len += sizeof(struct sockaddr);
306 } else {
307 len += sa->sa_len;
308 }
309 sa = NEXT_SA(sa);
310 } else {
311 rti_info[i] = NULL;
312 }
313 }
314 return len;
315 }
316
317 static void
print_address(const char * pre,const struct sockaddr * sa,const char * post,u_char asFamily)318 print_address(const char *pre, const struct sockaddr *sa, const char *post, u_char asFamily)
319 {
320 if (sa == NULL) {
321 T_LOG("%s(NULL)%s",
322 pre != NULL ? pre : "",
323 post != NULL ? post : "");
324 return;
325 }
326 if (sa->sa_len == 0) {
327 T_LOG("%ssa_len 0%s",
328 pre != NULL ? pre : "",
329 post != NULL ? post : "");
330 return;
331 }
332 if (sa->sa_len == 1) {
333 T_LOG("%ssa_len 1%s",
334 pre != NULL ? pre : "",
335 post != NULL ? post : "");
336 return;
337 }
338
339 // If not forced
340 if (asFamily == AF_UNSPEC) {
341 asFamily = sa->sa_family;
342 }
343 switch (asFamily) {
344 case AF_INET: {
345 print_sockaddr_in(pre, sa, post);
346 break;
347 }
348 case AF_INET6: {
349 print_sockaddr_in6(pre, sa, post);
350 break;
351 }
352 case AF_LINK: {
353 print_sockaddr_dl(pre, sa, post);
354 break;
355 }
356 default:
357 print_sockaddr(pre, sa, post);
358 break;
359 }
360 }
361
362 static void
print_rti_info(struct sockaddr * rti_info[])363 print_rti_info(struct sockaddr *rti_info[])
364 {
365 struct sockaddr *sa;
366 u_char asFamily = 0;
367
368 if ((sa = rti_info[RTAX_IFA])) {
369 asFamily = sa->sa_family;
370 print_address(" RTAX_IFA ", sa, "\n", 0);
371 }
372 if ((sa = rti_info[RTAX_DST])) {
373 asFamily = sa->sa_family;
374 print_address(" RTAX_DST ", sa, "\n", 0);
375 }
376 if ((sa = rti_info[RTAX_BRD])) {
377 print_address(" RTAX_BRD ", sa, "\n", asFamily);
378 }
379
380 if ((sa = rti_info[RTAX_NETMASK])) {
381 print_address(" RTAX_NETMASK ", sa, "\n", asFamily);
382 }
383
384 if ((sa = rti_info[RTAX_GATEWAY])) {
385 print_address(" RTAX_GATEWAY ", sa, "\n", 0);
386 }
387
388 if ((sa = rti_info[RTAX_GENMASK])) {
389 print_address(" RTAX_GENMASK ", sa, "\n", asFamily);
390 }
391
392 if ((sa = rti_info[RTAX_AUTHOR])) {
393 print_address(" RTAX_AUTHOR ", sa, "\n", asFamily);
394 }
395
396 if ((sa = rti_info[RTAX_IFP])) {
397 print_address(" RTAX_IFP ", sa, "\n", 0);
398 }
399 }
400
401 static void
print_rt_iflist2(const char * label)402 print_rt_iflist2(const char *label)
403 {
404 size_t len;
405 int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 };
406 unsigned char *buf = NULL;
407 unsigned char *lim, *next;
408 struct if_msghdr *ifmsg;
409
410 T_LOG("interface address list for %s", label);
411
412 T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, NULL, &len, NULL, 0), "sysctl NET_RT_IFLIST2");
413
414 T_QUIET; T_ASSERT_NOTNULL(buf = calloc(1, len), "rt_if_list_buf calloc(1, %zd)", len);
415
416 T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, buf, &len, NULL, 0), "sysctl NET_RT_IFLIST2");
417
418 lim = buf + len;
419 for (next = buf; next < lim; next += ifmsg->ifm_msglen) {
420 ifmsg = (struct if_msghdr *)(void *)next;
421 char ifname[IF_NAMESIZE + 1];
422
423 if (ifmsg->ifm_type == RTM_IFINFO2) {
424 struct if_msghdr2 *ifm = (struct if_msghdr2 *)ifmsg;
425 struct sockaddr *sa = (struct sockaddr *)(ifm + 1);
426
427 (void)if_indextoname(ifm->ifm_index, ifname);
428 T_LOG("interface: %s", ifname);
429 print_address(" PRIMARY ", sa, "", 0);
430 } else if (ifmsg->ifm_type == RTM_NEWADDR) {
431 struct sockaddr *rti_info[RTAX_MAX];
432 struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifmsg;
433
434 (void) get_rti_info(ifam->ifam_addrs, (struct sockaddr *)(ifam + 1), rti_info);
435
436 print_rti_info(rti_info);
437 }
438 }
439 free(buf);
440 }
441
442 static int
check_rt_if_list_for_pattern(const char * label,unsigned char pattern,size_t pattern_size)443 check_rt_if_list_for_pattern(const char *label, unsigned char pattern, size_t pattern_size)
444 {
445 size_t i;
446 size_t len;
447 int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
448 unsigned char *rt_if_list_buf = NULL;
449 int count = 0;
450 unsigned char *pattern_buf = NULL;
451
452 T_QUIET; T_ASSERT_NOTNULL(pattern_buf = calloc(1, pattern_size), "pattern_buf calloc(1, %zd)", pattern_size);
453 memset(pattern_buf, pattern, pattern_size);
454
455 T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, NULL, &len, NULL, 0), "sysctl NET_RT_IFLIST");
456
457 T_QUIET; T_ASSERT_NOTNULL(rt_if_list_buf = calloc(1, len), "rt_if_list_buf calloc(1, %zd)", len);
458
459 T_QUIET; T_EXPECT_POSIX_SUCCESS(sysctl(mib, 6, rt_if_list_buf, &len, NULL, 0), "sysctl NET_RT_IFLIST");
460
461 if (label != NULL) {
462 T_LOG("%s sysctl NET_RT_IFLIST buffer length %zd\n", label, len);
463 }
464
465 count = 0;
466 for (i = 0; i < len - pattern_size; i++) {
467 if (memcmp(rt_if_list_buf + i, pattern_buf, pattern_size) == 0) {
468 count++;
469 i += pattern_size - 1;
470 }
471 }
472
473 if (label != NULL) {
474 if (label != NULL && count > 0) {
475 T_LOG("%s found pattern at %zd count %d times\n", label, i, count);
476 HexDump(rt_if_list_buf, len);
477 }
478 }
479
480 free(rt_if_list_buf);
481 free(pattern_buf);
482
483 return count;
484 }
485
486 static bool
find_unused_pattern_in_rt_if_list(unsigned char * pattern,size_t pattern_size)487 find_unused_pattern_in_rt_if_list(unsigned char *pattern, size_t pattern_size)
488 {
489 bool found_pattern = false;
490 unsigned char i;
491 unsigned char *pattern_buf = NULL;
492
493 T_QUIET; T_ASSERT_NOTNULL(pattern_buf = calloc(1, pattern_size), "pattern_buf calloc(1, %zd)", pattern_size);
494
495 /* Try 10 times to find an unused pattern */
496 for (i = 1; i < 255; i++) {
497 if (check_rt_if_list_for_pattern(NULL, i, pattern_size) == 0) {
498 found_pattern = true;
499 *pattern = i;
500 memset(pattern_buf, i, pattern_size);
501 T_LOG("PATTERN: ");
502 HexDump(pattern_buf, pattern_size);
503 break;
504 }
505 }
506 free(pattern_buf);
507
508 return found_pattern;
509 }
510
511 static const char *
ioc_str(unsigned long cmd)512 ioc_str(unsigned long cmd)
513 {
514 #define X(a) case a: return #a;
515
516 switch (cmd) {
517 SIOC_LIST
518
519 default:
520 break;
521 }
522 return "";
523 }
524
525 struct ioc_ifreq {
526 unsigned long ioc_cmd;
527 uint8_t salen;
528 uint8_t safamily;
529 const char *sastr;
530 int error; // 0 means no error, -1, end of list, otherwise expected errno
531 };
532
533 static struct ioc_ifreq ioc_list[] = {
534 { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.1", EINVAL },
535 { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.1", EADDRNOTAVAIL },
536 { SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.1", EADDRNOTAVAIL },
537 { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.1", EADDRNOTAVAIL },
538
539 { SIOCSIFADDR, 0xf0, AF_INET6, "10.2.3.1", EINVAL },
540 { SIOCDIFADDR, 0xf0, AF_INET6, "10.2.3.1", EADDRNOTAVAIL },
541 { SIOCDIFADDR, 0xf0, AF_INET, "10.2.3.1", EADDRNOTAVAIL },
542 { SIOCDIFADDR, 0xf0, AF_INET, "10.2.3.1", EADDRNOTAVAIL },
543
544 { SIOCSIFADDR, 0, AF_INET6, "10.2.3.1", EINVAL },
545 { SIOCDIFADDR, 0, AF_INET6, "10.2.3.1", EADDRNOTAVAIL },
546 { SIOCDIFADDR, 0, AF_INET, "10.2.3.1", EADDRNOTAVAIL },
547 { SIOCDIFADDR, 0, AF_INET, "10.2.3.1", EADDRNOTAVAIL },
548
549 { SIOCSIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.2", 0 },
550 { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET6, "10.2.3.2", 0 },
551
552 { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.3", 0 },
553 { SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.3", 0 },
554
555 { SIOCSIFADDR, sizeof(struct sockaddr_in6), AF_INET6, "10.2.3.4", EINVAL },
556 { SIOCDIFADDR, sizeof(struct sockaddr_in6), AF_INET, "10.2.3.4", EADDRNOTAVAIL },
557
558 { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.5", 0 },
559 { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "0.0.0.0", EADDRNOTAVAIL },
560 { SIOCDIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.5", 0 },
561
562 { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "10.2.3.6", 0 },
563
564 { SIOCSIFNETMASK, sizeof(struct sockaddr_in), 0, "ff.00.00.00", 0 },
565 { SIOCSIFNETMASK, sizeof(struct sockaddr_in), AF_INET, "ff.00.00.00", 0 },
566 { SIOCSIFNETMASK, sizeof(struct sockaddr_in), AF_INET6, "ff.f.00.00", 0 },
567
568 { SIOCSIFNETMASK, sizeof(struct sockaddr_in6), 0, "ff.ff.00.00", 0 },
569 { SIOCSIFNETMASK, sizeof(struct sockaddr_in6), AF_INET, "ff.ff.00.00", 0 },
570 { SIOCSIFNETMASK, sizeof(struct sockaddr_in6), AF_INET6, "ff.ff.f0.00", 0 },
571
572 { SIOCSIFNETMASK, 0, 0, "ff.ff.00.00", 0 },
573 { SIOCSIFNETMASK, 0, AF_INET, "ff.ff.00.00", 0 },
574 { SIOCSIFNETMASK, 0, AF_INET6, "ff.ff.f0.00", 0 },
575
576 { SIOCSIFNETMASK, 0xf0, 0, "ff.ff.00.00", 0 },
577 { SIOCSIFNETMASK, 0xf0, AF_INET, "ff.ff.00.00", 0 },
578 { SIOCSIFNETMASK, 0xf0, AF_INET6, "ff.ff.f0.00", 0 },
579
580 { SIOCSIFBRDADDR, sizeof(struct sockaddr_in), 0, "10.255.255.255", 0 },
581 { SIOCSIFBRDADDR, sizeof(struct sockaddr_in), AF_INET, "10.255.255.255", 0 },
582 { SIOCSIFBRDADDR, sizeof(struct sockaddr_in), AF_INET6, "10.255.255.255", 0 },
583 { SIOCSIFBRDADDR, sizeof(struct sockaddr_in6), AF_INET, "10.255.255.255", 0 },
584
585 { SIOCSIFBRDADDR, 0xf0, 0, "10.255.255.255", 0 },
586 { SIOCSIFBRDADDR, 0xf0, AF_INET, "10.255.255.255", 0 },
587 { SIOCSIFBRDADDR, 0xf0, AF_INET6, "10.255.255.255", 0 },
588 { SIOCSIFBRDADDR, 0xf0, AF_INET, "10.255.255.255", 0 },
589
590 { SIOCSIFBRDADDR, 0, 0, "10.255.255.255", 0 },
591 { SIOCSIFBRDADDR, 0, AF_INET, "10.255.255.255", 0 },
592 { SIOCSIFBRDADDR, 0, AF_INET6, "10.255.255.255", 0 },
593 { SIOCSIFBRDADDR, 0, AF_INET, "10.255.255.255", 0 },
594
595 { 0, 0, 0, "", -1 },
596 };
597
598 static void
test_sioc_ifr_bounds(struct ioc_ifreq * ioc_ifreq,int s,const char * ifname)599 test_sioc_ifr_bounds(struct ioc_ifreq *ioc_ifreq, int s, const char *ifname)
600 {
601 struct ifreq ifr = {};
602 unsigned char pattern;
603 struct sockaddr_in *sin;
604
605 T_LOG("");
606 T_LOG("TEST CASE: %s ioctl(%s, sa_len %u, sa_family %u, %s) -> %d", __func__,
607 ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->salen, ioc_ifreq->safamily, ioc_ifreq->sastr, ioc_ifreq->error);
608
609
610 if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) {
611 T_SKIP("Could not find unused pattern");
612 }
613
614 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
615 memset(&ifr.ifr_addr.sa_data, pattern, sizeof(ifr.ifr_dstaddr.sa_data));
616
617 sin = (struct sockaddr_in *)(void *)&ifr.ifr_addr;
618 sin->sin_len = ioc_ifreq->salen;
619 sin->sin_family = ioc_ifreq->safamily;
620 sin->sin_addr.s_addr = inet_addr(ioc_ifreq->sastr);
621
622 int retval;
623 if (ioc_ifreq->error == 0) {
624 T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr),
625 "%s, %s: retval %d", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval);
626 } else {
627 T_EXPECT_POSIX_FAILURE(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr), ioc_ifreq->error,
628 "%s, %s: retval %d errno %s", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval, strerror(errno));
629 }
630
631 T_EXPECT_EQ(check_rt_if_list_for_pattern("test_sioc_ifr_bounds", pattern, PATTERN_SIZE), 0, "pattern should not be found");
632
633
634 fflush(stdout);
635 fflush(stderr);
636 }
637
638 T_DECL(sioc_ifr_bounds, "test bound checks on struct ifreq addresses passed to interface ioctls",
639 T_META_ASROOT(true))
640 {
641 int s = -1;
642 char ifname[IFNAMSIZ];
643
644 T_LOG("%s", __func__);
645
646 T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket");
647
648 strlcpy(ifname, IF_NAME, sizeof(ifname));
649
650 int error = 0;
651 if ((error = ifnet_create(s, ifname, sizeof(ifname))) != 0) {
652 if (error == EINVAL) {
653 T_SKIP("The system does not support the %s cloning interface", IF_NAME);
654 }
655 T_SKIP("This test failed creating a %s cloning interface", IF_NAME);
656 }
657 T_LOG("created clone interface '%s'", ifname);
658
659 struct ioc_ifreq *ioc_ifreq;
660 for (ioc_ifreq = ioc_list; ioc_ifreq->error != -1; ioc_ifreq++) {
661 test_sioc_ifr_bounds(ioc_ifreq, s, ifname);
662 }
663 print_rt_iflist2(__func__);
664 (void)ifnet_destroy(s, ifname, true);
665
666 close(s);
667 }
668
669 struct ioc_ifra {
670 const char *description;
671
672 uint8_t addr_len;
673 uint8_t addr_fam;
674 const char *addr_str;
675
676 uint8_t broad_len;
677 uint8_t broad_fam;
678 const char *broad_str;
679
680 uint8_t mask_len;
681 uint8_t mask_fam;
682 const char *mask_str;
683
684 int error; // 0 means no error, -1, end of list, otherwise expected errno
685 };
686
687 static struct ioc_ifra ioc_ifra_list[] = {
688 {
689 .description = "fully formed",
690 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.1.1.1",
691 .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "1.1.1.255",
692 .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.0.0",
693 .error = 0
694 },
695 {
696 .description = "addr_len 0",
697 .addr_len = 0, .addr_fam = AF_INET, .addr_str = "10.2.2.0",
698 .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255",
699 .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0",
700 .error = 0
701 },
702 {
703 .description = "addr_len 1",
704 .addr_len = 1, .addr_fam = AF_INET, .addr_str = "10.2.2.1",
705 .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255",
706 .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0",
707 .error = 0
708 },
709 {
710 .description = "addr_len 250",
711 .addr_len = 250, .addr_fam = AF_INET, .addr_str = "10.2.2.250",
712 .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.2.2.255",
713 .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.0.0.0",
714 .error = 0
715 },
716 {
717 .description = "addr_family AF_INET6",
718 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET6, .addr_str = "10.3.3.3",
719 .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.3.255.255",
720 .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.255.0",
721 .error = EINVAL
722 },
723 {
724 .description = "broadcast_len 0xf0",
725 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.4.4.4",
726 .broad_len = 0xf0, .broad_fam = AF_INET, .broad_str = "10.4.4.255",
727 .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.255.0",
728 .error = 0
729 },
730 {
731 .description = "broadcast_family AF_INET6",
732 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.5.5.5",
733 .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET6, .broad_str = "10.5.5.255",
734 .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET, .mask_str = "255.255.0.0",
735 .error = 0
736 },
737 {
738 .description = "mask_len 0xf0",
739 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.6.6.6",
740 .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "1.6.6.255",
741 .mask_len = 0xf0, .mask_fam = AF_INET, .mask_str = "255.255.0.0",
742 .error = 0
743 },
744 {
745 .description = "mask_family AF_INET6",
746 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.7.7.7",
747 .broad_len = sizeof(struct sockaddr_in), .broad_fam = AF_INET, .broad_str = "10.7.7.255",
748 .mask_len = sizeof(struct sockaddr_in), .mask_fam = AF_INET6, .mask_str = "255.255.0.0",
749 .error = 0
750 },
751 {
752 .description = "ifra address only",
753 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.8.8.8",
754 .broad_len = 0, .broad_str = NULL,
755 .mask_len = 0, .mask_str = NULL,
756 .error = 0
757 },
758 {
759 .description = "ifra mask len 1",
760 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.1",
761 .broad_len = 0, .broad_str = NULL,
762 .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
763 .error = 0
764 },
765 {
766 .description = "ifra mask len 3",
767 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.3",
768 .broad_len = 0, .broad_str = NULL,
769 .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
770 .error = 0
771 },
772 {
773 .description = "ifra mask len 5",
774 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.5",
775 .broad_len = 0, .broad_str = NULL,
776 .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
777 .error = 0
778 },
779 {
780 .description = "ifra mask len 7",
781 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.7",
782 .broad_len = 0, .broad_str = NULL,
783 .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
784 .error = 0
785 },
786 {
787 .description = "ifra mask len 9",
788 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.9",
789 .broad_len = 0, .broad_str = NULL,
790 .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
791 .error = 0
792 },
793 {
794 .description = "ifra mask len 11",
795 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.11",
796 .broad_len = 0, .broad_str = NULL,
797 .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
798 .error = 0
799 },
800 {
801 .description = "ifra mask len 13",
802 .addr_len = sizeof(struct sockaddr_in), .addr_fam = AF_INET, .addr_str = "10.9.9.13",
803 .broad_len = 0, .broad_str = NULL,
804 .mask_len = 1, .mask_fam = AF_INET, .mask_str = "255.255.255.0",
805 .error = 0
806 },
807 {
808 .description = NULL,
809 .error = -1
810 }
811 };
812
813 T_DECL(sioc_ifra_addr_bounds, "test bound checks on socket address passed to interface ioctls",
814 T_META_ASROOT(true))
815 {
816 int s = -1;
817
818 T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket");
819
820 char ifname[IFNAMSIZ];
821 strlcpy(ifname, IF_NAME, sizeof(ifname));
822 int error = 0;
823 if ((error = ifnet_create(s, ifname, sizeof(ifname))) != 0) {
824 if (error == EINVAL) {
825 T_SKIP("The system does not support the %s cloning interface", IF_NAME);
826 }
827 T_SKIP("This test failed creating a %s cloning interface", IF_NAME);
828 }
829 T_LOG("created clone interface '%s'", ifname);
830
831 struct ioc_ifra *ioc_ifra;
832
833 for (ioc_ifra = ioc_ifra_list; ioc_ifra->error != -1; ioc_ifra++) {
834 struct in_aliasreq ifra = {};
835 unsigned char pattern;
836 int retval;
837
838 T_LOG("");
839 T_LOG("TEST CASE: %s, ioctl(SIOCAIFADDR, %s)", ioc_ifra->description, ioc_ifra->addr_str != NULL ? ioc_ifra->addr_str : "");
840
841 if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) {
842 T_SKIP("Could not find unused pattern in rt_if_list");
843 return;
844 }
845
846 memset(&ifra, pattern, sizeof(ifra));
847
848 strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
849
850 ifra.ifra_addr.sin_len = ioc_ifra->addr_len;
851 ifra.ifra_addr.sin_family = ioc_ifra->addr_fam;
852 if (ioc_ifra->addr_str != NULL) {
853 ifra.ifra_addr.sin_addr.s_addr = inet_addr(ioc_ifra->addr_str);
854 }
855
856 ifra.ifra_broadaddr.sin_len = ioc_ifra->broad_len;
857 ifra.ifra_broadaddr.sin_family = ioc_ifra->broad_fam;
858 if (ioc_ifra->broad_str != NULL) {
859 ifra.ifra_broadaddr.sin_addr.s_addr = inet_addr(ioc_ifra->broad_str);
860 }
861
862 ifra.ifra_mask.sin_len = ioc_ifra->mask_len;
863 ifra.ifra_mask.sin_family = ioc_ifra->mask_fam;
864 if (ioc_ifra->mask_str != NULL) {
865 ifra.ifra_mask.sin_addr.s_addr = inet_addr(ioc_ifra->mask_str);
866 }
867
868 if (ioc_ifra->error == 0) {
869 T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, SIOCAIFADDR, &ifra), "SIOCAIFADDR retval %d", retval);
870 } else {
871 T_EXPECT_POSIX_FAILURE(retval = ioctl(s, SIOCAIFADDR, &ifra), EINVAL, "SIOCAIFADDR retval %d, %s", retval, strerror(errno));
872 }
873
874 T_EXPECT_EQ(check_rt_if_list_for_pattern("after ioctl SIOCAIFADDR", pattern, PATTERN_SIZE), 0, "pattern should not be found");
875 }
876
877 print_rt_iflist2(__func__);
878
879 (void)ifnet_destroy(s, ifname, true);
880
881 close(s);
882 }
883
884 T_DECL(sioc_ifr_dstaddr_leak, "test bound checks on socket address passed to interface ioctls",
885 T_META_ASROOT(true))
886 {
887 int s = -1;
888 struct ifreq ifr = {};
889 unsigned char pattern;
890 struct ifaddrs *ifap = NULL, *ifa;
891 bool found_gif0 = false;
892
893 T_QUIET; T_EXPECT_POSIX_SUCCESS(getifaddrs(&ifap), "getifaddrs");
894 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
895 if (strcmp(ifa->ifa_name, "gif0") == 0) {
896 found_gif0 = true;
897 break;
898 }
899 }
900 freeifaddrs(ifap);
901 ifap = NULL;
902 if (found_gif0 == false) {
903 T_SKIP("gif0 does not exists");
904 }
905
906 if (find_unused_pattern_in_rt_if_list(&pattern, PATTERN_SIZE) == false) {
907 T_SKIP("Could not find unused pattern");
908 return;
909 }
910
911 T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket");
912
913 strlcpy(ifr.ifr_name, "gif0", sizeof(ifr.ifr_name));
914 ifr.ifr_dstaddr.sa_family = AF_INET6;
915 ifr.ifr_dstaddr.sa_len = 0xf0;
916 memset(&ifr.ifr_dstaddr.sa_data, pattern, PATTERN_SIZE);
917
918 T_EXPECT_POSIX_SUCCESS(ioctl(s, SIOCSIFDSTADDR, &ifr), "ioctl(SIOCSIFDSTADDR)");
919
920 print_rt_iflist2(__func__);
921
922 close(s);
923
924 T_EXPECT_EQ(check_rt_if_list_for_pattern("AFTER", pattern, PATTERN_SIZE), 0, "pattern should not be found");
925 }
926
927 static struct ioc_ifreq ioc_list_config[] = {
928 { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "0.0.0.0", EINVAL },
929 { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "255.255.255.255", EINVAL },
930 { SIOCSIFADDR, sizeof(struct sockaddr_in), AF_INET, "238.207.49.91", EINVAL },
931
932 { SIOCAIFADDR_IN6, sizeof(struct sockaddr_in6), AF_INET6, "::", EINVAL },
933 { SIOCAIFADDR_IN6, sizeof(struct sockaddr_in6), AF_INET6, "ff33:40:fd25:549c:675b::1", EINVAL },
934 { SIOCAIFADDR_IN6, sizeof(struct sockaddr_in6), AF_INET6, "::ffff:0a0a:0a0a", EINVAL },
935 { SIOCAIFADDR_IN6, sizeof(struct sockaddr_in6), AF_INET6, "::0a0a:0a0a", EINVAL },
936
937 { 0, 0, 0, "", -1 },
938 };
939
940 static void
test_sioc_ifr_addr_config_v4(struct ioc_ifreq * ioc_ifreq,int s,const char * ifname)941 test_sioc_ifr_addr_config_v4(struct ioc_ifreq *ioc_ifreq, int s, const char *ifname)
942 {
943 struct ifreq ifr = {};
944 struct sockaddr_in *sin;
945
946 T_LOG("");
947 T_LOG("TEST CASE: %s ioctl(%s, sa_len %u, sa_family %u, %s) -> %d", __func__,
948 ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->salen, ioc_ifreq->safamily, ioc_ifreq->sastr, ioc_ifreq->error);
949
950
951 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
952
953 sin = (struct sockaddr_in *)(void *)&ifr.ifr_addr;
954 sin->sin_len = ioc_ifreq->salen;
955 sin->sin_family = ioc_ifreq->safamily;
956 sin->sin_addr.s_addr = inet_addr(ioc_ifreq->sastr);
957
958 int retval;
959 if (ioc_ifreq->error == 0) {
960 T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr),
961 "%s, %s: retval %d", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval);
962 } else {
963 T_EXPECT_POSIX_FAILURE(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifr), ioc_ifreq->error,
964 "%s, %s: retval %d errno %s", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval, strerror(errno));
965 }
966
967 fflush(stdout);
968 fflush(stderr);
969 }
970
971 static void
test_sioc_ifr_addr_config_v6(struct ioc_ifreq * ioc_ifreq,int s,const char * ifname)972 test_sioc_ifr_addr_config_v6(struct ioc_ifreq *ioc_ifreq, int s, const char *ifname)
973 {
974 struct in6_aliasreq ifra = {{ 0 }, { 0 }, { 0 }, { 0 }, 0, { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME }};
975 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(void *)&ifra.ifra_addr;
976 struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)(void *)&ifra.ifra_prefixmask;
977 T_LOG("");
978 T_LOG("TEST CASE: %s ioctl(%s, sa_len %u, sa_family %u, %s) -> %d", __func__,
979 ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->salen, ioc_ifreq->safamily, ioc_ifreq->sastr, ioc_ifreq->error);
980
981 strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
982
983 sin6->sin6_len = ioc_ifreq->salen;
984 sin6->sin6_family = ioc_ifreq->safamily;
985 T_ASSERT_EQ(inet_pton(AF_INET6, ioc_ifreq->sastr, &sin6->sin6_addr), 1, NULL);
986 sin6->sin6_scope_id = if_nametoindex(ifname);
987
988 mask6->sin6_len = ioc_ifreq->salen;
989 mask6->sin6_family = ioc_ifreq->safamily;
990 T_ASSERT_EQ(inet_pton(AF_INET6, "ffff:ffff:ffff:ffff::", &mask6->sin6_addr), 1, NULL);
991
992 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
993 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
994
995 int retval;
996 if (ioc_ifreq->error == 0) {
997 T_EXPECT_POSIX_SUCCESS(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifra),
998 "%s, %s: retval %d", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval);
999 } else {
1000 T_EXPECT_POSIX_FAILURE(retval = ioctl(s, ioc_ifreq->ioc_cmd, &ifra), ioc_ifreq->error,
1001 "%s, %s: retval %d errno %s", ioc_str(ioc_ifreq->ioc_cmd), ioc_ifreq->sastr, retval, strerror(errno));
1002 }
1003
1004 fflush(stdout);
1005 fflush(stderr);
1006 }
1007
1008
1009 T_DECL(sioc_ifr_addr_config, "test failure cases for interface address configuration ioctls",
1010 T_META_ASROOT(true))
1011 {
1012 int s = -1;
1013 int s6 = -1;
1014 char ifname[IFNAMSIZ];
1015
1016 T_LOG("%s", __func__);
1017
1018 T_QUIET; T_EXPECT_POSIX_SUCCESS(s = socket(AF_INET, SOCK_DGRAM, 0), "socket");
1019 T_QUIET; T_EXPECT_POSIX_SUCCESS(s6 = socket(AF_INET6, SOCK_DGRAM, 0), "socket");
1020
1021 strlcpy(ifname, IF_NAME, sizeof(ifname));
1022
1023 int error = 0;
1024 if ((error = ifnet_create(s, ifname, sizeof(ifname))) != 0) {
1025 if (error == EINVAL) {
1026 T_SKIP("The system does not support the %s cloning interface", IF_NAME);
1027 }
1028 T_SKIP("This test failed creating a %s cloning interface", IF_NAME);
1029 }
1030 T_LOG("created clone interface '%s'", ifname);
1031
1032 struct ioc_ifreq *ioc_ifreq;
1033 for (ioc_ifreq = ioc_list_config; ioc_ifreq->error != -1; ioc_ifreq++) {
1034 if (ioc_ifreq->safamily == AF_INET) {
1035 test_sioc_ifr_addr_config_v4(ioc_ifreq, s, ifname);
1036 } else if (ioc_ifreq->safamily == AF_INET6) {
1037 test_sioc_ifr_addr_config_v6(ioc_ifreq, s6, ifname);
1038 }
1039 }
1040 print_rt_iflist2(__func__);
1041 (void)ifnet_destroy(s, ifname, true);
1042
1043 close(s);
1044 close(s6);
1045 }
1046
1047 /**
1048 ** Test SIOCPROTOATTACH, SIOCPROTOATTACH_IN6
1049 **/
1050 static int S_socket = -1;
1051
1052 static int
get_inet_dgram_socket(void)1053 get_inet_dgram_socket(void)
1054 {
1055 if (S_socket >= 0) {
1056 return S_socket;
1057 }
1058 S_socket = socket(AF_INET, SOCK_DGRAM, 0);
1059 T_QUIET;
1060 T_ASSERT_POSIX_SUCCESS(S_socket, "socket(AF_INET, SOCK_DGRAM, 0)");
1061 return S_socket;
1062 }
1063
1064 static void
close_inet_dgram_socket(void)1065 close_inet_dgram_socket(void)
1066 {
1067 if (S_socket >= 0) {
1068 close(S_socket);
1069 S_socket = -1;
1070 }
1071 }
1072
1073 static int S_socket_6 = -1;
1074
1075 static int
get_inet6_dgram_socket(void)1076 get_inet6_dgram_socket(void)
1077 {
1078 if (S_socket_6 >= 0) {
1079 return S_socket_6;
1080 }
1081 S_socket_6 = socket(AF_INET6, SOCK_DGRAM, 0);
1082 T_QUIET;
1083 T_ASSERT_POSIX_SUCCESS(S_socket_6, "socket(AF_INET6, SOCK_DGRAM, 0)");
1084 return S_socket_6;
1085 }
1086
1087 static void
close_inet6_dgram_socket(void)1088 close_inet6_dgram_socket(void)
1089 {
1090 if (S_socket_6 >= 0) {
1091 close(S_socket_6);
1092 S_socket_6 = -1;
1093 }
1094 }
1095
1096 static char ifname[IFNAMSIZ];
1097
1098 static void
test_proto_attach_cleanup(void)1099 test_proto_attach_cleanup(void)
1100 {
1101 if (ifname[0] != '\0') {
1102 int s;
1103
1104 s = get_inet_dgram_socket();
1105 (void)ifnet_destroy(s, ifname, false);
1106 T_LOG("Destroyed '%s'", ifname);
1107 ifname[0] = '\0';
1108 }
1109 }
1110
1111 static void
test_proto_attach_atend(void)1112 test_proto_attach_atend(void)
1113 {
1114 test_proto_attach_cleanup();
1115 close_inet_dgram_socket();
1116 close_inet6_dgram_socket();
1117 }
1118
1119 static void
test_proto_attach(void)1120 test_proto_attach(void)
1121 {
1122 int error;
1123 struct ifreq ifr;
1124 int s;
1125 int s6;
1126
1127 T_ATEND(test_proto_attach_atend);
1128 s = get_inet_dgram_socket();
1129 strlcpy(ifname, "feth", sizeof(ifname));
1130 error = ifnet_create(s, ifname, sizeof(ifname));
1131 if (error != 0) {
1132 if (error == EINVAL) {
1133 T_SKIP("%s cloning interface not supported", ifname);
1134 }
1135 T_SKIP("%s cloning interface failed", ifname);
1136 }
1137 T_LOG("Created '%s'", ifname);
1138
1139 /* first proto attach should succeed */
1140 bzero(&ifr, sizeof(ifr));
1141 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1142 error = ioctl(s, SIOCPROTOATTACH, &ifr);
1143 T_ASSERT_POSIX_SUCCESS(error, "SIOCPROTOATTACH %s succeeded",
1144 ifr.ifr_name);
1145
1146 /* second proto attach should fail with EEXIST */
1147 error = ioctl(s, SIOCPROTOATTACH, &ifr);
1148 T_ASSERT_POSIX_FAILURE(error, EEXIST,
1149 "SIOCPROTOATTACH %s failed as expected",
1150 ifr.ifr_name);
1151
1152 /* first proto attach should succeed */
1153 s6 = get_inet6_dgram_socket();
1154 bzero(&ifr, sizeof(ifr));
1155 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1156 error = ioctl(s6, SIOCPROTOATTACH_IN6, &ifr);
1157 T_ASSERT_POSIX_SUCCESS(error,
1158 "SIOCPROTOATTACH_IN6 %s succeeded",
1159 ifr.ifr_name);
1160
1161 /* second proto attach should fail with EEXIST */
1162 error = ioctl(s6, SIOCPROTOATTACH_IN6, &ifr);
1163 T_ASSERT_POSIX_FAILURE(error, EEXIST,
1164 "SIOCPROTOATTACH_IN6 %s failed as expected",
1165 ifr.ifr_name);
1166 test_proto_attach_cleanup();
1167 }
1168
1169 T_DECL(sioc_proto_attach, "test protocol attachment",
1170 T_META_ASROOT(true))
1171 {
1172 test_proto_attach();
1173 }
1174