11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 2023 Brad House
41cb0ef41Sopenharmony_ci *
51cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
61cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
71cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
81cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
101cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
111cb0ef41Sopenharmony_ci *
121cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
131cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
141cb0ef41Sopenharmony_ci * Software.
151cb0ef41Sopenharmony_ci *
161cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
191cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
221cb0ef41Sopenharmony_ci * SOFTWARE.
231cb0ef41Sopenharmony_ci *
241cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_ci#include "ares_setup.h"
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci#ifdef USE_WINSOCK
301cb0ef41Sopenharmony_ci#  include <winsock2.h>
311cb0ef41Sopenharmony_ci#  include <ws2tcpip.h>
321cb0ef41Sopenharmony_ci#  if defined(HAVE_IPHLPAPI_H)
331cb0ef41Sopenharmony_ci#    include <iphlpapi.h>
341cb0ef41Sopenharmony_ci#  endif
351cb0ef41Sopenharmony_ci#  if defined(HAVE_NETIOAPI_H)
361cb0ef41Sopenharmony_ci#    include <netioapi.h>
371cb0ef41Sopenharmony_ci#  endif
381cb0ef41Sopenharmony_ci#endif
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H
411cb0ef41Sopenharmony_ci#  include <sys/types.h>
421cb0ef41Sopenharmony_ci#endif
431cb0ef41Sopenharmony_ci#ifdef HAVE_SYS_SOCKET_H
441cb0ef41Sopenharmony_ci#  include <sys/socket.h>
451cb0ef41Sopenharmony_ci#endif
461cb0ef41Sopenharmony_ci#ifdef HAVE_NET_IF_H
471cb0ef41Sopenharmony_ci#  include <net/if.h>
481cb0ef41Sopenharmony_ci#endif
491cb0ef41Sopenharmony_ci#ifdef HAVE_IFADDRS_H
501cb0ef41Sopenharmony_ci#  include <ifaddrs.h>
511cb0ef41Sopenharmony_ci#endif
521cb0ef41Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H
531cb0ef41Sopenharmony_ci#  include <sys/ioctl.h>
541cb0ef41Sopenharmony_ci#endif
551cb0ef41Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
561cb0ef41Sopenharmony_ci#  include <netinet/in.h>
571cb0ef41Sopenharmony_ci#endif
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci#include "ares.h"
601cb0ef41Sopenharmony_ci#include "ares_private.h"
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_cistatic ares_status_t ares__iface_ips_enumerate(ares__iface_ips_t *ips,
631cb0ef41Sopenharmony_ci                                               const char        *name);
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_citypedef struct {
661cb0ef41Sopenharmony_ci  char                  *name;
671cb0ef41Sopenharmony_ci  struct ares_addr       addr;
681cb0ef41Sopenharmony_ci  unsigned char          netmask;
691cb0ef41Sopenharmony_ci  unsigned int           ll_scope;
701cb0ef41Sopenharmony_ci  ares__iface_ip_flags_t flags;
711cb0ef41Sopenharmony_ci} ares__iface_ip_t;
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_cistruct ares__iface_ips {
741cb0ef41Sopenharmony_ci  ares__iface_ip_t      *ips;
751cb0ef41Sopenharmony_ci  size_t                 cnt;
761cb0ef41Sopenharmony_ci  size_t                 alloc_size;
771cb0ef41Sopenharmony_ci  ares__iface_ip_flags_t enum_flags;
781cb0ef41Sopenharmony_ci};
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_cistatic ares__iface_ips_t *ares__iface_ips_alloc(ares__iface_ip_flags_t flags)
811cb0ef41Sopenharmony_ci{
821cb0ef41Sopenharmony_ci  ares__iface_ips_t *ips = ares_malloc_zero(sizeof(*ips));
831cb0ef41Sopenharmony_ci  if (ips == NULL) {
841cb0ef41Sopenharmony_ci    return NULL;
851cb0ef41Sopenharmony_ci  }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  /* Prealloc 4 entries */
881cb0ef41Sopenharmony_ci  ips->alloc_size = 4;
891cb0ef41Sopenharmony_ci  ips->ips        = ares_malloc_zero(ips->alloc_size * sizeof(*ips->ips));
901cb0ef41Sopenharmony_ci  if (ips->ips == NULL) {
911cb0ef41Sopenharmony_ci    ares_free(ips);
921cb0ef41Sopenharmony_ci    return NULL;
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci  ips->enum_flags = flags;
951cb0ef41Sopenharmony_ci  return ips;
961cb0ef41Sopenharmony_ci}
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_cistatic void ares__iface_ip_destroy(ares__iface_ip_t *ip)
991cb0ef41Sopenharmony_ci{
1001cb0ef41Sopenharmony_ci  if (ip == NULL) {
1011cb0ef41Sopenharmony_ci    return;
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci  ares_free(ip->name);
1041cb0ef41Sopenharmony_ci  memset(ip, 0, sizeof(*ip));
1051cb0ef41Sopenharmony_ci}
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_civoid ares__iface_ips_destroy(ares__iface_ips_t *ips)
1081cb0ef41Sopenharmony_ci{
1091cb0ef41Sopenharmony_ci  size_t i;
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  if (ips == NULL) {
1121cb0ef41Sopenharmony_ci    return;
1131cb0ef41Sopenharmony_ci  }
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  for (i = 0; i < ips->cnt; i++) {
1161cb0ef41Sopenharmony_ci    ares__iface_ip_destroy(&ips->ips[i]);
1171cb0ef41Sopenharmony_ci  }
1181cb0ef41Sopenharmony_ci  ares_free(ips->ips);
1191cb0ef41Sopenharmony_ci  ares_free(ips);
1201cb0ef41Sopenharmony_ci}
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ciares_status_t ares__iface_ips(ares__iface_ips_t    **ips,
1231cb0ef41Sopenharmony_ci                              ares__iface_ip_flags_t flags, const char *name)
1241cb0ef41Sopenharmony_ci{
1251cb0ef41Sopenharmony_ci  ares_status_t status;
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  if (ips == NULL) {
1281cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
1291cb0ef41Sopenharmony_ci  }
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  *ips = ares__iface_ips_alloc(flags);
1321cb0ef41Sopenharmony_ci  if (*ips == NULL) {
1331cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
1341cb0ef41Sopenharmony_ci  }
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci  status = ares__iface_ips_enumerate(*ips, name);
1371cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
1381cb0ef41Sopenharmony_ci    ares__iface_ips_destroy(*ips);
1391cb0ef41Sopenharmony_ci    *ips = NULL;
1401cb0ef41Sopenharmony_ci    return status;
1411cb0ef41Sopenharmony_ci  }
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
1441cb0ef41Sopenharmony_ci}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_cistatic ares_status_t
1471cb0ef41Sopenharmony_ci  ares__iface_ips_add(ares__iface_ips_t *ips, ares__iface_ip_flags_t flags,
1481cb0ef41Sopenharmony_ci                      const char *name, const struct ares_addr *addr,
1491cb0ef41Sopenharmony_ci                      unsigned char netmask, unsigned int ll_scope)
1501cb0ef41Sopenharmony_ci{
1511cb0ef41Sopenharmony_ci  size_t idx;
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  if (ips == NULL || name == NULL || addr == NULL) {
1541cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
1551cb0ef41Sopenharmony_ci  }
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  /* Don't want loopback */
1581cb0ef41Sopenharmony_ci  if (flags & ARES_IFACE_IP_LOOPBACK &&
1591cb0ef41Sopenharmony_ci      !(ips->enum_flags & ARES_IFACE_IP_LOOPBACK)) {
1601cb0ef41Sopenharmony_ci    return ARES_SUCCESS;
1611cb0ef41Sopenharmony_ci  }
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci  /* Don't want offline */
1641cb0ef41Sopenharmony_ci  if (flags & ARES_IFACE_IP_OFFLINE &&
1651cb0ef41Sopenharmony_ci      !(ips->enum_flags & ARES_IFACE_IP_OFFLINE)) {
1661cb0ef41Sopenharmony_ci    return ARES_SUCCESS;
1671cb0ef41Sopenharmony_ci  }
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  /* Check for link-local */
1701cb0ef41Sopenharmony_ci  if (ares__addr_is_linklocal(addr)) {
1711cb0ef41Sopenharmony_ci    flags |= ARES_IFACE_IP_LINKLOCAL;
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci  if (flags & ARES_IFACE_IP_LINKLOCAL &&
1741cb0ef41Sopenharmony_ci      !(ips->enum_flags & ARES_IFACE_IP_LINKLOCAL)) {
1751cb0ef41Sopenharmony_ci    return ARES_SUCCESS;
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci  /* Set address flag based on address provided */
1791cb0ef41Sopenharmony_ci  if (addr->family == AF_INET) {
1801cb0ef41Sopenharmony_ci    flags |= ARES_IFACE_IP_V4;
1811cb0ef41Sopenharmony_ci  }
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci  if (addr->family == AF_INET6) {
1841cb0ef41Sopenharmony_ci    flags |= ARES_IFACE_IP_V6;
1851cb0ef41Sopenharmony_ci  }
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci  /* If they specified either v4 or v6 validate flags otherwise assume they
1881cb0ef41Sopenharmony_ci   * want to enumerate both */
1891cb0ef41Sopenharmony_ci  if (ips->enum_flags & (ARES_IFACE_IP_V4 | ARES_IFACE_IP_V6)) {
1901cb0ef41Sopenharmony_ci    if (flags & ARES_IFACE_IP_V4 && !(ips->enum_flags & ARES_IFACE_IP_V4)) {
1911cb0ef41Sopenharmony_ci      return ARES_SUCCESS;
1921cb0ef41Sopenharmony_ci    }
1931cb0ef41Sopenharmony_ci    if (flags & ARES_IFACE_IP_V6 && !(ips->enum_flags & ARES_IFACE_IP_V6)) {
1941cb0ef41Sopenharmony_ci      return ARES_SUCCESS;
1951cb0ef41Sopenharmony_ci    }
1961cb0ef41Sopenharmony_ci  }
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci  /* Allocate more ips */
1991cb0ef41Sopenharmony_ci  if (ips->cnt + 1 > ips->alloc_size) {
2001cb0ef41Sopenharmony_ci    void  *temp;
2011cb0ef41Sopenharmony_ci    size_t alloc_size;
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci    alloc_size = ares__round_up_pow2(ips->alloc_size + 1);
2041cb0ef41Sopenharmony_ci    temp = ares_realloc_zero(ips->ips, ips->alloc_size * sizeof(*ips->ips),
2051cb0ef41Sopenharmony_ci                             alloc_size * sizeof(*ips->ips));
2061cb0ef41Sopenharmony_ci    if (temp == NULL) {
2071cb0ef41Sopenharmony_ci      return ARES_ENOMEM;
2081cb0ef41Sopenharmony_ci    }
2091cb0ef41Sopenharmony_ci    ips->ips        = temp;
2101cb0ef41Sopenharmony_ci    ips->alloc_size = alloc_size;
2111cb0ef41Sopenharmony_ci  }
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  /* Add */
2141cb0ef41Sopenharmony_ci  idx = ips->cnt++;
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  ips->ips[idx].flags    = flags;
2171cb0ef41Sopenharmony_ci  ips->ips[idx].netmask  = netmask;
2181cb0ef41Sopenharmony_ci  ips->ips[idx].ll_scope = ll_scope;
2191cb0ef41Sopenharmony_ci  memcpy(&ips->ips[idx].addr, addr, sizeof(*addr));
2201cb0ef41Sopenharmony_ci  ips->ips[idx].name = ares_strdup(name);
2211cb0ef41Sopenharmony_ci  if (ips->ips[idx].name == NULL) {
2221cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
2231cb0ef41Sopenharmony_ci  }
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
2261cb0ef41Sopenharmony_ci}
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_cisize_t ares__iface_ips_cnt(const ares__iface_ips_t *ips)
2291cb0ef41Sopenharmony_ci{
2301cb0ef41Sopenharmony_ci  if (ips == NULL) {
2311cb0ef41Sopenharmony_ci    return 0;
2321cb0ef41Sopenharmony_ci  }
2331cb0ef41Sopenharmony_ci  return ips->cnt;
2341cb0ef41Sopenharmony_ci}
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ciconst char *ares__iface_ips_get_name(const ares__iface_ips_t *ips, size_t idx)
2371cb0ef41Sopenharmony_ci{
2381cb0ef41Sopenharmony_ci  if (ips == NULL || idx >= ips->cnt) {
2391cb0ef41Sopenharmony_ci    return NULL;
2401cb0ef41Sopenharmony_ci  }
2411cb0ef41Sopenharmony_ci  return ips->ips[idx].name;
2421cb0ef41Sopenharmony_ci}
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ciconst struct ares_addr *ares__iface_ips_get_addr(const ares__iface_ips_t *ips,
2451cb0ef41Sopenharmony_ci                                                 size_t                   idx)
2461cb0ef41Sopenharmony_ci{
2471cb0ef41Sopenharmony_ci  if (ips == NULL || idx >= ips->cnt) {
2481cb0ef41Sopenharmony_ci    return NULL;
2491cb0ef41Sopenharmony_ci  }
2501cb0ef41Sopenharmony_ci  return &ips->ips[idx].addr;
2511cb0ef41Sopenharmony_ci}
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ciares__iface_ip_flags_t ares__iface_ips_get_flags(const ares__iface_ips_t *ips,
2541cb0ef41Sopenharmony_ci                                                 size_t                   idx)
2551cb0ef41Sopenharmony_ci{
2561cb0ef41Sopenharmony_ci  if (ips == NULL || idx >= ips->cnt) {
2571cb0ef41Sopenharmony_ci    return 0;
2581cb0ef41Sopenharmony_ci  }
2591cb0ef41Sopenharmony_ci  return ips->ips[idx].flags;
2601cb0ef41Sopenharmony_ci}
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ciunsigned char ares__iface_ips_get_netmask(const ares__iface_ips_t *ips,
2631cb0ef41Sopenharmony_ci                                          size_t                   idx)
2641cb0ef41Sopenharmony_ci{
2651cb0ef41Sopenharmony_ci  if (ips == NULL || idx >= ips->cnt) {
2661cb0ef41Sopenharmony_ci    return 0;
2671cb0ef41Sopenharmony_ci  }
2681cb0ef41Sopenharmony_ci  return ips->ips[idx].netmask;
2691cb0ef41Sopenharmony_ci}
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_ciunsigned int ares__iface_ips_get_ll_scope(const ares__iface_ips_t *ips,
2721cb0ef41Sopenharmony_ci                                          size_t                   idx)
2731cb0ef41Sopenharmony_ci{
2741cb0ef41Sopenharmony_ci  if (ips == NULL || idx >= ips->cnt) {
2751cb0ef41Sopenharmony_ci    return 0;
2761cb0ef41Sopenharmony_ci  }
2771cb0ef41Sopenharmony_ci  return ips->ips[idx].ll_scope;
2781cb0ef41Sopenharmony_ci}
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci#ifdef USE_WINSOCK
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci#  if 0
2841cb0ef41Sopenharmony_cistatic char *wcharp_to_charp(const wchar_t *in)
2851cb0ef41Sopenharmony_ci{
2861cb0ef41Sopenharmony_ci  char *out;
2871cb0ef41Sopenharmony_ci  int   len;
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci  len = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL);
2901cb0ef41Sopenharmony_ci  if (len == -1) {
2911cb0ef41Sopenharmony_ci    return NULL;
2921cb0ef41Sopenharmony_ci  }
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci  out = ares_malloc_zero((size_t)len + 1);
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_ci  if (WideCharToMultiByte(CP_UTF8, 0, in, -1, out, len, NULL, NULL) == -1) {
2971cb0ef41Sopenharmony_ci    ares_free(out);
2981cb0ef41Sopenharmony_ci    return NULL;
2991cb0ef41Sopenharmony_ci  }
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci  return out;
3021cb0ef41Sopenharmony_ci}
3031cb0ef41Sopenharmony_ci#  endif
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_cistatic ares_bool_t name_match(const char *name, const char *adapter_name,
3061cb0ef41Sopenharmony_ci                              unsigned int ll_scope)
3071cb0ef41Sopenharmony_ci{
3081cb0ef41Sopenharmony_ci  if (name == NULL || *name == 0) {
3091cb0ef41Sopenharmony_ci    return ARES_TRUE;
3101cb0ef41Sopenharmony_ci  }
3111cb0ef41Sopenharmony_ci
3121cb0ef41Sopenharmony_ci  if (strcasecmp(name, adapter_name) == 0) {
3131cb0ef41Sopenharmony_ci    return ARES_TRUE;
3141cb0ef41Sopenharmony_ci  }
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci  if (ares_str_isnum(name) && (unsigned int)atoi(name) == ll_scope) {
3171cb0ef41Sopenharmony_ci    return ARES_TRUE;
3181cb0ef41Sopenharmony_ci  }
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci  return ARES_FALSE;
3211cb0ef41Sopenharmony_ci}
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_cistatic ares_status_t ares__iface_ips_enumerate(ares__iface_ips_t *ips,
3241cb0ef41Sopenharmony_ci                                               const char        *name)
3251cb0ef41Sopenharmony_ci{
3261cb0ef41Sopenharmony_ci  ULONG myflags = GAA_FLAG_INCLUDE_PREFIX /*|GAA_FLAG_INCLUDE_ALL_INTERFACES */;
3271cb0ef41Sopenharmony_ci  ULONG outBufLen = 0;
3281cb0ef41Sopenharmony_ci  DWORD retval;
3291cb0ef41Sopenharmony_ci  IP_ADAPTER_ADDRESSES *addresses = NULL;
3301cb0ef41Sopenharmony_ci  IP_ADAPTER_ADDRESSES *address   = NULL;
3311cb0ef41Sopenharmony_ci  ares_status_t         status    = ARES_SUCCESS;
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci  /* Get necessary buffer size */
3341cb0ef41Sopenharmony_ci  GetAdaptersAddresses(AF_UNSPEC, myflags, NULL, NULL, &outBufLen);
3351cb0ef41Sopenharmony_ci  if (outBufLen == 0) {
3361cb0ef41Sopenharmony_ci    status = ARES_EFILE;
3371cb0ef41Sopenharmony_ci    goto done;
3381cb0ef41Sopenharmony_ci  }
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci  addresses = ares_malloc_zero(outBufLen);
3411cb0ef41Sopenharmony_ci  if (addresses == NULL) {
3421cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
3431cb0ef41Sopenharmony_ci    goto done;
3441cb0ef41Sopenharmony_ci  }
3451cb0ef41Sopenharmony_ci
3461cb0ef41Sopenharmony_ci  retval =
3471cb0ef41Sopenharmony_ci    GetAdaptersAddresses(AF_UNSPEC, myflags, NULL, addresses, &outBufLen);
3481cb0ef41Sopenharmony_ci  if (retval != ERROR_SUCCESS) {
3491cb0ef41Sopenharmony_ci    status = ARES_EFILE;
3501cb0ef41Sopenharmony_ci    goto done;
3511cb0ef41Sopenharmony_ci  }
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ci  for (address = addresses; address != NULL; address = address->Next) {
3541cb0ef41Sopenharmony_ci    IP_ADAPTER_UNICAST_ADDRESS *ipaddr     = NULL;
3551cb0ef41Sopenharmony_ci    ares__iface_ip_flags_t      addrflag   = 0;
3561cb0ef41Sopenharmony_ci    char                        ifname[64] = "";
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci#  if defined(HAVE_CONVERTINTERFACEINDEXTOLUID) && \
3591cb0ef41Sopenharmony_ci    defined(HAVE_CONVERTINTERFACELUIDTONAMEA)
3601cb0ef41Sopenharmony_ci    /* Retrieve name from interface index.
3611cb0ef41Sopenharmony_ci     * address->AdapterName appears to be a GUID/UUID of some sort, not a name.
3621cb0ef41Sopenharmony_ci     * address->FriendlyName is user-changeable.
3631cb0ef41Sopenharmony_ci     * That said, this doesn't appear to help us out on systems that don't
3641cb0ef41Sopenharmony_ci     * have if_nametoindex() or if_indextoname() as they don't have these
3651cb0ef41Sopenharmony_ci     * functions either! */
3661cb0ef41Sopenharmony_ci    NET_LUID luid;
3671cb0ef41Sopenharmony_ci    ConvertInterfaceIndexToLuid(address->IfIndex, &luid);
3681cb0ef41Sopenharmony_ci    ConvertInterfaceLuidToNameA(&luid, ifname, sizeof(ifname));
3691cb0ef41Sopenharmony_ci#  else
3701cb0ef41Sopenharmony_ci    ares_strcpy(ifname, address->AdapterName, sizeof(ifname));
3711cb0ef41Sopenharmony_ci#  endif
3721cb0ef41Sopenharmony_ci
3731cb0ef41Sopenharmony_ci    if (address->OperStatus != IfOperStatusUp) {
3741cb0ef41Sopenharmony_ci      addrflag |= ARES_IFACE_IP_OFFLINE;
3751cb0ef41Sopenharmony_ci    }
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci    if (address->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
3781cb0ef41Sopenharmony_ci      addrflag |= ARES_IFACE_IP_LOOPBACK;
3791cb0ef41Sopenharmony_ci    }
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci    for (ipaddr = address->FirstUnicastAddress; ipaddr != NULL;
3821cb0ef41Sopenharmony_ci         ipaddr = ipaddr->Next) {
3831cb0ef41Sopenharmony_ci      struct ares_addr addr;
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci      if (ipaddr->Address.lpSockaddr->sa_family == AF_INET) {
3861cb0ef41Sopenharmony_ci        const struct sockaddr_in *sockaddr_in =
3871cb0ef41Sopenharmony_ci          (const struct sockaddr_in *)((void *)ipaddr->Address.lpSockaddr);
3881cb0ef41Sopenharmony_ci        addr.family = AF_INET;
3891cb0ef41Sopenharmony_ci        memcpy(&addr.addr.addr4, &sockaddr_in->sin_addr,
3901cb0ef41Sopenharmony_ci               sizeof(addr.addr.addr4));
3911cb0ef41Sopenharmony_ci      } else if (ipaddr->Address.lpSockaddr->sa_family == AF_INET6) {
3921cb0ef41Sopenharmony_ci        const struct sockaddr_in6 *sockaddr_in6 =
3931cb0ef41Sopenharmony_ci          (const struct sockaddr_in6 *)((void *)ipaddr->Address.lpSockaddr);
3941cb0ef41Sopenharmony_ci        addr.family = AF_INET6;
3951cb0ef41Sopenharmony_ci        memcpy(&addr.addr.addr6, &sockaddr_in6->sin6_addr,
3961cb0ef41Sopenharmony_ci               sizeof(addr.addr.addr6));
3971cb0ef41Sopenharmony_ci      } else {
3981cb0ef41Sopenharmony_ci        /* Unknown */
3991cb0ef41Sopenharmony_ci        continue;
4001cb0ef41Sopenharmony_ci      }
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ci      /* Sometimes windows may use numerics to indicate a DNS server's adapter,
4031cb0ef41Sopenharmony_ci       * which corresponds to the index rather than the name.  Check and
4041cb0ef41Sopenharmony_ci       * validate both. */
4051cb0ef41Sopenharmony_ci      if (!name_match(name, ifname, address->Ipv6IfIndex)) {
4061cb0ef41Sopenharmony_ci        continue;
4071cb0ef41Sopenharmony_ci      }
4081cb0ef41Sopenharmony_ci
4091cb0ef41Sopenharmony_ci      status = ares__iface_ips_add(ips, addrflag, ifname, &addr,
4101cb0ef41Sopenharmony_ci                                   ipaddr->OnLinkPrefixLength /* netmask */,
4111cb0ef41Sopenharmony_ci                                   address->Ipv6IfIndex /* ll_scope */);
4121cb0ef41Sopenharmony_ci
4131cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
4141cb0ef41Sopenharmony_ci        goto done;
4151cb0ef41Sopenharmony_ci      }
4161cb0ef41Sopenharmony_ci    }
4171cb0ef41Sopenharmony_ci  }
4181cb0ef41Sopenharmony_ci
4191cb0ef41Sopenharmony_cidone:
4201cb0ef41Sopenharmony_ci  ares_free(addresses);
4211cb0ef41Sopenharmony_ci  return status;
4221cb0ef41Sopenharmony_ci}
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_ci#elif defined(HAVE_GETIFADDRS)
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_cistatic unsigned char count_addr_bits(const unsigned char *addr, size_t addr_len)
4271cb0ef41Sopenharmony_ci{
4281cb0ef41Sopenharmony_ci  size_t        i;
4291cb0ef41Sopenharmony_ci  unsigned char count = 0;
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_ci  for (i = 0; i < addr_len; i++) {
4321cb0ef41Sopenharmony_ci    count += ares__count_bits_u8(addr[i]);
4331cb0ef41Sopenharmony_ci  }
4341cb0ef41Sopenharmony_ci  return count;
4351cb0ef41Sopenharmony_ci}
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_cistatic ares_status_t ares__iface_ips_enumerate(ares__iface_ips_t *ips,
4381cb0ef41Sopenharmony_ci                                               const char        *name)
4391cb0ef41Sopenharmony_ci{
4401cb0ef41Sopenharmony_ci  struct ifaddrs *ifap   = NULL;
4411cb0ef41Sopenharmony_ci  struct ifaddrs *ifa    = NULL;
4421cb0ef41Sopenharmony_ci  ares_status_t   status = ARES_SUCCESS;
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci  if (getifaddrs(&ifap) != 0) {
4451cb0ef41Sopenharmony_ci    status = ARES_EFILE;
4461cb0ef41Sopenharmony_ci    goto done;
4471cb0ef41Sopenharmony_ci  }
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
4501cb0ef41Sopenharmony_ci    ares__iface_ip_flags_t addrflag = 0;
4511cb0ef41Sopenharmony_ci    struct ares_addr       addr;
4521cb0ef41Sopenharmony_ci    unsigned char          netmask  = 0;
4531cb0ef41Sopenharmony_ci    unsigned int           ll_scope = 0;
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_ci    if (ifa->ifa_addr == NULL) {
4561cb0ef41Sopenharmony_ci      continue;
4571cb0ef41Sopenharmony_ci    }
4581cb0ef41Sopenharmony_ci
4591cb0ef41Sopenharmony_ci    if (!(ifa->ifa_flags & IFF_UP)) {
4601cb0ef41Sopenharmony_ci      addrflag |= ARES_IFACE_IP_OFFLINE;
4611cb0ef41Sopenharmony_ci    }
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci    if (ifa->ifa_flags & IFF_LOOPBACK) {
4641cb0ef41Sopenharmony_ci      addrflag |= ARES_IFACE_IP_LOOPBACK;
4651cb0ef41Sopenharmony_ci    }
4661cb0ef41Sopenharmony_ci
4671cb0ef41Sopenharmony_ci    if (ifa->ifa_addr->sa_family == AF_INET) {
4681cb0ef41Sopenharmony_ci      const struct sockaddr_in *sockaddr_in =
4691cb0ef41Sopenharmony_ci        (const struct sockaddr_in *)((void *)ifa->ifa_addr);
4701cb0ef41Sopenharmony_ci      addr.family = AF_INET;
4711cb0ef41Sopenharmony_ci      memcpy(&addr.addr.addr4, &sockaddr_in->sin_addr, sizeof(addr.addr.addr4));
4721cb0ef41Sopenharmony_ci      /* netmask */
4731cb0ef41Sopenharmony_ci      sockaddr_in = (struct sockaddr_in *)((void *)ifa->ifa_netmask);
4741cb0ef41Sopenharmony_ci      netmask     = count_addr_bits((const void *)&sockaddr_in->sin_addr, 4);
4751cb0ef41Sopenharmony_ci    } else if (ifa->ifa_addr->sa_family == AF_INET6) {
4761cb0ef41Sopenharmony_ci      const struct sockaddr_in6 *sockaddr_in6 =
4771cb0ef41Sopenharmony_ci        (const struct sockaddr_in6 *)((void *)ifa->ifa_addr);
4781cb0ef41Sopenharmony_ci      addr.family = AF_INET6;
4791cb0ef41Sopenharmony_ci      memcpy(&addr.addr.addr6, &sockaddr_in6->sin6_addr,
4801cb0ef41Sopenharmony_ci             sizeof(addr.addr.addr6));
4811cb0ef41Sopenharmony_ci      /* netmask */
4821cb0ef41Sopenharmony_ci      sockaddr_in6 = (struct sockaddr_in6 *)((void *)ifa->ifa_netmask);
4831cb0ef41Sopenharmony_ci      netmask = count_addr_bits((const void *)&sockaddr_in6->sin6_addr, 16);
4841cb0ef41Sopenharmony_ci#  ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
4851cb0ef41Sopenharmony_ci      ll_scope = sockaddr_in6->sin6_scope_id;
4861cb0ef41Sopenharmony_ci#  endif
4871cb0ef41Sopenharmony_ci    } else {
4881cb0ef41Sopenharmony_ci      /* unknown */
4891cb0ef41Sopenharmony_ci      continue;
4901cb0ef41Sopenharmony_ci    }
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci    /* Name mismatch */
4931cb0ef41Sopenharmony_ci    if (strcasecmp(ifa->ifa_name, name) != 0) {
4941cb0ef41Sopenharmony_ci      continue;
4951cb0ef41Sopenharmony_ci    }
4961cb0ef41Sopenharmony_ci
4971cb0ef41Sopenharmony_ci    status = ares__iface_ips_add(ips, addrflag, ifa->ifa_name, &addr, netmask,
4981cb0ef41Sopenharmony_ci                                 ll_scope);
4991cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
5001cb0ef41Sopenharmony_ci      goto done;
5011cb0ef41Sopenharmony_ci    }
5021cb0ef41Sopenharmony_ci  }
5031cb0ef41Sopenharmony_ci
5041cb0ef41Sopenharmony_cidone:
5051cb0ef41Sopenharmony_ci  freeifaddrs(ifap);
5061cb0ef41Sopenharmony_ci  return status;
5071cb0ef41Sopenharmony_ci}
5081cb0ef41Sopenharmony_ci
5091cb0ef41Sopenharmony_ci#else
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_cistatic ares_status_t ares__iface_ips_enumerate(ares__iface_ips_t *ips,
5121cb0ef41Sopenharmony_ci                                               const char        *name)
5131cb0ef41Sopenharmony_ci{
5141cb0ef41Sopenharmony_ci  (void)ips;
5151cb0ef41Sopenharmony_ci  (void)name;
5161cb0ef41Sopenharmony_ci  return ARES_ENOTIMP;
5171cb0ef41Sopenharmony_ci}
5181cb0ef41Sopenharmony_ci
5191cb0ef41Sopenharmony_ci#endif
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci
5221cb0ef41Sopenharmony_ciunsigned int ares__if_nametoindex(const char *name)
5231cb0ef41Sopenharmony_ci{
5241cb0ef41Sopenharmony_ci#ifdef HAVE_IF_NAMETOINDEX
5251cb0ef41Sopenharmony_ci  return if_nametoindex(name);
5261cb0ef41Sopenharmony_ci#else
5271cb0ef41Sopenharmony_ci  ares_status_t      status;
5281cb0ef41Sopenharmony_ci  ares__iface_ips_t *ips = NULL;
5291cb0ef41Sopenharmony_ci  size_t             i;
5301cb0ef41Sopenharmony_ci  unsigned int       index = 0;
5311cb0ef41Sopenharmony_ci
5321cb0ef41Sopenharmony_ci  status =
5331cb0ef41Sopenharmony_ci    ares__iface_ips(&ips, ARES_IFACE_IP_V6 | ARES_IFACE_IP_LINKLOCAL, name);
5341cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
5351cb0ef41Sopenharmony_ci    goto done;
5361cb0ef41Sopenharmony_ci  }
5371cb0ef41Sopenharmony_ci
5381cb0ef41Sopenharmony_ci  for (i = 0; i < ares__iface_ips_cnt(ips); i++) {
5391cb0ef41Sopenharmony_ci    if (ares__iface_ips_get_flags(ips, i) & ARES_IFACE_IP_LINKLOCAL) {
5401cb0ef41Sopenharmony_ci      index = ares__iface_ips_get_ll_scope(ips, i);
5411cb0ef41Sopenharmony_ci      goto done;
5421cb0ef41Sopenharmony_ci    }
5431cb0ef41Sopenharmony_ci  }
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_cidone:
5461cb0ef41Sopenharmony_ci  ares__iface_ips_destroy(ips);
5471cb0ef41Sopenharmony_ci  return index;
5481cb0ef41Sopenharmony_ci#endif
5491cb0ef41Sopenharmony_ci}
5501cb0ef41Sopenharmony_ci
5511cb0ef41Sopenharmony_ciconst char *ares__if_indextoname(unsigned int index, char *name,
5521cb0ef41Sopenharmony_ci                                 size_t name_len)
5531cb0ef41Sopenharmony_ci{
5541cb0ef41Sopenharmony_ci#ifdef HAVE_IF_INDEXTONAME
5551cb0ef41Sopenharmony_ci  if (name_len < IF_NAMESIZE) {
5561cb0ef41Sopenharmony_ci    return NULL;
5571cb0ef41Sopenharmony_ci  }
5581cb0ef41Sopenharmony_ci  return if_indextoname(index, name);
5591cb0ef41Sopenharmony_ci#else
5601cb0ef41Sopenharmony_ci  ares_status_t      status;
5611cb0ef41Sopenharmony_ci  ares__iface_ips_t *ips = NULL;
5621cb0ef41Sopenharmony_ci  size_t             i;
5631cb0ef41Sopenharmony_ci  const char        *ptr = NULL;
5641cb0ef41Sopenharmony_ci
5651cb0ef41Sopenharmony_ci  if (name_len < IF_NAMESIZE) {
5661cb0ef41Sopenharmony_ci    goto done;
5671cb0ef41Sopenharmony_ci  }
5681cb0ef41Sopenharmony_ci
5691cb0ef41Sopenharmony_ci  if (index == 0) {
5701cb0ef41Sopenharmony_ci    goto done;
5711cb0ef41Sopenharmony_ci  }
5721cb0ef41Sopenharmony_ci
5731cb0ef41Sopenharmony_ci  status =
5741cb0ef41Sopenharmony_ci    ares__iface_ips(&ips, ARES_IFACE_IP_V6 | ARES_IFACE_IP_LINKLOCAL, NULL);
5751cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
5761cb0ef41Sopenharmony_ci    goto done;
5771cb0ef41Sopenharmony_ci  }
5781cb0ef41Sopenharmony_ci
5791cb0ef41Sopenharmony_ci  for (i = 0; i < ares__iface_ips_cnt(ips); i++) {
5801cb0ef41Sopenharmony_ci    if (ares__iface_ips_get_flags(ips, i) & ARES_IFACE_IP_LINKLOCAL &&
5811cb0ef41Sopenharmony_ci        ares__iface_ips_get_ll_scope(ips, i) == index) {
5821cb0ef41Sopenharmony_ci      ares_strcpy(name, ares__iface_ips_get_name(ips, i), name_len);
5831cb0ef41Sopenharmony_ci      ptr = name;
5841cb0ef41Sopenharmony_ci      goto done;
5851cb0ef41Sopenharmony_ci    }
5861cb0ef41Sopenharmony_ci  }
5871cb0ef41Sopenharmony_ci
5881cb0ef41Sopenharmony_cidone:
5891cb0ef41Sopenharmony_ci  ares__iface_ips_destroy(ips);
5901cb0ef41Sopenharmony_ci  return ptr;
5911cb0ef41Sopenharmony_ci#endif
5921cb0ef41Sopenharmony_ci}
593