1 /* 2 * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* $Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp $ */ 19 20 #include <config.h> 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <errno.h> 25 #include <sys/types.h> 26 #include <winsock2.h> 27 #include <ws2tcpip.h> 28 #include <gaa_compat.h> 29 30 #include <isc/interfaceiter.h> 31 #include <isc/mem.h> 32 #include <isc/result.h> 33 #include <isc/string.h> 34 #include <isc/strerror.h> 35 #include <isc/types.h> 36 #include <isc/util.h> 37 #include <isc/win32os.h> 38 39 void InitSockets(void); 40 41 42 #define IFITER_MAGIC 0x49464954U /* IFIT. */ 43 #define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC) 44 45 struct isc_interfaceiter { 46 unsigned int magic; /* Magic number. */ 47 /* common fields */ 48 isc_mem_t *mctx; 49 isc_interface_t current; /* Current interface data. */ 50 isc_result_t result; /* Last result code. */ 51 /* fields used if GetAdaptersAddresses is available at runtime */ 52 IP_ADAPTER_ADDRESSES * ipaa; /* GAA() result buffer */ 53 ULONG ipaasize; /* Bytes allocated */ 54 IP_ADAPTER_ADDRESSES * ipaaCur; /* enumeration position */ 55 IP_ADAPTER_UNICAST_ADDRESS *ipuaCur; /* enumeration subposition */ 56 /* fields used for the older address enumeration ioctls */ 57 SOCKET socket; 58 INTERFACE_INFO IFData; /* Current Interface Info */ 59 int numIF; /* Current Interface count */ 60 int v4IF; /* Number of IPv4 Interfaces */ 61 INTERFACE_INFO *buf4; /* Buffer for WSAIoctl data. */ 62 unsigned int buf4size; /* Bytes allocated. */ 63 INTERFACE_INFO *pos4; /* Current offset in IF List */ 64 SOCKET_ADDRESS_LIST *buf6; 65 unsigned int buf6size; /* Bytes allocated. */ 66 unsigned int pos6; /* buf6 index, counts down */ 67 struct in6_addr loop__1; /* ::1 node-scope localhost */ 68 struct in6_addr loopfe80__1; /* fe80::1 link-scope localhost */ 69 }; 70 71 typedef ULONG (WINAPI *PGETADAPTERSADDRESSES)( 72 ULONG Family, 73 ULONG Flags, 74 PVOID Reserved, 75 PIP_ADAPTER_ADDRESSES AdapterAddresses, 76 PULONG SizePointer 77 ); 78 79 static isc_boolean_t use_GAA; 80 static isc_boolean_t use_GAA_determined; 81 static HMODULE hmod_iphlpapi; 82 static PGETADAPTERSADDRESSES pGAA; 83 84 85 /* 86 * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces. 87 * We assume no sane system will have more than than 1K of IP addresses on 88 * all of its adapters. 89 */ 90 #define IFCONF_SIZE_INITIAL 16 91 #define IFCONF_SIZE_INCREMENT 64 92 #define IFCONF_SIZE_MAX 1040 93 94 95 /* Common utility functions */ 96 97 /* 98 * Windows always provides 255.255.255.255 as the the broadcast 99 * address. ntpd needs to know the broadcast address which will target 100 * only that network interface, not all. Reconstruct it from the 101 * address and mask. 102 */ 103 static void 104 get_broadcastaddr(isc_netaddr_t *bcastaddr, isc_netaddr_t *addr, isc_netaddr_t *netmask) { 105 106 isc_uint32_t * b; 107 isc_uint32_t a, n; 108 109 b = (isc_uint32_t *)&bcastaddr->type.in; 110 a = *(isc_uint32_t *)&addr->type.in; 111 n = *(isc_uint32_t *)&netmask->type.in; 112 113 *b = a | ~n; 114 } 115 116 isc_result_t 117 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { 118 char strbuf[ISC_STRERRORSIZE]; 119 isc_interfaceiter_t *iter; 120 isc_result_t result; 121 unsigned int major; 122 unsigned int minor; 123 unsigned int spmajor; 124 ULONG err; 125 int tries; 126 int error; 127 unsigned long bytesReturned = 0; 128 129 REQUIRE(mctx != NULL); 130 REQUIRE(iterp != NULL); 131 REQUIRE(*iterp == NULL); 132 133 iter = isc_mem_get(mctx, sizeof(*iter)); 134 if (iter == NULL) 135 return (ISC_R_NOMEMORY); 136 137 InitSockets(); 138 139 iter->mctx = mctx; 140 iter->ipaa = NULL; 141 iter->buf4 = NULL; 142 iter->buf6 = NULL; 143 iter->pos4 = NULL; 144 iter->ipaaCur = NULL; 145 iter->ipuaCur = NULL; 146 iter->ipaasize = 0; 147 iter->pos6 = 0; 148 iter->buf6size = 0; 149 iter->buf4size = 0; 150 iter->result = ISC_R_FAILURE; 151 iter->numIF = 0; 152 iter->v4IF = 0; 153 154 /* 155 * Use GetAdaptersAddresses in preference to ioctls when running 156 * on Windows XP SP1 or later. Earlier GetAdaptersAddresses do 157 * not appear to provide enough information to associate unicast 158 * addresses with their prefixes. 159 */ 160 if (!use_GAA_determined) { 161 major = isc_win32os_majorversion(); 162 minor = isc_win32os_minorversion(); 163 spmajor = isc_win32os_servicepackmajor(); 164 if (major > 5 || (5 == major && 165 (minor > 1 || (1 == minor && spmajor >= 1)))) { 166 if (NULL == hmod_iphlpapi) 167 hmod_iphlpapi = LoadLibrary("iphlpapi"); 168 if (NULL != hmod_iphlpapi) 169 pGAA = (PGETADAPTERSADDRESSES) 170 GetProcAddress( 171 hmod_iphlpapi, 172 "GetAdaptersAddresses"); 173 if (NULL != pGAA) 174 use_GAA = ISC_TRUE; 175 } 176 use_GAA_determined = ISC_TRUE; 177 } 178 179 if (!use_GAA) 180 goto use_ioctls; 181 182 iter->ipaasize = 16 * 1024; 183 184 for (tries = 0; tries < 5; tries++) { 185 iter->ipaa = isc_mem_reallocate(mctx, iter->ipaa, 186 iter->ipaasize); 187 if (NULL == iter->ipaa) { 188 result = ISC_R_NOMEMORY; 189 goto put_iter; 190 } 191 err = (*pGAA)( 192 AF_UNSPEC, 193 GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST, 194 NULL, 195 iter->ipaa, 196 &iter->ipaasize); 197 if (NO_ERROR == err || ERROR_BUFFER_OVERFLOW != err) 198 break; 199 } 200 201 if (NO_ERROR != err) { 202 isc__strerror(err, strbuf, sizeof(strbuf)); 203 UNEXPECTED_ERROR(__FILE__, __LINE__, 204 "GetAdaptersAddresses: %s", 205 strbuf); 206 result = ISC_R_UNEXPECTED; 207 goto gaa_failure; 208 } 209 210 iter->ipaaCur = iter->ipaa; 211 goto success; 212 213 use_ioctls: 214 /* 215 * Create an unbound datagram socket to do the 216 * SIO_GET_INTERFACE_LIST WSAIoctl on. 217 */ 218 if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 219 error = WSAGetLastError(); 220 if (error == WSAEAFNOSUPPORT) 221 goto inet6_only; 222 isc__strerror(error, strbuf, sizeof(strbuf)); 223 UNEXPECTED_ERROR(__FILE__, __LINE__, 224 "making interface scan socket: %s", 225 strbuf); 226 result = ISC_R_UNEXPECTED; 227 goto put_iter; 228 } 229 230 /* 231 * Get the interface configuration, allocating more memory if 232 * necessary. 233 */ 234 iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO); 235 236 for (;;) { 237 iter->buf4 = isc_mem_get(mctx, iter->buf4size); 238 if (iter->buf4 == NULL) { 239 result = ISC_R_NOMEMORY; 240 goto alloc_failure; 241 } 242 243 if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST, 244 0, 0, iter->buf4, iter->buf4size, 245 &bytesReturned, 0, 0) == SOCKET_ERROR) 246 { 247 error = WSAGetLastError(); 248 if (error != WSAEFAULT && error != WSAENOBUFS) { 249 errno = error; 250 isc__strerror(error, strbuf, sizeof(strbuf)); 251 UNEXPECTED_ERROR(__FILE__, __LINE__, 252 "get interface configuration: %s", 253 strbuf); 254 result = ISC_R_UNEXPECTED; 255 goto ioctl_failure; 256 } 257 /* 258 * EINVAL. Retry with a bigger buffer. 259 */ 260 } else { 261 /* 262 * The WSAIoctl succeeded. 263 * If the number of the returned bytes is the same 264 * as the buffer size, we will grow it just in 265 * case and retry. 266 */ 267 if (bytesReturned > 0 && 268 (bytesReturned < iter->buf4size)) 269 break; 270 } 271 if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) { 272 UNEXPECTED_ERROR(__FILE__, __LINE__, 273 "get interface configuration: " 274 "maximum buffer size exceeded"); 275 result = ISC_R_UNEXPECTED; 276 goto ioctl_failure; 277 } 278 isc_mem_put(mctx, iter->buf4, iter->buf4size); 279 280 iter->buf4size += IFCONF_SIZE_INCREMENT * 281 sizeof(INTERFACE_INFO); 282 } 283 284 /* 285 * A newly created iterator has an undefined position 286 * until isc_interfaceiter_first() is called. 287 */ 288 iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO); 289 290 /* We don't need the socket any more, so close it */ 291 closesocket(iter->socket); 292 293 inet6_only: 294 /* 295 * Create an unbound datagram socket to do the 296 * SIO_ADDRESS_LIST_QUERY WSAIoctl on. 297 */ 298 if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 299 error = WSAGetLastError(); 300 if (error == WSAEAFNOSUPPORT) 301 goto success; 302 isc__strerror(error, strbuf, sizeof(strbuf)); 303 UNEXPECTED_ERROR(__FILE__, __LINE__, 304 "making interface scan socket: %s", 305 strbuf); 306 result = ISC_R_UNEXPECTED; 307 goto put_iter; 308 } 309 310 /* 311 * Get the interface configuration, allocating more memory if 312 * necessary. 313 */ 314 iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) + 315 IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS); 316 317 for (;;) { 318 iter->buf6 = isc_mem_get(mctx, iter->buf6size); 319 if (iter->buf6 == NULL) { 320 result = ISC_R_NOMEMORY; 321 goto ioctl_failure; 322 } 323 324 if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY, 325 0, 0, iter->buf6, iter->buf6size, 326 &bytesReturned, 0, 0) == SOCKET_ERROR) 327 { 328 error = WSAGetLastError(); 329 if (error != WSAEFAULT && error != WSAENOBUFS) { 330 errno = error; 331 isc__strerror(error, strbuf, sizeof(strbuf)); 332 UNEXPECTED_ERROR(__FILE__, __LINE__, 333 "sio address list query: %s", 334 strbuf); 335 result = ISC_R_UNEXPECTED; 336 goto ioctl6_failure; 337 } 338 /* 339 * EINVAL. Retry with a bigger buffer. 340 */ 341 } else 342 break; 343 344 if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) { 345 UNEXPECTED_ERROR(__FILE__, __LINE__, 346 "get interface configuration: " 347 "maximum buffer size exceeded"); 348 result = ISC_R_UNEXPECTED; 349 goto ioctl6_failure; 350 } 351 isc_mem_put(mctx, iter->buf6, iter->buf6size); 352 353 iter->buf6size += IFCONF_SIZE_INCREMENT * 354 sizeof(SOCKET_ADDRESS); 355 } 356 357 /* 358 * initialize loop__1 to [::1] and loopfe80__1 to [fe80::1]. 359 * used by internal_current6(). 360 */ 361 memset(&iter->loop__1, 0, sizeof(iter->loop__1)); 362 memset(&iter->loopfe80__1, 0, sizeof(iter->loopfe80__1)); 363 iter->loop__1.s6_addr[15] = 1; 364 iter->loopfe80__1.s6_addr[15] = 1; 365 iter->loopfe80__1.s6_addr[0] = 0xfe; 366 iter->loopfe80__1.s6_addr[1] = 0x80; 367 368 closesocket(iter->socket); 369 370 success: 371 iter->magic = IFITER_MAGIC; 372 *iterp = iter; 373 return (ISC_R_SUCCESS); 374 375 gaa_failure: 376 isc_mem_put(mctx, iter->ipaa, iter->ipaasize); 377 goto put_iter; 378 379 ioctl6_failure: 380 isc_mem_put(mctx, iter->buf6, iter->buf6size); 381 382 ioctl_failure: 383 if (iter->buf4 != NULL) 384 isc_mem_put(mctx, iter->buf4, iter->buf4size); 385 386 alloc_failure: 387 if (iter->socket >= 0) 388 (void) closesocket(iter->socket); 389 390 put_iter: 391 isc_mem_put(mctx, iter, sizeof(*iter)); 392 return (result); 393 } 394 395 static unsigned char 396 GAA_find_prefix(isc_interfaceiter_t *iter) { 397 IP_ADAPTER_PREFIX * ipap; 398 IP_ADAPTER_PREFIX * ipap_match; 399 int match_len; 400 int max_len; 401 isc_netaddr_t target; 402 u_short af; 403 isc_netaddr_t pfx; 404 int pfx_len; 405 size_t nbytes; 406 unsigned char nbits; 407 unsigned char * pbits; 408 unsigned int octets; 409 410 match_len = 0; 411 ipap_match = NULL; 412 isc_netaddr_fromsockaddr(&target, 413 (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr); 414 af = (u_short)target.family; 415 INSIST(AF_INET == af || AF_INET6 == af); 416 max_len = (AF_INET6 == af) ? 128 : 32; 417 iter->current.netmask.family = af; 418 for (ipap = iter->ipaaCur->FirstPrefix; 419 ipap != NULL; 420 ipap = ipap->Next) { 421 if (ipap->Address.lpSockaddr->sa_family != af) 422 continue; 423 isc_netaddr_fromsockaddr(&pfx, 424 (isc_sockaddr_t *)ipap->Address.lpSockaddr); 425 pfx_len = ipap->PrefixLength; 426 INSIST(0 <= pfx_len && pfx_len <= max_len); 427 if (pfx_len > match_len && pfx_len < max_len && 428 isc_netaddr_eqprefix(&target, &pfx, pfx_len)) { 429 ipap_match = ipap; 430 match_len = pfx_len; 431 } 432 } 433 if (NULL == ipap_match) { 434 /* presume all-ones mask */ 435 if (AF_INET6 == af) 436 octets = sizeof(iter->current.netmask.type.in6); 437 else 438 octets = sizeof(iter->current.netmask.type.in); 439 memset(&iter->current.netmask.type, 0xFF, octets); 440 return (8 * (unsigned char)octets); 441 } 442 nbytes = match_len / 8; 443 nbits = match_len % 8; 444 memset(&iter->current.netmask.type.in6, 0xFF, nbytes); 445 pbits = (void *)&iter->current.netmask.type.in6; 446 pbits += nbytes; 447 *pbits |= 0xFF << (8 - nbits); 448 return ((unsigned char)match_len); 449 } 450 451 static isc_result_t 452 internal_current_GAA(isc_interfaceiter_t *iter) { 453 IP_ADAPTER_ADDRESSES *adap; 454 IP_ADAPTER_UNICAST_ADDRESS *addr; 455 unsigned char prefix_len; 456 457 REQUIRE(iter->ipaaCur != NULL); 458 REQUIRE(iter->ipuaCur != NULL); 459 adap = iter->ipaaCur; 460 addr = iter->ipuaCur; 461 if (IpDadStatePreferred != addr->DadState) 462 return (ISC_R_IGNORE); 463 memset(&iter->current, 0, sizeof(iter->current)); 464 iter->current.af = addr->Address.lpSockaddr->sa_family; 465 isc_netaddr_fromsockaddr(&iter->current.address, 466 (isc_sockaddr_t *)addr->Address.lpSockaddr); 467 if (AF_INET6 == iter->current.af) 468 iter->current.ifindex = adap->Ipv6IfIndex; 469 iter->current.name[0] = '\0'; 470 WideCharToMultiByte( 471 CP_ACP, 472 0, 473 adap->FriendlyName, 474 -1, 475 iter->current.name, 476 sizeof(iter->current.name), 477 NULL, 478 NULL); 479 iter->current.name[sizeof(iter->current.name) - 1] = '\0'; 480 if (IfOperStatusUp == adap->OperStatus) 481 iter->current.flags |= INTERFACE_F_UP; 482 if (IF_TYPE_PPP == adap->IfType) 483 iter->current.flags |= INTERFACE_F_POINTTOPOINT; 484 else if (IF_TYPE_SOFTWARE_LOOPBACK == adap->IfType) 485 iter->current.flags |= INTERFACE_F_LOOPBACK; 486 if ((IP_ADAPTER_NO_MULTICAST & adap->Flags) == 0) 487 iter->current.flags |= INTERFACE_F_MULTICAST; 488 if (IpSuffixOriginRandom == addr->SuffixOrigin) 489 iter->current.flags |= INTERFACE_F_PRIVACY; 490 491 prefix_len = GAA_find_prefix(iter); 492 /* I'm failing to see a broadcast flag via GAA */ 493 if (AF_INET == iter->current.af && prefix_len < 32 && 494 (INTERFACE_F_LOOPBACK & iter->current.flags) == 0) { 495 iter->current.flags |= INTERFACE_F_BROADCAST; 496 get_broadcastaddr(&iter->current.broadcast, 497 &iter->current.address, 498 &iter->current.netmask); 499 } 500 return (ISC_R_SUCCESS); 501 } 502 503 /* 504 * Get information about the current interface to iter->current. 505 * If successful, return ISC_R_SUCCESS. 506 * If the interface has an unsupported address family, or if 507 * some operation on it fails, return ISC_R_IGNORE to make 508 * the higher-level iterator code ignore it. 509 */ 510 511 static isc_result_t 512 internal_current(isc_interfaceiter_t *iter) { 513 BOOL ifNamed = FALSE; 514 unsigned long flags; 515 516 REQUIRE(VALID_IFITER(iter)); 517 REQUIRE(iter->numIF >= 0); 518 519 memset(&iter->current, 0, sizeof(iter->current)); 520 iter->current.af = AF_INET; 521 522 isc_netaddr_fromsockaddr(&iter->current.address, 523 (isc_sockaddr_t *)&(iter->IFData.iiAddress)); 524 525 /* 526 * Get interface flags. 527 */ 528 529 iter->current.flags = 0; 530 flags = iter->IFData.iiFlags; 531 532 if ((flags & IFF_UP) != 0) 533 iter->current.flags |= INTERFACE_F_UP; 534 535 if ((flags & IFF_BROADCAST) != 0) 536 iter->current.flags |= INTERFACE_F_BROADCAST; 537 538 if ((flags & IFF_MULTICAST) != 0) 539 iter->current.flags |= INTERFACE_F_MULTICAST; 540 541 if ((flags & IFF_POINTTOPOINT) != 0) { 542 iter->current.flags |= INTERFACE_F_POINTTOPOINT; 543 snprintf(iter->current.name, sizeof(iter->current.name), 544 "PPP %d", iter->numIF); 545 ifNamed = TRUE; 546 } 547 548 if ((flags & IFF_LOOPBACK) != 0) { 549 iter->current.flags |= INTERFACE_F_LOOPBACK; 550 snprintf(iter->current.name, sizeof(iter->current.name), 551 "v4loop %d", iter->numIF); 552 ifNamed = TRUE; 553 } 554 555 /* 556 * If the interface is point-to-point, get the destination address. 557 */ 558 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) 559 isc_netaddr_fromsockaddr(&iter->current.dstaddress, 560 (isc_sockaddr_t *)&(iter->IFData.iiBroadcastAddress)); 561 562 /* 563 * Get the network mask. 564 */ 565 isc_netaddr_fromsockaddr(&iter->current.netmask, 566 (isc_sockaddr_t *)&(iter->IFData.iiNetmask)); 567 568 /* 569 * If the interface is broadcast, get the broadcast address, 570 * based on the unicast address and network mask. 571 */ 572 if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) 573 get_broadcastaddr(&iter->current.broadcast, 574 &iter->current.address, 575 &iter->current.netmask); 576 577 if (ifNamed == FALSE) 578 snprintf(iter->current.name, sizeof(iter->current.name), 579 "IPv4 %d", iter->numIF); 580 581 return (ISC_R_SUCCESS); 582 } 583 584 static isc_result_t 585 internal_current6(isc_interfaceiter_t *iter) { 586 BOOL ifNamed = FALSE; 587 struct sockaddr_in6 *psa6; 588 BOOL localhostSeen; 589 int i; 590 591 REQUIRE(VALID_IFITER(iter)); 592 REQUIRE(iter->pos6 >= 0); 593 REQUIRE(iter->buf6 != 0); 594 595 memset(&iter->current, 0, sizeof(iter->current)); 596 iter->current.af = AF_INET6; 597 598 /* 599 * synthesize localhost ::1 before returning the rest, if ::1 600 * is not on the list. 601 */ 602 if (iter->pos6 >= (unsigned)iter->buf6->iAddressCount) { 603 localhostSeen = FALSE; 604 for (i = 0; i < iter->buf6->iAddressCount; i++) { 605 psa6 = (struct sockaddr_in6 *) 606 iter->buf6->Address[i].lpSockaddr; 607 if (!memcmp(&iter->loop__1, &psa6->sin6_addr, 608 sizeof(iter->loop__1))) { 609 localhostSeen = TRUE; 610 break; 611 } 612 } 613 if (localhostSeen) 614 iter->pos6 = iter->buf6->iAddressCount - 1; 615 } 616 617 if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) { 618 isc_netaddr_fromsockaddr(&iter->current.address, 619 (isc_sockaddr_t *)iter->buf6->Address[iter->pos6].lpSockaddr); 620 } else { 621 iter->current.address.family = AF_INET6; 622 memcpy(&iter->current.address.type.in6, &iter->loop__1, 623 sizeof(iter->current.address.type.in6)); 624 } 625 626 /* 627 * Get interface flags. 628 */ 629 630 iter->current.flags = INTERFACE_F_UP | INTERFACE_F_MULTICAST; 631 632 if (!memcmp(&iter->current.address.type.in6, &iter->loop__1, 633 sizeof(iter->current.address.type.in6)) || 634 !memcmp(&iter->current.address.type.in6, &iter->loopfe80__1, 635 sizeof(iter->current.address.type.in6))) { 636 637 iter->current.flags |= INTERFACE_F_LOOPBACK; 638 snprintf(iter->current.name, sizeof(iter->current.name), 639 "v6loop %d", 640 iter->buf6->iAddressCount - iter->pos6); 641 ifNamed = TRUE; 642 } 643 644 if (ifNamed == FALSE) 645 snprintf(iter->current.name, sizeof(iter->current.name), 646 "IPv6 %d", 647 iter->buf6->iAddressCount - iter->pos6); 648 649 memset(iter->current.netmask.type.in6.s6_addr, 0xff, 650 sizeof(iter->current.netmask.type.in6.s6_addr)); 651 iter->current.netmask.family = AF_INET6; 652 return (ISC_R_SUCCESS); 653 } 654 655 static isc_result_t 656 internal_next_GAA(isc_interfaceiter_t *iter) { 657 REQUIRE(use_GAA); 658 if (NULL == iter->ipaaCur) 659 return (ISC_R_NOMORE); 660 if (NULL == iter->ipuaCur) 661 iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; 662 else 663 iter->ipuaCur = iter->ipuaCur->Next; 664 while (NULL == iter->ipuaCur) { 665 iter->ipaaCur = iter->ipaaCur->Next; 666 if (NULL == iter->ipaaCur) 667 return (ISC_R_NOMORE); 668 iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; 669 } 670 return (ISC_R_SUCCESS); 671 } 672 673 /* 674 * Step the iterator to the next interface. Unlike 675 * isc_interfaceiter_next(), this may leave the iterator 676 * positioned on an interface that will ultimately 677 * be ignored. Return ISC_R_NOMORE if there are no more 678 * interfaces, otherwise ISC_R_SUCCESS. 679 */ 680 static isc_result_t 681 internal_next(isc_interfaceiter_t *iter) { 682 if (iter->numIF >= iter->v4IF) 683 return (ISC_R_NOMORE); 684 685 /* 686 * The first one needs to be set up to point to the last 687 * Element of the array. Go to the end and back up 688 * Microsoft's implementation is peculiar for returning 689 * the list in reverse order 690 */ 691 692 if (iter->numIF == 0) 693 iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF)); 694 695 iter->pos4--; 696 if (&(iter->pos4) < &(iter->buf4)) 697 return (ISC_R_NOMORE); 698 699 memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO)); 700 memcpy(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO)); 701 iter->numIF++; 702 703 return (ISC_R_SUCCESS); 704 } 705 706 static isc_result_t 707 internal_next6(isc_interfaceiter_t *iter) { 708 if (iter->pos6 == 0) 709 return (ISC_R_NOMORE); 710 iter->pos6--; 711 return (ISC_R_SUCCESS); 712 } 713 714 isc_result_t 715 isc_interfaceiter_current(isc_interfaceiter_t *iter, 716 isc_interface_t *ifdata) { 717 REQUIRE(iter->result == ISC_R_SUCCESS); 718 memcpy(ifdata, &iter->current, sizeof(*ifdata)); 719 return (ISC_R_SUCCESS); 720 } 721 722 isc_result_t 723 isc_interfaceiter_first(isc_interfaceiter_t *iter) { 724 REQUIRE(VALID_IFITER(iter)); 725 REQUIRE(use_GAA_determined); 726 /* 727 * SIO_ADDRESS_LIST_QUERY (used to query IPv6 addresses) 728 * intentionally omits localhost addresses [::1] and [::fe80] in 729 * some cases. ntpd depends on enumerating [::1] to listen on 730 * it, and ntpq and ntpdc default to "localhost" as the target, 731 * so they will attempt to talk to [::1]:123 and fail. This 732 * means we need to synthesize ::1, which we will do first, 733 * hence iAddressCount + 1. internal_next6() will decrement 734 * it before the first use as an index, and internal_current6() 735 * will treat pos6 == iAddressCount as a sign to synthesize 736 * [::1] if needed. 737 */ 738 if (!use_GAA && iter->buf6 != NULL) 739 iter->pos6 = iter->buf6->iAddressCount + 1; 740 iter->result = ISC_R_SUCCESS; 741 return (isc_interfaceiter_next(iter)); 742 } 743 744 isc_result_t 745 isc_interfaceiter_next(isc_interfaceiter_t *iter) { 746 isc_result_t result; 747 748 REQUIRE(VALID_IFITER(iter)); 749 REQUIRE(iter->result == ISC_R_SUCCESS); 750 REQUIRE(use_GAA_determined); 751 752 if (use_GAA) { 753 do { 754 result = internal_next_GAA(iter); 755 if (ISC_R_NOMORE == result) 756 goto set_result; 757 result = internal_current_GAA(iter); 758 } while (ISC_R_IGNORE == result); 759 goto set_result; 760 } 761 762 for (;;) { 763 result = internal_next(iter); 764 if (result == ISC_R_NOMORE) { 765 result = internal_next6(iter); 766 if (result != ISC_R_SUCCESS) 767 break; 768 result = internal_current6(iter); 769 if (result != ISC_R_IGNORE) 770 break; 771 } else if (result != ISC_R_SUCCESS) 772 break; 773 result = internal_current(iter); 774 if (result != ISC_R_IGNORE) 775 break; 776 } 777 set_result: 778 iter->result = result; 779 return (result); 780 } 781 782 void 783 isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) { 784 isc_interfaceiter_t *iter; 785 786 REQUIRE(iterp != NULL); 787 iter = *iterp; 788 REQUIRE(VALID_IFITER(iter)); 789 REQUIRE(use_GAA_determined); 790 791 if (use_GAA) { 792 REQUIRE(NULL == iter->buf4); 793 REQUIRE(NULL == iter->buf4); 794 if (iter->ipaa != NULL) 795 isc_mem_put(iter->mctx, iter->ipaa, iter->ipaasize); 796 } else { 797 REQUIRE(NULL == iter->ipaa); 798 if (iter->buf4 != NULL) 799 isc_mem_put(iter->mctx, iter->buf4, iter->buf4size); 800 if (iter->buf6 != NULL) 801 isc_mem_put(iter->mctx, iter->buf6, iter->buf6size); 802 } 803 804 iter->magic = 0; 805 isc_mem_put(iter->mctx, iter, sizeof(*iter)); 806 *iterp = NULL; 807 } 808