1*eabc0478Schristos /* $NetBSD: interfaceiter.c,v 1.2 2024/08/18 20:47:16 christos Exp $ */ 2897be3a4Schristos 3897be3a4Schristos /* 4897be3a4Schristos * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") 5897be3a4Schristos * Copyright (C) 1999-2001 Internet Software Consortium. 6897be3a4Schristos * 7897be3a4Schristos * Permission to use, copy, modify, and/or distribute this software for any 8897be3a4Schristos * purpose with or without fee is hereby granted, provided that the above 9897be3a4Schristos * copyright notice and this permission notice appear in all copies. 10897be3a4Schristos * 11897be3a4Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12897be3a4Schristos * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13897be3a4Schristos * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14897be3a4Schristos * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15897be3a4Schristos * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16897be3a4Schristos * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17897be3a4Schristos * PERFORMANCE OF THIS SOFTWARE. 18897be3a4Schristos */ 19897be3a4Schristos 20897be3a4Schristos /* Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp */ 21897be3a4Schristos 22897be3a4Schristos #include <config.h> 23897be3a4Schristos 24897be3a4Schristos #include <stdio.h> 25897be3a4Schristos #include <stdlib.h> 26897be3a4Schristos #include <errno.h> 27897be3a4Schristos #include <sys/types.h> 28897be3a4Schristos #include <winsock2.h> 29897be3a4Schristos #include <ws2tcpip.h> 30897be3a4Schristos #include <gaa_compat.h> 31897be3a4Schristos 32897be3a4Schristos #include <isc/interfaceiter.h> 33897be3a4Schristos #include <isc/mem.h> 34897be3a4Schristos #include <isc/result.h> 35897be3a4Schristos #include <isc/string.h> 36897be3a4Schristos #include <isc/strerror.h> 37897be3a4Schristos #include <isc/types.h> 38897be3a4Schristos #include <isc/util.h> 39897be3a4Schristos #include <isc/win32os.h> 40897be3a4Schristos 41897be3a4Schristos void InitSockets(void); 42897be3a4Schristos 43897be3a4Schristos 44897be3a4Schristos #define IFITER_MAGIC 0x49464954U /* IFIT. */ 45897be3a4Schristos #define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC) 46897be3a4Schristos 47897be3a4Schristos struct isc_interfaceiter { 48897be3a4Schristos unsigned int magic; /* Magic number. */ 49897be3a4Schristos /* common fields */ 50897be3a4Schristos isc_mem_t *mctx; 51897be3a4Schristos isc_interface_t current; /* Current interface data. */ 52897be3a4Schristos isc_result_t result; /* Last result code. */ 53897be3a4Schristos /* fields used if GetAdaptersAddresses is available at runtime */ 54897be3a4Schristos IP_ADAPTER_ADDRESSES * ipaa; /* GAA() result buffer */ 55897be3a4Schristos ULONG ipaasize; /* Bytes allocated */ 56897be3a4Schristos IP_ADAPTER_ADDRESSES * ipaaCur; /* enumeration position */ 57897be3a4Schristos IP_ADAPTER_UNICAST_ADDRESS *ipuaCur; /* enumeration subposition */ 58897be3a4Schristos /* fields used for the older address enumeration ioctls */ 59897be3a4Schristos SOCKET socket; 60897be3a4Schristos INTERFACE_INFO IFData; /* Current Interface Info */ 61897be3a4Schristos int numIF; /* Current Interface count */ 62897be3a4Schristos int v4IF; /* Number of IPv4 Interfaces */ 63897be3a4Schristos INTERFACE_INFO *buf4; /* Buffer for WSAIoctl data. */ 64897be3a4Schristos unsigned int buf4size; /* Bytes allocated. */ 65897be3a4Schristos INTERFACE_INFO *pos4; /* Current offset in IF List */ 66897be3a4Schristos SOCKET_ADDRESS_LIST *buf6; 67897be3a4Schristos unsigned int buf6size; /* Bytes allocated. */ 68897be3a4Schristos unsigned int pos6; /* buf6 index, counts down */ 69897be3a4Schristos struct in6_addr loop__1; /* ::1 node-scope localhost */ 70897be3a4Schristos struct in6_addr loopfe80__1; /* fe80::1 link-scope localhost */ 71897be3a4Schristos }; 72897be3a4Schristos 73897be3a4Schristos typedef ULONG (WINAPI *PGETADAPTERSADDRESSES)( 74897be3a4Schristos ULONG Family, 75897be3a4Schristos ULONG Flags, 76897be3a4Schristos PVOID Reserved, 77897be3a4Schristos PIP_ADAPTER_ADDRESSES AdapterAddresses, 78897be3a4Schristos PULONG SizePointer 79897be3a4Schristos ); 80897be3a4Schristos 81897be3a4Schristos static isc_boolean_t use_GAA; 82897be3a4Schristos static isc_boolean_t use_GAA_determined; 83897be3a4Schristos static HMODULE hmod_iphlpapi; 84897be3a4Schristos static PGETADAPTERSADDRESSES pGAA; 85897be3a4Schristos 86897be3a4Schristos 87897be3a4Schristos /* 88897be3a4Schristos * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces. 89897be3a4Schristos * We assume no sane system will have more than than 1K of IP addresses on 90897be3a4Schristos * all of its adapters. 91897be3a4Schristos */ 92897be3a4Schristos #define IFCONF_SIZE_INITIAL 16 93897be3a4Schristos #define IFCONF_SIZE_INCREMENT 64 94897be3a4Schristos #define IFCONF_SIZE_MAX 1040 95897be3a4Schristos 96897be3a4Schristos 97897be3a4Schristos /* Common utility functions */ 98897be3a4Schristos 99897be3a4Schristos /* 100897be3a4Schristos * Windows always provides 255.255.255.255 as the the broadcast 101897be3a4Schristos * address. ntpd needs to know the broadcast address which will target 102897be3a4Schristos * only that network interface, not all. Reconstruct it from the 103897be3a4Schristos * address and mask. 104897be3a4Schristos */ 105897be3a4Schristos static void 106897be3a4Schristos get_broadcastaddr(isc_netaddr_t *bcastaddr, isc_netaddr_t *addr, isc_netaddr_t *netmask) { 107897be3a4Schristos 108897be3a4Schristos isc_uint32_t * b; 109897be3a4Schristos isc_uint32_t a, n; 110897be3a4Schristos 111897be3a4Schristos b = (isc_uint32_t *)&bcastaddr->type.in; 112897be3a4Schristos a = *(isc_uint32_t *)&addr->type.in; 113897be3a4Schristos n = *(isc_uint32_t *)&netmask->type.in; 114897be3a4Schristos 115897be3a4Schristos *b = a | ~n; 116897be3a4Schristos } 117897be3a4Schristos 118897be3a4Schristos isc_result_t 119897be3a4Schristos isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { 120897be3a4Schristos char strbuf[ISC_STRERRORSIZE]; 121897be3a4Schristos isc_interfaceiter_t *iter; 122897be3a4Schristos isc_result_t result; 123897be3a4Schristos unsigned int major; 124897be3a4Schristos unsigned int minor; 125897be3a4Schristos unsigned int spmajor; 126897be3a4Schristos ULONG err; 127897be3a4Schristos int tries; 128897be3a4Schristos int error; 129897be3a4Schristos unsigned long bytesReturned = 0; 130897be3a4Schristos 131897be3a4Schristos REQUIRE(mctx != NULL); 132897be3a4Schristos REQUIRE(iterp != NULL); 133897be3a4Schristos REQUIRE(*iterp == NULL); 134897be3a4Schristos 135897be3a4Schristos iter = isc_mem_get(mctx, sizeof(*iter)); 136897be3a4Schristos if (iter == NULL) 137897be3a4Schristos return (ISC_R_NOMEMORY); 138897be3a4Schristos 139897be3a4Schristos InitSockets(); 140897be3a4Schristos 141897be3a4Schristos iter->mctx = mctx; 142897be3a4Schristos iter->ipaa = NULL; 143897be3a4Schristos iter->buf4 = NULL; 144897be3a4Schristos iter->buf6 = NULL; 145897be3a4Schristos iter->pos4 = NULL; 146897be3a4Schristos iter->ipaaCur = NULL; 147897be3a4Schristos iter->ipuaCur = NULL; 148897be3a4Schristos iter->ipaasize = 0; 149897be3a4Schristos iter->pos6 = 0; 150897be3a4Schristos iter->buf6size = 0; 151897be3a4Schristos iter->buf4size = 0; 152897be3a4Schristos iter->result = ISC_R_FAILURE; 153897be3a4Schristos iter->numIF = 0; 154897be3a4Schristos iter->v4IF = 0; 155897be3a4Schristos 156897be3a4Schristos /* 157897be3a4Schristos * Use GetAdaptersAddresses in preference to ioctls when running 158897be3a4Schristos * on Windows XP SP1 or later. Earlier GetAdaptersAddresses do 159897be3a4Schristos * not appear to provide enough information to associate unicast 160897be3a4Schristos * addresses with their prefixes. 161897be3a4Schristos */ 162897be3a4Schristos if (!use_GAA_determined) { 163897be3a4Schristos major = isc_win32os_majorversion(); 164897be3a4Schristos minor = isc_win32os_minorversion(); 165897be3a4Schristos spmajor = isc_win32os_servicepackmajor(); 166897be3a4Schristos if (major > 5 || (5 == major && 167897be3a4Schristos (minor > 1 || (1 == minor && spmajor >= 1)))) { 168897be3a4Schristos if (NULL == hmod_iphlpapi) 169897be3a4Schristos hmod_iphlpapi = LoadLibrary("iphlpapi"); 170897be3a4Schristos if (NULL != hmod_iphlpapi) 171897be3a4Schristos pGAA = (PGETADAPTERSADDRESSES) 172897be3a4Schristos GetProcAddress( 173897be3a4Schristos hmod_iphlpapi, 174897be3a4Schristos "GetAdaptersAddresses"); 175897be3a4Schristos if (NULL != pGAA) 176897be3a4Schristos use_GAA = ISC_TRUE; 177897be3a4Schristos } 178897be3a4Schristos use_GAA_determined = ISC_TRUE; 179897be3a4Schristos } 180897be3a4Schristos 181897be3a4Schristos if (!use_GAA) 182897be3a4Schristos goto use_ioctls; 183897be3a4Schristos 184897be3a4Schristos iter->ipaasize = 16 * 1024; 185897be3a4Schristos 186897be3a4Schristos for (tries = 0; tries < 5; tries++) { 187897be3a4Schristos iter->ipaa = isc_mem_reallocate(mctx, iter->ipaa, 188897be3a4Schristos iter->ipaasize); 189897be3a4Schristos if (NULL == iter->ipaa) { 190897be3a4Schristos result = ISC_R_NOMEMORY; 191897be3a4Schristos goto put_iter; 192897be3a4Schristos } 193897be3a4Schristos err = (*pGAA)( 194897be3a4Schristos AF_UNSPEC, 195897be3a4Schristos GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST, 196897be3a4Schristos NULL, 197897be3a4Schristos iter->ipaa, 198897be3a4Schristos &iter->ipaasize); 199897be3a4Schristos if (NO_ERROR == err || ERROR_BUFFER_OVERFLOW != err) 200897be3a4Schristos break; 201897be3a4Schristos } 202897be3a4Schristos 203897be3a4Schristos if (NO_ERROR != err) { 204897be3a4Schristos isc__strerror(err, strbuf, sizeof(strbuf)); 205897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 206897be3a4Schristos "GetAdaptersAddresses: %s", 207897be3a4Schristos strbuf); 208897be3a4Schristos result = ISC_R_UNEXPECTED; 209897be3a4Schristos goto gaa_failure; 210897be3a4Schristos } 211897be3a4Schristos 212897be3a4Schristos iter->ipaaCur = iter->ipaa; 213897be3a4Schristos goto success; 214897be3a4Schristos 215897be3a4Schristos use_ioctls: 216897be3a4Schristos /* 217897be3a4Schristos * Create an unbound datagram socket to do the 218897be3a4Schristos * SIO_GET_INTERFACE_LIST WSAIoctl on. 219897be3a4Schristos */ 220897be3a4Schristos if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 221897be3a4Schristos error = WSAGetLastError(); 222897be3a4Schristos if (error == WSAEAFNOSUPPORT) 223897be3a4Schristos goto inet6_only; 224897be3a4Schristos isc__strerror(error, strbuf, sizeof(strbuf)); 225897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 226897be3a4Schristos "making interface scan socket: %s", 227897be3a4Schristos strbuf); 228897be3a4Schristos result = ISC_R_UNEXPECTED; 229897be3a4Schristos goto put_iter; 230897be3a4Schristos } 231897be3a4Schristos 232897be3a4Schristos /* 233897be3a4Schristos * Get the interface configuration, allocating more memory if 234897be3a4Schristos * necessary. 235897be3a4Schristos */ 236897be3a4Schristos iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO); 237897be3a4Schristos 238897be3a4Schristos for (;;) { 239897be3a4Schristos iter->buf4 = isc_mem_get(mctx, iter->buf4size); 240897be3a4Schristos if (iter->buf4 == NULL) { 241897be3a4Schristos result = ISC_R_NOMEMORY; 242897be3a4Schristos goto alloc_failure; 243897be3a4Schristos } 244897be3a4Schristos 245897be3a4Schristos if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST, 246897be3a4Schristos 0, 0, iter->buf4, iter->buf4size, 247897be3a4Schristos &bytesReturned, 0, 0) == SOCKET_ERROR) 248897be3a4Schristos { 249897be3a4Schristos error = WSAGetLastError(); 250897be3a4Schristos if (error != WSAEFAULT && error != WSAENOBUFS) { 251897be3a4Schristos errno = error; 252897be3a4Schristos isc__strerror(error, strbuf, sizeof(strbuf)); 253897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 254897be3a4Schristos "get interface configuration: %s", 255897be3a4Schristos strbuf); 256897be3a4Schristos result = ISC_R_UNEXPECTED; 257897be3a4Schristos goto ioctl_failure; 258897be3a4Schristos } 259897be3a4Schristos /* 260897be3a4Schristos * EINVAL. Retry with a bigger buffer. 261897be3a4Schristos */ 262897be3a4Schristos } else { 263897be3a4Schristos /* 264897be3a4Schristos * The WSAIoctl succeeded. 265897be3a4Schristos * If the number of the returned bytes is the same 266897be3a4Schristos * as the buffer size, we will grow it just in 267897be3a4Schristos * case and retry. 268897be3a4Schristos */ 269897be3a4Schristos if (bytesReturned > 0 && 270897be3a4Schristos (bytesReturned < iter->buf4size)) 271897be3a4Schristos break; 272897be3a4Schristos } 273897be3a4Schristos if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) { 274897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 275897be3a4Schristos "get interface configuration: " 276897be3a4Schristos "maximum buffer size exceeded"); 277897be3a4Schristos result = ISC_R_UNEXPECTED; 278897be3a4Schristos goto ioctl_failure; 279897be3a4Schristos } 280897be3a4Schristos isc_mem_put(mctx, iter->buf4, iter->buf4size); 281897be3a4Schristos 282897be3a4Schristos iter->buf4size += IFCONF_SIZE_INCREMENT * 283897be3a4Schristos sizeof(INTERFACE_INFO); 284897be3a4Schristos } 285897be3a4Schristos 286897be3a4Schristos /* 287897be3a4Schristos * A newly created iterator has an undefined position 288897be3a4Schristos * until isc_interfaceiter_first() is called. 289897be3a4Schristos */ 290897be3a4Schristos iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO); 291897be3a4Schristos 292897be3a4Schristos /* We don't need the socket any more, so close it */ 293897be3a4Schristos closesocket(iter->socket); 294897be3a4Schristos 295897be3a4Schristos inet6_only: 296897be3a4Schristos /* 297897be3a4Schristos * Create an unbound datagram socket to do the 298897be3a4Schristos * SIO_ADDRESS_LIST_QUERY WSAIoctl on. 299897be3a4Schristos */ 300897be3a4Schristos if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 301897be3a4Schristos error = WSAGetLastError(); 302897be3a4Schristos if (error == WSAEAFNOSUPPORT) 303897be3a4Schristos goto success; 304897be3a4Schristos isc__strerror(error, strbuf, sizeof(strbuf)); 305897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 306897be3a4Schristos "making interface scan socket: %s", 307897be3a4Schristos strbuf); 308897be3a4Schristos result = ISC_R_UNEXPECTED; 309897be3a4Schristos goto put_iter; 310897be3a4Schristos } 311897be3a4Schristos 312897be3a4Schristos /* 313897be3a4Schristos * Get the interface configuration, allocating more memory if 314897be3a4Schristos * necessary. 315897be3a4Schristos */ 316897be3a4Schristos iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) + 317897be3a4Schristos IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS); 318897be3a4Schristos 319897be3a4Schristos for (;;) { 320897be3a4Schristos iter->buf6 = isc_mem_get(mctx, iter->buf6size); 321897be3a4Schristos if (iter->buf6 == NULL) { 322897be3a4Schristos result = ISC_R_NOMEMORY; 323897be3a4Schristos goto ioctl_failure; 324897be3a4Schristos } 325897be3a4Schristos 326897be3a4Schristos if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY, 327897be3a4Schristos 0, 0, iter->buf6, iter->buf6size, 328897be3a4Schristos &bytesReturned, 0, 0) == SOCKET_ERROR) 329897be3a4Schristos { 330897be3a4Schristos error = WSAGetLastError(); 331897be3a4Schristos if (error != WSAEFAULT && error != WSAENOBUFS) { 332897be3a4Schristos errno = error; 333897be3a4Schristos isc__strerror(error, strbuf, sizeof(strbuf)); 334897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 335897be3a4Schristos "sio address list query: %s", 336897be3a4Schristos strbuf); 337897be3a4Schristos result = ISC_R_UNEXPECTED; 338897be3a4Schristos goto ioctl6_failure; 339897be3a4Schristos } 340897be3a4Schristos /* 341897be3a4Schristos * EINVAL. Retry with a bigger buffer. 342897be3a4Schristos */ 343897be3a4Schristos } else 344897be3a4Schristos break; 345897be3a4Schristos 346897be3a4Schristos if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) { 347897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, 348897be3a4Schristos "get interface configuration: " 349897be3a4Schristos "maximum buffer size exceeded"); 350897be3a4Schristos result = ISC_R_UNEXPECTED; 351897be3a4Schristos goto ioctl6_failure; 352897be3a4Schristos } 353897be3a4Schristos isc_mem_put(mctx, iter->buf6, iter->buf6size); 354897be3a4Schristos 355897be3a4Schristos iter->buf6size += IFCONF_SIZE_INCREMENT * 356897be3a4Schristos sizeof(SOCKET_ADDRESS); 357897be3a4Schristos } 358897be3a4Schristos 359897be3a4Schristos /* 360897be3a4Schristos * initialize loop__1 to [::1] and loopfe80__1 to [fe80::1]. 361897be3a4Schristos * used by internal_current6(). 362897be3a4Schristos */ 363897be3a4Schristos memset(&iter->loop__1, 0, sizeof(iter->loop__1)); 364897be3a4Schristos memset(&iter->loopfe80__1, 0, sizeof(iter->loopfe80__1)); 365897be3a4Schristos iter->loop__1.s6_addr[15] = 1; 366897be3a4Schristos iter->loopfe80__1.s6_addr[15] = 1; 367897be3a4Schristos iter->loopfe80__1.s6_addr[0] = 0xfe; 368897be3a4Schristos iter->loopfe80__1.s6_addr[1] = 0x80; 369897be3a4Schristos 370897be3a4Schristos closesocket(iter->socket); 371897be3a4Schristos 372897be3a4Schristos success: 373897be3a4Schristos iter->magic = IFITER_MAGIC; 374897be3a4Schristos *iterp = iter; 375897be3a4Schristos return (ISC_R_SUCCESS); 376897be3a4Schristos 377897be3a4Schristos gaa_failure: 378897be3a4Schristos isc_mem_put(mctx, iter->ipaa, iter->ipaasize); 379897be3a4Schristos goto put_iter; 380897be3a4Schristos 381897be3a4Schristos ioctl6_failure: 382897be3a4Schristos isc_mem_put(mctx, iter->buf6, iter->buf6size); 383897be3a4Schristos 384897be3a4Schristos ioctl_failure: 385897be3a4Schristos if (iter->buf4 != NULL) 386897be3a4Schristos isc_mem_put(mctx, iter->buf4, iter->buf4size); 387897be3a4Schristos 388897be3a4Schristos alloc_failure: 389897be3a4Schristos if (iter->socket >= 0) 390897be3a4Schristos (void) closesocket(iter->socket); 391897be3a4Schristos 392897be3a4Schristos put_iter: 393897be3a4Schristos isc_mem_put(mctx, iter, sizeof(*iter)); 394897be3a4Schristos return (result); 395897be3a4Schristos } 396897be3a4Schristos 397897be3a4Schristos static unsigned char 398897be3a4Schristos GAA_find_prefix(isc_interfaceiter_t *iter) { 399897be3a4Schristos IP_ADAPTER_PREFIX * ipap; 400897be3a4Schristos IP_ADAPTER_PREFIX * ipap_match; 401897be3a4Schristos int match_len; 402897be3a4Schristos int max_len; 403897be3a4Schristos isc_netaddr_t target; 404897be3a4Schristos u_short af; 405897be3a4Schristos isc_netaddr_t pfx; 406897be3a4Schristos int pfx_len; 407897be3a4Schristos size_t nbytes; 408897be3a4Schristos unsigned char nbits; 409897be3a4Schristos unsigned char * pbits; 410897be3a4Schristos unsigned int octets; 411897be3a4Schristos 412897be3a4Schristos match_len = 0; 413897be3a4Schristos ipap_match = NULL; 414897be3a4Schristos isc_netaddr_fromsockaddr(&target, 415897be3a4Schristos (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr); 416897be3a4Schristos af = (u_short)target.family; 417897be3a4Schristos INSIST(AF_INET == af || AF_INET6 == af); 418897be3a4Schristos max_len = (AF_INET6 == af) ? 128 : 32; 419897be3a4Schristos iter->current.netmask.family = af; 420897be3a4Schristos for (ipap = iter->ipaaCur->FirstPrefix; 421897be3a4Schristos ipap != NULL; 422897be3a4Schristos ipap = ipap->Next) { 423897be3a4Schristos if (ipap->Address.lpSockaddr->sa_family != af) 424897be3a4Schristos continue; 425897be3a4Schristos isc_netaddr_fromsockaddr(&pfx, 426897be3a4Schristos (isc_sockaddr_t *)ipap->Address.lpSockaddr); 427897be3a4Schristos pfx_len = ipap->PrefixLength; 428897be3a4Schristos INSIST(0 <= pfx_len && pfx_len <= max_len); 429897be3a4Schristos if (pfx_len > match_len && pfx_len < max_len && 430897be3a4Schristos isc_netaddr_eqprefix(&target, &pfx, pfx_len)) { 431897be3a4Schristos ipap_match = ipap; 432897be3a4Schristos match_len = pfx_len; 433897be3a4Schristos } 434897be3a4Schristos } 435897be3a4Schristos if (NULL == ipap_match) { 436897be3a4Schristos /* presume all-ones mask */ 437897be3a4Schristos if (AF_INET6 == af) 438897be3a4Schristos octets = sizeof(iter->current.netmask.type.in6); 439897be3a4Schristos else 440897be3a4Schristos octets = sizeof(iter->current.netmask.type.in); 441897be3a4Schristos memset(&iter->current.netmask.type, 0xFF, octets); 442897be3a4Schristos return (8 * (unsigned char)octets); 443897be3a4Schristos } 444897be3a4Schristos nbytes = match_len / 8; 445897be3a4Schristos nbits = match_len % 8; 446897be3a4Schristos memset(&iter->current.netmask.type.in6, 0xFF, nbytes); 447897be3a4Schristos pbits = (void *)&iter->current.netmask.type.in6; 448897be3a4Schristos pbits += nbytes; 449897be3a4Schristos *pbits |= 0xFF << (8 - nbits); 450897be3a4Schristos return ((unsigned char)match_len); 451897be3a4Schristos } 452897be3a4Schristos 453897be3a4Schristos static isc_result_t 454897be3a4Schristos internal_current_GAA(isc_interfaceiter_t *iter) { 455897be3a4Schristos IP_ADAPTER_ADDRESSES *adap; 456897be3a4Schristos IP_ADAPTER_UNICAST_ADDRESS *addr; 457897be3a4Schristos unsigned char prefix_len; 458897be3a4Schristos 459897be3a4Schristos REQUIRE(iter->ipaaCur != NULL); 460897be3a4Schristos REQUIRE(iter->ipuaCur != NULL); 461897be3a4Schristos adap = iter->ipaaCur; 462897be3a4Schristos addr = iter->ipuaCur; 463897be3a4Schristos if (IpDadStatePreferred != addr->DadState) 464897be3a4Schristos return (ISC_R_IGNORE); 465897be3a4Schristos memset(&iter->current, 0, sizeof(iter->current)); 466897be3a4Schristos iter->current.af = addr->Address.lpSockaddr->sa_family; 467897be3a4Schristos isc_netaddr_fromsockaddr(&iter->current.address, 468897be3a4Schristos (isc_sockaddr_t *)addr->Address.lpSockaddr); 469897be3a4Schristos if (AF_INET6 == iter->current.af) 470897be3a4Schristos iter->current.ifindex = adap->Ipv6IfIndex; 471897be3a4Schristos iter->current.name[0] = '\0'; 472897be3a4Schristos WideCharToMultiByte( 473897be3a4Schristos CP_ACP, 474897be3a4Schristos 0, 475897be3a4Schristos adap->FriendlyName, 476897be3a4Schristos -1, 477897be3a4Schristos iter->current.name, 478897be3a4Schristos sizeof(iter->current.name), 479897be3a4Schristos NULL, 480897be3a4Schristos NULL); 481897be3a4Schristos iter->current.name[sizeof(iter->current.name) - 1] = '\0'; 482897be3a4Schristos if (IfOperStatusUp == adap->OperStatus) 483897be3a4Schristos iter->current.flags |= INTERFACE_F_UP; 484897be3a4Schristos if (IF_TYPE_PPP == adap->IfType) 485897be3a4Schristos iter->current.flags |= INTERFACE_F_POINTTOPOINT; 486897be3a4Schristos else if (IF_TYPE_SOFTWARE_LOOPBACK == adap->IfType) 487897be3a4Schristos iter->current.flags |= INTERFACE_F_LOOPBACK; 488897be3a4Schristos if ((IP_ADAPTER_NO_MULTICAST & adap->Flags) == 0) 489897be3a4Schristos iter->current.flags |= INTERFACE_F_MULTICAST; 490897be3a4Schristos if (IpSuffixOriginRandom == addr->SuffixOrigin) 491897be3a4Schristos iter->current.flags |= INTERFACE_F_PRIVACY; 492897be3a4Schristos 493897be3a4Schristos prefix_len = GAA_find_prefix(iter); 494897be3a4Schristos /* I'm failing to see a broadcast flag via GAA */ 495897be3a4Schristos if (AF_INET == iter->current.af && prefix_len < 32 && 496897be3a4Schristos (INTERFACE_F_LOOPBACK & iter->current.flags) == 0) { 497897be3a4Schristos iter->current.flags |= INTERFACE_F_BROADCAST; 498897be3a4Schristos get_broadcastaddr(&iter->current.broadcast, 499897be3a4Schristos &iter->current.address, 500897be3a4Schristos &iter->current.netmask); 501897be3a4Schristos } 502897be3a4Schristos return (ISC_R_SUCCESS); 503897be3a4Schristos } 504897be3a4Schristos 505897be3a4Schristos /* 506897be3a4Schristos * Get information about the current interface to iter->current. 507897be3a4Schristos * If successful, return ISC_R_SUCCESS. 508897be3a4Schristos * If the interface has an unsupported address family, or if 509897be3a4Schristos * some operation on it fails, return ISC_R_IGNORE to make 510897be3a4Schristos * the higher-level iterator code ignore it. 511897be3a4Schristos */ 512897be3a4Schristos 513897be3a4Schristos static isc_result_t 514897be3a4Schristos internal_current(isc_interfaceiter_t *iter) { 515897be3a4Schristos BOOL ifNamed = FALSE; 516897be3a4Schristos unsigned long flags; 517897be3a4Schristos 518897be3a4Schristos REQUIRE(VALID_IFITER(iter)); 519897be3a4Schristos REQUIRE(iter->numIF >= 0); 520897be3a4Schristos 521897be3a4Schristos memset(&iter->current, 0, sizeof(iter->current)); 522897be3a4Schristos iter->current.af = AF_INET; 523897be3a4Schristos 524897be3a4Schristos isc_netaddr_fromsockaddr(&iter->current.address, 525897be3a4Schristos (isc_sockaddr_t *)&(iter->IFData.iiAddress)); 526897be3a4Schristos 527897be3a4Schristos /* 528897be3a4Schristos * Get interface flags. 529897be3a4Schristos */ 530897be3a4Schristos 531897be3a4Schristos iter->current.flags = 0; 532897be3a4Schristos flags = iter->IFData.iiFlags; 533897be3a4Schristos 534897be3a4Schristos if ((flags & IFF_UP) != 0) 535897be3a4Schristos iter->current.flags |= INTERFACE_F_UP; 536897be3a4Schristos 537897be3a4Schristos if ((flags & IFF_BROADCAST) != 0) 538897be3a4Schristos iter->current.flags |= INTERFACE_F_BROADCAST; 539897be3a4Schristos 540897be3a4Schristos if ((flags & IFF_MULTICAST) != 0) 541897be3a4Schristos iter->current.flags |= INTERFACE_F_MULTICAST; 542897be3a4Schristos 543897be3a4Schristos if ((flags & IFF_POINTTOPOINT) != 0) { 544897be3a4Schristos iter->current.flags |= INTERFACE_F_POINTTOPOINT; 545897be3a4Schristos snprintf(iter->current.name, sizeof(iter->current.name), 546897be3a4Schristos "PPP %d", iter->numIF); 547897be3a4Schristos ifNamed = TRUE; 548897be3a4Schristos } 549897be3a4Schristos 550897be3a4Schristos if ((flags & IFF_LOOPBACK) != 0) { 551897be3a4Schristos iter->current.flags |= INTERFACE_F_LOOPBACK; 552897be3a4Schristos snprintf(iter->current.name, sizeof(iter->current.name), 553897be3a4Schristos "v4loop %d", iter->numIF); 554897be3a4Schristos ifNamed = TRUE; 555897be3a4Schristos } 556897be3a4Schristos 557897be3a4Schristos /* 558897be3a4Schristos * If the interface is point-to-point, get the destination address. 559897be3a4Schristos */ 560897be3a4Schristos if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) 561897be3a4Schristos isc_netaddr_fromsockaddr(&iter->current.dstaddress, 562897be3a4Schristos (isc_sockaddr_t *)&(iter->IFData.iiBroadcastAddress)); 563897be3a4Schristos 564897be3a4Schristos /* 565897be3a4Schristos * Get the network mask. 566897be3a4Schristos */ 567897be3a4Schristos isc_netaddr_fromsockaddr(&iter->current.netmask, 568897be3a4Schristos (isc_sockaddr_t *)&(iter->IFData.iiNetmask)); 569897be3a4Schristos 570897be3a4Schristos /* 571897be3a4Schristos * If the interface is broadcast, get the broadcast address, 572897be3a4Schristos * based on the unicast address and network mask. 573897be3a4Schristos */ 574897be3a4Schristos if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) 575897be3a4Schristos get_broadcastaddr(&iter->current.broadcast, 576897be3a4Schristos &iter->current.address, 577897be3a4Schristos &iter->current.netmask); 578897be3a4Schristos 579897be3a4Schristos if (ifNamed == FALSE) 580897be3a4Schristos snprintf(iter->current.name, sizeof(iter->current.name), 581897be3a4Schristos "IPv4 %d", iter->numIF); 582897be3a4Schristos 583897be3a4Schristos return (ISC_R_SUCCESS); 584897be3a4Schristos } 585897be3a4Schristos 586897be3a4Schristos static isc_result_t 587897be3a4Schristos internal_current6(isc_interfaceiter_t *iter) { 588897be3a4Schristos BOOL ifNamed = FALSE; 589897be3a4Schristos struct sockaddr_in6 *psa6; 590897be3a4Schristos BOOL localhostSeen; 591897be3a4Schristos int i; 592897be3a4Schristos 593897be3a4Schristos REQUIRE(VALID_IFITER(iter)); 594897be3a4Schristos REQUIRE(iter->pos6 >= 0); 595897be3a4Schristos REQUIRE(iter->buf6 != 0); 596897be3a4Schristos 597897be3a4Schristos memset(&iter->current, 0, sizeof(iter->current)); 598897be3a4Schristos iter->current.af = AF_INET6; 599897be3a4Schristos 600897be3a4Schristos /* 601897be3a4Schristos * synthesize localhost ::1 before returning the rest, if ::1 602897be3a4Schristos * is not on the list. 603897be3a4Schristos */ 604897be3a4Schristos if (iter->pos6 >= (unsigned)iter->buf6->iAddressCount) { 605897be3a4Schristos localhostSeen = FALSE; 606897be3a4Schristos for (i = 0; i < iter->buf6->iAddressCount; i++) { 607897be3a4Schristos psa6 = (struct sockaddr_in6 *) 608897be3a4Schristos iter->buf6->Address[i].lpSockaddr; 609897be3a4Schristos if (!memcmp(&iter->loop__1, &psa6->sin6_addr, 610897be3a4Schristos sizeof(iter->loop__1))) { 611897be3a4Schristos localhostSeen = TRUE; 612897be3a4Schristos break; 613897be3a4Schristos } 614897be3a4Schristos } 615897be3a4Schristos if (localhostSeen) 616897be3a4Schristos iter->pos6 = iter->buf6->iAddressCount - 1; 617897be3a4Schristos } 618897be3a4Schristos 619897be3a4Schristos if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) { 620897be3a4Schristos isc_netaddr_fromsockaddr(&iter->current.address, 621897be3a4Schristos (isc_sockaddr_t *)iter->buf6->Address[iter->pos6].lpSockaddr); 622897be3a4Schristos } else { 623897be3a4Schristos iter->current.address.family = AF_INET6; 624897be3a4Schristos memcpy(&iter->current.address.type.in6, &iter->loop__1, 625897be3a4Schristos sizeof(iter->current.address.type.in6)); 626897be3a4Schristos } 627897be3a4Schristos 628897be3a4Schristos /* 629897be3a4Schristos * Get interface flags. 630897be3a4Schristos */ 631897be3a4Schristos 632897be3a4Schristos iter->current.flags = INTERFACE_F_UP | INTERFACE_F_MULTICAST; 633897be3a4Schristos 634897be3a4Schristos if (!memcmp(&iter->current.address.type.in6, &iter->loop__1, 635897be3a4Schristos sizeof(iter->current.address.type.in6)) || 636897be3a4Schristos !memcmp(&iter->current.address.type.in6, &iter->loopfe80__1, 637897be3a4Schristos sizeof(iter->current.address.type.in6))) { 638897be3a4Schristos 639897be3a4Schristos iter->current.flags |= INTERFACE_F_LOOPBACK; 640897be3a4Schristos snprintf(iter->current.name, sizeof(iter->current.name), 641897be3a4Schristos "v6loop %d", 642897be3a4Schristos iter->buf6->iAddressCount - iter->pos6); 643897be3a4Schristos ifNamed = TRUE; 644897be3a4Schristos } 645897be3a4Schristos 646897be3a4Schristos if (ifNamed == FALSE) 647897be3a4Schristos snprintf(iter->current.name, sizeof(iter->current.name), 648897be3a4Schristos "IPv6 %d", 649897be3a4Schristos iter->buf6->iAddressCount - iter->pos6); 650897be3a4Schristos 651897be3a4Schristos memset(iter->current.netmask.type.in6.s6_addr, 0xff, 652897be3a4Schristos sizeof(iter->current.netmask.type.in6.s6_addr)); 653897be3a4Schristos iter->current.netmask.family = AF_INET6; 654897be3a4Schristos return (ISC_R_SUCCESS); 655897be3a4Schristos } 656897be3a4Schristos 657897be3a4Schristos static isc_result_t 658897be3a4Schristos internal_next_GAA(isc_interfaceiter_t *iter) { 659897be3a4Schristos REQUIRE(use_GAA); 660897be3a4Schristos if (NULL == iter->ipaaCur) 661897be3a4Schristos return (ISC_R_NOMORE); 662897be3a4Schristos if (NULL == iter->ipuaCur) 663897be3a4Schristos iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; 664897be3a4Schristos else 665897be3a4Schristos iter->ipuaCur = iter->ipuaCur->Next; 666897be3a4Schristos while (NULL == iter->ipuaCur) { 667897be3a4Schristos iter->ipaaCur = iter->ipaaCur->Next; 668897be3a4Schristos if (NULL == iter->ipaaCur) 669897be3a4Schristos return (ISC_R_NOMORE); 670897be3a4Schristos iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; 671897be3a4Schristos } 672897be3a4Schristos return (ISC_R_SUCCESS); 673897be3a4Schristos } 674897be3a4Schristos 675897be3a4Schristos /* 676897be3a4Schristos * Step the iterator to the next interface. Unlike 677897be3a4Schristos * isc_interfaceiter_next(), this may leave the iterator 678897be3a4Schristos * positioned on an interface that will ultimately 679897be3a4Schristos * be ignored. Return ISC_R_NOMORE if there are no more 680897be3a4Schristos * interfaces, otherwise ISC_R_SUCCESS. 681897be3a4Schristos */ 682897be3a4Schristos static isc_result_t 683897be3a4Schristos internal_next(isc_interfaceiter_t *iter) { 684897be3a4Schristos if (iter->numIF >= iter->v4IF) 685897be3a4Schristos return (ISC_R_NOMORE); 686897be3a4Schristos 687897be3a4Schristos /* 688897be3a4Schristos * The first one needs to be set up to point to the last 689897be3a4Schristos * Element of the array. Go to the end and back up 690897be3a4Schristos * Microsoft's implementation is peculiar for returning 691897be3a4Schristos * the list in reverse order 692897be3a4Schristos */ 693897be3a4Schristos 694897be3a4Schristos if (iter->numIF == 0) 695897be3a4Schristos iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF)); 696897be3a4Schristos 697897be3a4Schristos iter->pos4--; 698897be3a4Schristos if (&(iter->pos4) < &(iter->buf4)) 699897be3a4Schristos return (ISC_R_NOMORE); 700897be3a4Schristos 701897be3a4Schristos memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO)); 702897be3a4Schristos memcpy(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO)); 703897be3a4Schristos iter->numIF++; 704897be3a4Schristos 705897be3a4Schristos return (ISC_R_SUCCESS); 706897be3a4Schristos } 707897be3a4Schristos 708897be3a4Schristos static isc_result_t 709897be3a4Schristos internal_next6(isc_interfaceiter_t *iter) { 710897be3a4Schristos if (iter->pos6 == 0) 711897be3a4Schristos return (ISC_R_NOMORE); 712897be3a4Schristos iter->pos6--; 713897be3a4Schristos return (ISC_R_SUCCESS); 714897be3a4Schristos } 715897be3a4Schristos 716897be3a4Schristos isc_result_t 717897be3a4Schristos isc_interfaceiter_current(isc_interfaceiter_t *iter, 718897be3a4Schristos isc_interface_t *ifdata) { 719897be3a4Schristos REQUIRE(iter->result == ISC_R_SUCCESS); 720897be3a4Schristos memcpy(ifdata, &iter->current, sizeof(*ifdata)); 721897be3a4Schristos return (ISC_R_SUCCESS); 722897be3a4Schristos } 723897be3a4Schristos 724897be3a4Schristos isc_result_t 725897be3a4Schristos isc_interfaceiter_first(isc_interfaceiter_t *iter) { 726897be3a4Schristos REQUIRE(VALID_IFITER(iter)); 727897be3a4Schristos REQUIRE(use_GAA_determined); 728897be3a4Schristos /* 729897be3a4Schristos * SIO_ADDRESS_LIST_QUERY (used to query IPv6 addresses) 730897be3a4Schristos * intentionally omits localhost addresses [::1] and [::fe80] in 731897be3a4Schristos * some cases. ntpd depends on enumerating [::1] to listen on 732897be3a4Schristos * it, and ntpq and ntpdc default to "localhost" as the target, 733897be3a4Schristos * so they will attempt to talk to [::1]:123 and fail. This 734897be3a4Schristos * means we need to synthesize ::1, which we will do first, 735897be3a4Schristos * hence iAddressCount + 1. internal_next6() will decrement 736897be3a4Schristos * it before the first use as an index, and internal_current6() 737897be3a4Schristos * will treat pos6 == iAddressCount as a sign to synthesize 738897be3a4Schristos * [::1] if needed. 739897be3a4Schristos */ 740897be3a4Schristos if (!use_GAA && iter->buf6 != NULL) 741897be3a4Schristos iter->pos6 = iter->buf6->iAddressCount + 1; 742897be3a4Schristos iter->result = ISC_R_SUCCESS; 743897be3a4Schristos return (isc_interfaceiter_next(iter)); 744897be3a4Schristos } 745897be3a4Schristos 746897be3a4Schristos isc_result_t 747897be3a4Schristos isc_interfaceiter_next(isc_interfaceiter_t *iter) { 748897be3a4Schristos isc_result_t result; 749897be3a4Schristos 750897be3a4Schristos REQUIRE(VALID_IFITER(iter)); 751897be3a4Schristos REQUIRE(iter->result == ISC_R_SUCCESS); 752897be3a4Schristos REQUIRE(use_GAA_determined); 753897be3a4Schristos 754897be3a4Schristos if (use_GAA) { 755897be3a4Schristos do { 756897be3a4Schristos result = internal_next_GAA(iter); 757897be3a4Schristos if (ISC_R_NOMORE == result) 758897be3a4Schristos goto set_result; 759897be3a4Schristos result = internal_current_GAA(iter); 760897be3a4Schristos } while (ISC_R_IGNORE == result); 761897be3a4Schristos goto set_result; 762897be3a4Schristos } 763897be3a4Schristos 764897be3a4Schristos for (;;) { 765897be3a4Schristos result = internal_next(iter); 766897be3a4Schristos if (result == ISC_R_NOMORE) { 767897be3a4Schristos result = internal_next6(iter); 768897be3a4Schristos if (result != ISC_R_SUCCESS) 769897be3a4Schristos break; 770897be3a4Schristos result = internal_current6(iter); 771897be3a4Schristos if (result != ISC_R_IGNORE) 772897be3a4Schristos break; 773897be3a4Schristos } else if (result != ISC_R_SUCCESS) 774897be3a4Schristos break; 775897be3a4Schristos result = internal_current(iter); 776897be3a4Schristos if (result != ISC_R_IGNORE) 777897be3a4Schristos break; 778897be3a4Schristos } 779897be3a4Schristos set_result: 780897be3a4Schristos iter->result = result; 781897be3a4Schristos return (result); 782897be3a4Schristos } 783897be3a4Schristos 784897be3a4Schristos void 785897be3a4Schristos isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) { 786897be3a4Schristos isc_interfaceiter_t *iter; 787897be3a4Schristos 788897be3a4Schristos REQUIRE(iterp != NULL); 789897be3a4Schristos iter = *iterp; 790897be3a4Schristos REQUIRE(VALID_IFITER(iter)); 791897be3a4Schristos REQUIRE(use_GAA_determined); 792897be3a4Schristos 793897be3a4Schristos if (use_GAA) { 794897be3a4Schristos REQUIRE(NULL == iter->buf4); 795897be3a4Schristos REQUIRE(NULL == iter->buf4); 796897be3a4Schristos if (iter->ipaa != NULL) 797897be3a4Schristos isc_mem_put(iter->mctx, iter->ipaa, iter->ipaasize); 798897be3a4Schristos } else { 799897be3a4Schristos REQUIRE(NULL == iter->ipaa); 800897be3a4Schristos if (iter->buf4 != NULL) 801897be3a4Schristos isc_mem_put(iter->mctx, iter->buf4, iter->buf4size); 802897be3a4Schristos if (iter->buf6 != NULL) 803897be3a4Schristos isc_mem_put(iter->mctx, iter->buf6, iter->buf6size); 804897be3a4Schristos } 805897be3a4Schristos 806897be3a4Schristos iter->magic = 0; 807897be3a4Schristos isc_mem_put(iter->mctx, iter, sizeof(*iter)); 808897be3a4Schristos *iterp = NULL; 809897be3a4Schristos } 810