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