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