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