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