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