1/* 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * ifutil.c 26 * - network interface utility routines 27 */ 28 29/* 30 * Modification History 31 * 32 * June 23, 2009 Dieter Siegmund (dieter@apple.com) 33 * - split out from ipconfigd.c 34 */ 35 36 37#include <stdlib.h> 38#include <unistd.h> 39#include <syslog.h> 40#include <string.h> 41#include <sys/socket.h> 42#include <net/if.h> 43#include <netinet/in.h> 44#include <netinet/in_var.h> 45#include <netinet/icmp6.h> 46#include <net/if_media.h> 47#include <net/if_dl.h> 48#include <sys/types.h> 49#include <arpa/inet.h> 50#include <sys/param.h> 51#include <sys/sysctl.h> 52#include <sys/errno.h> 53#include <sys/ioctl.h> 54#include "ifutil.h" 55#include "rtutil.h" 56#include "symbol_scope.h" 57#include "mylog.h" 58#include "CGA.h" 59 60PRIVATE_EXTERN int 61inet_dgram_socket() 62{ 63 return (socket(AF_INET, SOCK_DGRAM, 0)); 64} 65 66STATIC int 67siocsifflags(int s, const char * name, short flags) 68{ 69 struct ifreq ifr; 70 int ret; 71 72 bzero(&ifr, sizeof(ifr)); 73 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 74 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr); 75 if (ret < 0) { 76 return (ret); 77 } 78 ifr.ifr_flags |= flags; 79 return (ioctl(s, SIOCSIFFLAGS, &ifr)); 80} 81 82STATIC int 83siocsifmtu(int s, const char * name, int mtu) 84{ 85 struct ifreq ifr; 86 87 bzero(&ifr, sizeof(ifr)); 88 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 89 ifr.ifr_mtu = mtu; 90 return (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr)); 91} 92 93STATIC int 94siocprotoattach(int s, const char * name) 95{ 96 struct ifreq ifr; 97 98 bzero(&ifr, sizeof(ifr)); 99 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 100 return (ioctl(s, SIOCPROTOATTACH, &ifr)); 101} 102 103PRIVATE_EXTERN int 104interface_set_mtu(const char * ifname, int mtu) 105{ 106 int ret = 0; 107 int s = inet_dgram_socket(); 108 109 if (s < 0) { 110 ret = errno; 111 } 112 else { 113 if (siocsifmtu(s, ifname, mtu) < 0) { 114 ret = errno; 115 my_log(LOG_NOTICE, "siocsifmtu(%s, %d) failed, %s (%d)", 116 ifname, mtu, strerror(ret), ret); 117 } 118 close(s); 119 } 120 return (ret); 121 122} 123 124PRIVATE_EXTERN int 125inet_attach_interface(const char * ifname) 126{ 127 int ret = 0; 128 int s = inet_dgram_socket(); 129 130 if (s < 0) { 131 ret = errno; 132 goto done; 133 } 134 135 if (siocprotoattach(s, ifname) < 0) { 136 ret = errno; 137 if (ret != EEXIST && ret != ENXIO) { 138 my_log(LOG_DEBUG, "siocprotoattach(%s) failed, %s (%d)", 139 ifname, strerror(errno), errno); 140 } 141 } 142 (void)siocsifflags(s, ifname, IFF_UP); 143 close(s); 144 145 done: 146 return (ret); 147} 148 149STATIC int 150siocprotodetach(int s, const char * name) 151{ 152 struct ifreq ifr; 153 154 bzero(&ifr, sizeof(ifr)); 155 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 156 return (ioctl(s, SIOCPROTODETACH, &ifr)); 157} 158 159PRIVATE_EXTERN int 160inet_detach_interface(const char * ifname) 161{ 162 int ret = 0; 163 int s = inet_dgram_socket(); 164 165 if (s < 0) { 166 ret = errno; 167 goto done; 168 } 169 if (siocprotodetach(s, ifname) < 0) { 170 ret = errno; 171 if (ret != ENXIO) { 172 my_log(LOG_ERR, "siocprotodetach(%s) failed, %s (%d)", 173 ifname, strerror(errno), errno); 174 } 175 } 176 close(s); 177 178 done: 179 return (ret); 180} 181 182STATIC int 183siocautoaddr(int s, const char * name, int value) 184{ 185 struct ifreq ifr; 186 187 bzero(&ifr, sizeof(ifr)); 188 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 189 ifr.ifr_data = (caddr_t)(intptr_t)value; 190 return (ioctl(s, SIOCAUTOADDR, &ifr)); 191} 192 193PRIVATE_EXTERN int 194inet_set_autoaddr(const char * ifname, int val) 195{ 196 int s = inet_dgram_socket(); 197 int ret = 0; 198 199 if (s < 0) { 200 ret = errno; 201 my_log(LOG_ERR, 202 "inet_set_autoaddr(%s, %d): socket() failed, %s (%d)", 203 ifname, val, strerror(errno), errno); 204 } 205 else { 206 if (siocautoaddr(s, ifname, val) < 0) { 207 ret = errno; 208 if (ret != ENXIO) { 209 my_log(LOG_ERR, "inet_set_autoaddr(%s, %d) failed, %s (%d)", 210 ifname, val, strerror(errno), errno); 211 } 212 } 213 close(s); 214 } 215 return (ret); 216} 217 218STATIC void 219set_sockaddr_in(struct sockaddr_in * sin_p, struct in_addr addr) 220{ 221 sin_p->sin_len = sizeof(struct sockaddr_in); 222 sin_p->sin_family = AF_INET; 223 sin_p->sin_addr = addr; 224 return; 225} 226 227PRIVATE_EXTERN int 228inet_difaddr(int s, const char * name, const struct in_addr addr) 229{ 230 struct ifreq ifr; 231 232 bzero(&ifr, sizeof(ifr)); 233 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 234 /* ALIGN: ifr.ifr_addr is aligned (in union), cast okay. */ 235 set_sockaddr_in((struct sockaddr_in *)(void *)&ifr.ifr_addr, addr); 236 return (ioctl(s, SIOCDIFADDR, &ifr)); 237} 238 239PRIVATE_EXTERN int 240inet_aifaddr(int s, const char * name, struct in_addr addr, 241 const struct in_addr * mask, 242 const struct in_addr * broadaddr) 243{ 244 struct in_aliasreq ifra; 245 246 bzero(&ifra, sizeof(ifra)); 247 strncpy(ifra.ifra_name, name, sizeof(ifra.ifra_name)); 248 set_sockaddr_in(&ifra.ifra_addr, addr); 249 if (mask != NULL) { 250 set_sockaddr_in(&ifra.ifra_mask, *mask); 251 } 252 if (broadaddr != NULL) { 253 set_sockaddr_in(&ifra.ifra_broadaddr, *broadaddr); 254 } 255 return (ioctl(s, SIOCAIFADDR, &ifra)); 256} 257 258#include <netinet6/in6_var.h> 259#include <netinet6/nd6.h> 260 261STATIC int 262count_prefix_bits(void * val, int size) 263{ 264 int bit; 265 int byte; 266 uint8_t * name = (uint8_t *)val; 267 int plen = 0; 268 269 /* look for prefix bytes that have all bits set */ 270 for (byte = 0; byte < size; byte++, plen += 8) { 271 if (name[byte] != 0xff) { 272 break; 273 } 274 } 275 276 /* all of the bits were set */ 277 if (byte == size) { 278 return (plen); 279 } 280 281 /* we have the prefix length when we seee the first bit that isn't set */ 282 for (bit = 7; bit != 0; bit--, plen++) { 283 if (!(name[byte] & (1 << bit))) { 284 break; 285 } 286 } 287 288 /* valididate that no bits are set after the last bit */ 289 for (; bit != 0; bit--) { 290 if (name[byte] & (1 << bit)) { 291 /* not a simple prefix */ 292 return (0); 293 } 294 } 295 byte++; 296 for (; byte < size; byte++) { 297 if (name[byte]) { 298 /* not a simple prefix */ 299 return (0); 300 } 301 } 302 return (plen); 303} 304 305PRIVATE_EXTERN int 306inet6_dgram_socket() 307{ 308 return (socket(AF_INET6, SOCK_DGRAM, 0)); 309} 310 311STATIC int 312siocprotoattach_in6(int s, const char * name) 313{ 314 struct in6_aliasreq ifra; 315 316 bzero(&ifra, sizeof(ifra)); 317 strncpy(ifra.ifra_name, name, sizeof(ifra.ifra_name)); 318 return (ioctl(s, SIOCPROTOATTACH_IN6, &ifra)); 319} 320 321STATIC int 322siocprotodetach_in6(int s, const char * name) 323{ 324 struct in6_ifreq ifr; 325 326 bzero(&ifr, sizeof(ifr)); 327 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 328 return (ioctl(s, SIOCPROTODETACH_IN6, &ifr)); 329} 330 331STATIC int 332siocll_start(int s, const char * name) 333{ 334 struct in6_aliasreq ifra_in6; 335 336 bzero(&ifra_in6, sizeof(ifra_in6)); 337 strncpy(ifra_in6.ifra_name, name, sizeof(ifra_in6.ifra_name)); 338 return (ioctl(s, SIOCLL_START, &ifra_in6)); 339} 340 341STATIC int 342ll_start(int s, const char * name, boolean_t use_cga) 343{ 344 struct in6_llstartreq req; 345 346 if (use_cga == FALSE || !CGAIsEnabled()) { 347 return (siocll_start(s, name)); 348 } 349 bzero(&req, sizeof(req)); 350 strncpy(req.llsr_name, name, sizeof(req.llsr_name)); 351 CGAPrepareSetForInterface(name, &req.llsr_cgaprep); 352 req.llsr_lifetime.ia6t_vltime = -1; 353 req.llsr_lifetime.ia6t_pltime = -1; 354 return (ioctl(s, SIOCLL_CGASTART, &req)); 355} 356 357STATIC int 358siocll_stop(int s, const char * name) 359{ 360 struct in6_ifreq ifr; 361 362 bzero(&ifr, sizeof(ifr)); 363 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 364 return (ioctl(s, SIOCLL_STOP, &ifr)); 365} 366 367STATIC void 368set_sockaddr_in6(struct sockaddr_in6 * sin6_p, const struct in6_addr * addr) 369{ 370 sin6_p->sin6_family = AF_INET6; 371 sin6_p->sin6_len = sizeof(struct sockaddr_in6); 372 sin6_p->sin6_addr = *addr; 373 return; 374} 375 376STATIC int 377siocgifaflag_in6(int s, const char * ifname, const struct in6_addr * in6_addr, 378 uint16_t * ret_flags) 379{ 380 struct in6_ifreq ifr6; 381 382 bzero((char *)&ifr6, sizeof(ifr6)); 383 strncpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 384 set_sockaddr_in6(&ifr6.ifr_addr, in6_addr); 385 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 386 return (-1); 387 } 388 *ret_flags = ifr6.ifr_ifru.ifru_flags6; 389 return (0); 390} 391 392PRIVATE_EXTERN int 393inet6_attach_interface(const char * ifname) 394{ 395 int ret = 0; 396 int s = inet6_dgram_socket(); 397 398 if (s < 0) { 399 ret = errno; 400 my_log(LOG_ERR, 401 "inet6_attach_interface(%s): socket() failed, %s (%d)", 402 ifname, strerror(ret), ret); 403 goto done; 404 } 405 if (siocprotoattach_in6(s, ifname) < 0) { 406 ret = errno; 407 if (ret != EEXIST && ret != ENXIO) { 408 my_log(LOG_DEBUG, "siocprotoattach_in6(%s) failed, %s (%d)", 409 ifname, strerror(errno), errno); 410 } 411 } 412 (void)siocsifflags(s, ifname, IFF_UP); 413 close(s); 414 415 done: 416 return (ret); 417} 418 419PRIVATE_EXTERN int 420inet6_detach_interface(const char * ifname) 421{ 422 int ret = 0; 423 int s = inet6_dgram_socket(); 424 425 if (s < 0) { 426 ret = errno; 427 my_log(LOG_ERR, 428 "inet6_detach_interface(%s): socket() failed, %s (%d)", 429 ifname, strerror(ret), ret); 430 goto done; 431 } 432 if (siocprotodetach_in6(s, ifname) < 0) { 433 ret = errno; 434 if (ret != ENXIO) { 435 my_log(LOG_DEBUG, "siocprotodetach_in6(%s) failed, %s (%d)", 436 ifname, strerror(errno), errno); 437 } 438 } 439 close(s); 440 441 done: 442 return (ret); 443} 444 445PRIVATE_EXTERN int 446inet6_linklocal_start(const char * ifname, boolean_t use_cga) 447{ 448 int ret = 0; 449 int s = inet6_dgram_socket(); 450 451 if (s < 0) { 452 ret = errno; 453 my_log(LOG_ERR, 454 "inet6_linklocal_start(%s): socket() failed, %s (%d)", 455 ifname, strerror(ret), ret); 456 goto done; 457 } 458 if (ll_start(s, ifname, use_cga) < 0) { 459 ret = errno; 460 if (errno != ENXIO) { 461 my_log(LOG_ERR, "siocll_start(%s) failed, %s (%d)", 462 ifname, strerror(errno), errno); 463 } 464 } 465 close(s); 466 done: 467 return (ret); 468} 469 470PRIVATE_EXTERN int 471inet6_linklocal_stop(const char * ifname) 472{ 473 int ret = 0; 474 int s = inet6_dgram_socket(); 475 476 if (s < 0) { 477 ret = errno; 478 my_log(LOG_ERR, 479 "inet6_linklocal_stop(%s): socket() failed, %s (%d)", 480 ifname, strerror(ret), ret); 481 goto done; 482 } 483 if (siocll_stop(s, ifname) < 0) { 484 ret = errno; 485 if (errno != ENXIO) { 486 my_log(LOG_ERR, "siocll_stop(%s) failed, %s (%d)", 487 ifname, strerror(errno), errno); 488 } 489 } 490 close(s); 491 492 done: 493 return (ret); 494} 495 496STATIC int 497siocautoconf_start(int s, const char * if_name) 498{ 499 struct in6_ifreq ifr; 500 501 bzero(&ifr, sizeof(ifr)); 502 strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 503 return (ioctl(s, SIOCAUTOCONF_START, &ifr)); 504} 505 506STATIC int 507siocautoconf_stop(int s, const char * if_name) 508{ 509 struct in6_ifreq ifr; 510 511 bzero(&ifr, sizeof(ifr)); 512 strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 513 return (ioctl(s, SIOCAUTOCONF_STOP, &ifr)); 514} 515 516PRIVATE_EXTERN int 517inet6_rtadv_enable(const char * if_name) 518{ 519 int ret = 0; 520 int s = inet6_dgram_socket(); 521 522 if (s < 0) { 523 ret = errno; 524 my_log(LOG_ERR, 525 "inet6_rtadv_enable(%s): socket() failed, %s (%d)", 526 if_name, strerror(ret), ret); 527 goto done; 528 } 529 if (siocautoconf_start(s, if_name) < 0) { 530 ret = errno; 531 if (errno != ENXIO) { 532 my_log(LOG_ERR, "siocautoconf_start(%s) failed, %s (%d)", 533 if_name, strerror(errno), errno); 534 } 535 } 536 close(s); 537 done: 538 return (ret); 539} 540 541PRIVATE_EXTERN int 542inet6_rtadv_disable(const char * if_name) 543{ 544 int ret = 0; 545 int s = inet6_dgram_socket(); 546 547 if (s < 0) { 548 ret = errno; 549 my_log(LOG_ERR, 550 "inet6_rtadv_disable(%s): socket() failed, %s (%d)", 551 if_name, strerror(ret), ret); 552 goto done; 553 } 554 if (siocautoconf_stop(s, if_name) < 0) { 555 ret = errno; 556 if (errno != ENXIO) { 557 my_log(LOG_ERR, "siocautoconf_stop(%s) failed, %s (%d)", 558 if_name, strerror(errno), errno); 559 } 560 } 561 close(s); 562 done: 563 return (ret); 564} 565 566PRIVATE_EXTERN int 567inet6_difaddr(int s, const char * name, const struct in6_addr * addr) 568{ 569 struct in6_ifreq ifr; 570 571 bzero(&ifr, sizeof(ifr)); 572 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 573 if (addr != NULL) { 574 set_sockaddr_in6(&ifr.ifr_ifru.ifru_addr, addr); 575 } 576 return (ioctl(s, SIOCDIFADDR_IN6, &ifr)); 577} 578 579/* 580 * from netinet6/in6.c 581 */ 582STATIC void 583in6_len2mask(struct in6_addr * mask, int len) 584{ 585 int i; 586 587 bzero(mask, sizeof(*mask)); 588 for (i = 0; i < len / 8; i++) 589 mask->s6_addr[i] = 0xff; 590 if (len % 8) 591 mask->s6_addr[i] = (0xff00 >> (len % 8)) & 0xff; 592} 593 594STATIC void 595in6_maskaddr(struct in6_addr * addr, const struct in6_addr * mask) 596{ 597 int i; 598 599 for (i = 0; i < sizeof(addr->s6_addr); i++) { 600 addr->s6_addr[i] &= mask->s6_addr[i]; 601 } 602 return; 603} 604 605PRIVATE_EXTERN void 606in6_netaddr(struct in6_addr * addr, int len) 607{ 608 struct in6_addr mask; 609 610 in6_len2mask(&mask, len); 611 in6_maskaddr(addr, &mask); 612 return; 613} 614 615PRIVATE_EXTERN int 616inet6_get_prefix_length(const struct in6_addr * addr, int if_index) 617{ 618 char * buf = NULL; 619 size_t buf_len; 620 struct in6_prefix * end; 621 int mib[] = { 622 CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST 623 }; 624 struct in6_prefix * next; 625 int prefix_length = 0; 626 struct in6_prefix * scan; 627 628 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &buf_len, NULL, 0) 629 < 0) { 630 goto done; 631 } 632 buf_len += 1024; 633 buf = malloc(buf_len); 634 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &buf_len, NULL, 0) 635 < 0) { 636 goto done; 637 } 638 639 /* ALIGN: buf is aligned (from malloc), cast ok. */ 640 end = (struct in6_prefix *)(void *)(buf + buf_len); 641 for (scan = (struct in6_prefix *)(void *)buf; scan < end; scan = next) { 642 struct sockaddr_in6 * advrtr; 643 struct in6_addr netaddr; 644 645 advrtr = (struct sockaddr_in6 *)(scan + 1); 646 next = (struct in6_prefix *)&advrtr[scan->advrtrs]; 647 648 if (if_index != 0 && if_index != scan->if_index) { 649 continue; 650 } 651 netaddr = *addr; 652 in6_netaddr(&netaddr, scan->prefixlen); 653 if (IN6_ARE_ADDR_EQUAL(&netaddr, &scan->prefix.sin6_addr)) { 654 prefix_length = scan->prefixlen; 655 break; 656 } 657 } 658 659 done: 660 if (buf != NULL) { 661 free(buf); 662 } 663 return (prefix_length); 664} 665 666PRIVATE_EXTERN int 667inet6_aifaddr(int s, const char * name, const struct in6_addr * addr, 668 const struct in6_addr * dstaddr, int prefix_length, 669 u_int32_t valid_lifetime, u_int32_t preferred_lifetime) 670{ 671 struct in6_aliasreq ifra_in6; 672 673 bzero(&ifra_in6, sizeof(ifra_in6)); 674 strncpy(ifra_in6.ifra_name, name, sizeof(ifra_in6.ifra_name)); 675 ifra_in6.ifra_lifetime.ia6t_vltime = valid_lifetime; 676 ifra_in6.ifra_lifetime.ia6t_pltime = preferred_lifetime; 677 if (addr != NULL) { 678 set_sockaddr_in6(&ifra_in6.ifra_addr, addr); 679 } 680 if (dstaddr != NULL) { 681 set_sockaddr_in6(&ifra_in6.ifra_dstaddr, dstaddr); 682 } 683 if (prefix_length != 0) { 684 struct in6_addr prefixmask; 685 686 in6_len2mask(&prefixmask, prefix_length); 687 set_sockaddr_in6(&ifra_in6.ifra_prefixmask, &prefixmask); 688 } 689 return (ioctl(s, SIOCAIFADDR_IN6, &ifra_in6)); 690} 691 692STATIC int 693inet6_if_ioctl(const char * ifname, unsigned long request) 694{ 695 struct in6_ifreq ifr; 696 int ret = 0; 697 int s; 698 699 s = inet6_dgram_socket(); 700 if (s < 0) { 701 ret = errno; 702 goto done; 703 } 704 bzero(&ifr, sizeof(ifr)); 705 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 706 707 if (ioctl(s, request, &ifr) < 0) { 708 ret = errno; 709 } 710 done: 711 if (s >=0) { 712 close(s); 713 } 714 return (ret); 715} 716 717PRIVATE_EXTERN int 718inet6_flush_prefixes(const char * ifname) 719{ 720 return (inet6_if_ioctl(ifname, SIOCSPFXFLUSH_IN6)); 721} 722 723PRIVATE_EXTERN int 724inet6_flush_routes(const char * ifname) 725{ 726 return (inet6_if_ioctl(ifname, SIOCSRTRFLUSH_IN6)); 727} 728 729STATIC boolean_t 730inet6_sysctl_get_int(int code, int * ret_value_p) 731{ 732 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; 733 size_t size; 734 735 mib[3] = code; 736 size = sizeof(*ret_value_p); 737 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), ret_value_p, &size, NULL, 0) 738 < 0) { 739 my_log(LOG_ERR, "inet6_sysctl_get_int(%d) failed, %s", code, 740 strerror(errno)); 741 return (FALSE); 742 } 743 return (TRUE); 744} 745 746PRIVATE_EXTERN boolean_t 747inet6_forwarding_is_enabled(void) 748{ 749 int enabled = 0; 750 751 if (inet6_sysctl_get_int(IPV6CTL_FORWARDING, &enabled) == FALSE) { 752 return (FALSE); 753 } 754 return (enabled != 0); 755} 756 757PRIVATE_EXTERN boolean_t 758inet6_set_perform_nud(const char * if_name, boolean_t perform_nud) 759{ 760 boolean_t need_set = FALSE; 761 struct in6_ndireq nd; 762 int s; 763 boolean_t success = FALSE; 764 765 s = inet6_dgram_socket(); 766 if (s < 0) { 767 my_log_fl(LOG_ERR, "socket failed, %s", strerror(errno)); 768 goto done; 769 } 770 bzero(&nd, sizeof(nd)); 771 strncpy(nd.ifname, if_name, sizeof(nd.ifname)); 772 if (ioctl(s, SIOCGIFINFO_IN6, &nd)) { 773 my_log_fl(LOG_ERR, "SIOCGIFINFO_IN6(%s) failed, %s", 774 if_name, strerror(errno)); 775 goto done; 776 } 777 if (perform_nud) { 778 if ((nd.ndi.flags & ND6_IFF_PERFORMNUD) == 0) { 779 nd.ndi.flags |= ND6_IFF_PERFORMNUD; 780 need_set = TRUE; 781 } 782 } 783 else if ((nd.ndi.flags & ND6_IFF_PERFORMNUD) != 0) { 784 nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; 785 need_set = TRUE; 786 } 787 if (need_set) { 788 if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd)) { 789 my_log_fl(LOG_ERR, "SIOCSIFINFO_FLAGS(%s) failed, %s", 790 if_name, strerror(errno)); 791 goto done; 792 } 793 } 794 success = TRUE; 795 done: 796 if (s >= 0) { 797 close(s); 798 } 799 return (success); 800} 801 802STATIC char * 803get_if_info(int if_index, int af, int * ret_len_p) 804{ 805 char * buf = NULL; 806 size_t buf_len = 0; 807 int mib[6]; 808 809 mib[0] = CTL_NET; 810 mib[1] = PF_ROUTE; 811 mib[2] = 0; 812 mib[3] = af; 813 mib[4] = NET_RT_IFLIST; 814 mib[5] = if_index; 815 816 *ret_len_p = 0; 817 if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) < 0) { 818 fprintf(stderr, "sysctl() size failed: %s", strerror(errno)); 819 goto failed; 820 } 821 buf_len *= 2; /* just in case something changes */ 822 buf = malloc(buf_len); 823 if (sysctl(mib, 6, buf, &buf_len, NULL, 0) < 0) { 824 free(buf); 825 buf = NULL; 826 fprintf(stderr, "sysctl() failed: %s", strerror(errno)); 827 goto failed; 828 } 829 *ret_len_p = buf_len; 830 831 failed: 832 return (buf); 833} 834 835PRIVATE_EXTERN void 836inet6_addrlist_copy(inet6_addrlist_t * addr_list_p, int if_index) 837{ 838 int addr_index = 0; 839 char * buf = NULL; 840 char * buf_end; 841 int buf_len; 842 int count; 843 int error; 844 int i; 845 char ifname[IFNAMSIZ + 1]; 846 inet6_addrinfo_t * list = NULL; 847 char * scan; 848 struct rt_msghdr * rtm; 849 int s = -1; 850 851 buf = get_if_info(if_index, AF_INET6, &buf_len); 852 if (buf == NULL) { 853 goto done; 854 } 855 buf_end = buf + buf_len; 856 857 addr_list_p->linklocal = NULL; 858 859 /* figure out how many IPv6 addresses there are */ 860 count = 0; 861 ifname[0] = '\0'; 862 for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) { 863 struct if_msghdr * ifm; 864 865 /* ALIGN: buf aligned (from calling get_if_info), scan aligned, 866 * cast ok. */ 867 rtm = (struct rt_msghdr *)(void *)scan; 868 if (rtm->rtm_version != RTM_VERSION) { 869 continue; 870 } 871 switch (rtm->rtm_type) { 872 case RTM_IFINFO: 873 ifm = (struct if_msghdr *)rtm; 874 if (ifm->ifm_addrs & RTA_IFP) { 875 struct sockaddr_dl * dl_p; 876 877 dl_p = (struct sockaddr_dl *)(ifm + 1); 878 if (dl_p->sdl_nlen == 0 879 || dl_p->sdl_nlen >= sizeof(ifname)) { 880 goto done; 881 } 882 bcopy(dl_p->sdl_data, ifname, dl_p->sdl_nlen); 883 ifname[dl_p->sdl_nlen] = '\0'; 884 } 885 break; 886 case RTM_NEWADDR: 887 count++; 888 break; 889 default: 890 break; 891 } 892 } 893 if (ifname[0] == '\0') { 894 goto done; 895 } 896 if (count == 0) { 897 goto done; 898 } 899 if (count > INET6_ADDRLIST_N_STATIC) { 900 list = (inet6_addrinfo_t *)malloc(sizeof(*list) * count); 901 if (list == NULL) { 902 goto done; 903 } 904 } 905 else { 906 list = addr_list_p->list_static; 907 } 908 for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) { 909 boolean_t got_address = FALSE; 910 struct ifa_msghdr * ifam; 911 struct rt_addrinfo info; 912 913 rtm = (struct rt_msghdr *)(void *)scan; 914 if (rtm->rtm_version != RTM_VERSION) { 915 continue; 916 } 917 if (rtm->rtm_type == RTM_NEWADDR) { 918 ifam = (struct ifa_msghdr *)rtm; 919 info.rti_addrs = ifam->ifam_addrs; 920 error = rt_xaddrs((char *)(ifam + 1), 921 ((char *)ifam) + ifam->ifam_msglen, 922 &info); 923 if (error) { 924 fprintf(stderr, "couldn't extract rt_addrinfo %s (%d)\n", 925 strerror(error), error); 926 goto done; 927 } 928 for (i = 0; i < RTAX_MAX; i++) { 929 struct sockaddr_in6 * sin6_p; 930 931 /* ALIGN: info.rti_info aligned (sockaddr), cast ok. */ 932 sin6_p = (struct sockaddr_in6 *)(void *)info.rti_info[i]; 933 if (sin6_p == NULL 934 || sin6_p->sin6_len < sizeof(struct sockaddr_in6)) { 935 continue; 936 } 937 switch (i) { 938 case RTAX_NETMASK: 939 list[addr_index].prefix_length 940 = count_prefix_bits(&sin6_p->sin6_addr, 941 sizeof(sin6_p->sin6_addr)); 942 break; 943 case RTAX_IFA: 944 list[addr_index].addr = sin6_p->sin6_addr; 945 got_address = TRUE; 946 break; 947 default: 948 break; 949 } 950 } 951 if (got_address) { 952 if (s < 0) { 953 s = inet6_dgram_socket(); 954 } 955 if (s >= 0) { 956 siocgifaflag_in6(s, ifname, 957 &list[addr_index].addr, 958 &list[addr_index].addr_flags); 959 } 960 /* Mask the v6 LL scope id */ 961 if (IN6_IS_ADDR_LINKLOCAL(&list[addr_index].addr)) { 962 list[addr_index].addr.s6_addr16[1] = 0; 963 if (addr_list_p->linklocal == NULL) { 964 addr_list_p->linklocal = &list[addr_index]; 965 } 966 } 967 addr_index++; 968 } 969 } 970 } 971 if (addr_index == 0) { 972 if (list != addr_list_p->list_static) { 973 free(list); 974 } 975 list = NULL; 976 } 977 978 done: 979 if (s >= 0) { 980 close(s); 981 } 982 if (buf != NULL) { 983 free(buf); 984 } 985 addr_list_p->list = list; 986 addr_list_p->count = addr_index; 987 return; 988} 989 990PRIVATE_EXTERN void 991inet6_addrlist_print(const inet6_addrlist_t * addr_list_p) 992{ 993 int i; 994 inet6_addrinfo_t * scan; 995 996 for (i = 0, scan = addr_list_p->list; i < addr_list_p->count; i++, scan++) { 997 char ntopbuf[INET6_ADDRSTRLEN]; 998 999 printf("%s/%d flags 0x%04x\n", 1000 inet_ntop(AF_INET6, &scan->addr, 1001 ntopbuf, sizeof(ntopbuf)), 1002 scan->prefix_length, 1003 scan->addr_flags); 1004 } 1005 return; 1006} 1007 1008PRIVATE_EXTERN void 1009inet6_addrlist_free(inet6_addrlist_t * addr_list_p) 1010{ 1011 if (addr_list_p->list == NULL) { 1012 return; 1013 } 1014 if (addr_list_p->list != addr_list_p->list_static) { 1015 free(addr_list_p->list); 1016 } 1017 inet6_addrlist_init(addr_list_p); 1018 return; 1019} 1020 1021PRIVATE_EXTERN void 1022inet6_addrlist_init(inet6_addrlist_t * addr_list_p) 1023{ 1024 addr_list_p->list = NULL; 1025 addr_list_p->count = 0; 1026 addr_list_p->linklocal = NULL; 1027 return; 1028} 1029 1030PRIVATE_EXTERN boolean_t 1031inet6_addrlist_contains_address(const inet6_addrlist_t * addr_list_p, 1032 const inet6_addrinfo_t * addr) 1033{ 1034 int i; 1035 inet6_addrinfo_t * scan; 1036 1037 for (i = 0, scan = addr_list_p->list; i < addr_list_p->count; i++, scan++) { 1038 if (IN6_ARE_ADDR_EQUAL(&scan->addr, &addr->addr) 1039 && (scan->prefix_length == addr->prefix_length)) { 1040 return (TRUE); 1041 } 1042 } 1043 return (FALSE); 1044} 1045 1046PRIVATE_EXTERN inet6_addrinfo_t * 1047inet6_addrlist_get_linklocal(const inet6_addrlist_t * addr_list_p) 1048{ 1049 if (addr_list_p != NULL) { 1050 return (addr_list_p->linklocal); 1051 } 1052 return (NULL); 1053} 1054 1055#if TEST_INET6_ADDRLIST || TEST_IPV6_LL 1056#include <stdio.h> 1057#include <stdlib.h> 1058#include "util.h" 1059 1060PRIVATE_EXTERN Boolean G_IPConfiguration_verbose = 1; 1061 1062STATIC bool S_cga_enabled; 1063 1064PRIVATE_EXTERN bool 1065CGAIsEnabled(void) 1066{ 1067 return (S_cga_enabled); 1068} 1069 1070PRIVATE_EXTERN void 1071CGAPrepareSetForInterface(const char * name, struct in6_cga_prepare * cga_prep) 1072{ 1073 if (S_cga_enabled == FALSE) { 1074 return; 1075 } 1076 cga_prep->cga_security_level = 0; 1077 fill_with_random(cga_prep->cga_modifier.octets, 1078 sizeof(cga_prep->cga_modifier.octets)); 1079 return; 1080} 1081 1082#endif /* TEST_INET6_ADDRLIST || TEST_IPV6_LL */ 1083 1084#if TEST_INET6_ADDRLIST 1085int 1086main(int argc, char * argv[]) 1087{ 1088 inet6_addrlist_t addresses; 1089 int if_index; 1090 1091 if (argc < 2) { 1092 fprintf(stderr, "you must specify the interface\n"); 1093 exit(1); 1094 } 1095 if_index = if_nametoindex(argv[1]); 1096 if (if_index == 0) { 1097 fprintf(stderr, "No such interface '%s'\n", argv[1]); 1098 exit(2); 1099 } 1100 inet6_addrlist_copy(&addresses, if_index); 1101 inet6_addrlist_print(&addresses); 1102 inet6_addrlist_free(&addresses); 1103 exit(0); 1104 return(0); 1105} 1106#endif /* TEST_INET6_ADDRLIST */ 1107 1108#if TEST_IPV6_LL 1109STATIC void 1110usage() 1111{ 1112 fprintf(stderr, "usage: ipv6ll start | stop <ifname> [ <cga> ]\n"); 1113 exit(1); 1114} 1115 1116int 1117main(int argc, char * argv[]) 1118{ 1119 int is_start = 0; 1120 1121 if (argc < 3) { 1122 usage(); 1123 } 1124 if (strcasecmp(argv[1], "start") == 0) { 1125 is_start = 1; 1126 } 1127 else if (strcasecmp(argv[1], "stop") == 0) { 1128 } 1129 else { 1130 usage(); 1131 } 1132 1133 if (is_start) { 1134 S_cga_enabled = (argc > 3); 1135 if (inet6_linklocal_start(argv[2], TRUE) != 0) { 1136 exit(1); 1137 } 1138 if (inet6_rtadv_enable(argv[2]) != 0) { 1139 exit(1); 1140 } 1141 } 1142 else { 1143 inet6_rtadv_disable(argv[2]); 1144 if (inet6_linklocal_stop(argv[2]) != 0) { 1145 exit(1); 1146 } 1147 } 1148 exit(0); 1149 return (0); 1150 1151} 1152 1153#endif /* TEST_IPV6_LL */ 1154