11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 1998, 2011, 2013 Massachusetts Institute of Technology
41cb0ef41Sopenharmony_ci * Copyright (c) 2017 Christian Ammer
51cb0ef41Sopenharmony_ci * Copyright (c) 2019 Andrew Selivanov
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
291cb0ef41Sopenharmony_ci#include "ares_setup.h"
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci#ifdef HAVE_GETSERVBYNAME_R
321cb0ef41Sopenharmony_ci#  if !defined(GETSERVBYNAME_R_ARGS) || (GETSERVBYNAME_R_ARGS < 4) || \
331cb0ef41Sopenharmony_ci    (GETSERVBYNAME_R_ARGS > 6)
341cb0ef41Sopenharmony_ci#    error "you MUST specify a valid number of arguments for getservbyname_r"
351cb0ef41Sopenharmony_ci#  endif
361cb0ef41Sopenharmony_ci#endif
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
391cb0ef41Sopenharmony_ci#  include <netinet/in.h>
401cb0ef41Sopenharmony_ci#endif
411cb0ef41Sopenharmony_ci#ifdef HAVE_NETDB_H
421cb0ef41Sopenharmony_ci#  include <netdb.h>
431cb0ef41Sopenharmony_ci#endif
441cb0ef41Sopenharmony_ci#ifdef HAVE_ARPA_INET_H
451cb0ef41Sopenharmony_ci#  include <arpa/inet.h>
461cb0ef41Sopenharmony_ci#endif
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci#include "ares_nameser.h"
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci#ifdef HAVE_STRINGS_H
511cb0ef41Sopenharmony_ci#  include <strings.h>
521cb0ef41Sopenharmony_ci#endif
531cb0ef41Sopenharmony_ci#include <assert.h>
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci#ifdef HAVE_LIMITS_H
561cb0ef41Sopenharmony_ci#  include <limits.h>
571cb0ef41Sopenharmony_ci#endif
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci#include "ares.h"
601cb0ef41Sopenharmony_ci#include "ares_private.h"
611cb0ef41Sopenharmony_ci#include "ares_dns.h"
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci#ifdef WATT32
641cb0ef41Sopenharmony_ci#  undef WIN32
651cb0ef41Sopenharmony_ci#endif
661cb0ef41Sopenharmony_ci#ifdef WIN32
671cb0ef41Sopenharmony_ci#  include "ares_platform.h"
681cb0ef41Sopenharmony_ci#endif
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_cistruct host_query {
711cb0ef41Sopenharmony_ci  ares_channel_t            *channel;
721cb0ef41Sopenharmony_ci  char                      *name;
731cb0ef41Sopenharmony_ci  unsigned short             port; /* in host order */
741cb0ef41Sopenharmony_ci  ares_addrinfo_callback     callback;
751cb0ef41Sopenharmony_ci  void                      *arg;
761cb0ef41Sopenharmony_ci  struct ares_addrinfo_hints hints;
771cb0ef41Sopenharmony_ci  int    sent_family; /* this family is what was is being used */
781cb0ef41Sopenharmony_ci  size_t timeouts;    /* number of timeouts we saw for this request */
791cb0ef41Sopenharmony_ci  char  *lookups; /* Duplicate memory from channel because of ares_reinit() */
801cb0ef41Sopenharmony_ci  const char *remaining_lookups; /* types of lookup we need to perform ("fb" by
811cb0ef41Sopenharmony_ci                                    default, file and dns respectively) */
821cb0ef41Sopenharmony_ci  char      **domains; /* duplicate from channel for ares_reinit() safety */
831cb0ef41Sopenharmony_ci  size_t      ndomains;
841cb0ef41Sopenharmony_ci  struct ares_addrinfo *ai;          /* store results between lookups */
851cb0ef41Sopenharmony_ci  unsigned short        qid_a;       /* qid for A request */
861cb0ef41Sopenharmony_ci  unsigned short        qid_aaaa;    /* qid for AAAA request */
871cb0ef41Sopenharmony_ci  size_t                remaining;   /* number of DNS answers waiting for */
881cb0ef41Sopenharmony_ci  ares_ssize_t          next_domain; /* next search domain to try */
891cb0ef41Sopenharmony_ci  size_t
901cb0ef41Sopenharmony_ci    nodata_cnt; /* Track nodata responses to possibly override final result */
911cb0ef41Sopenharmony_ci};
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_cistatic const struct ares_addrinfo_hints default_hints = {
941cb0ef41Sopenharmony_ci  0,         /* ai_flags */
951cb0ef41Sopenharmony_ci  AF_UNSPEC, /* ai_family */
961cb0ef41Sopenharmony_ci  0,         /* ai_socktype */
971cb0ef41Sopenharmony_ci  0,         /* ai_protocol */
981cb0ef41Sopenharmony_ci};
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci/* forward declarations */
1011cb0ef41Sopenharmony_cistatic void        host_callback(void *arg, int status, int timeouts,
1021cb0ef41Sopenharmony_ci                                 unsigned char *abuf, int alen);
1031cb0ef41Sopenharmony_cistatic ares_bool_t as_is_first(const struct host_query *hquery);
1041cb0ef41Sopenharmony_cistatic ares_bool_t as_is_only(const struct host_query *hquery);
1051cb0ef41Sopenharmony_cistatic ares_bool_t next_dns_lookup(struct host_query *hquery);
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_cistruct ares_addrinfo_cname *
1081cb0ef41Sopenharmony_ci  ares__append_addrinfo_cname(struct ares_addrinfo_cname **head)
1091cb0ef41Sopenharmony_ci{
1101cb0ef41Sopenharmony_ci  struct ares_addrinfo_cname *tail = ares_malloc_zero(sizeof(*tail));
1111cb0ef41Sopenharmony_ci  struct ares_addrinfo_cname *last = *head;
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  if (tail == NULL) {
1141cb0ef41Sopenharmony_ci    return NULL;
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  if (!last) {
1181cb0ef41Sopenharmony_ci    *head = tail;
1191cb0ef41Sopenharmony_ci    return tail;
1201cb0ef41Sopenharmony_ci  }
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  while (last->next) {
1231cb0ef41Sopenharmony_ci    last = last->next;
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  last->next = tail;
1271cb0ef41Sopenharmony_ci  return tail;
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_civoid ares__addrinfo_cat_cnames(struct ares_addrinfo_cname **head,
1311cb0ef41Sopenharmony_ci                               struct ares_addrinfo_cname  *tail)
1321cb0ef41Sopenharmony_ci{
1331cb0ef41Sopenharmony_ci  struct ares_addrinfo_cname *last = *head;
1341cb0ef41Sopenharmony_ci  if (!last) {
1351cb0ef41Sopenharmony_ci    *head = tail;
1361cb0ef41Sopenharmony_ci    return;
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  while (last->next) {
1401cb0ef41Sopenharmony_ci    last = last->next;
1411cb0ef41Sopenharmony_ci  }
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci  last->next = tail;
1441cb0ef41Sopenharmony_ci}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci/* Allocate new addrinfo and append to the tail. */
1471cb0ef41Sopenharmony_cistruct ares_addrinfo_node *
1481cb0ef41Sopenharmony_ci  ares__append_addrinfo_node(struct ares_addrinfo_node **head)
1491cb0ef41Sopenharmony_ci{
1501cb0ef41Sopenharmony_ci  struct ares_addrinfo_node *tail = ares_malloc_zero(sizeof(*tail));
1511cb0ef41Sopenharmony_ci  struct ares_addrinfo_node *last = *head;
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  if (tail == NULL) {
1541cb0ef41Sopenharmony_ci    return NULL;
1551cb0ef41Sopenharmony_ci  }
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  if (!last) {
1581cb0ef41Sopenharmony_ci    *head = tail;
1591cb0ef41Sopenharmony_ci    return tail;
1601cb0ef41Sopenharmony_ci  }
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  while (last->ai_next) {
1631cb0ef41Sopenharmony_ci    last = last->ai_next;
1641cb0ef41Sopenharmony_ci  }
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  last->ai_next = tail;
1671cb0ef41Sopenharmony_ci  return tail;
1681cb0ef41Sopenharmony_ci}
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_civoid ares__addrinfo_cat_nodes(struct ares_addrinfo_node **head,
1711cb0ef41Sopenharmony_ci                              struct ares_addrinfo_node  *tail)
1721cb0ef41Sopenharmony_ci{
1731cb0ef41Sopenharmony_ci  struct ares_addrinfo_node *last = *head;
1741cb0ef41Sopenharmony_ci  if (!last) {
1751cb0ef41Sopenharmony_ci    *head = tail;
1761cb0ef41Sopenharmony_ci    return;
1771cb0ef41Sopenharmony_ci  }
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  while (last->ai_next) {
1801cb0ef41Sopenharmony_ci    last = last->ai_next;
1811cb0ef41Sopenharmony_ci  }
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci  last->ai_next = tail;
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci/* Resolve service name into port number given in host byte order.
1871cb0ef41Sopenharmony_ci * If not resolved, return 0.
1881cb0ef41Sopenharmony_ci */
1891cb0ef41Sopenharmony_cistatic unsigned short lookup_service(const char *service, int flags)
1901cb0ef41Sopenharmony_ci{
1911cb0ef41Sopenharmony_ci  const char     *proto;
1921cb0ef41Sopenharmony_ci  struct servent *sep;
1931cb0ef41Sopenharmony_ci#ifdef HAVE_GETSERVBYNAME_R
1941cb0ef41Sopenharmony_ci  struct servent se;
1951cb0ef41Sopenharmony_ci  char           tmpbuf[4096];
1961cb0ef41Sopenharmony_ci#endif
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci  if (service) {
1991cb0ef41Sopenharmony_ci    if (flags & ARES_NI_UDP) {
2001cb0ef41Sopenharmony_ci      proto = "udp";
2011cb0ef41Sopenharmony_ci    } else if (flags & ARES_NI_SCTP) {
2021cb0ef41Sopenharmony_ci      proto = "sctp";
2031cb0ef41Sopenharmony_ci    } else if (flags & ARES_NI_DCCP) {
2041cb0ef41Sopenharmony_ci      proto = "dccp";
2051cb0ef41Sopenharmony_ci    } else {
2061cb0ef41Sopenharmony_ci      proto = "tcp";
2071cb0ef41Sopenharmony_ci    }
2081cb0ef41Sopenharmony_ci#ifdef HAVE_GETSERVBYNAME_R
2091cb0ef41Sopenharmony_ci    memset(&se, 0, sizeof(se));
2101cb0ef41Sopenharmony_ci    sep = &se;
2111cb0ef41Sopenharmony_ci    memset(tmpbuf, 0, sizeof(tmpbuf));
2121cb0ef41Sopenharmony_ci#  if GETSERVBYNAME_R_ARGS == 6
2131cb0ef41Sopenharmony_ci    if (getservbyname_r(service, proto, &se, (void *)tmpbuf, sizeof(tmpbuf),
2141cb0ef41Sopenharmony_ci                        &sep) != 0) {
2151cb0ef41Sopenharmony_ci      sep = NULL; /* LCOV_EXCL_LINE: buffer large so this never fails */
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci#  elif GETSERVBYNAME_R_ARGS == 5
2181cb0ef41Sopenharmony_ci    sep = getservbyname_r(service, proto, &se, (void *)tmpbuf, sizeof(tmpbuf));
2191cb0ef41Sopenharmony_ci#  elif GETSERVBYNAME_R_ARGS == 4
2201cb0ef41Sopenharmony_ci    if (getservbyname_r(service, proto, &se, (void *)tmpbuf) != 0) {
2211cb0ef41Sopenharmony_ci      sep = NULL;
2221cb0ef41Sopenharmony_ci    }
2231cb0ef41Sopenharmony_ci#  else
2241cb0ef41Sopenharmony_ci    /* Lets just hope the OS uses TLS! */
2251cb0ef41Sopenharmony_ci    sep = getservbyname(service, proto);
2261cb0ef41Sopenharmony_ci#  endif
2271cb0ef41Sopenharmony_ci#else
2281cb0ef41Sopenharmony_ci    /* Lets just hope the OS uses TLS! */
2291cb0ef41Sopenharmony_ci#  if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
2301cb0ef41Sopenharmony_ci    sep = getservbyname(service, (char *)proto);
2311cb0ef41Sopenharmony_ci#  else
2321cb0ef41Sopenharmony_ci    sep = getservbyname(service, proto);
2331cb0ef41Sopenharmony_ci#  endif
2341cb0ef41Sopenharmony_ci#endif
2351cb0ef41Sopenharmony_ci    return (sep ? ntohs((unsigned short)sep->s_port) : 0);
2361cb0ef41Sopenharmony_ci  }
2371cb0ef41Sopenharmony_ci  return 0;
2381cb0ef41Sopenharmony_ci}
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ci/* If the name looks like an IP address or an error occurred,
2411cb0ef41Sopenharmony_ci * fake up a host entry, end the query immediately, and return true.
2421cb0ef41Sopenharmony_ci * Otherwise return false.
2431cb0ef41Sopenharmony_ci */
2441cb0ef41Sopenharmony_cistatic ares_bool_t fake_addrinfo(const char *name, unsigned short port,
2451cb0ef41Sopenharmony_ci                                 const struct ares_addrinfo_hints *hints,
2461cb0ef41Sopenharmony_ci                                 struct ares_addrinfo             *ai,
2471cb0ef41Sopenharmony_ci                                 ares_addrinfo_callback callback, void *arg)
2481cb0ef41Sopenharmony_ci{
2491cb0ef41Sopenharmony_ci  struct ares_addrinfo_cname *cname;
2501cb0ef41Sopenharmony_ci  ares_status_t               status = ARES_SUCCESS;
2511cb0ef41Sopenharmony_ci  ares_bool_t                 result = ARES_FALSE;
2521cb0ef41Sopenharmony_ci  int                         family = hints->ai_family;
2531cb0ef41Sopenharmony_ci  if (family == AF_INET || family == AF_INET6 || family == AF_UNSPEC) {
2541cb0ef41Sopenharmony_ci    /* It only looks like an IP address if it's all numbers and dots. */
2551cb0ef41Sopenharmony_ci    size_t      numdots = 0;
2561cb0ef41Sopenharmony_ci    ares_bool_t valid   = ARES_TRUE;
2571cb0ef41Sopenharmony_ci    const char *p;
2581cb0ef41Sopenharmony_ci    for (p = name; *p; p++) {
2591cb0ef41Sopenharmony_ci      if (!ISDIGIT(*p) && *p != '.') {
2601cb0ef41Sopenharmony_ci        valid = ARES_FALSE;
2611cb0ef41Sopenharmony_ci        break;
2621cb0ef41Sopenharmony_ci      } else if (*p == '.') {
2631cb0ef41Sopenharmony_ci        numdots++;
2641cb0ef41Sopenharmony_ci      }
2651cb0ef41Sopenharmony_ci    }
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci    /* if we don't have 3 dots, it is illegal
2681cb0ef41Sopenharmony_ci     * (although inet_pton doesn't think so).
2691cb0ef41Sopenharmony_ci     */
2701cb0ef41Sopenharmony_ci    if (numdots != 3 || !valid) {
2711cb0ef41Sopenharmony_ci      result = ARES_FALSE;
2721cb0ef41Sopenharmony_ci    } else {
2731cb0ef41Sopenharmony_ci      struct in_addr addr4;
2741cb0ef41Sopenharmony_ci      result =
2751cb0ef41Sopenharmony_ci        ares_inet_pton(AF_INET, name, &addr4) < 1 ? ARES_FALSE : ARES_TRUE;
2761cb0ef41Sopenharmony_ci      if (result) {
2771cb0ef41Sopenharmony_ci        status = ares_append_ai_node(AF_INET, port, 0, &addr4, &ai->nodes);
2781cb0ef41Sopenharmony_ci        if (status != ARES_SUCCESS) {
2791cb0ef41Sopenharmony_ci          callback(arg, (int)status, 0, NULL);
2801cb0ef41Sopenharmony_ci          return ARES_TRUE;
2811cb0ef41Sopenharmony_ci        }
2821cb0ef41Sopenharmony_ci      }
2831cb0ef41Sopenharmony_ci    }
2841cb0ef41Sopenharmony_ci  }
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci  if (!result && (family == AF_INET6 || family == AF_UNSPEC)) {
2871cb0ef41Sopenharmony_ci    struct ares_in6_addr addr6;
2881cb0ef41Sopenharmony_ci    result =
2891cb0ef41Sopenharmony_ci      ares_inet_pton(AF_INET6, name, &addr6) < 1 ? ARES_FALSE : ARES_TRUE;
2901cb0ef41Sopenharmony_ci    if (result) {
2911cb0ef41Sopenharmony_ci      status = ares_append_ai_node(AF_INET6, port, 0, &addr6, &ai->nodes);
2921cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
2931cb0ef41Sopenharmony_ci        callback(arg, (int)status, 0, NULL);
2941cb0ef41Sopenharmony_ci        return ARES_TRUE;
2951cb0ef41Sopenharmony_ci      }
2961cb0ef41Sopenharmony_ci    }
2971cb0ef41Sopenharmony_ci  }
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci  if (!result) {
3001cb0ef41Sopenharmony_ci    return ARES_FALSE;
3011cb0ef41Sopenharmony_ci  }
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_ci  if (hints->ai_flags & ARES_AI_CANONNAME) {
3041cb0ef41Sopenharmony_ci    cname = ares__append_addrinfo_cname(&ai->cnames);
3051cb0ef41Sopenharmony_ci    if (!cname) {
3061cb0ef41Sopenharmony_ci      ares_freeaddrinfo(ai);
3071cb0ef41Sopenharmony_ci      callback(arg, ARES_ENOMEM, 0, NULL);
3081cb0ef41Sopenharmony_ci      return ARES_TRUE;
3091cb0ef41Sopenharmony_ci    }
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci    /* Duplicate the name, to avoid a constness violation. */
3121cb0ef41Sopenharmony_ci    cname->name = ares_strdup(name);
3131cb0ef41Sopenharmony_ci    if (!cname->name) {
3141cb0ef41Sopenharmony_ci      ares_freeaddrinfo(ai);
3151cb0ef41Sopenharmony_ci      callback(arg, ARES_ENOMEM, 0, NULL);
3161cb0ef41Sopenharmony_ci      return ARES_TRUE;
3171cb0ef41Sopenharmony_ci    }
3181cb0ef41Sopenharmony_ci  }
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci  ai->nodes->ai_socktype = hints->ai_socktype;
3211cb0ef41Sopenharmony_ci  ai->nodes->ai_protocol = hints->ai_protocol;
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_ci  callback(arg, ARES_SUCCESS, 0, ai);
3241cb0ef41Sopenharmony_ci  return ARES_TRUE;
3251cb0ef41Sopenharmony_ci}
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_cistatic void end_hquery(struct host_query *hquery, ares_status_t status)
3281cb0ef41Sopenharmony_ci{
3291cb0ef41Sopenharmony_ci  struct ares_addrinfo_node  sentinel;
3301cb0ef41Sopenharmony_ci  struct ares_addrinfo_node *next;
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci  if (status == ARES_SUCCESS) {
3331cb0ef41Sopenharmony_ci    if (!(hquery->hints.ai_flags & ARES_AI_NOSORT) && hquery->ai->nodes) {
3341cb0ef41Sopenharmony_ci      sentinel.ai_next = hquery->ai->nodes;
3351cb0ef41Sopenharmony_ci      ares__sortaddrinfo(hquery->channel, &sentinel);
3361cb0ef41Sopenharmony_ci      hquery->ai->nodes = sentinel.ai_next;
3371cb0ef41Sopenharmony_ci    }
3381cb0ef41Sopenharmony_ci    next = hquery->ai->nodes;
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci    while (next) {
3411cb0ef41Sopenharmony_ci      next->ai_socktype = hquery->hints.ai_socktype;
3421cb0ef41Sopenharmony_ci      next->ai_protocol = hquery->hints.ai_protocol;
3431cb0ef41Sopenharmony_ci      next              = next->ai_next;
3441cb0ef41Sopenharmony_ci    }
3451cb0ef41Sopenharmony_ci  } else {
3461cb0ef41Sopenharmony_ci    /* Clean up what we have collected by so far. */
3471cb0ef41Sopenharmony_ci    ares_freeaddrinfo(hquery->ai);
3481cb0ef41Sopenharmony_ci    hquery->ai = NULL;
3491cb0ef41Sopenharmony_ci  }
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci  hquery->callback(hquery->arg, (int)status, (int)hquery->timeouts, hquery->ai);
3521cb0ef41Sopenharmony_ci  ares__strsplit_free(hquery->domains, hquery->ndomains);
3531cb0ef41Sopenharmony_ci  ares_free(hquery->lookups);
3541cb0ef41Sopenharmony_ci  ares_free(hquery->name);
3551cb0ef41Sopenharmony_ci  ares_free(hquery);
3561cb0ef41Sopenharmony_ci}
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ciares_bool_t ares__is_localhost(const char *name)
3591cb0ef41Sopenharmony_ci{
3601cb0ef41Sopenharmony_ci  /* RFC6761 6.3 says : The domain "localhost." and any names falling within
3611cb0ef41Sopenharmony_ci   * ".localhost." */
3621cb0ef41Sopenharmony_ci  size_t len;
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci  if (name == NULL) {
3651cb0ef41Sopenharmony_ci    return ARES_FALSE;
3661cb0ef41Sopenharmony_ci  }
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci  if (strcmp(name, "localhost") == 0) {
3691cb0ef41Sopenharmony_ci    return ARES_TRUE;
3701cb0ef41Sopenharmony_ci  }
3711cb0ef41Sopenharmony_ci
3721cb0ef41Sopenharmony_ci  len = ares_strlen(name);
3731cb0ef41Sopenharmony_ci  if (len < 10 /* strlen(".localhost") */) {
3741cb0ef41Sopenharmony_ci    return ARES_FALSE;
3751cb0ef41Sopenharmony_ci  }
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci  if (strcmp(name + (len - 10 /* strlen(".localhost") */), ".localhost") == 0) {
3781cb0ef41Sopenharmony_ci    return ARES_TRUE;
3791cb0ef41Sopenharmony_ci  }
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  return ARES_FALSE;
3821cb0ef41Sopenharmony_ci}
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_cistatic ares_status_t file_lookup(struct host_query *hquery)
3851cb0ef41Sopenharmony_ci{
3861cb0ef41Sopenharmony_ci  const ares_hosts_entry_t *entry;
3871cb0ef41Sopenharmony_ci  ares_status_t             status;
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci  /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */
3901cb0ef41Sopenharmony_ci  if (ares__is_onion_domain(hquery->name)) {
3911cb0ef41Sopenharmony_ci    return ARES_ENOTFOUND;
3921cb0ef41Sopenharmony_ci  }
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci  status = ares__hosts_search_host(
3951cb0ef41Sopenharmony_ci    hquery->channel,
3961cb0ef41Sopenharmony_ci    (hquery->hints.ai_flags & ARES_AI_ENVHOSTS) ? ARES_TRUE : ARES_FALSE,
3971cb0ef41Sopenharmony_ci    hquery->name, &entry);
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
4001cb0ef41Sopenharmony_ci    goto done;
4011cb0ef41Sopenharmony_ci  }
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci  status = ares__hosts_entry_to_addrinfo(
4041cb0ef41Sopenharmony_ci    entry, hquery->name, hquery->hints.ai_family, hquery->port,
4051cb0ef41Sopenharmony_ci    (hquery->hints.ai_flags & ARES_AI_CANONNAME) ? ARES_TRUE : ARES_FALSE,
4061cb0ef41Sopenharmony_ci    hquery->ai);
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
4091cb0ef41Sopenharmony_ci    goto done;
4101cb0ef41Sopenharmony_ci  }
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_ci
4131cb0ef41Sopenharmony_cidone:
4141cb0ef41Sopenharmony_ci  /* RFC6761 section 6.3 #3 states that "Name resolution APIs and libraries
4151cb0ef41Sopenharmony_ci   * SHOULD recognize localhost names as special and SHOULD always return the
4161cb0ef41Sopenharmony_ci   * IP loopback address for address queries".
4171cb0ef41Sopenharmony_ci   * We will also ignore ALL errors when trying to resolve localhost, such
4181cb0ef41Sopenharmony_ci   * as permissions errors reading /etc/hosts or a malformed /etc/hosts */
4191cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS && status != ARES_ENOMEM &&
4201cb0ef41Sopenharmony_ci      ares__is_localhost(hquery->name)) {
4211cb0ef41Sopenharmony_ci    return ares__addrinfo_localhost(hquery->name, hquery->port, &hquery->hints,
4221cb0ef41Sopenharmony_ci                                    hquery->ai);
4231cb0ef41Sopenharmony_ci  }
4241cb0ef41Sopenharmony_ci
4251cb0ef41Sopenharmony_ci  return status;
4261cb0ef41Sopenharmony_ci}
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_cistatic void next_lookup(struct host_query *hquery, ares_status_t status)
4291cb0ef41Sopenharmony_ci{
4301cb0ef41Sopenharmony_ci  switch (*hquery->remaining_lookups) {
4311cb0ef41Sopenharmony_ci    case 'b':
4321cb0ef41Sopenharmony_ci      /* RFC6761 section 6.3 #3 says "Name resolution APIs SHOULD NOT send
4331cb0ef41Sopenharmony_ci       * queries for localhost names to their configured caching DNS
4341cb0ef41Sopenharmony_ci       * server(s)."
4351cb0ef41Sopenharmony_ci       * Otherwise, DNS lookup. */
4361cb0ef41Sopenharmony_ci      if (!ares__is_localhost(hquery->name) && next_dns_lookup(hquery)) {
4371cb0ef41Sopenharmony_ci        break;
4381cb0ef41Sopenharmony_ci      }
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci      hquery->remaining_lookups++;
4411cb0ef41Sopenharmony_ci      next_lookup(hquery, status);
4421cb0ef41Sopenharmony_ci      break;
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci    case 'f':
4451cb0ef41Sopenharmony_ci      /* Host file lookup */
4461cb0ef41Sopenharmony_ci      if (file_lookup(hquery) == ARES_SUCCESS) {
4471cb0ef41Sopenharmony_ci        end_hquery(hquery, ARES_SUCCESS);
4481cb0ef41Sopenharmony_ci        break;
4491cb0ef41Sopenharmony_ci      }
4501cb0ef41Sopenharmony_ci      hquery->remaining_lookups++;
4511cb0ef41Sopenharmony_ci      next_lookup(hquery, status);
4521cb0ef41Sopenharmony_ci      break;
4531cb0ef41Sopenharmony_ci    default:
4541cb0ef41Sopenharmony_ci      /* No lookup left */
4551cb0ef41Sopenharmony_ci      end_hquery(hquery, status);
4561cb0ef41Sopenharmony_ci      break;
4571cb0ef41Sopenharmony_ci  }
4581cb0ef41Sopenharmony_ci}
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_cistatic void terminate_retries(const struct host_query *hquery,
4611cb0ef41Sopenharmony_ci                              unsigned short           qid)
4621cb0ef41Sopenharmony_ci{
4631cb0ef41Sopenharmony_ci  unsigned short term_qid =
4641cb0ef41Sopenharmony_ci    (qid == hquery->qid_a) ? hquery->qid_aaaa : hquery->qid_a;
4651cb0ef41Sopenharmony_ci  const ares_channel_t *channel = hquery->channel;
4661cb0ef41Sopenharmony_ci  struct query         *query   = NULL;
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_ci  /* No other outstanding queries, nothing to do */
4691cb0ef41Sopenharmony_ci  if (!hquery->remaining) {
4701cb0ef41Sopenharmony_ci    return;
4711cb0ef41Sopenharmony_ci  }
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci  query = ares__htable_szvp_get_direct(channel->queries_by_qid, term_qid);
4741cb0ef41Sopenharmony_ci  if (query == NULL) {
4751cb0ef41Sopenharmony_ci    return;
4761cb0ef41Sopenharmony_ci  }
4771cb0ef41Sopenharmony_ci
4781cb0ef41Sopenharmony_ci  query->no_retries = ARES_TRUE;
4791cb0ef41Sopenharmony_ci}
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_cistatic void host_callback(void *arg, int status, int timeouts,
4821cb0ef41Sopenharmony_ci                          unsigned char *abuf, int alen)
4831cb0ef41Sopenharmony_ci{
4841cb0ef41Sopenharmony_ci  struct host_query *hquery         = (struct host_query *)arg;
4851cb0ef41Sopenharmony_ci  ares_status_t      addinfostatus  = ARES_SUCCESS;
4861cb0ef41Sopenharmony_ci  unsigned short     qid            = 0;
4871cb0ef41Sopenharmony_ci  hquery->timeouts                 += (size_t)timeouts;
4881cb0ef41Sopenharmony_ci  hquery->remaining--;
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ci  if (status == ARES_SUCCESS) {
4911cb0ef41Sopenharmony_ci    if (alen < 0) {
4921cb0ef41Sopenharmony_ci      addinfostatus = ARES_EBADRESP;
4931cb0ef41Sopenharmony_ci    } else {
4941cb0ef41Sopenharmony_ci      addinfostatus = ares__parse_into_addrinfo(abuf, (size_t)alen, ARES_TRUE,
4951cb0ef41Sopenharmony_ci                                                hquery->port, hquery->ai);
4961cb0ef41Sopenharmony_ci    }
4971cb0ef41Sopenharmony_ci    if (addinfostatus == ARES_SUCCESS && alen >= HFIXEDSZ) {
4981cb0ef41Sopenharmony_ci      qid = DNS_HEADER_QID(abuf); /* Converts to host byte order */
4991cb0ef41Sopenharmony_ci      terminate_retries(hquery, qid);
5001cb0ef41Sopenharmony_ci    }
5011cb0ef41Sopenharmony_ci  }
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ci  if (!hquery->remaining) {
5041cb0ef41Sopenharmony_ci    if (status == ARES_EDESTRUCTION || status == ARES_ECANCELLED) {
5051cb0ef41Sopenharmony_ci      /* must make sure we don't do next_lookup() on destroy or cancel,
5061cb0ef41Sopenharmony_ci       * and return the appropriate status.  We won't return a partial
5071cb0ef41Sopenharmony_ci       * result in this case. */
5081cb0ef41Sopenharmony_ci      end_hquery(hquery, (ares_status_t)status);
5091cb0ef41Sopenharmony_ci    } else if (addinfostatus != ARES_SUCCESS && addinfostatus != ARES_ENODATA) {
5101cb0ef41Sopenharmony_ci      /* error in parsing result e.g. no memory */
5111cb0ef41Sopenharmony_ci      if (addinfostatus == ARES_EBADRESP && hquery->ai->nodes) {
5121cb0ef41Sopenharmony_ci        /* We got a bad response from server, but at least one query
5131cb0ef41Sopenharmony_ci         * ended with ARES_SUCCESS */
5141cb0ef41Sopenharmony_ci        end_hquery(hquery, ARES_SUCCESS);
5151cb0ef41Sopenharmony_ci      } else {
5161cb0ef41Sopenharmony_ci        end_hquery(hquery, addinfostatus);
5171cb0ef41Sopenharmony_ci      }
5181cb0ef41Sopenharmony_ci    } else if (hquery->ai->nodes) {
5191cb0ef41Sopenharmony_ci      /* at least one query ended with ARES_SUCCESS */
5201cb0ef41Sopenharmony_ci      end_hquery(hquery, ARES_SUCCESS);
5211cb0ef41Sopenharmony_ci    } else if (status == ARES_ENOTFOUND || status == ARES_ENODATA ||
5221cb0ef41Sopenharmony_ci               addinfostatus == ARES_ENODATA) {
5231cb0ef41Sopenharmony_ci      if (status == ARES_ENODATA || addinfostatus == ARES_ENODATA) {
5241cb0ef41Sopenharmony_ci        hquery->nodata_cnt++;
5251cb0ef41Sopenharmony_ci      }
5261cb0ef41Sopenharmony_ci      next_lookup(hquery,
5271cb0ef41Sopenharmony_ci                  hquery->nodata_cnt ? ARES_ENODATA : (ares_status_t)status);
5281cb0ef41Sopenharmony_ci    } else {
5291cb0ef41Sopenharmony_ci      end_hquery(hquery, (ares_status_t)status);
5301cb0ef41Sopenharmony_ci    }
5311cb0ef41Sopenharmony_ci  }
5321cb0ef41Sopenharmony_ci
5331cb0ef41Sopenharmony_ci  /* at this point we keep on waiting for the next query to finish */
5341cb0ef41Sopenharmony_ci}
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_cistatic void ares_getaddrinfo_int(ares_channel_t *channel, const char *name,
5371cb0ef41Sopenharmony_ci                                 const char                       *service,
5381cb0ef41Sopenharmony_ci                                 const struct ares_addrinfo_hints *hints,
5391cb0ef41Sopenharmony_ci                                 ares_addrinfo_callback callback, void *arg)
5401cb0ef41Sopenharmony_ci{
5411cb0ef41Sopenharmony_ci  struct host_query    *hquery;
5421cb0ef41Sopenharmony_ci  unsigned short        port = 0;
5431cb0ef41Sopenharmony_ci  int                   family;
5441cb0ef41Sopenharmony_ci  struct ares_addrinfo *ai;
5451cb0ef41Sopenharmony_ci  char                 *alias_name = NULL;
5461cb0ef41Sopenharmony_ci  ares_status_t         status;
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_ci  if (!hints) {
5491cb0ef41Sopenharmony_ci    hints = &default_hints;
5501cb0ef41Sopenharmony_ci  }
5511cb0ef41Sopenharmony_ci
5521cb0ef41Sopenharmony_ci  family = hints->ai_family;
5531cb0ef41Sopenharmony_ci
5541cb0ef41Sopenharmony_ci  /* Right now we only know how to look up Internet addresses
5551cb0ef41Sopenharmony_ci     and unspec means try both basically. */
5561cb0ef41Sopenharmony_ci  if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) {
5571cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOTIMP, 0, NULL);
5581cb0ef41Sopenharmony_ci    return;
5591cb0ef41Sopenharmony_ci  }
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci  if (ares__is_onion_domain(name)) {
5621cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOTFOUND, 0, NULL);
5631cb0ef41Sopenharmony_ci    return;
5641cb0ef41Sopenharmony_ci  }
5651cb0ef41Sopenharmony_ci
5661cb0ef41Sopenharmony_ci  /* perform HOSTALIAS resolution (technically this function does some other
5671cb0ef41Sopenharmony_ci   * things we are going to ignore) */
5681cb0ef41Sopenharmony_ci  status = ares__single_domain(channel, name, &alias_name);
5691cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
5701cb0ef41Sopenharmony_ci    callback(arg, (int)status, 0, NULL);
5711cb0ef41Sopenharmony_ci    return;
5721cb0ef41Sopenharmony_ci  }
5731cb0ef41Sopenharmony_ci
5741cb0ef41Sopenharmony_ci  if (alias_name) {
5751cb0ef41Sopenharmony_ci    name = alias_name;
5761cb0ef41Sopenharmony_ci  }
5771cb0ef41Sopenharmony_ci
5781cb0ef41Sopenharmony_ci  if (service) {
5791cb0ef41Sopenharmony_ci    if (hints->ai_flags & ARES_AI_NUMERICSERV) {
5801cb0ef41Sopenharmony_ci      unsigned long val;
5811cb0ef41Sopenharmony_ci      errno = 0;
5821cb0ef41Sopenharmony_ci      val   = strtoul(service, NULL, 0);
5831cb0ef41Sopenharmony_ci      if ((val == 0 && errno != 0) || val > 65535) {
5841cb0ef41Sopenharmony_ci        ares_free(alias_name);
5851cb0ef41Sopenharmony_ci        callback(arg, ARES_ESERVICE, 0, NULL);
5861cb0ef41Sopenharmony_ci        return;
5871cb0ef41Sopenharmony_ci      }
5881cb0ef41Sopenharmony_ci      port = (unsigned short)val;
5891cb0ef41Sopenharmony_ci    } else {
5901cb0ef41Sopenharmony_ci      port = lookup_service(service, 0);
5911cb0ef41Sopenharmony_ci      if (!port) {
5921cb0ef41Sopenharmony_ci        unsigned long val;
5931cb0ef41Sopenharmony_ci        errno = 0;
5941cb0ef41Sopenharmony_ci        val   = strtoul(service, NULL, 0);
5951cb0ef41Sopenharmony_ci        if ((val == 0 && errno != 0) || val > 65535) {
5961cb0ef41Sopenharmony_ci          ares_free(alias_name);
5971cb0ef41Sopenharmony_ci          callback(arg, ARES_ESERVICE, 0, NULL);
5981cb0ef41Sopenharmony_ci          return;
5991cb0ef41Sopenharmony_ci        }
6001cb0ef41Sopenharmony_ci        port = (unsigned short)val;
6011cb0ef41Sopenharmony_ci      }
6021cb0ef41Sopenharmony_ci    }
6031cb0ef41Sopenharmony_ci  }
6041cb0ef41Sopenharmony_ci
6051cb0ef41Sopenharmony_ci  ai = ares_malloc_zero(sizeof(*ai));
6061cb0ef41Sopenharmony_ci  if (!ai) {
6071cb0ef41Sopenharmony_ci    ares_free(alias_name);
6081cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOMEM, 0, NULL);
6091cb0ef41Sopenharmony_ci    return;
6101cb0ef41Sopenharmony_ci  }
6111cb0ef41Sopenharmony_ci
6121cb0ef41Sopenharmony_ci  if (fake_addrinfo(name, port, hints, ai, callback, arg)) {
6131cb0ef41Sopenharmony_ci    ares_free(alias_name);
6141cb0ef41Sopenharmony_ci    return;
6151cb0ef41Sopenharmony_ci  }
6161cb0ef41Sopenharmony_ci
6171cb0ef41Sopenharmony_ci  /* Allocate and fill in the host query structure. */
6181cb0ef41Sopenharmony_ci  hquery = ares_malloc_zero(sizeof(*hquery));
6191cb0ef41Sopenharmony_ci  if (!hquery) {
6201cb0ef41Sopenharmony_ci    ares_free(alias_name);
6211cb0ef41Sopenharmony_ci    ares_freeaddrinfo(ai);
6221cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOMEM, 0, NULL);
6231cb0ef41Sopenharmony_ci    return;
6241cb0ef41Sopenharmony_ci  }
6251cb0ef41Sopenharmony_ci  memset(hquery, 0, sizeof(*hquery));
6261cb0ef41Sopenharmony_ci  hquery->name = ares_strdup(name);
6271cb0ef41Sopenharmony_ci  ares_free(alias_name);
6281cb0ef41Sopenharmony_ci  if (!hquery->name) {
6291cb0ef41Sopenharmony_ci    ares_free(hquery);
6301cb0ef41Sopenharmony_ci    ares_freeaddrinfo(ai);
6311cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOMEM, 0, NULL);
6321cb0ef41Sopenharmony_ci    return;
6331cb0ef41Sopenharmony_ci  }
6341cb0ef41Sopenharmony_ci  hquery->lookups = ares_strdup(channel->lookups);
6351cb0ef41Sopenharmony_ci  if (!hquery->lookups) {
6361cb0ef41Sopenharmony_ci    ares_free(hquery->name);
6371cb0ef41Sopenharmony_ci    ares_free(hquery);
6381cb0ef41Sopenharmony_ci    ares_freeaddrinfo(ai);
6391cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOMEM, 0, NULL);
6401cb0ef41Sopenharmony_ci    return;
6411cb0ef41Sopenharmony_ci  }
6421cb0ef41Sopenharmony_ci
6431cb0ef41Sopenharmony_ci  if (channel->ndomains) {
6441cb0ef41Sopenharmony_ci    /* Duplicate for ares_reinit() safety */
6451cb0ef41Sopenharmony_ci    hquery->domains =
6461cb0ef41Sopenharmony_ci      ares__strsplit_duplicate(channel->domains, channel->ndomains);
6471cb0ef41Sopenharmony_ci    if (hquery->domains == NULL) {
6481cb0ef41Sopenharmony_ci      ares_free(hquery->lookups);
6491cb0ef41Sopenharmony_ci      ares_free(hquery->name);
6501cb0ef41Sopenharmony_ci      ares_free(hquery);
6511cb0ef41Sopenharmony_ci      ares_freeaddrinfo(ai);
6521cb0ef41Sopenharmony_ci      callback(arg, ARES_ENOMEM, 0, NULL);
6531cb0ef41Sopenharmony_ci      return;
6541cb0ef41Sopenharmony_ci    }
6551cb0ef41Sopenharmony_ci    hquery->ndomains = channel->ndomains;
6561cb0ef41Sopenharmony_ci  }
6571cb0ef41Sopenharmony_ci
6581cb0ef41Sopenharmony_ci  hquery->port              = port;
6591cb0ef41Sopenharmony_ci  hquery->channel           = channel;
6601cb0ef41Sopenharmony_ci  hquery->hints             = *hints;
6611cb0ef41Sopenharmony_ci  hquery->sent_family       = -1; /* nothing is sent yet */
6621cb0ef41Sopenharmony_ci  hquery->callback          = callback;
6631cb0ef41Sopenharmony_ci  hquery->arg               = arg;
6641cb0ef41Sopenharmony_ci  hquery->remaining_lookups = hquery->lookups;
6651cb0ef41Sopenharmony_ci  hquery->ai                = ai;
6661cb0ef41Sopenharmony_ci  hquery->next_domain       = -1;
6671cb0ef41Sopenharmony_ci
6681cb0ef41Sopenharmony_ci  /* Start performing lookups according to channel->lookups. */
6691cb0ef41Sopenharmony_ci  next_lookup(hquery, ARES_ECONNREFUSED /* initial error code */);
6701cb0ef41Sopenharmony_ci}
6711cb0ef41Sopenharmony_ci
6721cb0ef41Sopenharmony_civoid ares_getaddrinfo(ares_channel_t *channel, const char *name,
6731cb0ef41Sopenharmony_ci                      const char                       *service,
6741cb0ef41Sopenharmony_ci                      const struct ares_addrinfo_hints *hints,
6751cb0ef41Sopenharmony_ci                      ares_addrinfo_callback callback, void *arg)
6761cb0ef41Sopenharmony_ci{
6771cb0ef41Sopenharmony_ci  if (channel == NULL) {
6781cb0ef41Sopenharmony_ci    return;
6791cb0ef41Sopenharmony_ci  }
6801cb0ef41Sopenharmony_ci  ares__channel_lock(channel);
6811cb0ef41Sopenharmony_ci  ares_getaddrinfo_int(channel, name, service, hints, callback, arg);
6821cb0ef41Sopenharmony_ci  ares__channel_unlock(channel);
6831cb0ef41Sopenharmony_ci}
6841cb0ef41Sopenharmony_ci
6851cb0ef41Sopenharmony_cistatic ares_bool_t next_dns_lookup(struct host_query *hquery)
6861cb0ef41Sopenharmony_ci{
6871cb0ef41Sopenharmony_ci  char         *s              = NULL;
6881cb0ef41Sopenharmony_ci  ares_bool_t   is_s_allocated = ARES_FALSE;
6891cb0ef41Sopenharmony_ci  ares_status_t status;
6901cb0ef41Sopenharmony_ci
6911cb0ef41Sopenharmony_ci  /* if next_domain == -1 and as_is_first is true, try hquery->name */
6921cb0ef41Sopenharmony_ci  if (hquery->next_domain == -1) {
6931cb0ef41Sopenharmony_ci    if (as_is_first(hquery)) {
6941cb0ef41Sopenharmony_ci      s = hquery->name;
6951cb0ef41Sopenharmony_ci    }
6961cb0ef41Sopenharmony_ci    hquery->next_domain = 0;
6971cb0ef41Sopenharmony_ci  }
6981cb0ef41Sopenharmony_ci
6991cb0ef41Sopenharmony_ci  /* if as_is_first is false, try hquery->name at last */
7001cb0ef41Sopenharmony_ci  if (!s && (size_t)hquery->next_domain == hquery->ndomains) {
7011cb0ef41Sopenharmony_ci    if (!as_is_first(hquery)) {
7021cb0ef41Sopenharmony_ci      s = hquery->name;
7031cb0ef41Sopenharmony_ci    }
7041cb0ef41Sopenharmony_ci    hquery->next_domain++;
7051cb0ef41Sopenharmony_ci  }
7061cb0ef41Sopenharmony_ci
7071cb0ef41Sopenharmony_ci  if (!s && (size_t)hquery->next_domain < hquery->ndomains &&
7081cb0ef41Sopenharmony_ci      !as_is_only(hquery)) {
7091cb0ef41Sopenharmony_ci    status = ares__cat_domain(hquery->name,
7101cb0ef41Sopenharmony_ci                              hquery->domains[hquery->next_domain++], &s);
7111cb0ef41Sopenharmony_ci    if (status == ARES_SUCCESS) {
7121cb0ef41Sopenharmony_ci      is_s_allocated = ARES_TRUE;
7131cb0ef41Sopenharmony_ci    }
7141cb0ef41Sopenharmony_ci  }
7151cb0ef41Sopenharmony_ci
7161cb0ef41Sopenharmony_ci  if (s) {
7171cb0ef41Sopenharmony_ci    /* NOTE: hquery may be invalidated during the call to ares_query_qid(),
7181cb0ef41Sopenharmony_ci     *       so should not be referenced after this point */
7191cb0ef41Sopenharmony_ci    switch (hquery->hints.ai_family) {
7201cb0ef41Sopenharmony_ci      case AF_INET:
7211cb0ef41Sopenharmony_ci        hquery->remaining += 1;
7221cb0ef41Sopenharmony_ci        ares_query_qid(hquery->channel, s, C_IN, T_A, host_callback, hquery,
7231cb0ef41Sopenharmony_ci                       &hquery->qid_a);
7241cb0ef41Sopenharmony_ci        break;
7251cb0ef41Sopenharmony_ci      case AF_INET6:
7261cb0ef41Sopenharmony_ci        hquery->remaining += 1;
7271cb0ef41Sopenharmony_ci        ares_query_qid(hquery->channel, s, C_IN, T_AAAA, host_callback, hquery,
7281cb0ef41Sopenharmony_ci                       &hquery->qid_aaaa);
7291cb0ef41Sopenharmony_ci        break;
7301cb0ef41Sopenharmony_ci      case AF_UNSPEC:
7311cb0ef41Sopenharmony_ci        hquery->remaining += 2;
7321cb0ef41Sopenharmony_ci        ares_query_qid(hquery->channel, s, C_IN, T_A, host_callback, hquery,
7331cb0ef41Sopenharmony_ci                       &hquery->qid_a);
7341cb0ef41Sopenharmony_ci        ares_query_qid(hquery->channel, s, C_IN, T_AAAA, host_callback, hquery,
7351cb0ef41Sopenharmony_ci                       &hquery->qid_aaaa);
7361cb0ef41Sopenharmony_ci        break;
7371cb0ef41Sopenharmony_ci      default:
7381cb0ef41Sopenharmony_ci        break;
7391cb0ef41Sopenharmony_ci    }
7401cb0ef41Sopenharmony_ci    if (is_s_allocated) {
7411cb0ef41Sopenharmony_ci      ares_free(s);
7421cb0ef41Sopenharmony_ci    }
7431cb0ef41Sopenharmony_ci    return ARES_TRUE;
7441cb0ef41Sopenharmony_ci  } else {
7451cb0ef41Sopenharmony_ci    assert(!hquery->ai->nodes);
7461cb0ef41Sopenharmony_ci    return ARES_FALSE;
7471cb0ef41Sopenharmony_ci  }
7481cb0ef41Sopenharmony_ci}
7491cb0ef41Sopenharmony_ci
7501cb0ef41Sopenharmony_cistatic ares_bool_t as_is_first(const struct host_query *hquery)
7511cb0ef41Sopenharmony_ci{
7521cb0ef41Sopenharmony_ci  const char *p;
7531cb0ef41Sopenharmony_ci  size_t      ndots = 0;
7541cb0ef41Sopenharmony_ci  for (p = hquery->name; p && *p; p++) {
7551cb0ef41Sopenharmony_ci    if (*p == '.') {
7561cb0ef41Sopenharmony_ci      ndots++;
7571cb0ef41Sopenharmony_ci    }
7581cb0ef41Sopenharmony_ci  }
7591cb0ef41Sopenharmony_ci  if (as_is_only(hquery)) {
7601cb0ef41Sopenharmony_ci    /* prevent ARES_EBADNAME for valid FQDN, where ndots < channel->ndots  */
7611cb0ef41Sopenharmony_ci    return ARES_TRUE;
7621cb0ef41Sopenharmony_ci  }
7631cb0ef41Sopenharmony_ci  return ndots >= hquery->channel->ndots ? ARES_TRUE : ARES_FALSE;
7641cb0ef41Sopenharmony_ci}
7651cb0ef41Sopenharmony_ci
7661cb0ef41Sopenharmony_cistatic ares_bool_t as_is_only(const struct host_query *hquery)
7671cb0ef41Sopenharmony_ci{
7681cb0ef41Sopenharmony_ci  size_t nname = ares_strlen(hquery->name);
7691cb0ef41Sopenharmony_ci  if (hquery->channel->flags & ARES_FLAG_NOSEARCH) {
7701cb0ef41Sopenharmony_ci    return ARES_TRUE;
7711cb0ef41Sopenharmony_ci  }
7721cb0ef41Sopenharmony_ci  if (hquery->name != NULL && nname && hquery->name[nname - 1] == '.') {
7731cb0ef41Sopenharmony_ci    return ARES_TRUE;
7741cb0ef41Sopenharmony_ci  }
7751cb0ef41Sopenharmony_ci  return ARES_FALSE;
7761cb0ef41Sopenharmony_ci}
777