11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 1998 Massachusetts Institute of Technology
41cb0ef41Sopenharmony_ci * Copyright (c) 2008 Daniel Stenberg
51cb0ef41Sopenharmony_ci * Copyright (c) 2023 Brad House
61cb0ef41Sopenharmony_ci *
71cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
81cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
91cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
101cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
111cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
121cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
131cb0ef41Sopenharmony_ci *
141cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
151cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
161cb0ef41Sopenharmony_ci * Software.
171cb0ef41Sopenharmony_ci *
181cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
191cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
201cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
211cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
221cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
231cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
241cb0ef41Sopenharmony_ci * SOFTWARE.
251cb0ef41Sopenharmony_ci *
261cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
271cb0ef41Sopenharmony_ci */
281cb0ef41Sopenharmony_ci#include "ares_setup.h"
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci#ifdef HAVE_ARPA_INET_H
311cb0ef41Sopenharmony_ci#  include <arpa/inet.h>
321cb0ef41Sopenharmony_ci#endif
331cb0ef41Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H
341cb0ef41Sopenharmony_ci#  include <sys/types.h>
351cb0ef41Sopenharmony_ci#endif
361cb0ef41Sopenharmony_ci#ifdef HAVE_SYS_SOCKET_H
371cb0ef41Sopenharmony_ci#  include <sys/socket.h>
381cb0ef41Sopenharmony_ci#endif
391cb0ef41Sopenharmony_ci#ifdef HAVE_NET_IF_H
401cb0ef41Sopenharmony_ci#  include <net/if.h>
411cb0ef41Sopenharmony_ci#endif
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci#if defined(USE_WINSOCK)
441cb0ef41Sopenharmony_ci#  if defined(HAVE_IPHLPAPI_H)
451cb0ef41Sopenharmony_ci#    include <iphlpapi.h>
461cb0ef41Sopenharmony_ci#  endif
471cb0ef41Sopenharmony_ci#  if defined(HAVE_NETIOAPI_H)
481cb0ef41Sopenharmony_ci#    include <netioapi.h>
491cb0ef41Sopenharmony_ci#  endif
501cb0ef41Sopenharmony_ci#endif
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci#include "ares.h"
531cb0ef41Sopenharmony_ci#include "ares_data.h"
541cb0ef41Sopenharmony_ci#include "ares_inet_net_pton.h"
551cb0ef41Sopenharmony_ci#include "ares_private.h"
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_citypedef struct {
581cb0ef41Sopenharmony_ci  struct ares_addr addr;
591cb0ef41Sopenharmony_ci  unsigned short   tcp_port;
601cb0ef41Sopenharmony_ci  unsigned short   udp_port;
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  char             ll_iface[IF_NAMESIZE];
631cb0ef41Sopenharmony_ci  unsigned int     ll_scope;
641cb0ef41Sopenharmony_ci} ares_sconfig_t;
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_cistatic ares_bool_t ares__addr_match(const struct ares_addr *addr1,
671cb0ef41Sopenharmony_ci                                    const struct ares_addr *addr2)
681cb0ef41Sopenharmony_ci{
691cb0ef41Sopenharmony_ci  if (addr1 == NULL && addr2 == NULL) {
701cb0ef41Sopenharmony_ci    return ARES_TRUE;
711cb0ef41Sopenharmony_ci  }
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  if (addr1 == NULL || addr2 == NULL) {
741cb0ef41Sopenharmony_ci    return ARES_FALSE;
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  if (addr1->family != addr2->family) {
781cb0ef41Sopenharmony_ci    return ARES_FALSE;
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  if (addr1->family == AF_INET && memcmp(&addr1->addr.addr4, &addr2->addr.addr4,
821cb0ef41Sopenharmony_ci                                         sizeof(addr1->addr.addr4)) == 0) {
831cb0ef41Sopenharmony_ci    return ARES_TRUE;
841cb0ef41Sopenharmony_ci  }
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  if (addr1->family == AF_INET6 &&
871cb0ef41Sopenharmony_ci      memcmp(&addr1->addr.addr6._S6_un._S6_u8, &addr2->addr.addr6._S6_un._S6_u8,
881cb0ef41Sopenharmony_ci             sizeof(addr1->addr.addr6._S6_un._S6_u8)) == 0) {
891cb0ef41Sopenharmony_ci    return ARES_TRUE;
901cb0ef41Sopenharmony_ci  }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  return ARES_FALSE;
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ciares_bool_t ares__subnet_match(const struct ares_addr *addr,
961cb0ef41Sopenharmony_ci                               const struct ares_addr *subnet,
971cb0ef41Sopenharmony_ci                               unsigned char           netmask)
981cb0ef41Sopenharmony_ci{
991cb0ef41Sopenharmony_ci  const unsigned char *addr_ptr;
1001cb0ef41Sopenharmony_ci  const unsigned char *subnet_ptr;
1011cb0ef41Sopenharmony_ci  size_t               len;
1021cb0ef41Sopenharmony_ci  size_t               i;
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  if (addr == NULL || subnet == NULL) {
1051cb0ef41Sopenharmony_ci    return ARES_FALSE;
1061cb0ef41Sopenharmony_ci  }
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  if (addr->family != subnet->family) {
1091cb0ef41Sopenharmony_ci    return ARES_FALSE;
1101cb0ef41Sopenharmony_ci  }
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  if (addr->family == AF_INET) {
1131cb0ef41Sopenharmony_ci    addr_ptr   = (const unsigned char *)&addr->addr.addr4;
1141cb0ef41Sopenharmony_ci    subnet_ptr = (const unsigned char *)&subnet->addr.addr4;
1151cb0ef41Sopenharmony_ci    len        = 4;
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci    if (netmask > 32) {
1181cb0ef41Sopenharmony_ci      return ARES_FALSE;
1191cb0ef41Sopenharmony_ci    }
1201cb0ef41Sopenharmony_ci  } else if (addr->family == AF_INET6) {
1211cb0ef41Sopenharmony_ci    addr_ptr   = (const unsigned char *)&addr->addr.addr6;
1221cb0ef41Sopenharmony_ci    subnet_ptr = (const unsigned char *)&subnet->addr.addr6;
1231cb0ef41Sopenharmony_ci    len        = 16;
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci    if (netmask > 128) {
1261cb0ef41Sopenharmony_ci      return ARES_FALSE;
1271cb0ef41Sopenharmony_ci    }
1281cb0ef41Sopenharmony_ci  } else {
1291cb0ef41Sopenharmony_ci    return ARES_FALSE;
1301cb0ef41Sopenharmony_ci  }
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  for (i = 0; i < len && netmask > 0; i++) {
1331cb0ef41Sopenharmony_ci    unsigned char mask = 0xff;
1341cb0ef41Sopenharmony_ci    if (netmask < 8) {
1351cb0ef41Sopenharmony_ci      mask    <<= (8 - netmask);
1361cb0ef41Sopenharmony_ci      netmask   = 0;
1371cb0ef41Sopenharmony_ci    } else {
1381cb0ef41Sopenharmony_ci      netmask -= 8;
1391cb0ef41Sopenharmony_ci    }
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    if ((addr_ptr[i] & mask) != (subnet_ptr[i] & mask)) {
1421cb0ef41Sopenharmony_ci      return ARES_FALSE;
1431cb0ef41Sopenharmony_ci    }
1441cb0ef41Sopenharmony_ci  }
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  return ARES_TRUE;
1471cb0ef41Sopenharmony_ci}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ciares_bool_t ares__addr_is_linklocal(const struct ares_addr *addr)
1501cb0ef41Sopenharmony_ci{
1511cb0ef41Sopenharmony_ci  struct ares_addr    subnet;
1521cb0ef41Sopenharmony_ci  const unsigned char subnetaddr[16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
1531cb0ef41Sopenharmony_ci                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1541cb0ef41Sopenharmony_ci                                         0x00, 0x00, 0x00, 0x00 };
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  /* fe80::/10 */
1571cb0ef41Sopenharmony_ci  subnet.family = AF_INET6;
1581cb0ef41Sopenharmony_ci  memcpy(&subnet.addr.addr6, subnetaddr, 16);
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  return ares__subnet_match(addr, &subnet, 10);
1611cb0ef41Sopenharmony_ci}
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_cistatic ares_bool_t ares_server_blacklisted(const struct ares_addr *addr)
1641cb0ef41Sopenharmony_ci{
1651cb0ef41Sopenharmony_ci  /* A list of blacklisted IPv6 subnets. */
1661cb0ef41Sopenharmony_ci  const struct {
1671cb0ef41Sopenharmony_ci    const unsigned char netbase[16];
1681cb0ef41Sopenharmony_ci    unsigned char       netmask;
1691cb0ef41Sopenharmony_ci  } blacklist_v6[] = {
1701cb0ef41Sopenharmony_ci  /* fec0::/10 was deprecated by [RFC3879] in September 2004. Formerly a
1711cb0ef41Sopenharmony_ci  * Site-Local scoped address prefix.  These are never valid DNS servers,
1721cb0ef41Sopenharmony_ci  * but are known to be returned at least sometimes on Windows and Android.
1731cb0ef41Sopenharmony_ci  */
1741cb0ef41Sopenharmony_ci    {{ 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1751cb0ef41Sopenharmony_ci        0x00, 0x00, 0x00, 0x00 },
1761cb0ef41Sopenharmony_ci     10}
1771cb0ef41Sopenharmony_ci  };
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  size_t i;
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  if (addr->family != AF_INET6) {
1821cb0ef41Sopenharmony_ci    return ARES_FALSE;
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  /* See if ipaddr matches any of the entries in the blacklist. */
1861cb0ef41Sopenharmony_ci  for (i = 0; i < sizeof(blacklist_v6) / sizeof(*blacklist_v6); i++) {
1871cb0ef41Sopenharmony_ci    struct ares_addr subnet;
1881cb0ef41Sopenharmony_ci    subnet.family = AF_INET6;
1891cb0ef41Sopenharmony_ci    memcpy(&subnet.addr.addr6, blacklist_v6[i].netbase, 16);
1901cb0ef41Sopenharmony_ci    if (ares__subnet_match(addr, &subnet, blacklist_v6[i].netmask)) {
1911cb0ef41Sopenharmony_ci      return ARES_TRUE;
1921cb0ef41Sopenharmony_ci    }
1931cb0ef41Sopenharmony_ci  }
1941cb0ef41Sopenharmony_ci  return ARES_FALSE;
1951cb0ef41Sopenharmony_ci}
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci/* Parse address and port in these formats, either ipv4 or ipv6 addresses
1981cb0ef41Sopenharmony_ci * are allowed:
1991cb0ef41Sopenharmony_ci *   ipaddr
2001cb0ef41Sopenharmony_ci *   ipv4addr:port
2011cb0ef41Sopenharmony_ci *   [ipaddr]
2021cb0ef41Sopenharmony_ci *   [ipaddr]:port
2031cb0ef41Sopenharmony_ci *
2041cb0ef41Sopenharmony_ci * Modifiers: %iface
2051cb0ef41Sopenharmony_ci *
2061cb0ef41Sopenharmony_ci * TODO: #domain modifier
2071cb0ef41Sopenharmony_ci *
2081cb0ef41Sopenharmony_ci * If a port is not specified, will set port to 0.
2091cb0ef41Sopenharmony_ci *
2101cb0ef41Sopenharmony_ci * Will fail if an IPv6 nameserver as detected by
2111cb0ef41Sopenharmony_ci * ares_ipv6_server_blacklisted()
2121cb0ef41Sopenharmony_ci *
2131cb0ef41Sopenharmony_ci * Returns an error code on failure, else ARES_SUCCESS
2141cb0ef41Sopenharmony_ci */
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_cistatic ares_status_t parse_nameserver(ares__buf_t *buf, ares_sconfig_t *sconfig)
2171cb0ef41Sopenharmony_ci{
2181cb0ef41Sopenharmony_ci  ares_status_t status;
2191cb0ef41Sopenharmony_ci  char          ipaddr[INET6_ADDRSTRLEN] = "";
2201cb0ef41Sopenharmony_ci  size_t        addrlen;
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  memset(sconfig, 0, sizeof(*sconfig));
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci  /* Consume any leading whitespace */
2251cb0ef41Sopenharmony_ci  ares__buf_consume_whitespace(buf, ARES_TRUE);
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci  /* pop off IP address.  If it is in [ ] then it can be ipv4 or ipv6.  If
2281cb0ef41Sopenharmony_ci   * not, ipv4 only */
2291cb0ef41Sopenharmony_ci  if (ares__buf_begins_with(buf, (const unsigned char *)"[", 1)) {
2301cb0ef41Sopenharmony_ci    /* Consume [ */
2311cb0ef41Sopenharmony_ci    ares__buf_consume(buf, 1);
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci    ares__buf_tag(buf);
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci    /* Consume until ] */
2361cb0ef41Sopenharmony_ci    if (ares__buf_consume_until_charset(buf, (const unsigned char *)"]", 1,
2371cb0ef41Sopenharmony_ci                                        ARES_TRUE) == 0) {
2381cb0ef41Sopenharmony_ci      return ARES_EBADSTR;
2391cb0ef41Sopenharmony_ci    }
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci    status = ares__buf_tag_fetch_string(buf, ipaddr, sizeof(ipaddr));
2421cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
2431cb0ef41Sopenharmony_ci      return status;
2441cb0ef41Sopenharmony_ci    }
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci    /* Skip over ] */
2471cb0ef41Sopenharmony_ci    ares__buf_consume(buf, 1);
2481cb0ef41Sopenharmony_ci  } else {
2491cb0ef41Sopenharmony_ci    size_t offset;
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci    /* Not in [ ], see if '.' is in first 4 characters, if it is, then its ipv4,
2521cb0ef41Sopenharmony_ci     * otherwise treat as ipv6 */
2531cb0ef41Sopenharmony_ci    ares__buf_tag(buf);
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci    offset = ares__buf_consume_until_charset(buf, (const unsigned char *)".", 1,
2561cb0ef41Sopenharmony_ci                                             ARES_TRUE);
2571cb0ef41Sopenharmony_ci    ares__buf_tag_rollback(buf);
2581cb0ef41Sopenharmony_ci    ares__buf_tag(buf);
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci    if (offset > 0 && offset < 4) {
2611cb0ef41Sopenharmony_ci      /* IPv4 */
2621cb0ef41Sopenharmony_ci      if (ares__buf_consume_charset(buf, (const unsigned char *)"0123456789.",
2631cb0ef41Sopenharmony_ci                                    11) == 0) {
2641cb0ef41Sopenharmony_ci        return ARES_EBADSTR;
2651cb0ef41Sopenharmony_ci      }
2661cb0ef41Sopenharmony_ci    } else {
2671cb0ef41Sopenharmony_ci      /* IPv6 */
2681cb0ef41Sopenharmony_ci      const unsigned char ipv6_charset[] = "ABCDEFabcdef0123456789.:";
2691cb0ef41Sopenharmony_ci      if (ares__buf_consume_charset(buf, ipv6_charset, sizeof(ipv6_charset)) ==
2701cb0ef41Sopenharmony_ci          0) {
2711cb0ef41Sopenharmony_ci        return ARES_EBADSTR;
2721cb0ef41Sopenharmony_ci      }
2731cb0ef41Sopenharmony_ci    }
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_ci    status = ares__buf_tag_fetch_string(buf, ipaddr, sizeof(ipaddr));
2761cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
2771cb0ef41Sopenharmony_ci      return status;
2781cb0ef41Sopenharmony_ci    }
2791cb0ef41Sopenharmony_ci  }
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci  /* Convert ip address from string to network byte order */
2821cb0ef41Sopenharmony_ci  sconfig->addr.family = AF_UNSPEC;
2831cb0ef41Sopenharmony_ci  if (ares_dns_pton(ipaddr, &sconfig->addr, &addrlen) == NULL) {
2841cb0ef41Sopenharmony_ci    return ARES_EBADSTR;
2851cb0ef41Sopenharmony_ci  }
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ci  /* Pull off port */
2881cb0ef41Sopenharmony_ci  if (ares__buf_begins_with(buf, (const unsigned char *)":", 1)) {
2891cb0ef41Sopenharmony_ci    char portstr[6];
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci    /* Consume : */
2921cb0ef41Sopenharmony_ci    ares__buf_consume(buf, 1);
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci    ares__buf_tag(buf);
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_ci    /* Read numbers */
2971cb0ef41Sopenharmony_ci    if (ares__buf_consume_charset(buf, (const unsigned char *)"0123456789",
2981cb0ef41Sopenharmony_ci                                  10) == 0) {
2991cb0ef41Sopenharmony_ci      return ARES_EBADSTR;
3001cb0ef41Sopenharmony_ci    }
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci    status = ares__buf_tag_fetch_string(buf, portstr, sizeof(portstr));
3031cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
3041cb0ef41Sopenharmony_ci      return status;
3051cb0ef41Sopenharmony_ci    }
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci    sconfig->udp_port = (unsigned short)atoi(portstr);
3081cb0ef41Sopenharmony_ci    sconfig->tcp_port = sconfig->udp_port;
3091cb0ef41Sopenharmony_ci  }
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci  /* Pull off interface modifier */
3121cb0ef41Sopenharmony_ci  if (ares__buf_begins_with(buf, (const unsigned char *)"%", 1)) {
3131cb0ef41Sopenharmony_ci    const unsigned char iface_charset[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3141cb0ef41Sopenharmony_ci                                          "abcdefghijklmnopqrstuvwxyz"
3151cb0ef41Sopenharmony_ci                                          "0123456789.-_\\:{}";
3161cb0ef41Sopenharmony_ci    /* Consume % */
3171cb0ef41Sopenharmony_ci    ares__buf_consume(buf, 1);
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci    ares__buf_tag(buf);
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci    if (ares__buf_consume_charset(buf, iface_charset, sizeof(iface_charset)) ==
3221cb0ef41Sopenharmony_ci        0) {
3231cb0ef41Sopenharmony_ci      return ARES_EBADSTR;
3241cb0ef41Sopenharmony_ci    }
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci    status = ares__buf_tag_fetch_string(buf, sconfig->ll_iface,
3271cb0ef41Sopenharmony_ci                                        sizeof(sconfig->ll_iface));
3281cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
3291cb0ef41Sopenharmony_ci      return status;
3301cb0ef41Sopenharmony_ci    }
3311cb0ef41Sopenharmony_ci  }
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci  /* Consume any trailing whitespace so we can bail out if there is something
3341cb0ef41Sopenharmony_ci   * after we didn't read */
3351cb0ef41Sopenharmony_ci  ares__buf_consume_whitespace(buf, ARES_TRUE);
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  if (ares__buf_len(buf) != 0) {
3381cb0ef41Sopenharmony_ci    return ARES_EBADSTR;
3391cb0ef41Sopenharmony_ci  }
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
3421cb0ef41Sopenharmony_ci}
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_cistatic ares_status_t ares__sconfig_linklocal(ares_sconfig_t *s,
3451cb0ef41Sopenharmony_ci                                             const char     *ll_iface)
3461cb0ef41Sopenharmony_ci{
3471cb0ef41Sopenharmony_ci  unsigned int ll_scope = 0;
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci  if (ares_str_isnum(ll_iface)) {
3501cb0ef41Sopenharmony_ci    char ifname[IF_NAMESIZE] = "";
3511cb0ef41Sopenharmony_ci    ll_scope                 = (unsigned int)atoi(ll_iface);
3521cb0ef41Sopenharmony_ci    if (ares__if_indextoname(ll_scope, ifname, sizeof(ifname)) == NULL) {
3531cb0ef41Sopenharmony_ci      DEBUGF(fprintf(stderr, "Interface %s for ipv6 Link Local not found\n",
3541cb0ef41Sopenharmony_ci                     ll_iface));
3551cb0ef41Sopenharmony_ci      return ARES_ENOTFOUND;
3561cb0ef41Sopenharmony_ci    }
3571cb0ef41Sopenharmony_ci    ares_strcpy(s->ll_iface, ifname, sizeof(s->ll_iface));
3581cb0ef41Sopenharmony_ci    s->ll_scope = ll_scope;
3591cb0ef41Sopenharmony_ci    return ARES_SUCCESS;
3601cb0ef41Sopenharmony_ci  }
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_ci  ll_scope = ares__if_nametoindex(ll_iface);
3631cb0ef41Sopenharmony_ci  if (ll_scope == 0) {
3641cb0ef41Sopenharmony_ci    DEBUGF(fprintf(stderr, "Interface %s for ipv6 Link Local not found\n",
3651cb0ef41Sopenharmony_ci                   ll_iface));
3661cb0ef41Sopenharmony_ci    return ARES_ENOTFOUND;
3671cb0ef41Sopenharmony_ci  }
3681cb0ef41Sopenharmony_ci  ares_strcpy(s->ll_iface, ll_iface, sizeof(s->ll_iface));
3691cb0ef41Sopenharmony_ci  s->ll_scope = ll_scope;
3701cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
3711cb0ef41Sopenharmony_ci}
3721cb0ef41Sopenharmony_ci
3731cb0ef41Sopenharmony_ciares_status_t ares__sconfig_append(ares__llist_t         **sconfig,
3741cb0ef41Sopenharmony_ci                                   const struct ares_addr *addr,
3751cb0ef41Sopenharmony_ci                                   unsigned short          udp_port,
3761cb0ef41Sopenharmony_ci                                   unsigned short          tcp_port,
3771cb0ef41Sopenharmony_ci                                   const char             *ll_iface)
3781cb0ef41Sopenharmony_ci{
3791cb0ef41Sopenharmony_ci  ares_sconfig_t *s;
3801cb0ef41Sopenharmony_ci  ares_status_t   status;
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_ci  if (sconfig == NULL || addr == NULL) {
3831cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
3841cb0ef41Sopenharmony_ci  }
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci  /* Silently skip blacklisted IPv6 servers. */
3871cb0ef41Sopenharmony_ci  if (ares_server_blacklisted(addr)) {
3881cb0ef41Sopenharmony_ci    return ARES_SUCCESS;
3891cb0ef41Sopenharmony_ci  }
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ci  s = ares_malloc_zero(sizeof(*s));
3921cb0ef41Sopenharmony_ci  if (s == NULL) {
3931cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
3941cb0ef41Sopenharmony_ci  }
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_ci  if (*sconfig == NULL) {
3971cb0ef41Sopenharmony_ci    *sconfig = ares__llist_create(ares_free);
3981cb0ef41Sopenharmony_ci    if (*sconfig == NULL) {
3991cb0ef41Sopenharmony_ci      status = ARES_ENOMEM;
4001cb0ef41Sopenharmony_ci      goto fail;
4011cb0ef41Sopenharmony_ci    }
4021cb0ef41Sopenharmony_ci  }
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci  memcpy(&s->addr, addr, sizeof(s->addr));
4051cb0ef41Sopenharmony_ci  s->udp_port = udp_port;
4061cb0ef41Sopenharmony_ci  s->tcp_port = tcp_port;
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  /* Handle link-local enumeration */
4091cb0ef41Sopenharmony_ci  if (ares_strlen(ll_iface) && ares__addr_is_linklocal(&s->addr)) {
4101cb0ef41Sopenharmony_ci    status = ares__sconfig_linklocal(s, ll_iface);
4111cb0ef41Sopenharmony_ci    /* Silently ignore this entry */
4121cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
4131cb0ef41Sopenharmony_ci      status = ARES_SUCCESS;
4141cb0ef41Sopenharmony_ci      goto fail;
4151cb0ef41Sopenharmony_ci    }
4161cb0ef41Sopenharmony_ci  }
4171cb0ef41Sopenharmony_ci
4181cb0ef41Sopenharmony_ci  if (ares__llist_insert_last(*sconfig, s) == NULL) {
4191cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
4201cb0ef41Sopenharmony_ci    goto fail;
4211cb0ef41Sopenharmony_ci  }
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
4241cb0ef41Sopenharmony_ci
4251cb0ef41Sopenharmony_cifail:
4261cb0ef41Sopenharmony_ci  ares_free(s);
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci  return status;
4291cb0ef41Sopenharmony_ci}
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_ci/* Add the IPv4 or IPv6 nameservers in str (separated by commas or spaces) to
4321cb0ef41Sopenharmony_ci * the servers list, updating servers and nservers as required.
4331cb0ef41Sopenharmony_ci *
4341cb0ef41Sopenharmony_ci * If a nameserver is encapsulated in [ ] it may optionally include a port
4351cb0ef41Sopenharmony_ci * suffix, e.g.:
4361cb0ef41Sopenharmony_ci *    [127.0.0.1]:59591
4371cb0ef41Sopenharmony_ci *
4381cb0ef41Sopenharmony_ci * The extended format is required to support OpenBSD's resolv.conf format:
4391cb0ef41Sopenharmony_ci *   https://man.openbsd.org/OpenBSD-5.1/resolv.conf.5
4401cb0ef41Sopenharmony_ci * As well as MacOS libresolv that may include a non-default port number.
4411cb0ef41Sopenharmony_ci *
4421cb0ef41Sopenharmony_ci * This will silently ignore blacklisted IPv6 nameservers as detected by
4431cb0ef41Sopenharmony_ci * ares_ipv6_server_blacklisted().
4441cb0ef41Sopenharmony_ci *
4451cb0ef41Sopenharmony_ci * Returns an error code on failure, else ARES_SUCCESS.
4461cb0ef41Sopenharmony_ci */
4471cb0ef41Sopenharmony_ciares_status_t ares__sconfig_append_fromstr(ares__llist_t **sconfig,
4481cb0ef41Sopenharmony_ci                                           const char     *str,
4491cb0ef41Sopenharmony_ci                                           ares_bool_t     ignore_invalid)
4501cb0ef41Sopenharmony_ci{
4511cb0ef41Sopenharmony_ci  ares_status_t       status = ARES_SUCCESS;
4521cb0ef41Sopenharmony_ci  ares__buf_t        *buf    = NULL;
4531cb0ef41Sopenharmony_ci  ares__llist_t      *list   = NULL;
4541cb0ef41Sopenharmony_ci  ares__llist_node_t *node;
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_ci  /* On Windows, there may be more than one nameserver specified in the same
4571cb0ef41Sopenharmony_ci   * registry key, so we parse input as a space or comma separated list.
4581cb0ef41Sopenharmony_ci   */
4591cb0ef41Sopenharmony_ci  buf = ares__buf_create_const((const unsigned char *)str, ares_strlen(str));
4601cb0ef41Sopenharmony_ci  if (buf == NULL) {
4611cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
4621cb0ef41Sopenharmony_ci    goto done;
4631cb0ef41Sopenharmony_ci  }
4641cb0ef41Sopenharmony_ci
4651cb0ef41Sopenharmony_ci  status = ares__buf_split(buf, (const unsigned char *)" ,", 2,
4661cb0ef41Sopenharmony_ci                           ARES_BUF_SPLIT_NONE, &list);
4671cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
4681cb0ef41Sopenharmony_ci    goto done;
4691cb0ef41Sopenharmony_ci  }
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci  for (node = ares__llist_node_first(list); node != NULL;
4721cb0ef41Sopenharmony_ci       node = ares__llist_node_next(node)) {
4731cb0ef41Sopenharmony_ci    ares__buf_t   *entry = ares__llist_node_val(node);
4741cb0ef41Sopenharmony_ci    ares_sconfig_t s;
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci    status = parse_nameserver(entry, &s);
4771cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
4781cb0ef41Sopenharmony_ci      if (ignore_invalid) {
4791cb0ef41Sopenharmony_ci        continue;
4801cb0ef41Sopenharmony_ci      } else {
4811cb0ef41Sopenharmony_ci        goto done;
4821cb0ef41Sopenharmony_ci      }
4831cb0ef41Sopenharmony_ci    }
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ci    status = ares__sconfig_append(sconfig, &s.addr, s.udp_port, s.tcp_port,
4861cb0ef41Sopenharmony_ci                                  s.ll_iface);
4871cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
4881cb0ef41Sopenharmony_ci      goto done;
4891cb0ef41Sopenharmony_ci    }
4901cb0ef41Sopenharmony_ci  }
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci  status = ARES_SUCCESS;
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_cidone:
4951cb0ef41Sopenharmony_ci  ares__llist_destroy(list);
4961cb0ef41Sopenharmony_ci  ares__buf_destroy(buf);
4971cb0ef41Sopenharmony_ci  return status;
4981cb0ef41Sopenharmony_ci}
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_cistatic unsigned short ares__sconfig_get_port(const ares_channel_t *channel,
5011cb0ef41Sopenharmony_ci                                             const ares_sconfig_t *s,
5021cb0ef41Sopenharmony_ci                                             ares_bool_t           is_tcp)
5031cb0ef41Sopenharmony_ci{
5041cb0ef41Sopenharmony_ci  unsigned short port = is_tcp ? s->tcp_port : s->udp_port;
5051cb0ef41Sopenharmony_ci
5061cb0ef41Sopenharmony_ci  if (port == 0) {
5071cb0ef41Sopenharmony_ci    port = is_tcp ? channel->tcp_port : channel->udp_port;
5081cb0ef41Sopenharmony_ci  }
5091cb0ef41Sopenharmony_ci
5101cb0ef41Sopenharmony_ci  if (port == 0) {
5111cb0ef41Sopenharmony_ci    port = 53;
5121cb0ef41Sopenharmony_ci  }
5131cb0ef41Sopenharmony_ci
5141cb0ef41Sopenharmony_ci  return port;
5151cb0ef41Sopenharmony_ci}
5161cb0ef41Sopenharmony_ci
5171cb0ef41Sopenharmony_cistatic ares__slist_node_t *ares__server_find(ares_channel_t       *channel,
5181cb0ef41Sopenharmony_ci                                             const ares_sconfig_t *s)
5191cb0ef41Sopenharmony_ci{
5201cb0ef41Sopenharmony_ci  ares__slist_node_t *node;
5211cb0ef41Sopenharmony_ci
5221cb0ef41Sopenharmony_ci  for (node = ares__slist_node_first(channel->servers); node != NULL;
5231cb0ef41Sopenharmony_ci       node = ares__slist_node_next(node)) {
5241cb0ef41Sopenharmony_ci    const struct server_state *server = ares__slist_node_val(node);
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci    if (!ares__addr_match(&server->addr, &s->addr)) {
5271cb0ef41Sopenharmony_ci      continue;
5281cb0ef41Sopenharmony_ci    }
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci    if (server->tcp_port != ares__sconfig_get_port(channel, s, ARES_TRUE)) {
5311cb0ef41Sopenharmony_ci      continue;
5321cb0ef41Sopenharmony_ci    }
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci    if (server->udp_port != ares__sconfig_get_port(channel, s, ARES_FALSE)) {
5351cb0ef41Sopenharmony_ci      continue;
5361cb0ef41Sopenharmony_ci    }
5371cb0ef41Sopenharmony_ci
5381cb0ef41Sopenharmony_ci    return node;
5391cb0ef41Sopenharmony_ci  }
5401cb0ef41Sopenharmony_ci  return NULL;
5411cb0ef41Sopenharmony_ci}
5421cb0ef41Sopenharmony_ci
5431cb0ef41Sopenharmony_cistatic ares_bool_t ares__server_isdup(const ares_channel_t *channel,
5441cb0ef41Sopenharmony_ci                                      ares__llist_node_t   *s)
5451cb0ef41Sopenharmony_ci{
5461cb0ef41Sopenharmony_ci  /* Scan backwards to see if this is a duplicate */
5471cb0ef41Sopenharmony_ci  ares__llist_node_t   *prev;
5481cb0ef41Sopenharmony_ci  const ares_sconfig_t *server = ares__llist_node_val(s);
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_ci  for (prev = ares__llist_node_prev(s); prev != NULL;
5511cb0ef41Sopenharmony_ci       prev = ares__llist_node_prev(prev)) {
5521cb0ef41Sopenharmony_ci    const ares_sconfig_t *p = ares__llist_node_val(prev);
5531cb0ef41Sopenharmony_ci
5541cb0ef41Sopenharmony_ci    if (!ares__addr_match(&server->addr, &p->addr)) {
5551cb0ef41Sopenharmony_ci      continue;
5561cb0ef41Sopenharmony_ci    }
5571cb0ef41Sopenharmony_ci
5581cb0ef41Sopenharmony_ci    if (ares__sconfig_get_port(channel, server, ARES_TRUE) !=
5591cb0ef41Sopenharmony_ci        ares__sconfig_get_port(channel, p, ARES_TRUE)) {
5601cb0ef41Sopenharmony_ci      continue;
5611cb0ef41Sopenharmony_ci    }
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci    if (ares__sconfig_get_port(channel, server, ARES_FALSE) !=
5641cb0ef41Sopenharmony_ci        ares__sconfig_get_port(channel, p, ARES_FALSE)) {
5651cb0ef41Sopenharmony_ci      continue;
5661cb0ef41Sopenharmony_ci    }
5671cb0ef41Sopenharmony_ci
5681cb0ef41Sopenharmony_ci    return ARES_TRUE;
5691cb0ef41Sopenharmony_ci  }
5701cb0ef41Sopenharmony_ci
5711cb0ef41Sopenharmony_ci  return ARES_FALSE;
5721cb0ef41Sopenharmony_ci}
5731cb0ef41Sopenharmony_ci
5741cb0ef41Sopenharmony_cistatic ares_status_t ares__server_create(ares_channel_t       *channel,
5751cb0ef41Sopenharmony_ci                                         const ares_sconfig_t *sconfig,
5761cb0ef41Sopenharmony_ci                                         size_t                idx)
5771cb0ef41Sopenharmony_ci{
5781cb0ef41Sopenharmony_ci  ares_status_t        status;
5791cb0ef41Sopenharmony_ci  struct server_state *server = ares_malloc_zero(sizeof(*server));
5801cb0ef41Sopenharmony_ci
5811cb0ef41Sopenharmony_ci  if (server == NULL) {
5821cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
5831cb0ef41Sopenharmony_ci  }
5841cb0ef41Sopenharmony_ci
5851cb0ef41Sopenharmony_ci  server->idx         = idx;
5861cb0ef41Sopenharmony_ci  server->channel     = channel;
5871cb0ef41Sopenharmony_ci  server->udp_port    = ares__sconfig_get_port(channel, sconfig, ARES_FALSE);
5881cb0ef41Sopenharmony_ci  server->tcp_port    = ares__sconfig_get_port(channel, sconfig, ARES_TRUE);
5891cb0ef41Sopenharmony_ci  server->addr.family = sconfig->addr.family;
5901cb0ef41Sopenharmony_ci
5911cb0ef41Sopenharmony_ci  if (sconfig->addr.family == AF_INET) {
5921cb0ef41Sopenharmony_ci    memcpy(&server->addr.addr.addr4, &sconfig->addr.addr.addr4,
5931cb0ef41Sopenharmony_ci           sizeof(server->addr.addr.addr4));
5941cb0ef41Sopenharmony_ci  } else if (sconfig->addr.family == AF_INET6) {
5951cb0ef41Sopenharmony_ci    memcpy(&server->addr.addr.addr6, &sconfig->addr.addr.addr6,
5961cb0ef41Sopenharmony_ci           sizeof(server->addr.addr.addr6));
5971cb0ef41Sopenharmony_ci  }
5981cb0ef41Sopenharmony_ci
5991cb0ef41Sopenharmony_ci  /* Copy over link-local settings */
6001cb0ef41Sopenharmony_ci  if (ares_strlen(sconfig->ll_iface)) {
6011cb0ef41Sopenharmony_ci    ares_strcpy(server->ll_iface, sconfig->ll_iface, sizeof(server->ll_iface));
6021cb0ef41Sopenharmony_ci    server->ll_scope = sconfig->ll_scope;
6031cb0ef41Sopenharmony_ci  }
6041cb0ef41Sopenharmony_ci
6051cb0ef41Sopenharmony_ci  server->tcp_parser = ares__buf_create();
6061cb0ef41Sopenharmony_ci  if (server->tcp_parser == NULL) {
6071cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
6081cb0ef41Sopenharmony_ci    goto done;
6091cb0ef41Sopenharmony_ci  }
6101cb0ef41Sopenharmony_ci
6111cb0ef41Sopenharmony_ci  server->tcp_send = ares__buf_create();
6121cb0ef41Sopenharmony_ci  if (server->tcp_send == NULL) {
6131cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
6141cb0ef41Sopenharmony_ci    goto done;
6151cb0ef41Sopenharmony_ci  }
6161cb0ef41Sopenharmony_ci
6171cb0ef41Sopenharmony_ci  server->connections = ares__llist_create(NULL);
6181cb0ef41Sopenharmony_ci  if (server->connections == NULL) {
6191cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
6201cb0ef41Sopenharmony_ci    goto done;
6211cb0ef41Sopenharmony_ci  }
6221cb0ef41Sopenharmony_ci
6231cb0ef41Sopenharmony_ci  if (ares__slist_insert(channel->servers, server) == NULL) {
6241cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
6251cb0ef41Sopenharmony_ci    goto done;
6261cb0ef41Sopenharmony_ci  }
6271cb0ef41Sopenharmony_ci
6281cb0ef41Sopenharmony_ci  status = ARES_SUCCESS;
6291cb0ef41Sopenharmony_ci
6301cb0ef41Sopenharmony_cidone:
6311cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
6321cb0ef41Sopenharmony_ci    ares__destroy_server(server);
6331cb0ef41Sopenharmony_ci  }
6341cb0ef41Sopenharmony_ci
6351cb0ef41Sopenharmony_ci  return status;
6361cb0ef41Sopenharmony_ci}
6371cb0ef41Sopenharmony_ci
6381cb0ef41Sopenharmony_cistatic ares_bool_t ares__server_in_newconfig(const struct server_state *server,
6391cb0ef41Sopenharmony_ci                                             ares__llist_t             *srvlist)
6401cb0ef41Sopenharmony_ci{
6411cb0ef41Sopenharmony_ci  ares__llist_node_t   *node;
6421cb0ef41Sopenharmony_ci  const ares_channel_t *channel = server->channel;
6431cb0ef41Sopenharmony_ci
6441cb0ef41Sopenharmony_ci  for (node = ares__llist_node_first(srvlist); node != NULL;
6451cb0ef41Sopenharmony_ci       node = ares__llist_node_next(node)) {
6461cb0ef41Sopenharmony_ci    const ares_sconfig_t *s = ares__llist_node_val(node);
6471cb0ef41Sopenharmony_ci
6481cb0ef41Sopenharmony_ci    if (!ares__addr_match(&server->addr, &s->addr)) {
6491cb0ef41Sopenharmony_ci      continue;
6501cb0ef41Sopenharmony_ci    }
6511cb0ef41Sopenharmony_ci
6521cb0ef41Sopenharmony_ci    if (server->tcp_port != ares__sconfig_get_port(channel, s, ARES_TRUE)) {
6531cb0ef41Sopenharmony_ci      continue;
6541cb0ef41Sopenharmony_ci    }
6551cb0ef41Sopenharmony_ci
6561cb0ef41Sopenharmony_ci    if (server->udp_port != ares__sconfig_get_port(channel, s, ARES_FALSE)) {
6571cb0ef41Sopenharmony_ci      continue;
6581cb0ef41Sopenharmony_ci    }
6591cb0ef41Sopenharmony_ci
6601cb0ef41Sopenharmony_ci    return ARES_TRUE;
6611cb0ef41Sopenharmony_ci  }
6621cb0ef41Sopenharmony_ci
6631cb0ef41Sopenharmony_ci  return ARES_FALSE;
6641cb0ef41Sopenharmony_ci}
6651cb0ef41Sopenharmony_ci
6661cb0ef41Sopenharmony_cistatic void ares__servers_remove_stale(ares_channel_t *channel,
6671cb0ef41Sopenharmony_ci                                       ares__llist_t  *srvlist)
6681cb0ef41Sopenharmony_ci{
6691cb0ef41Sopenharmony_ci  ares__slist_node_t *snode = ares__slist_node_first(channel->servers);
6701cb0ef41Sopenharmony_ci
6711cb0ef41Sopenharmony_ci  while (snode != NULL) {
6721cb0ef41Sopenharmony_ci    ares__slist_node_t        *snext  = ares__slist_node_next(snode);
6731cb0ef41Sopenharmony_ci    const struct server_state *server = ares__slist_node_val(snode);
6741cb0ef41Sopenharmony_ci    if (!ares__server_in_newconfig(server, srvlist)) {
6751cb0ef41Sopenharmony_ci      /* This will clean up all server state via the destruction callback and
6761cb0ef41Sopenharmony_ci       * move any queries to new servers */
6771cb0ef41Sopenharmony_ci      ares__slist_node_destroy(snode);
6781cb0ef41Sopenharmony_ci    }
6791cb0ef41Sopenharmony_ci    snode = snext;
6801cb0ef41Sopenharmony_ci  }
6811cb0ef41Sopenharmony_ci}
6821cb0ef41Sopenharmony_ci
6831cb0ef41Sopenharmony_cistatic void ares__servers_trim_single(ares_channel_t *channel)
6841cb0ef41Sopenharmony_ci{
6851cb0ef41Sopenharmony_ci  while (ares__slist_len(channel->servers) > 1) {
6861cb0ef41Sopenharmony_ci    ares__slist_node_destroy(ares__slist_node_last(channel->servers));
6871cb0ef41Sopenharmony_ci  }
6881cb0ef41Sopenharmony_ci}
6891cb0ef41Sopenharmony_ci
6901cb0ef41Sopenharmony_ciares_status_t ares__servers_update(ares_channel_t *channel,
6911cb0ef41Sopenharmony_ci                                   ares__llist_t  *server_list,
6921cb0ef41Sopenharmony_ci                                   ares_bool_t     user_specified)
6931cb0ef41Sopenharmony_ci{
6941cb0ef41Sopenharmony_ci  ares__llist_node_t *node;
6951cb0ef41Sopenharmony_ci  size_t              idx = 0;
6961cb0ef41Sopenharmony_ci  ares_status_t       status;
6971cb0ef41Sopenharmony_ci
6981cb0ef41Sopenharmony_ci  if (channel == NULL) {
6991cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
7001cb0ef41Sopenharmony_ci  }
7011cb0ef41Sopenharmony_ci
7021cb0ef41Sopenharmony_ci  ares__channel_lock(channel);
7031cb0ef41Sopenharmony_ci
7041cb0ef41Sopenharmony_ci  /* NOTE: a NULL or zero entry server list is considered valid due to
7051cb0ef41Sopenharmony_ci   *       real-world people needing support for this for their test harnesses
7061cb0ef41Sopenharmony_ci   */
7071cb0ef41Sopenharmony_ci
7081cb0ef41Sopenharmony_ci  /* Add new entries */
7091cb0ef41Sopenharmony_ci  for (node = ares__llist_node_first(server_list); node != NULL;
7101cb0ef41Sopenharmony_ci       node = ares__llist_node_next(node)) {
7111cb0ef41Sopenharmony_ci    const ares_sconfig_t *sconfig = ares__llist_node_val(node);
7121cb0ef41Sopenharmony_ci    ares__slist_node_t   *snode;
7131cb0ef41Sopenharmony_ci
7141cb0ef41Sopenharmony_ci    /* Don't add duplicate servers! */
7151cb0ef41Sopenharmony_ci    if (ares__server_isdup(channel, node)) {
7161cb0ef41Sopenharmony_ci      continue;
7171cb0ef41Sopenharmony_ci    }
7181cb0ef41Sopenharmony_ci
7191cb0ef41Sopenharmony_ci    snode = ares__server_find(channel, sconfig);
7201cb0ef41Sopenharmony_ci    if (snode != NULL) {
7211cb0ef41Sopenharmony_ci      struct server_state *server = ares__slist_node_val(snode);
7221cb0ef41Sopenharmony_ci
7231cb0ef41Sopenharmony_ci      /* Copy over link-local settings.  Its possible some of this data has
7241cb0ef41Sopenharmony_ci       * changed, maybe ...  */
7251cb0ef41Sopenharmony_ci      if (ares_strlen(sconfig->ll_iface)) {
7261cb0ef41Sopenharmony_ci        ares_strcpy(server->ll_iface, sconfig->ll_iface,
7271cb0ef41Sopenharmony_ci                    sizeof(server->ll_iface));
7281cb0ef41Sopenharmony_ci        server->ll_scope = sconfig->ll_scope;
7291cb0ef41Sopenharmony_ci      }
7301cb0ef41Sopenharmony_ci
7311cb0ef41Sopenharmony_ci      if (server->idx != idx) {
7321cb0ef41Sopenharmony_ci        server->idx = idx;
7331cb0ef41Sopenharmony_ci        /* Index changed, reinsert node, doesn't require any memory
7341cb0ef41Sopenharmony_ci         * allocations so can't fail. */
7351cb0ef41Sopenharmony_ci        ares__slist_node_reinsert(snode);
7361cb0ef41Sopenharmony_ci      }
7371cb0ef41Sopenharmony_ci    } else {
7381cb0ef41Sopenharmony_ci      status = ares__server_create(channel, sconfig, idx);
7391cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
7401cb0ef41Sopenharmony_ci        goto done;
7411cb0ef41Sopenharmony_ci      }
7421cb0ef41Sopenharmony_ci    }
7431cb0ef41Sopenharmony_ci
7441cb0ef41Sopenharmony_ci    idx++;
7451cb0ef41Sopenharmony_ci  }
7461cb0ef41Sopenharmony_ci
7471cb0ef41Sopenharmony_ci  /* Remove any servers that don't exist in the current configuration */
7481cb0ef41Sopenharmony_ci  ares__servers_remove_stale(channel, server_list);
7491cb0ef41Sopenharmony_ci
7501cb0ef41Sopenharmony_ci  /* Trim to one server if ARES_FLAG_PRIMARY is set. */
7511cb0ef41Sopenharmony_ci  if (channel->flags & ARES_FLAG_PRIMARY) {
7521cb0ef41Sopenharmony_ci    ares__servers_trim_single(channel);
7531cb0ef41Sopenharmony_ci  }
7541cb0ef41Sopenharmony_ci
7551cb0ef41Sopenharmony_ci  if (user_specified) {
7561cb0ef41Sopenharmony_ci    /* Save servers as if they were passed in as an option */
7571cb0ef41Sopenharmony_ci    channel->optmask |= ARES_OPT_SERVERS;
7581cb0ef41Sopenharmony_ci  }
7591cb0ef41Sopenharmony_ci
7601cb0ef41Sopenharmony_ci  /* Clear any cached query results */
7611cb0ef41Sopenharmony_ci  ares__qcache_flush(channel->qcache);
7621cb0ef41Sopenharmony_ci
7631cb0ef41Sopenharmony_ci  status = ARES_SUCCESS;
7641cb0ef41Sopenharmony_ci
7651cb0ef41Sopenharmony_cidone:
7661cb0ef41Sopenharmony_ci  ares__channel_unlock(channel);
7671cb0ef41Sopenharmony_ci  return status;
7681cb0ef41Sopenharmony_ci}
7691cb0ef41Sopenharmony_ci
7701cb0ef41Sopenharmony_cistatic ares_status_t
7711cb0ef41Sopenharmony_ci  ares_addr_node_to_server_config_llist(const struct ares_addr_node *servers,
7721cb0ef41Sopenharmony_ci                                        ares__llist_t              **llist)
7731cb0ef41Sopenharmony_ci{
7741cb0ef41Sopenharmony_ci  const struct ares_addr_node *node;
7751cb0ef41Sopenharmony_ci  ares__llist_t               *s;
7761cb0ef41Sopenharmony_ci
7771cb0ef41Sopenharmony_ci  *llist = NULL;
7781cb0ef41Sopenharmony_ci
7791cb0ef41Sopenharmony_ci  s = ares__llist_create(ares_free);
7801cb0ef41Sopenharmony_ci  if (s == NULL) {
7811cb0ef41Sopenharmony_ci    goto fail;
7821cb0ef41Sopenharmony_ci  }
7831cb0ef41Sopenharmony_ci
7841cb0ef41Sopenharmony_ci  for (node = servers; node != NULL; node = node->next) {
7851cb0ef41Sopenharmony_ci    ares_sconfig_t *sconfig;
7861cb0ef41Sopenharmony_ci
7871cb0ef41Sopenharmony_ci    /* Invalid entry */
7881cb0ef41Sopenharmony_ci    if (node->family != AF_INET && node->family != AF_INET6) {
7891cb0ef41Sopenharmony_ci      continue;
7901cb0ef41Sopenharmony_ci    }
7911cb0ef41Sopenharmony_ci
7921cb0ef41Sopenharmony_ci    sconfig = ares_malloc_zero(sizeof(*sconfig));
7931cb0ef41Sopenharmony_ci    if (sconfig == NULL) {
7941cb0ef41Sopenharmony_ci      goto fail;
7951cb0ef41Sopenharmony_ci    }
7961cb0ef41Sopenharmony_ci
7971cb0ef41Sopenharmony_ci    sconfig->addr.family = node->family;
7981cb0ef41Sopenharmony_ci    if (node->family == AF_INET) {
7991cb0ef41Sopenharmony_ci      memcpy(&sconfig->addr.addr.addr4, &node->addr.addr4,
8001cb0ef41Sopenharmony_ci             sizeof(sconfig->addr.addr.addr4));
8011cb0ef41Sopenharmony_ci    } else if (sconfig->addr.family == AF_INET6) {
8021cb0ef41Sopenharmony_ci      memcpy(&sconfig->addr.addr.addr6, &node->addr.addr6,
8031cb0ef41Sopenharmony_ci             sizeof(sconfig->addr.addr.addr6));
8041cb0ef41Sopenharmony_ci    }
8051cb0ef41Sopenharmony_ci
8061cb0ef41Sopenharmony_ci    if (ares__llist_insert_last(s, sconfig) == NULL) {
8071cb0ef41Sopenharmony_ci      ares_free(sconfig);
8081cb0ef41Sopenharmony_ci      goto fail;
8091cb0ef41Sopenharmony_ci    }
8101cb0ef41Sopenharmony_ci  }
8111cb0ef41Sopenharmony_ci
8121cb0ef41Sopenharmony_ci  *llist = s;
8131cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
8141cb0ef41Sopenharmony_ci
8151cb0ef41Sopenharmony_cifail:
8161cb0ef41Sopenharmony_ci  ares__llist_destroy(s);
8171cb0ef41Sopenharmony_ci  return ARES_ENOMEM;
8181cb0ef41Sopenharmony_ci}
8191cb0ef41Sopenharmony_ci
8201cb0ef41Sopenharmony_cistatic ares_status_t ares_addr_port_node_to_server_config_llist(
8211cb0ef41Sopenharmony_ci  const struct ares_addr_port_node *servers, ares__llist_t **llist)
8221cb0ef41Sopenharmony_ci{
8231cb0ef41Sopenharmony_ci  const struct ares_addr_port_node *node;
8241cb0ef41Sopenharmony_ci  ares__llist_t                    *s;
8251cb0ef41Sopenharmony_ci
8261cb0ef41Sopenharmony_ci  *llist = NULL;
8271cb0ef41Sopenharmony_ci
8281cb0ef41Sopenharmony_ci  s = ares__llist_create(ares_free);
8291cb0ef41Sopenharmony_ci  if (s == NULL) {
8301cb0ef41Sopenharmony_ci    goto fail;
8311cb0ef41Sopenharmony_ci  }
8321cb0ef41Sopenharmony_ci
8331cb0ef41Sopenharmony_ci  for (node = servers; node != NULL; node = node->next) {
8341cb0ef41Sopenharmony_ci    ares_sconfig_t *sconfig;
8351cb0ef41Sopenharmony_ci
8361cb0ef41Sopenharmony_ci    /* Invalid entry */
8371cb0ef41Sopenharmony_ci    if (node->family != AF_INET && node->family != AF_INET6) {
8381cb0ef41Sopenharmony_ci      continue;
8391cb0ef41Sopenharmony_ci    }
8401cb0ef41Sopenharmony_ci
8411cb0ef41Sopenharmony_ci    sconfig = ares_malloc_zero(sizeof(*sconfig));
8421cb0ef41Sopenharmony_ci    if (sconfig == NULL) {
8431cb0ef41Sopenharmony_ci      goto fail;
8441cb0ef41Sopenharmony_ci    }
8451cb0ef41Sopenharmony_ci
8461cb0ef41Sopenharmony_ci    sconfig->addr.family = node->family;
8471cb0ef41Sopenharmony_ci    if (node->family == AF_INET) {
8481cb0ef41Sopenharmony_ci      memcpy(&sconfig->addr.addr.addr4, &node->addr.addr4,
8491cb0ef41Sopenharmony_ci             sizeof(sconfig->addr.addr.addr4));
8501cb0ef41Sopenharmony_ci    } else if (sconfig->addr.family == AF_INET6) {
8511cb0ef41Sopenharmony_ci      memcpy(&sconfig->addr.addr.addr6, &node->addr.addr6,
8521cb0ef41Sopenharmony_ci             sizeof(sconfig->addr.addr.addr6));
8531cb0ef41Sopenharmony_ci    }
8541cb0ef41Sopenharmony_ci
8551cb0ef41Sopenharmony_ci    sconfig->tcp_port = (unsigned short)node->tcp_port;
8561cb0ef41Sopenharmony_ci    sconfig->udp_port = (unsigned short)node->udp_port;
8571cb0ef41Sopenharmony_ci
8581cb0ef41Sopenharmony_ci    if (ares__llist_insert_last(s, sconfig) == NULL) {
8591cb0ef41Sopenharmony_ci      ares_free(sconfig);
8601cb0ef41Sopenharmony_ci      goto fail;
8611cb0ef41Sopenharmony_ci    }
8621cb0ef41Sopenharmony_ci  }
8631cb0ef41Sopenharmony_ci
8641cb0ef41Sopenharmony_ci  *llist = s;
8651cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
8661cb0ef41Sopenharmony_ci
8671cb0ef41Sopenharmony_cifail:
8681cb0ef41Sopenharmony_ci  ares__llist_destroy(s);
8691cb0ef41Sopenharmony_ci  return ARES_ENOMEM;
8701cb0ef41Sopenharmony_ci}
8711cb0ef41Sopenharmony_ci
8721cb0ef41Sopenharmony_ciares_status_t ares_in_addr_to_server_config_llist(const struct in_addr *servers,
8731cb0ef41Sopenharmony_ci                                                  size_t          nservers,
8741cb0ef41Sopenharmony_ci                                                  ares__llist_t **llist)
8751cb0ef41Sopenharmony_ci{
8761cb0ef41Sopenharmony_ci  size_t         i;
8771cb0ef41Sopenharmony_ci  ares__llist_t *s;
8781cb0ef41Sopenharmony_ci
8791cb0ef41Sopenharmony_ci  *llist = NULL;
8801cb0ef41Sopenharmony_ci
8811cb0ef41Sopenharmony_ci  s = ares__llist_create(ares_free);
8821cb0ef41Sopenharmony_ci  if (s == NULL) {
8831cb0ef41Sopenharmony_ci    goto fail;
8841cb0ef41Sopenharmony_ci  }
8851cb0ef41Sopenharmony_ci
8861cb0ef41Sopenharmony_ci  for (i = 0; servers != NULL && i < nservers; i++) {
8871cb0ef41Sopenharmony_ci    ares_sconfig_t *sconfig;
8881cb0ef41Sopenharmony_ci
8891cb0ef41Sopenharmony_ci    sconfig = ares_malloc_zero(sizeof(*sconfig));
8901cb0ef41Sopenharmony_ci    if (sconfig == NULL) {
8911cb0ef41Sopenharmony_ci      goto fail;
8921cb0ef41Sopenharmony_ci    }
8931cb0ef41Sopenharmony_ci
8941cb0ef41Sopenharmony_ci    sconfig->addr.family = AF_INET;
8951cb0ef41Sopenharmony_ci    memcpy(&sconfig->addr.addr.addr4, &servers[i],
8961cb0ef41Sopenharmony_ci           sizeof(sconfig->addr.addr.addr4));
8971cb0ef41Sopenharmony_ci
8981cb0ef41Sopenharmony_ci    if (ares__llist_insert_last(s, sconfig) == NULL) {
8991cb0ef41Sopenharmony_ci      goto fail;
9001cb0ef41Sopenharmony_ci    }
9011cb0ef41Sopenharmony_ci  }
9021cb0ef41Sopenharmony_ci
9031cb0ef41Sopenharmony_ci  *llist = s;
9041cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
9051cb0ef41Sopenharmony_ci
9061cb0ef41Sopenharmony_cifail:
9071cb0ef41Sopenharmony_ci  ares__llist_destroy(s);
9081cb0ef41Sopenharmony_ci  return ARES_ENOMEM;
9091cb0ef41Sopenharmony_ci}
9101cb0ef41Sopenharmony_ci
9111cb0ef41Sopenharmony_ciint ares_get_servers(ares_channel_t *channel, struct ares_addr_node **servers)
9121cb0ef41Sopenharmony_ci{
9131cb0ef41Sopenharmony_ci  struct ares_addr_node *srvr_head = NULL;
9141cb0ef41Sopenharmony_ci  struct ares_addr_node *srvr_last = NULL;
9151cb0ef41Sopenharmony_ci  struct ares_addr_node *srvr_curr;
9161cb0ef41Sopenharmony_ci  ares_status_t          status = ARES_SUCCESS;
9171cb0ef41Sopenharmony_ci  ares__slist_node_t    *node;
9181cb0ef41Sopenharmony_ci
9191cb0ef41Sopenharmony_ci  if (channel == NULL) {
9201cb0ef41Sopenharmony_ci    return ARES_ENODATA;
9211cb0ef41Sopenharmony_ci  }
9221cb0ef41Sopenharmony_ci
9231cb0ef41Sopenharmony_ci  ares__channel_lock(channel);
9241cb0ef41Sopenharmony_ci
9251cb0ef41Sopenharmony_ci  for (node = ares__slist_node_first(channel->servers); node != NULL;
9261cb0ef41Sopenharmony_ci       node = ares__slist_node_next(node)) {
9271cb0ef41Sopenharmony_ci    const struct server_state *server = ares__slist_node_val(node);
9281cb0ef41Sopenharmony_ci
9291cb0ef41Sopenharmony_ci    /* Allocate storage for this server node appending it to the list */
9301cb0ef41Sopenharmony_ci    srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_NODE);
9311cb0ef41Sopenharmony_ci    if (!srvr_curr) {
9321cb0ef41Sopenharmony_ci      status = ARES_ENOMEM;
9331cb0ef41Sopenharmony_ci      break;
9341cb0ef41Sopenharmony_ci    }
9351cb0ef41Sopenharmony_ci    if (srvr_last) {
9361cb0ef41Sopenharmony_ci      srvr_last->next = srvr_curr;
9371cb0ef41Sopenharmony_ci    } else {
9381cb0ef41Sopenharmony_ci      srvr_head = srvr_curr;
9391cb0ef41Sopenharmony_ci    }
9401cb0ef41Sopenharmony_ci    srvr_last = srvr_curr;
9411cb0ef41Sopenharmony_ci
9421cb0ef41Sopenharmony_ci    /* Fill this server node data */
9431cb0ef41Sopenharmony_ci    srvr_curr->family = server->addr.family;
9441cb0ef41Sopenharmony_ci    if (srvr_curr->family == AF_INET) {
9451cb0ef41Sopenharmony_ci      memcpy(&srvr_curr->addr.addr4, &server->addr.addr.addr4,
9461cb0ef41Sopenharmony_ci             sizeof(srvr_curr->addr.addr4));
9471cb0ef41Sopenharmony_ci    } else {
9481cb0ef41Sopenharmony_ci      memcpy(&srvr_curr->addr.addr6, &server->addr.addr.addr6,
9491cb0ef41Sopenharmony_ci             sizeof(srvr_curr->addr.addr6));
9501cb0ef41Sopenharmony_ci    }
9511cb0ef41Sopenharmony_ci  }
9521cb0ef41Sopenharmony_ci
9531cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
9541cb0ef41Sopenharmony_ci    ares_free_data(srvr_head);
9551cb0ef41Sopenharmony_ci    srvr_head = NULL;
9561cb0ef41Sopenharmony_ci  }
9571cb0ef41Sopenharmony_ci
9581cb0ef41Sopenharmony_ci  *servers = srvr_head;
9591cb0ef41Sopenharmony_ci
9601cb0ef41Sopenharmony_ci  ares__channel_unlock(channel);
9611cb0ef41Sopenharmony_ci
9621cb0ef41Sopenharmony_ci  return (int)status;
9631cb0ef41Sopenharmony_ci}
9641cb0ef41Sopenharmony_ci
9651cb0ef41Sopenharmony_ciint ares_get_servers_ports(ares_channel_t              *channel,
9661cb0ef41Sopenharmony_ci                           struct ares_addr_port_node **servers)
9671cb0ef41Sopenharmony_ci{
9681cb0ef41Sopenharmony_ci  struct ares_addr_port_node *srvr_head = NULL;
9691cb0ef41Sopenharmony_ci  struct ares_addr_port_node *srvr_last = NULL;
9701cb0ef41Sopenharmony_ci  struct ares_addr_port_node *srvr_curr;
9711cb0ef41Sopenharmony_ci  ares_status_t               status = ARES_SUCCESS;
9721cb0ef41Sopenharmony_ci  ares__slist_node_t         *node;
9731cb0ef41Sopenharmony_ci
9741cb0ef41Sopenharmony_ci  if (channel == NULL) {
9751cb0ef41Sopenharmony_ci    return ARES_ENODATA;
9761cb0ef41Sopenharmony_ci  }
9771cb0ef41Sopenharmony_ci
9781cb0ef41Sopenharmony_ci  ares__channel_lock(channel);
9791cb0ef41Sopenharmony_ci
9801cb0ef41Sopenharmony_ci  for (node = ares__slist_node_first(channel->servers); node != NULL;
9811cb0ef41Sopenharmony_ci       node = ares__slist_node_next(node)) {
9821cb0ef41Sopenharmony_ci    const struct server_state *server = ares__slist_node_val(node);
9831cb0ef41Sopenharmony_ci
9841cb0ef41Sopenharmony_ci    /* Allocate storage for this server node appending it to the list */
9851cb0ef41Sopenharmony_ci    srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_PORT_NODE);
9861cb0ef41Sopenharmony_ci    if (!srvr_curr) {
9871cb0ef41Sopenharmony_ci      status = ARES_ENOMEM;
9881cb0ef41Sopenharmony_ci      break;
9891cb0ef41Sopenharmony_ci    }
9901cb0ef41Sopenharmony_ci    if (srvr_last) {
9911cb0ef41Sopenharmony_ci      srvr_last->next = srvr_curr;
9921cb0ef41Sopenharmony_ci    } else {
9931cb0ef41Sopenharmony_ci      srvr_head = srvr_curr;
9941cb0ef41Sopenharmony_ci    }
9951cb0ef41Sopenharmony_ci    srvr_last = srvr_curr;
9961cb0ef41Sopenharmony_ci
9971cb0ef41Sopenharmony_ci    /* Fill this server node data */
9981cb0ef41Sopenharmony_ci    srvr_curr->family   = server->addr.family;
9991cb0ef41Sopenharmony_ci    srvr_curr->udp_port = server->udp_port;
10001cb0ef41Sopenharmony_ci    srvr_curr->tcp_port = server->tcp_port;
10011cb0ef41Sopenharmony_ci
10021cb0ef41Sopenharmony_ci    if (srvr_curr->family == AF_INET) {
10031cb0ef41Sopenharmony_ci      memcpy(&srvr_curr->addr.addr4, &server->addr.addr.addr4,
10041cb0ef41Sopenharmony_ci             sizeof(srvr_curr->addr.addr4));
10051cb0ef41Sopenharmony_ci    } else {
10061cb0ef41Sopenharmony_ci      memcpy(&srvr_curr->addr.addr6, &server->addr.addr.addr6,
10071cb0ef41Sopenharmony_ci             sizeof(srvr_curr->addr.addr6));
10081cb0ef41Sopenharmony_ci    }
10091cb0ef41Sopenharmony_ci  }
10101cb0ef41Sopenharmony_ci
10111cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
10121cb0ef41Sopenharmony_ci    ares_free_data(srvr_head);
10131cb0ef41Sopenharmony_ci    srvr_head = NULL;
10141cb0ef41Sopenharmony_ci  }
10151cb0ef41Sopenharmony_ci
10161cb0ef41Sopenharmony_ci  *servers = srvr_head;
10171cb0ef41Sopenharmony_ci
10181cb0ef41Sopenharmony_ci  ares__channel_unlock(channel);
10191cb0ef41Sopenharmony_ci  return (int)status;
10201cb0ef41Sopenharmony_ci}
10211cb0ef41Sopenharmony_ci
10221cb0ef41Sopenharmony_ciint ares_set_servers(ares_channel_t              *channel,
10231cb0ef41Sopenharmony_ci                     const struct ares_addr_node *servers)
10241cb0ef41Sopenharmony_ci{
10251cb0ef41Sopenharmony_ci  ares__llist_t *slist;
10261cb0ef41Sopenharmony_ci  ares_status_t  status;
10271cb0ef41Sopenharmony_ci
10281cb0ef41Sopenharmony_ci  if (channel == NULL) {
10291cb0ef41Sopenharmony_ci    return ARES_ENODATA;
10301cb0ef41Sopenharmony_ci  }
10311cb0ef41Sopenharmony_ci
10321cb0ef41Sopenharmony_ci  status = ares_addr_node_to_server_config_llist(servers, &slist);
10331cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
10341cb0ef41Sopenharmony_ci    return (int)status;
10351cb0ef41Sopenharmony_ci  }
10361cb0ef41Sopenharmony_ci
10371cb0ef41Sopenharmony_ci  /* NOTE: lock is in ares__servers_update() */
10381cb0ef41Sopenharmony_ci  status = ares__servers_update(channel, slist, ARES_TRUE);
10391cb0ef41Sopenharmony_ci
10401cb0ef41Sopenharmony_ci  ares__llist_destroy(slist);
10411cb0ef41Sopenharmony_ci
10421cb0ef41Sopenharmony_ci  return (int)status;
10431cb0ef41Sopenharmony_ci}
10441cb0ef41Sopenharmony_ci
10451cb0ef41Sopenharmony_ciint ares_set_servers_ports(ares_channel_t                   *channel,
10461cb0ef41Sopenharmony_ci                           const struct ares_addr_port_node *servers)
10471cb0ef41Sopenharmony_ci{
10481cb0ef41Sopenharmony_ci  ares__llist_t *slist;
10491cb0ef41Sopenharmony_ci  ares_status_t  status;
10501cb0ef41Sopenharmony_ci
10511cb0ef41Sopenharmony_ci  if (channel == NULL) {
10521cb0ef41Sopenharmony_ci    return ARES_ENODATA;
10531cb0ef41Sopenharmony_ci  }
10541cb0ef41Sopenharmony_ci
10551cb0ef41Sopenharmony_ci  status = ares_addr_port_node_to_server_config_llist(servers, &slist);
10561cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
10571cb0ef41Sopenharmony_ci    return (int)status;
10581cb0ef41Sopenharmony_ci  }
10591cb0ef41Sopenharmony_ci
10601cb0ef41Sopenharmony_ci  /* NOTE: lock is in ares__servers_update() */
10611cb0ef41Sopenharmony_ci  status = ares__servers_update(channel, slist, ARES_TRUE);
10621cb0ef41Sopenharmony_ci
10631cb0ef41Sopenharmony_ci  ares__llist_destroy(slist);
10641cb0ef41Sopenharmony_ci
10651cb0ef41Sopenharmony_ci  return (int)status;
10661cb0ef41Sopenharmony_ci}
10671cb0ef41Sopenharmony_ci
10681cb0ef41Sopenharmony_ci/* Incoming string format: host[:port][,host[:port]]... */
10691cb0ef41Sopenharmony_ci/* IPv6 addresses with ports require square brackets [fe80::1]:53 */
10701cb0ef41Sopenharmony_cistatic ares_status_t set_servers_csv(ares_channel_t *channel, const char *_csv)
10711cb0ef41Sopenharmony_ci{
10721cb0ef41Sopenharmony_ci  ares_status_t  status;
10731cb0ef41Sopenharmony_ci  ares__llist_t *slist = NULL;
10741cb0ef41Sopenharmony_ci
10751cb0ef41Sopenharmony_ci  if (channel == NULL) {
10761cb0ef41Sopenharmony_ci    return ARES_ENODATA;
10771cb0ef41Sopenharmony_ci  }
10781cb0ef41Sopenharmony_ci
10791cb0ef41Sopenharmony_ci  /* NOTE: lock is in ares__servers_update() */
10801cb0ef41Sopenharmony_ci
10811cb0ef41Sopenharmony_ci  if (ares_strlen(_csv) == 0) {
10821cb0ef41Sopenharmony_ci    /* blank all servers */
10831cb0ef41Sopenharmony_ci    return (ares_status_t)ares_set_servers_ports(channel, NULL);
10841cb0ef41Sopenharmony_ci  }
10851cb0ef41Sopenharmony_ci
10861cb0ef41Sopenharmony_ci  status = ares__sconfig_append_fromstr(&slist, _csv, ARES_FALSE);
10871cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
10881cb0ef41Sopenharmony_ci    ares__llist_destroy(slist);
10891cb0ef41Sopenharmony_ci    return status;
10901cb0ef41Sopenharmony_ci  }
10911cb0ef41Sopenharmony_ci
10921cb0ef41Sopenharmony_ci  /* NOTE: lock is in ares__servers_update() */
10931cb0ef41Sopenharmony_ci  status = ares__servers_update(channel, slist, ARES_TRUE);
10941cb0ef41Sopenharmony_ci
10951cb0ef41Sopenharmony_ci  ares__llist_destroy(slist);
10961cb0ef41Sopenharmony_ci
10971cb0ef41Sopenharmony_ci  return status;
10981cb0ef41Sopenharmony_ci}
10991cb0ef41Sopenharmony_ci
11001cb0ef41Sopenharmony_ci/* We'll go ahead and honor ports anyhow */
11011cb0ef41Sopenharmony_ciint ares_set_servers_csv(ares_channel_t *channel, const char *_csv)
11021cb0ef41Sopenharmony_ci{
11031cb0ef41Sopenharmony_ci  /* NOTE: lock is in ares__servers_update() */
11041cb0ef41Sopenharmony_ci  return (int)set_servers_csv(channel, _csv);
11051cb0ef41Sopenharmony_ci}
11061cb0ef41Sopenharmony_ci
11071cb0ef41Sopenharmony_ciint ares_set_servers_ports_csv(ares_channel_t *channel, const char *_csv)
11081cb0ef41Sopenharmony_ci{
11091cb0ef41Sopenharmony_ci  /* NOTE: lock is in ares__servers_update() */
11101cb0ef41Sopenharmony_ci  return (int)set_servers_csv(channel, _csv);
11111cb0ef41Sopenharmony_ci}
11121cb0ef41Sopenharmony_ci
11131cb0ef41Sopenharmony_cichar *ares_get_servers_csv(ares_channel_t *channel)
11141cb0ef41Sopenharmony_ci{
11151cb0ef41Sopenharmony_ci  ares__buf_t        *buf = NULL;
11161cb0ef41Sopenharmony_ci  char               *out = NULL;
11171cb0ef41Sopenharmony_ci  ares__slist_node_t *node;
11181cb0ef41Sopenharmony_ci
11191cb0ef41Sopenharmony_ci  ares__channel_lock(channel);
11201cb0ef41Sopenharmony_ci
11211cb0ef41Sopenharmony_ci  buf = ares__buf_create();
11221cb0ef41Sopenharmony_ci  if (buf == NULL) {
11231cb0ef41Sopenharmony_ci    goto done;
11241cb0ef41Sopenharmony_ci  }
11251cb0ef41Sopenharmony_ci
11261cb0ef41Sopenharmony_ci  for (node = ares__slist_node_first(channel->servers); node != NULL;
11271cb0ef41Sopenharmony_ci       node = ares__slist_node_next(node)) {
11281cb0ef41Sopenharmony_ci    ares_status_t              status;
11291cb0ef41Sopenharmony_ci    const struct server_state *server = ares__slist_node_val(node);
11301cb0ef41Sopenharmony_ci    char                       addr[64];
11311cb0ef41Sopenharmony_ci
11321cb0ef41Sopenharmony_ci    if (ares__buf_len(buf)) {
11331cb0ef41Sopenharmony_ci      status = ares__buf_append_byte(buf, ',');
11341cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
11351cb0ef41Sopenharmony_ci        goto done;
11361cb0ef41Sopenharmony_ci      }
11371cb0ef41Sopenharmony_ci    }
11381cb0ef41Sopenharmony_ci
11391cb0ef41Sopenharmony_ci    /* ipv4addr or [ipv6addr] */
11401cb0ef41Sopenharmony_ci    if (server->addr.family == AF_INET6) {
11411cb0ef41Sopenharmony_ci      status = ares__buf_append_byte(buf, '[');
11421cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
11431cb0ef41Sopenharmony_ci        goto done;
11441cb0ef41Sopenharmony_ci      }
11451cb0ef41Sopenharmony_ci    }
11461cb0ef41Sopenharmony_ci
11471cb0ef41Sopenharmony_ci    ares_inet_ntop(server->addr.family, &server->addr.addr, addr, sizeof(addr));
11481cb0ef41Sopenharmony_ci
11491cb0ef41Sopenharmony_ci    status = ares__buf_append_str(buf, addr);
11501cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
11511cb0ef41Sopenharmony_ci      goto done;
11521cb0ef41Sopenharmony_ci    }
11531cb0ef41Sopenharmony_ci
11541cb0ef41Sopenharmony_ci    if (server->addr.family == AF_INET6) {
11551cb0ef41Sopenharmony_ci      status = ares__buf_append_byte(buf, ']');
11561cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
11571cb0ef41Sopenharmony_ci        goto done;
11581cb0ef41Sopenharmony_ci      }
11591cb0ef41Sopenharmony_ci    }
11601cb0ef41Sopenharmony_ci
11611cb0ef41Sopenharmony_ci    /* :port */
11621cb0ef41Sopenharmony_ci    status = ares__buf_append_byte(buf, ':');
11631cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
11641cb0ef41Sopenharmony_ci      goto done;
11651cb0ef41Sopenharmony_ci    }
11661cb0ef41Sopenharmony_ci
11671cb0ef41Sopenharmony_ci    status = ares__buf_append_num_dec(buf, server->udp_port, 0);
11681cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
11691cb0ef41Sopenharmony_ci      goto done;
11701cb0ef41Sopenharmony_ci    }
11711cb0ef41Sopenharmony_ci
11721cb0ef41Sopenharmony_ci    /* %iface */
11731cb0ef41Sopenharmony_ci    if (ares_strlen(server->ll_iface)) {
11741cb0ef41Sopenharmony_ci      status = ares__buf_append_byte(buf, '%');
11751cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
11761cb0ef41Sopenharmony_ci        goto done;
11771cb0ef41Sopenharmony_ci      }
11781cb0ef41Sopenharmony_ci
11791cb0ef41Sopenharmony_ci      status = ares__buf_append_str(buf, server->ll_iface);
11801cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
11811cb0ef41Sopenharmony_ci        goto done;
11821cb0ef41Sopenharmony_ci      }
11831cb0ef41Sopenharmony_ci    }
11841cb0ef41Sopenharmony_ci  }
11851cb0ef41Sopenharmony_ci
11861cb0ef41Sopenharmony_ci  out = ares__buf_finish_str(buf, NULL);
11871cb0ef41Sopenharmony_ci  buf = NULL;
11881cb0ef41Sopenharmony_ci
11891cb0ef41Sopenharmony_cidone:
11901cb0ef41Sopenharmony_ci  ares__channel_unlock(channel);
11911cb0ef41Sopenharmony_ci  ares__buf_destroy(buf);
11921cb0ef41Sopenharmony_ci  return out;
11931cb0ef41Sopenharmony_ci}
1194