1258945Sroberto/* 2258945Sroberto * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 1999-2001 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18280849Scy/* $Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp $ */ 19258945Sroberto 20258945Sroberto#include <config.h> 21258945Sroberto 22258945Sroberto#include <stdio.h> 23258945Sroberto#include <stdlib.h> 24258945Sroberto#include <errno.h> 25280849Scy#include <sys/types.h> 26280849Scy#include <winsock2.h> 27280849Scy#include <ws2tcpip.h> 28280849Scy#include <gaa_compat.h> 29258945Sroberto 30258945Sroberto#include <isc/interfaceiter.h> 31258945Sroberto#include <isc/mem.h> 32258945Sroberto#include <isc/result.h> 33258945Sroberto#include <isc/string.h> 34258945Sroberto#include <isc/strerror.h> 35258945Sroberto#include <isc/types.h> 36258945Sroberto#include <isc/util.h> 37258945Sroberto#include <isc/win32os.h> 38258945Sroberto 39258945Srobertovoid InitSockets(void); 40258945Sroberto 41258945Sroberto 42258945Sroberto#define IFITER_MAGIC 0x49464954U /* IFIT. */ 43258945Sroberto#define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC) 44258945Sroberto 45258945Srobertostruct isc_interfaceiter { 46258945Sroberto unsigned int magic; /* Magic number. */ 47258945Sroberto /* common fields */ 48258945Sroberto isc_mem_t *mctx; 49258945Sroberto isc_interface_t current; /* Current interface data. */ 50258945Sroberto isc_result_t result; /* Last result code. */ 51258945Sroberto /* fields used if GetAdaptersAddresses is available at runtime */ 52258945Sroberto IP_ADAPTER_ADDRESSES * ipaa; /* GAA() result buffer */ 53258945Sroberto ULONG ipaasize; /* Bytes allocated */ 54258945Sroberto IP_ADAPTER_ADDRESSES * ipaaCur; /* enumeration position */ 55258945Sroberto IP_ADAPTER_UNICAST_ADDRESS *ipuaCur; /* enumeration subposition */ 56258945Sroberto /* fields used for the older address enumeration ioctls */ 57293650Sglebius SOCKET socket; 58258945Sroberto INTERFACE_INFO IFData; /* Current Interface Info */ 59258945Sroberto int numIF; /* Current Interface count */ 60258945Sroberto int v4IF; /* Number of IPv4 Interfaces */ 61258945Sroberto INTERFACE_INFO *buf4; /* Buffer for WSAIoctl data. */ 62258945Sroberto unsigned int buf4size; /* Bytes allocated. */ 63258945Sroberto INTERFACE_INFO *pos4; /* Current offset in IF List */ 64258945Sroberto SOCKET_ADDRESS_LIST *buf6; 65258945Sroberto unsigned int buf6size; /* Bytes allocated. */ 66258945Sroberto unsigned int pos6; /* buf6 index, counts down */ 67258945Sroberto struct in6_addr loop__1; /* ::1 node-scope localhost */ 68258945Sroberto struct in6_addr loopfe80__1; /* fe80::1 link-scope localhost */ 69258945Sroberto}; 70258945Sroberto 71258945Srobertotypedef ULONG (WINAPI *PGETADAPTERSADDRESSES)( 72258945Sroberto ULONG Family, 73258945Sroberto ULONG Flags, 74258945Sroberto PVOID Reserved, 75258945Sroberto PIP_ADAPTER_ADDRESSES AdapterAddresses, 76258945Sroberto PULONG SizePointer 77258945Sroberto); 78258945Sroberto 79258945Srobertostatic isc_boolean_t use_GAA; 80258945Srobertostatic isc_boolean_t use_GAA_determined; 81258945Srobertostatic HMODULE hmod_iphlpapi; 82258945Srobertostatic PGETADAPTERSADDRESSES pGAA; 83258945Sroberto 84258945Sroberto 85258945Sroberto/* 86258945Sroberto * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces. 87258945Sroberto * We assume no sane system will have more than than 1K of IP addresses on 88258945Sroberto * all of its adapters. 89258945Sroberto */ 90258945Sroberto#define IFCONF_SIZE_INITIAL 16 91258945Sroberto#define IFCONF_SIZE_INCREMENT 64 92258945Sroberto#define IFCONF_SIZE_MAX 1040 93258945Sroberto 94258945Sroberto 95258945Sroberto/* Common utility functions */ 96258945Sroberto 97258945Sroberto/* 98258945Sroberto * Windows always provides 255.255.255.255 as the the broadcast 99258945Sroberto * address. ntpd needs to know the broadcast address which will target 100258945Sroberto * only that network interface, not all. Reconstruct it from the 101258945Sroberto * address and mask. 102258945Sroberto */ 103258945Srobertostatic void 104258945Srobertoget_broadcastaddr(isc_netaddr_t *bcastaddr, isc_netaddr_t *addr, isc_netaddr_t *netmask) { 105258945Sroberto 106258945Sroberto isc_uint32_t * b; 107258945Sroberto isc_uint32_t a, n; 108258945Sroberto 109258945Sroberto b = (isc_uint32_t *)&bcastaddr->type.in; 110258945Sroberto a = *(isc_uint32_t *)&addr->type.in; 111258945Sroberto n = *(isc_uint32_t *)&netmask->type.in; 112258945Sroberto 113258945Sroberto *b = a | ~n; 114258945Sroberto} 115258945Sroberto 116258945Srobertoisc_result_t 117258945Srobertoisc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { 118258945Sroberto char strbuf[ISC_STRERRORSIZE]; 119258945Sroberto isc_interfaceiter_t *iter; 120258945Sroberto isc_result_t result; 121258945Sroberto unsigned int major; 122258945Sroberto unsigned int minor; 123258945Sroberto unsigned int spmajor; 124258945Sroberto ULONG err; 125258945Sroberto int tries; 126258945Sroberto int error; 127258945Sroberto unsigned long bytesReturned = 0; 128258945Sroberto 129258945Sroberto REQUIRE(mctx != NULL); 130258945Sroberto REQUIRE(iterp != NULL); 131258945Sroberto REQUIRE(*iterp == NULL); 132258945Sroberto 133258945Sroberto iter = isc_mem_get(mctx, sizeof(*iter)); 134258945Sroberto if (iter == NULL) 135258945Sroberto return (ISC_R_NOMEMORY); 136258945Sroberto 137258945Sroberto InitSockets(); 138258945Sroberto 139258945Sroberto iter->mctx = mctx; 140258945Sroberto iter->ipaa = NULL; 141258945Sroberto iter->buf4 = NULL; 142258945Sroberto iter->buf6 = NULL; 143258945Sroberto iter->pos4 = NULL; 144258945Sroberto iter->ipaaCur = NULL; 145258945Sroberto iter->ipuaCur = NULL; 146258945Sroberto iter->ipaasize = 0; 147258945Sroberto iter->pos6 = 0; 148258945Sroberto iter->buf6size = 0; 149258945Sroberto iter->buf4size = 0; 150258945Sroberto iter->result = ISC_R_FAILURE; 151258945Sroberto iter->numIF = 0; 152258945Sroberto iter->v4IF = 0; 153258945Sroberto 154258945Sroberto /* 155258945Sroberto * Use GetAdaptersAddresses in preference to ioctls when running 156258945Sroberto * on Windows XP SP1 or later. Earlier GetAdaptersAddresses do 157258945Sroberto * not appear to provide enough information to associate unicast 158258945Sroberto * addresses with their prefixes. 159258945Sroberto */ 160258945Sroberto if (!use_GAA_determined) { 161258945Sroberto major = isc_win32os_majorversion(); 162258945Sroberto minor = isc_win32os_minorversion(); 163258945Sroberto spmajor = isc_win32os_servicepackmajor(); 164258945Sroberto if (major > 5 || (5 == major && 165258945Sroberto (minor > 1 || (1 == minor && spmajor >= 1)))) { 166258945Sroberto if (NULL == hmod_iphlpapi) 167258945Sroberto hmod_iphlpapi = LoadLibrary("iphlpapi"); 168258945Sroberto if (NULL != hmod_iphlpapi) 169258945Sroberto pGAA = (PGETADAPTERSADDRESSES) 170258945Sroberto GetProcAddress( 171258945Sroberto hmod_iphlpapi, 172258945Sroberto "GetAdaptersAddresses"); 173258945Sroberto if (NULL != pGAA) 174258945Sroberto use_GAA = ISC_TRUE; 175258945Sroberto } 176258945Sroberto use_GAA_determined = ISC_TRUE; 177258945Sroberto } 178258945Sroberto 179258945Sroberto if (!use_GAA) 180258945Sroberto goto use_ioctls; 181258945Sroberto 182258945Sroberto iter->ipaasize = 16 * 1024; 183258945Sroberto 184258945Sroberto for (tries = 0; tries < 5; tries++) { 185258945Sroberto iter->ipaa = isc_mem_reallocate(mctx, iter->ipaa, 186258945Sroberto iter->ipaasize); 187258945Sroberto if (NULL == iter->ipaa) { 188258945Sroberto result = ISC_R_NOMEMORY; 189258945Sroberto goto put_iter; 190258945Sroberto } 191258945Sroberto err = (*pGAA)( 192258945Sroberto AF_UNSPEC, 193258945Sroberto GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST, 194258945Sroberto NULL, 195258945Sroberto iter->ipaa, 196258945Sroberto &iter->ipaasize); 197258945Sroberto if (NO_ERROR == err || ERROR_BUFFER_OVERFLOW != err) 198258945Sroberto break; 199258945Sroberto } 200258945Sroberto 201258945Sroberto if (NO_ERROR != err) { 202258945Sroberto isc__strerror(err, strbuf, sizeof(strbuf)); 203258945Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 204258945Sroberto "GetAdaptersAddresses: %s", 205258945Sroberto strbuf); 206258945Sroberto result = ISC_R_UNEXPECTED; 207258945Sroberto goto gaa_failure; 208258945Sroberto } 209258945Sroberto 210258945Sroberto iter->ipaaCur = iter->ipaa; 211258945Sroberto goto success; 212258945Sroberto 213258945Sroberto use_ioctls: 214258945Sroberto /* 215258945Sroberto * Create an unbound datagram socket to do the 216258945Sroberto * SIO_GET_INTERFACE_LIST WSAIoctl on. 217258945Sroberto */ 218258945Sroberto if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 219258945Sroberto error = WSAGetLastError(); 220258945Sroberto if (error == WSAEAFNOSUPPORT) 221258945Sroberto goto inet6_only; 222258945Sroberto isc__strerror(error, strbuf, sizeof(strbuf)); 223258945Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 224258945Sroberto "making interface scan socket: %s", 225258945Sroberto strbuf); 226258945Sroberto result = ISC_R_UNEXPECTED; 227258945Sroberto goto put_iter; 228258945Sroberto } 229258945Sroberto 230258945Sroberto /* 231258945Sroberto * Get the interface configuration, allocating more memory if 232258945Sroberto * necessary. 233258945Sroberto */ 234258945Sroberto iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO); 235258945Sroberto 236258945Sroberto for (;;) { 237258945Sroberto iter->buf4 = isc_mem_get(mctx, iter->buf4size); 238258945Sroberto if (iter->buf4 == NULL) { 239258945Sroberto result = ISC_R_NOMEMORY; 240258945Sroberto goto alloc_failure; 241258945Sroberto } 242258945Sroberto 243258945Sroberto if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST, 244258945Sroberto 0, 0, iter->buf4, iter->buf4size, 245258945Sroberto &bytesReturned, 0, 0) == SOCKET_ERROR) 246258945Sroberto { 247258945Sroberto error = WSAGetLastError(); 248258945Sroberto if (error != WSAEFAULT && error != WSAENOBUFS) { 249258945Sroberto errno = error; 250258945Sroberto isc__strerror(error, strbuf, sizeof(strbuf)); 251258945Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 252258945Sroberto "get interface configuration: %s", 253258945Sroberto strbuf); 254258945Sroberto result = ISC_R_UNEXPECTED; 255258945Sroberto goto ioctl_failure; 256258945Sroberto } 257258945Sroberto /* 258258945Sroberto * EINVAL. Retry with a bigger buffer. 259258945Sroberto */ 260258945Sroberto } else { 261258945Sroberto /* 262258945Sroberto * The WSAIoctl succeeded. 263258945Sroberto * If the number of the returned bytes is the same 264258945Sroberto * as the buffer size, we will grow it just in 265258945Sroberto * case and retry. 266258945Sroberto */ 267258945Sroberto if (bytesReturned > 0 && 268258945Sroberto (bytesReturned < iter->buf4size)) 269258945Sroberto break; 270258945Sroberto } 271258945Sroberto if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) { 272258945Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 273258945Sroberto "get interface configuration: " 274258945Sroberto "maximum buffer size exceeded"); 275258945Sroberto result = ISC_R_UNEXPECTED; 276258945Sroberto goto ioctl_failure; 277258945Sroberto } 278258945Sroberto isc_mem_put(mctx, iter->buf4, iter->buf4size); 279258945Sroberto 280258945Sroberto iter->buf4size += IFCONF_SIZE_INCREMENT * 281258945Sroberto sizeof(INTERFACE_INFO); 282258945Sroberto } 283258945Sroberto 284258945Sroberto /* 285258945Sroberto * A newly created iterator has an undefined position 286258945Sroberto * until isc_interfaceiter_first() is called. 287258945Sroberto */ 288258945Sroberto iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO); 289258945Sroberto 290258945Sroberto /* We don't need the socket any more, so close it */ 291258945Sroberto closesocket(iter->socket); 292258945Sroberto 293258945Sroberto inet6_only: 294258945Sroberto /* 295258945Sroberto * Create an unbound datagram socket to do the 296258945Sroberto * SIO_ADDRESS_LIST_QUERY WSAIoctl on. 297258945Sroberto */ 298258945Sroberto if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 299258945Sroberto error = WSAGetLastError(); 300258945Sroberto if (error == WSAEAFNOSUPPORT) 301258945Sroberto goto success; 302258945Sroberto isc__strerror(error, strbuf, sizeof(strbuf)); 303258945Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 304258945Sroberto "making interface scan socket: %s", 305258945Sroberto strbuf); 306258945Sroberto result = ISC_R_UNEXPECTED; 307258945Sroberto goto put_iter; 308258945Sroberto } 309258945Sroberto 310258945Sroberto /* 311258945Sroberto * Get the interface configuration, allocating more memory if 312258945Sroberto * necessary. 313258945Sroberto */ 314258945Sroberto iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) + 315258945Sroberto IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS); 316258945Sroberto 317258945Sroberto for (;;) { 318258945Sroberto iter->buf6 = isc_mem_get(mctx, iter->buf6size); 319258945Sroberto if (iter->buf6 == NULL) { 320258945Sroberto result = ISC_R_NOMEMORY; 321258945Sroberto goto ioctl_failure; 322258945Sroberto } 323258945Sroberto 324258945Sroberto if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY, 325258945Sroberto 0, 0, iter->buf6, iter->buf6size, 326258945Sroberto &bytesReturned, 0, 0) == SOCKET_ERROR) 327258945Sroberto { 328258945Sroberto error = WSAGetLastError(); 329258945Sroberto if (error != WSAEFAULT && error != WSAENOBUFS) { 330258945Sroberto errno = error; 331258945Sroberto isc__strerror(error, strbuf, sizeof(strbuf)); 332258945Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 333258945Sroberto "sio address list query: %s", 334258945Sroberto strbuf); 335258945Sroberto result = ISC_R_UNEXPECTED; 336258945Sroberto goto ioctl6_failure; 337258945Sroberto } 338258945Sroberto /* 339258945Sroberto * EINVAL. Retry with a bigger buffer. 340258945Sroberto */ 341258945Sroberto } else 342258945Sroberto break; 343258945Sroberto 344258945Sroberto if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) { 345258945Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 346258945Sroberto "get interface configuration: " 347258945Sroberto "maximum buffer size exceeded"); 348258945Sroberto result = ISC_R_UNEXPECTED; 349258945Sroberto goto ioctl6_failure; 350258945Sroberto } 351258945Sroberto isc_mem_put(mctx, iter->buf6, iter->buf6size); 352258945Sroberto 353258945Sroberto iter->buf6size += IFCONF_SIZE_INCREMENT * 354258945Sroberto sizeof(SOCKET_ADDRESS); 355258945Sroberto } 356258945Sroberto 357258945Sroberto /* 358258945Sroberto * initialize loop__1 to [::1] and loopfe80__1 to [fe80::1]. 359258945Sroberto * used by internal_current6(). 360258945Sroberto */ 361258945Sroberto memset(&iter->loop__1, 0, sizeof(iter->loop__1)); 362258945Sroberto memset(&iter->loopfe80__1, 0, sizeof(iter->loopfe80__1)); 363258945Sroberto iter->loop__1.s6_addr[15] = 1; 364258945Sroberto iter->loopfe80__1.s6_addr[15] = 1; 365258945Sroberto iter->loopfe80__1.s6_addr[0] = 0xfe; 366258945Sroberto iter->loopfe80__1.s6_addr[1] = 0x80; 367258945Sroberto 368258945Sroberto closesocket(iter->socket); 369258945Sroberto 370258945Sroberto success: 371258945Sroberto iter->magic = IFITER_MAGIC; 372258945Sroberto *iterp = iter; 373258945Sroberto return (ISC_R_SUCCESS); 374258945Sroberto 375258945Sroberto gaa_failure: 376258945Sroberto isc_mem_put(mctx, iter->ipaa, iter->ipaasize); 377258945Sroberto goto put_iter; 378258945Sroberto 379258945Sroberto ioctl6_failure: 380258945Sroberto isc_mem_put(mctx, iter->buf6, iter->buf6size); 381258945Sroberto 382258945Sroberto ioctl_failure: 383258945Sroberto if (iter->buf4 != NULL) 384258945Sroberto isc_mem_put(mctx, iter->buf4, iter->buf4size); 385258945Sroberto 386258945Sroberto alloc_failure: 387258945Sroberto if (iter->socket >= 0) 388258945Sroberto (void) closesocket(iter->socket); 389258945Sroberto 390258945Sroberto put_iter: 391258945Sroberto isc_mem_put(mctx, iter, sizeof(*iter)); 392258945Sroberto return (result); 393258945Sroberto} 394258945Sroberto 395258945Srobertostatic unsigned char 396258945SrobertoGAA_find_prefix(isc_interfaceiter_t *iter) { 397258945Sroberto IP_ADAPTER_PREFIX * ipap; 398258945Sroberto IP_ADAPTER_PREFIX * ipap_match; 399258945Sroberto int match_len; 400258945Sroberto int max_len; 401258945Sroberto isc_netaddr_t target; 402258945Sroberto u_short af; 403258945Sroberto isc_netaddr_t pfx; 404258945Sroberto int pfx_len; 405258945Sroberto size_t nbytes; 406258945Sroberto unsigned char nbits; 407258945Sroberto unsigned char * pbits; 408258945Sroberto unsigned int octets; 409258945Sroberto 410258945Sroberto match_len = 0; 411258945Sroberto ipap_match = NULL; 412258945Sroberto isc_netaddr_fromsockaddr(&target, 413258945Sroberto (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr); 414258945Sroberto af = (u_short)target.family; 415258945Sroberto INSIST(AF_INET == af || AF_INET6 == af); 416258945Sroberto max_len = (AF_INET6 == af) ? 128 : 32; 417258945Sroberto iter->current.netmask.family = af; 418258945Sroberto for (ipap = iter->ipaaCur->FirstPrefix; 419258945Sroberto ipap != NULL; 420258945Sroberto ipap = ipap->Next) { 421258945Sroberto if (ipap->Address.lpSockaddr->sa_family != af) 422258945Sroberto continue; 423258945Sroberto isc_netaddr_fromsockaddr(&pfx, 424258945Sroberto (isc_sockaddr_t *)ipap->Address.lpSockaddr); 425258945Sroberto pfx_len = ipap->PrefixLength; 426258945Sroberto INSIST(0 <= pfx_len && pfx_len <= max_len); 427258945Sroberto if (pfx_len > match_len && pfx_len < max_len && 428258945Sroberto isc_netaddr_eqprefix(&target, &pfx, pfx_len)) { 429258945Sroberto ipap_match = ipap; 430258945Sroberto match_len = pfx_len; 431258945Sroberto } 432258945Sroberto } 433258945Sroberto if (NULL == ipap_match) { 434258945Sroberto /* presume all-ones mask */ 435258945Sroberto if (AF_INET6 == af) 436258945Sroberto octets = sizeof(iter->current.netmask.type.in6); 437258945Sroberto else 438258945Sroberto octets = sizeof(iter->current.netmask.type.in); 439258945Sroberto memset(&iter->current.netmask.type, 0xFF, octets); 440258945Sroberto return (8 * (unsigned char)octets); 441258945Sroberto } 442258945Sroberto nbytes = match_len / 8; 443258945Sroberto nbits = match_len % 8; 444258945Sroberto memset(&iter->current.netmask.type.in6, 0xFF, nbytes); 445258945Sroberto pbits = (void *)&iter->current.netmask.type.in6; 446258945Sroberto pbits += nbytes; 447258945Sroberto *pbits |= 0xFF << (8 - nbits); 448258945Sroberto return ((unsigned char)match_len); 449258945Sroberto} 450258945Sroberto 451258945Srobertostatic isc_result_t 452258945Srobertointernal_current_GAA(isc_interfaceiter_t *iter) { 453258945Sroberto IP_ADAPTER_ADDRESSES *adap; 454258945Sroberto IP_ADAPTER_UNICAST_ADDRESS *addr; 455258945Sroberto unsigned char prefix_len; 456258945Sroberto 457258945Sroberto REQUIRE(iter->ipaaCur != NULL); 458258945Sroberto REQUIRE(iter->ipuaCur != NULL); 459258945Sroberto adap = iter->ipaaCur; 460258945Sroberto addr = iter->ipuaCur; 461258945Sroberto if (IpDadStatePreferred != addr->DadState) 462258945Sroberto return (ISC_R_IGNORE); 463258945Sroberto memset(&iter->current, 0, sizeof(iter->current)); 464258945Sroberto iter->current.af = addr->Address.lpSockaddr->sa_family; 465258945Sroberto isc_netaddr_fromsockaddr(&iter->current.address, 466258945Sroberto (isc_sockaddr_t *)addr->Address.lpSockaddr); 467258945Sroberto if (AF_INET6 == iter->current.af) 468258945Sroberto iter->current.ifindex = adap->Ipv6IfIndex; 469258945Sroberto iter->current.name[0] = '\0'; 470258945Sroberto WideCharToMultiByte( 471258945Sroberto CP_ACP, 472258945Sroberto 0, 473258945Sroberto adap->FriendlyName, 474258945Sroberto -1, 475258945Sroberto iter->current.name, 476258945Sroberto sizeof(iter->current.name), 477258945Sroberto NULL, 478258945Sroberto NULL); 479258945Sroberto iter->current.name[sizeof(iter->current.name) - 1] = '\0'; 480258945Sroberto if (IfOperStatusUp == adap->OperStatus) 481258945Sroberto iter->current.flags |= INTERFACE_F_UP; 482258945Sroberto if (IF_TYPE_PPP == adap->IfType) 483258945Sroberto iter->current.flags |= INTERFACE_F_POINTTOPOINT; 484258945Sroberto else if (IF_TYPE_SOFTWARE_LOOPBACK == adap->IfType) 485258945Sroberto iter->current.flags |= INTERFACE_F_LOOPBACK; 486258945Sroberto if ((IP_ADAPTER_NO_MULTICAST & adap->Flags) == 0) 487258945Sroberto iter->current.flags |= INTERFACE_F_MULTICAST; 488258945Sroberto if (IpSuffixOriginRandom == addr->SuffixOrigin) 489258945Sroberto iter->current.flags |= INTERFACE_F_PRIVACY; 490258945Sroberto 491258945Sroberto prefix_len = GAA_find_prefix(iter); 492258945Sroberto /* I'm failing to see a broadcast flag via GAA */ 493258945Sroberto if (AF_INET == iter->current.af && prefix_len < 32 && 494258945Sroberto (INTERFACE_F_LOOPBACK & iter->current.flags) == 0) { 495258945Sroberto iter->current.flags |= INTERFACE_F_BROADCAST; 496258945Sroberto get_broadcastaddr(&iter->current.broadcast, 497258945Sroberto &iter->current.address, 498258945Sroberto &iter->current.netmask); 499258945Sroberto } 500258945Sroberto return (ISC_R_SUCCESS); 501258945Sroberto} 502258945Sroberto 503258945Sroberto/* 504258945Sroberto * Get information about the current interface to iter->current. 505258945Sroberto * If successful, return ISC_R_SUCCESS. 506258945Sroberto * If the interface has an unsupported address family, or if 507258945Sroberto * some operation on it fails, return ISC_R_IGNORE to make 508258945Sroberto * the higher-level iterator code ignore it. 509258945Sroberto */ 510258945Sroberto 511258945Srobertostatic isc_result_t 512258945Srobertointernal_current(isc_interfaceiter_t *iter) { 513258945Sroberto BOOL ifNamed = FALSE; 514258945Sroberto unsigned long flags; 515258945Sroberto 516258945Sroberto REQUIRE(VALID_IFITER(iter)); 517258945Sroberto REQUIRE(iter->numIF >= 0); 518258945Sroberto 519258945Sroberto memset(&iter->current, 0, sizeof(iter->current)); 520258945Sroberto iter->current.af = AF_INET; 521258945Sroberto 522258945Sroberto isc_netaddr_fromsockaddr(&iter->current.address, 523258945Sroberto (isc_sockaddr_t *)&(iter->IFData.iiAddress)); 524258945Sroberto 525258945Sroberto /* 526258945Sroberto * Get interface flags. 527258945Sroberto */ 528258945Sroberto 529258945Sroberto iter->current.flags = 0; 530258945Sroberto flags = iter->IFData.iiFlags; 531258945Sroberto 532258945Sroberto if ((flags & IFF_UP) != 0) 533258945Sroberto iter->current.flags |= INTERFACE_F_UP; 534258945Sroberto 535258945Sroberto if ((flags & IFF_BROADCAST) != 0) 536258945Sroberto iter->current.flags |= INTERFACE_F_BROADCAST; 537258945Sroberto 538258945Sroberto if ((flags & IFF_MULTICAST) != 0) 539258945Sroberto iter->current.flags |= INTERFACE_F_MULTICAST; 540258945Sroberto 541258945Sroberto if ((flags & IFF_POINTTOPOINT) != 0) { 542258945Sroberto iter->current.flags |= INTERFACE_F_POINTTOPOINT; 543258945Sroberto snprintf(iter->current.name, sizeof(iter->current.name), 544258945Sroberto "PPP %d", iter->numIF); 545258945Sroberto ifNamed = TRUE; 546258945Sroberto } 547258945Sroberto 548258945Sroberto if ((flags & IFF_LOOPBACK) != 0) { 549258945Sroberto iter->current.flags |= INTERFACE_F_LOOPBACK; 550258945Sroberto snprintf(iter->current.name, sizeof(iter->current.name), 551258945Sroberto "v4loop %d", iter->numIF); 552258945Sroberto ifNamed = TRUE; 553258945Sroberto } 554258945Sroberto 555258945Sroberto /* 556258945Sroberto * If the interface is point-to-point, get the destination address. 557258945Sroberto */ 558258945Sroberto if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) 559258945Sroberto isc_netaddr_fromsockaddr(&iter->current.dstaddress, 560258945Sroberto (isc_sockaddr_t *)&(iter->IFData.iiBroadcastAddress)); 561258945Sroberto 562258945Sroberto /* 563258945Sroberto * Get the network mask. 564258945Sroberto */ 565258945Sroberto isc_netaddr_fromsockaddr(&iter->current.netmask, 566258945Sroberto (isc_sockaddr_t *)&(iter->IFData.iiNetmask)); 567258945Sroberto 568258945Sroberto /* 569258945Sroberto * If the interface is broadcast, get the broadcast address, 570258945Sroberto * based on the unicast address and network mask. 571258945Sroberto */ 572258945Sroberto if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) 573258945Sroberto get_broadcastaddr(&iter->current.broadcast, 574258945Sroberto &iter->current.address, 575258945Sroberto &iter->current.netmask); 576258945Sroberto 577258945Sroberto if (ifNamed == FALSE) 578258945Sroberto snprintf(iter->current.name, sizeof(iter->current.name), 579258945Sroberto "IPv4 %d", iter->numIF); 580258945Sroberto 581258945Sroberto return (ISC_R_SUCCESS); 582258945Sroberto} 583258945Sroberto 584258945Srobertostatic isc_result_t 585258945Srobertointernal_current6(isc_interfaceiter_t *iter) { 586258945Sroberto BOOL ifNamed = FALSE; 587258945Sroberto struct sockaddr_in6 *psa6; 588258945Sroberto BOOL localhostSeen; 589258945Sroberto int i; 590258945Sroberto 591258945Sroberto REQUIRE(VALID_IFITER(iter)); 592258945Sroberto REQUIRE(iter->pos6 >= 0); 593258945Sroberto REQUIRE(iter->buf6 != 0); 594258945Sroberto 595258945Sroberto memset(&iter->current, 0, sizeof(iter->current)); 596258945Sroberto iter->current.af = AF_INET6; 597258945Sroberto 598258945Sroberto /* 599258945Sroberto * synthesize localhost ::1 before returning the rest, if ::1 600258945Sroberto * is not on the list. 601258945Sroberto */ 602258945Sroberto if (iter->pos6 >= (unsigned)iter->buf6->iAddressCount) { 603258945Sroberto localhostSeen = FALSE; 604258945Sroberto for (i = 0; i < iter->buf6->iAddressCount; i++) { 605258945Sroberto psa6 = (struct sockaddr_in6 *) 606258945Sroberto iter->buf6->Address[i].lpSockaddr; 607258945Sroberto if (!memcmp(&iter->loop__1, &psa6->sin6_addr, 608258945Sroberto sizeof(iter->loop__1))) { 609258945Sroberto localhostSeen = TRUE; 610258945Sroberto break; 611258945Sroberto } 612258945Sroberto } 613258945Sroberto if (localhostSeen) 614258945Sroberto iter->pos6 = iter->buf6->iAddressCount - 1; 615258945Sroberto } 616258945Sroberto 617258945Sroberto if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) { 618258945Sroberto isc_netaddr_fromsockaddr(&iter->current.address, 619258945Sroberto (isc_sockaddr_t *)iter->buf6->Address[iter->pos6].lpSockaddr); 620258945Sroberto } else { 621258945Sroberto iter->current.address.family = AF_INET6; 622258945Sroberto memcpy(&iter->current.address.type.in6, &iter->loop__1, 623258945Sroberto sizeof(iter->current.address.type.in6)); 624258945Sroberto } 625258945Sroberto 626258945Sroberto /* 627258945Sroberto * Get interface flags. 628258945Sroberto */ 629258945Sroberto 630258945Sroberto iter->current.flags = INTERFACE_F_UP | INTERFACE_F_MULTICAST; 631258945Sroberto 632258945Sroberto if (!memcmp(&iter->current.address.type.in6, &iter->loop__1, 633258945Sroberto sizeof(iter->current.address.type.in6)) || 634258945Sroberto !memcmp(&iter->current.address.type.in6, &iter->loopfe80__1, 635258945Sroberto sizeof(iter->current.address.type.in6))) { 636258945Sroberto 637258945Sroberto iter->current.flags |= INTERFACE_F_LOOPBACK; 638258945Sroberto snprintf(iter->current.name, sizeof(iter->current.name), 639258945Sroberto "v6loop %d", 640258945Sroberto iter->buf6->iAddressCount - iter->pos6); 641258945Sroberto ifNamed = TRUE; 642258945Sroberto } 643258945Sroberto 644258945Sroberto if (ifNamed == FALSE) 645258945Sroberto snprintf(iter->current.name, sizeof(iter->current.name), 646258945Sroberto "IPv6 %d", 647258945Sroberto iter->buf6->iAddressCount - iter->pos6); 648258945Sroberto 649258945Sroberto memset(iter->current.netmask.type.in6.s6_addr, 0xff, 650258945Sroberto sizeof(iter->current.netmask.type.in6.s6_addr)); 651258945Sroberto iter->current.netmask.family = AF_INET6; 652258945Sroberto return (ISC_R_SUCCESS); 653258945Sroberto} 654258945Sroberto 655258945Srobertostatic isc_result_t 656258945Srobertointernal_next_GAA(isc_interfaceiter_t *iter) { 657258945Sroberto REQUIRE(use_GAA); 658258945Sroberto if (NULL == iter->ipaaCur) 659258945Sroberto return (ISC_R_NOMORE); 660258945Sroberto if (NULL == iter->ipuaCur) 661258945Sroberto iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; 662258945Sroberto else 663258945Sroberto iter->ipuaCur = iter->ipuaCur->Next; 664258945Sroberto while (NULL == iter->ipuaCur) { 665258945Sroberto iter->ipaaCur = iter->ipaaCur->Next; 666258945Sroberto if (NULL == iter->ipaaCur) 667258945Sroberto return (ISC_R_NOMORE); 668258945Sroberto iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; 669258945Sroberto } 670258945Sroberto return (ISC_R_SUCCESS); 671258945Sroberto} 672258945Sroberto 673258945Sroberto/* 674258945Sroberto * Step the iterator to the next interface. Unlike 675258945Sroberto * isc_interfaceiter_next(), this may leave the iterator 676258945Sroberto * positioned on an interface that will ultimately 677258945Sroberto * be ignored. Return ISC_R_NOMORE if there are no more 678258945Sroberto * interfaces, otherwise ISC_R_SUCCESS. 679258945Sroberto */ 680258945Srobertostatic isc_result_t 681258945Srobertointernal_next(isc_interfaceiter_t *iter) { 682258945Sroberto if (iter->numIF >= iter->v4IF) 683258945Sroberto return (ISC_R_NOMORE); 684258945Sroberto 685258945Sroberto /* 686258945Sroberto * The first one needs to be set up to point to the last 687258945Sroberto * Element of the array. Go to the end and back up 688258945Sroberto * Microsoft's implementation is peculiar for returning 689258945Sroberto * the list in reverse order 690258945Sroberto */ 691258945Sroberto 692258945Sroberto if (iter->numIF == 0) 693258945Sroberto iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF)); 694258945Sroberto 695258945Sroberto iter->pos4--; 696258945Sroberto if (&(iter->pos4) < &(iter->buf4)) 697258945Sroberto return (ISC_R_NOMORE); 698258945Sroberto 699258945Sroberto memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO)); 700258945Sroberto memcpy(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO)); 701258945Sroberto iter->numIF++; 702258945Sroberto 703258945Sroberto return (ISC_R_SUCCESS); 704258945Sroberto} 705258945Sroberto 706258945Srobertostatic isc_result_t 707258945Srobertointernal_next6(isc_interfaceiter_t *iter) { 708258945Sroberto if (iter->pos6 == 0) 709258945Sroberto return (ISC_R_NOMORE); 710258945Sroberto iter->pos6--; 711258945Sroberto return (ISC_R_SUCCESS); 712258945Sroberto} 713258945Sroberto 714258945Srobertoisc_result_t 715258945Srobertoisc_interfaceiter_current(isc_interfaceiter_t *iter, 716258945Sroberto isc_interface_t *ifdata) { 717258945Sroberto REQUIRE(iter->result == ISC_R_SUCCESS); 718258945Sroberto memcpy(ifdata, &iter->current, sizeof(*ifdata)); 719258945Sroberto return (ISC_R_SUCCESS); 720258945Sroberto} 721258945Sroberto 722258945Srobertoisc_result_t 723258945Srobertoisc_interfaceiter_first(isc_interfaceiter_t *iter) { 724258945Sroberto REQUIRE(VALID_IFITER(iter)); 725258945Sroberto REQUIRE(use_GAA_determined); 726258945Sroberto /* 727258945Sroberto * SIO_ADDRESS_LIST_QUERY (used to query IPv6 addresses) 728258945Sroberto * intentionally omits localhost addresses [::1] and [::fe80] in 729258945Sroberto * some cases. ntpd depends on enumerating [::1] to listen on 730258945Sroberto * it, and ntpq and ntpdc default to "localhost" as the target, 731258945Sroberto * so they will attempt to talk to [::1]:123 and fail. This 732258945Sroberto * means we need to synthesize ::1, which we will do first, 733258945Sroberto * hence iAddressCount + 1. internal_next6() will decrement 734258945Sroberto * it before the first use as an index, and internal_current6() 735258945Sroberto * will treat pos6 == iAddressCount as a sign to synthesize 736258945Sroberto * [::1] if needed. 737258945Sroberto */ 738258945Sroberto if (!use_GAA && iter->buf6 != NULL) 739258945Sroberto iter->pos6 = iter->buf6->iAddressCount + 1; 740258945Sroberto iter->result = ISC_R_SUCCESS; 741258945Sroberto return (isc_interfaceiter_next(iter)); 742258945Sroberto} 743258945Sroberto 744258945Srobertoisc_result_t 745258945Srobertoisc_interfaceiter_next(isc_interfaceiter_t *iter) { 746258945Sroberto isc_result_t result; 747258945Sroberto 748258945Sroberto REQUIRE(VALID_IFITER(iter)); 749258945Sroberto REQUIRE(iter->result == ISC_R_SUCCESS); 750258945Sroberto REQUIRE(use_GAA_determined); 751258945Sroberto 752258945Sroberto if (use_GAA) { 753258945Sroberto do { 754258945Sroberto result = internal_next_GAA(iter); 755258945Sroberto if (ISC_R_NOMORE == result) 756258945Sroberto goto set_result; 757258945Sroberto result = internal_current_GAA(iter); 758258945Sroberto } while (ISC_R_IGNORE == result); 759258945Sroberto goto set_result; 760258945Sroberto } 761258945Sroberto 762258945Sroberto for (;;) { 763258945Sroberto result = internal_next(iter); 764258945Sroberto if (result == ISC_R_NOMORE) { 765258945Sroberto result = internal_next6(iter); 766258945Sroberto if (result != ISC_R_SUCCESS) 767258945Sroberto break; 768258945Sroberto result = internal_current6(iter); 769258945Sroberto if (result != ISC_R_IGNORE) 770258945Sroberto break; 771258945Sroberto } else if (result != ISC_R_SUCCESS) 772258945Sroberto break; 773258945Sroberto result = internal_current(iter); 774258945Sroberto if (result != ISC_R_IGNORE) 775258945Sroberto break; 776258945Sroberto } 777258945Sroberto set_result: 778258945Sroberto iter->result = result; 779258945Sroberto return (result); 780258945Sroberto} 781258945Sroberto 782258945Srobertovoid 783258945Srobertoisc_interfaceiter_destroy(isc_interfaceiter_t **iterp) { 784258945Sroberto isc_interfaceiter_t *iter; 785258945Sroberto 786258945Sroberto REQUIRE(iterp != NULL); 787258945Sroberto iter = *iterp; 788258945Sroberto REQUIRE(VALID_IFITER(iter)); 789258945Sroberto REQUIRE(use_GAA_determined); 790258945Sroberto 791258945Sroberto if (use_GAA) { 792258945Sroberto REQUIRE(NULL == iter->buf4); 793258945Sroberto REQUIRE(NULL == iter->buf4); 794258945Sroberto if (iter->ipaa != NULL) 795258945Sroberto isc_mem_put(iter->mctx, iter->ipaa, iter->ipaasize); 796258945Sroberto } else { 797258945Sroberto REQUIRE(NULL == iter->ipaa); 798258945Sroberto if (iter->buf4 != NULL) 799258945Sroberto isc_mem_put(iter->mctx, iter->buf4, iter->buf4size); 800258945Sroberto if (iter->buf6 != NULL) 801258945Sroberto isc_mem_put(iter->mctx, iter->buf6, iter->buf6size); 802258945Sroberto } 803258945Sroberto 804258945Sroberto iter->magic = 0; 805258945Sroberto isc_mem_put(iter->mctx, iter, sizeof(*iter)); 806258945Sroberto *iterp = NULL; 807258945Sroberto} 808