deps: upgrade to c-ares v1.16.0

Refs: https://github.com/c-ares/c-ares/releases/tag/cares-1_16_0

PR-URL: https://github.com/nodejs/node/pull/32246
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: David Carlier <devnexen@gmail.com>
This commit is contained in:
Anna Henningsen
2020-03-13 09:08:40 +01:00
parent c011542484
commit 4cfcaaeef3
23 changed files with 2464 additions and 509 deletions

View File

@@ -52,7 +52,9 @@
'src/ares_fds.c',
'src/ares_free_hostent.c',
'src/ares_free_string.c',
'src/ares_freeaddrinfo.c',
'src/ares_getenv.h',
'src/ares_getaddrinfo.c',
'src/ares_gethostbyaddr.c',
'src/ares_gethostbyname.c',
'src/ares__get_hostent.c',
@@ -70,6 +72,7 @@
'src/ares_nowarn.c',
'src/ares_nowarn.h',
'src/ares_options.c',
'src/ares__parse_into_addrinfo.c',
'src/ares_parse_aaaa_reply.c',
'src/ares_parse_a_reply.c',
'src/ares_parse_mx_reply.c',
@@ -84,9 +87,11 @@
'src/ares_process.c',
'src/ares_query.c',
'src/ares__read_line.c',
'src/ares__readaddrinfo.c',
'src/ares_search.c',
'src/ares_send.c',
'src/ares_setup.h',
'src/ares__sortaddrinfo.c',
'src/ares_strcasecmp.c',
'src/ares_strcasecmp.h',
'src/ares_strdup.c',

View File

@@ -135,6 +135,9 @@ extern "C" {
/* More error codes */
#define ARES_ECANCELLED 24 /* introduced in 1.7.0 */
/* More ares_getaddrinfo error codes */
#define ARES_ESERVICE 25 /* introduced in 1.?.0 */
/* Flag values */
#define ARES_FLAG_USEVC (1 << 0)
#define ARES_FLAG_PRIMARY (1 << 1)
@@ -192,6 +195,8 @@ extern "C" {
#define ARES_AI_V4MAPPED (1 << 4)
#define ARES_AI_ALL (1 << 5)
#define ARES_AI_ADDRCONFIG (1 << 6)
#define ARES_AI_NOSORT (1 << 7)
#define ARES_AI_ENVHOSTS (1 << 8)
/* Reserved for future use */
#define ARES_AI_IDN (1 << 10)
#define ARES_AI_IDN_ALLOW_UNASSIGNED (1 << 11)
@@ -278,6 +283,8 @@ struct hostent;
struct timeval;
struct sockaddr;
struct ares_channeldata;
struct ares_addrinfo;
struct ares_addrinfo_hints;
typedef struct ares_channeldata *ares_channel;
@@ -306,6 +313,11 @@ typedef int (*ares_sock_config_callback)(ares_socket_t socket_fd,
int type,
void *data);
typedef void (*ares_addrinfo_callback)(void *arg,
int status,
int timeouts,
struct ares_addrinfo *res);
CARES_EXTERN int ares_library_init(int flags);
CARES_EXTERN int ares_library_init_mem(int flags,
@@ -369,6 +381,15 @@ CARES_EXTERN void ares_set_socket_configure_callback(ares_channel channel,
CARES_EXTERN int ares_set_sortlist(ares_channel channel,
const char *sortstr);
CARES_EXTERN void ares_getaddrinfo(ares_channel channel,
const char* node,
const char* service,
const struct ares_addrinfo_hints* hints,
ares_addrinfo_callback callback,
void* arg);
CARES_EXTERN void ares_freeaddrinfo(struct ares_addrinfo* ai);
/*
* Virtual function set to have user-managed socket IO.
* Note that all functions need to be defined, and when
@@ -558,6 +579,44 @@ struct ares_soa_reply {
unsigned int minttl;
};
/*
* Similar to addrinfo, but with extra ttl and missing canonname.
*/
struct ares_addrinfo_node {
int ai_ttl;
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
ares_socklen_t ai_addrlen;
struct sockaddr *ai_addr;
struct ares_addrinfo_node *ai_next;
};
/*
* alias - label of the resource record.
* name - value (canonical name) of the resource record.
* See RFC2181 10.1.1. CNAME terminology.
*/
struct ares_addrinfo_cname {
int ttl;
char *alias;
char *name;
struct ares_addrinfo_cname *next;
};
struct ares_addrinfo {
struct ares_addrinfo_cname *cnames;
struct ares_addrinfo_node *nodes;
};
struct ares_addrinfo_hints {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
};
/*
** Parse the buffer, starting at *abuf and of length alen bytes, previously
** obtained from an ares_search call. Put the results in *host, if nonnull.

View File

@@ -3,15 +3,15 @@
#define ARES__VERSION_H
/* This is the global package copyright */
#define ARES_COPYRIGHT "2004 - 2018 Daniel Stenberg, <daniel@haxx.se>."
#define ARES_COPYRIGHT "2004 - 2020 Daniel Stenberg, <daniel@haxx.se>."
#define ARES_VERSION_MAJOR 1
#define ARES_VERSION_MINOR 15
#define ARES_VERSION_MINOR 16
#define ARES_VERSION_PATCH 0
#define ARES_VERSION ((ARES_VERSION_MAJOR<<16)|\
(ARES_VERSION_MINOR<<8)|\
(ARES_VERSION_PATCH))
#define ARES_VERSION_STR "1.15.0"
#define ARES_VERSION_STR "1.16.0"
#if (ARES_VERSION >= 0x010700)
# define CARES_HAVE_ARES_LIBRARY_INIT 1

View File

@@ -2,9 +2,10 @@ c-ares
======
[![Build Status](https://travis-ci.org/c-ares/c-ares.svg?branch=master)](https://travis-ci.org/c-ares/c-ares)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/03i7151772eq3wn3/branch/master?svg=true)](https://ci.appveyor.com/project/c-ares/c-ares)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/aevgc5914tm72pvs/branch/master?svg=true)](https://ci.appveyor.com/project/c-ares/c-ares/branch/master)
[![Coverage Status](https://coveralls.io/repos/c-ares/c-ares/badge.svg?branch=master&service=github)](https://coveralls.io/github/c-ares/c-ares?branch=master)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/291/badge)](https://bestpractices.coreinfrastructure.org/projects/291)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/c-ares.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:c-ares)
[![Releases](https://coderelease.io/badge/c-ares/c-ares)](https://coderelease.io/github/repository/c-ares/c-ares)
This is c-ares, an asynchronous resolver library. It is intended for

View File

@@ -1,43 +1,85 @@
c-ares version 1.15.0
c-ares version 1.16.0
Changes:
o Add ares_init_options() configurability for path to resolv.conf file [1]
o Ability to exclude building of tools (adig, ahost, acountry) in CMake [3]
o Android: Support for domain search suffix [4]
o Report ARES_ENOTFOUND for .onion domain names as per RFC7686. [13]
o Introduction of ares_getaddrinfo() API which provides similar output
(including proper sorting as per RFC 6724) to the system native API, but
utilizes different data structures in order to provide additional information
such as TTLs and all aliases. Please reference the respective man pages for
usage details. [3] [4] [5] [7] [8] [13] [14] [15] [16] [17] [22]
o Parse SOA records from ns_t_any response [29] [30]
o CMake: Provide c-ares version in package export file [24]
o CMake: Add CPACK functionality for DEB and RPM [28]
o CMake: Generate PDB files during build [33] [34]
o CMake: Support manpage installation [37] [38]
Bug fixes:
o AIX build fix for trying to include both nameser_compat.h and
onameser_compat.h [2]
o Windows: Improve DNS suffixes extracting from WinNT registry [5]
o Fix modern GCC warnings [6]
o Apply the IPv6 server blacklist to all nameserver sources, not just Windows
[7]
o Fix warnings emitted by MSVC when using -W4 [8]
o Prevent changing name servers while queries are outstanding [9]
o Harden and rationalize c-ares timeout computation [10]
o Distribute ares_android.h [11]
o ares_set_servers_csv() on failure should not leave channel in a bad state
[12]
o Add missing docs to distribution
o Fix bad expectation in IPv6 localhost test. [1] [2]
o AutoTools: use XC_CHECK_BUILD_FLAGS instead of XC_CHECK_USER_FLAGS to prevent
complaints about CPPFLAGS in CFLAGS. [6]
o Fix .onion handling
o Command line usage was out of date for adig and ahost. [18]
o Typos in manpages [19] [20]
o If ares_getenv is defined, it must return a value on all platforms [21]
o If /etc/resolv.conf has invalid lookup values, use the defaults. [23]
o Tests: Separate live tests from SetServers* tests as only live tests should
require internet access. [25]
o ares_gethostbyname() should return ENODATA if no valid A or AAAA record is
found, but a CNAME was found. [26] [27]
o CMake: Rework library function checking to prevent unintended linking with
system libraries that aren't needed. [31] [32]
o Due to use of inet_addr() it was not possible to return 255.255.255.255 from
ares_gethostbyname(). [35] [36]
o CMake: Fix building of tests on Windows
Thanks go to these friendly people for their efforts and contributions:
@afalin, Andi Schnebinger, Ben Noordhuis, Brad House, Brad Spencer,
David Hotham, @flyingdutchman23, John Schember, Ruslan Baratov,
Sarat Addepalli, Tobias Nießen (11 contributors)
Abhishek Arya (@inferno-chromium), Adam Majer (@AdamMajer),
Andrew Selivanov (@ki11roy), Ben Noordhuis (@bnoordhuis),
Brad House (@bradh352), Christian Ammer (@ChristianAmmer), Dan Noé (@dnoe),
Daniel Stenberg (@bagder), Darrin Cullop (@dwcullop),
Dron Rathore (@DronRathore), Fabrice Fontaine (@ffontaine),
Gregor Jasny (@gjasny), @kedixa, Khaidi Chu (@XadillaX),
Kyle Edwards (@KyleFromKitware), @lifenjoiner, Michal Rostecki (@mrostecki),
Peter Eisentraut (@petere), Piotr Pietraszkiewicz (@ppietrasa),
Stephen Bryant (@bf-bryants), @tjwalton, Vy Nguyen (@oontvoo)
(22 contributors)
References to bug reports and discussions on issues:
[1] = https://github.com/c-ares/c-ares/issues/220
[2] = https://github.com/c-ares/c-ares/issues/224
[3] = https://github.com/c-ares/c-ares/issues/200
[4] = https://github.com/c-ares/c-ares/issues/207
[5] = https://github.com/c-ares/c-ares/pull/202
[6] = https://github.com/c-ares/c-ares/pull/201
[7] = https://github.com/c-ares/c-ares/pull/193
[8] = https://github.com/c-ares/c-ares/pull/192
[9] = https://github.com/c-ares/c-ares/pull/191
[1] = https://github.com/c-ares/c-ares/pull/227
[2] = https://github.com/c-ares/c-ares/issues/85
[3] = https://github.com/c-ares/c-ares/pull/112
[4] = https://github.com/c-ares/c-ares/pull/233
[5] = https://github.com/c-ares/c-ares/pull/234
[6] = https://github.com/c-ares/c-ares/pull/236
[7] = https://github.com/c-ares/c-ares/pull/235
[8] = https://github.com/c-ares/c-ares/pull/239
[9] = https://github.com/c-ares/c-ares/pull/241
[10] = https://github.com/c-ares/c-ares/pull/187
[11] = https://c-ares.haxx.se/mail/c-ares-archive-2018-04/0000.shtml
[12] = https://c-ares.haxx.se/mail/c-ares-archive-2018-03/0000.shtml
[13] = https://github.com/c-ares/c-ares/issues/196
[11] = https://github.com/c-ares/c-ares/pull/252
[12] = https://github.com/c-ares/c-ares/issues/251
[13] = https://github.com/c-ares/c-ares/pull/258
[14] = https://github.com/c-ares/c-ares/pull/257
[15] = https://github.com/c-ares/c-ares/pull/262
[16] = https://github.com/c-ares/c-ares/pull/264
[17] = https://github.com/c-ares/c-ares/pull/265
[18] = https://github.com/c-ares/c-ares/pull/256
[19] = https://github.com/c-ares/c-ares/pull/269
[20] = https://github.com/c-ares/c-ares/pull/275
[21] = https://github.com/c-ares/c-ares/pull/279
[22] = https://github.com/c-ares/c-ares/pull/290
[23] = https://github.com/c-ares/c-ares/pull/274
[24] = https://github.com/c-ares/c-ares/pull/296
[25] = https://github.com/c-ares/c-ares/pull/299
[26] = https://github.com/c-ares/c-ares/pull/304
[27] = https://github.com/c-ares/c-ares/issues/303
[28] = https://github.com/c-ares/c-ares/pull/283
[29] = https://github.com/c-ares/c-ares/pull/103
[30] = https://github.com/c-ares/c-ares/issues/102
[31] = https://github.com/c-ares/c-ares/pull/310
[32] = https://github.com/c-ares/c-ares/issues/307
[33] = https://github.com/c-ares/c-ares/pull/311
[34] = https://github.com/c-ares/c-ares/issues/245
[35] = https://github.com/c-ares/c-ares/issues/309
[36] = https://github.com/c-ares/c-ares/pull/312
[37] = https://github.com/c-ares/c-ares/issues/297
[38] = https://github.com/c-ares/c-ares/pull/314

View File

@@ -48,14 +48,14 @@ void ares__close_sockets(ares_channel channel, struct server_state *server)
if (server->tcp_socket != ARES_SOCKET_BAD)
{
SOCK_STATE_CALLBACK(channel, server->tcp_socket, 0, 0);
ares__socket_close(channel, server->tcp_socket);
ares__close_socket(channel, server->tcp_socket);
server->tcp_socket = ARES_SOCKET_BAD;
server->tcp_connection_generation = ++channel->tcp_connection_generation;
}
if (server->udp_socket != ARES_SOCKET_BAD)
{
SOCK_STATE_CALLBACK(channel, server->udp_socket, 0, 0);
ares__socket_close(channel, server->udp_socket);
ares__close_socket(channel, server->udp_socket);
server->udp_socket = ARES_SOCKET_BAD;
}
}

View File

@@ -138,8 +138,7 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
addr.addrV4.s_addr = INADDR_NONE;
if ((family == AF_INET) || (family == AF_UNSPEC))
{
addr.addrV4.s_addr = inet_addr(txtaddr);
if (addr.addrV4.s_addr != INADDR_NONE)
if (ares_inet_pton(AF_INET, txtaddr, &addr.addrV4) > 0)
{
/* Actual network address family and length. */
addr.family = AF_INET;

View File

@@ -0,0 +1,266 @@
/* Copyright (C) 2019 by Andrew Selivanov
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#include "ares_setup.h"
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h>
#else
# include "nameser.h"
#endif
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
# include <arpa/nameser_compat.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#include "ares.h"
#include "ares_dns.h"
#include "ares_private.h"
int ares__parse_into_addrinfo2(const unsigned char *abuf,
int alen,
char **question_hostname,
struct ares_addrinfo *ai)
{
unsigned int qdcount, ancount;
int status, i, rr_type, rr_class, rr_len, rr_ttl;
int got_a = 0, got_aaaa = 0, got_cname = 0;
long len;
const unsigned char *aptr;
char *hostname, *rr_name = NULL, *rr_data;
struct ares_addrinfo_cname *cname, *cnames = NULL;
struct ares_addrinfo_node *node, *nodes = NULL;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
*question_hostname = NULL;
/* Give up if abuf doesn't have room for a header. */
if (alen < HFIXEDSZ)
return ARES_EBADRESP;
/* Fetch the question and answer count from the header. */
qdcount = DNS_HEADER_QDCOUNT(abuf);
ancount = DNS_HEADER_ANCOUNT(abuf);
if (qdcount != 1)
return ARES_EBADRESP;
/* Expand the name from the question, and skip past the question. */
aptr = abuf + HFIXEDSZ;
status = ares__expand_name_for_response(aptr, abuf, alen, question_hostname, &len);
if (status != ARES_SUCCESS)
return status;
if (aptr + len + QFIXEDSZ > abuf + alen)
{
return ARES_EBADRESP;
}
hostname = *question_hostname;
aptr += len + QFIXEDSZ;
/* Examine each answer resource record (RR) in turn. */
for (i = 0; i < (int)ancount; i++)
{
/* Decode the RR up to the data field. */
status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
if (status != ARES_SUCCESS)
{
rr_name = NULL;
goto failed_stat;
}
aptr += len;
if (aptr + RRFIXEDSZ > abuf + alen)
{
status = ARES_EBADRESP;
goto failed_stat;
}
rr_type = DNS_RR_TYPE(aptr);
rr_class = DNS_RR_CLASS(aptr);
rr_len = DNS_RR_LEN(aptr);
rr_ttl = DNS_RR_TTL(aptr);
aptr += RRFIXEDSZ;
if (aptr + rr_len > abuf + alen)
{
status = ARES_EBADRESP;
goto failed_stat;
}
if (rr_class == C_IN && rr_type == T_A
&& rr_len == sizeof(struct in_addr)
&& strcasecmp(rr_name, hostname) == 0)
{
got_a = 1;
if (aptr + sizeof(struct in_addr) > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
goto failed_stat;
} /* LCOV_EXCL_STOP */
node = ares__append_addrinfo_node(&nodes);
if (!node)
{
status = ARES_ENOMEM;
goto failed_stat;
}
sin = ares_malloc(sizeof(struct sockaddr_in));
if (!sin)
{
status = ARES_ENOMEM;
goto failed_stat;
}
memset(sin, 0, sizeof(struct sockaddr_in));
memcpy(&sin->sin_addr.s_addr, aptr, sizeof(struct in_addr));
sin->sin_family = AF_INET;
node->ai_addr = (struct sockaddr *)sin;
node->ai_family = AF_INET;
node->ai_addrlen = sizeof(struct sockaddr_in);
node->ai_ttl = rr_ttl;
status = ARES_SUCCESS;
}
else if (rr_class == C_IN && rr_type == T_AAAA
&& rr_len == sizeof(struct ares_in6_addr)
&& strcasecmp(rr_name, hostname) == 0)
{
got_aaaa = 1;
if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
goto failed_stat;
} /* LCOV_EXCL_STOP */
node = ares__append_addrinfo_node(&nodes);
if (!node)
{
status = ARES_ENOMEM;
goto failed_stat;
}
sin6 = ares_malloc(sizeof(struct sockaddr_in6));
if (!sin6)
{
status = ARES_ENOMEM;
goto failed_stat;
}
memset(sin6, 0, sizeof(struct sockaddr_in6));
memcpy(&sin6->sin6_addr.s6_addr, aptr, sizeof(struct ares_in6_addr));
sin6->sin6_family = AF_INET6;
node->ai_addr = (struct sockaddr *)sin6;
node->ai_family = AF_INET6;
node->ai_addrlen = sizeof(struct sockaddr_in6);
node->ai_ttl = rr_ttl;
status = ARES_SUCCESS;
}
if (rr_class == C_IN && rr_type == T_CNAME)
{
got_cname = 1;
status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
&len);
if (status != ARES_SUCCESS)
{
goto failed_stat;
}
/* Decode the RR data and replace the hostname with it. */
/* SA: Seems wrong as it introduses order dependency. */
hostname = rr_data;
cname = ares__append_addrinfo_cname(&cnames);
if (!cname)
{
status = ARES_ENOMEM;
ares_free(rr_data);
goto failed_stat;
}
cname->ttl = rr_ttl;
cname->alias = rr_name;
cname->name = rr_data;
}
else
{
ares_free(rr_name);
}
aptr += rr_len;
if (aptr > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
goto failed_stat;
} /* LCOV_EXCL_STOP */
}
if (status == ARES_SUCCESS)
{
ares__addrinfo_cat_nodes(&ai->nodes, nodes);
if (got_cname)
{
ares__addrinfo_cat_cnames(&ai->cnames, cnames);
return status;
}
else if (got_a == 0 && got_aaaa == 0)
{
/* the check for naliases to be zero is to make sure CNAME responses
don't get caught here */
status = ARES_ENODATA;
}
}
return status;
failed_stat:
ares_free(rr_name);
ares__freeaddrinfo_cnames(cnames);
ares__freeaddrinfo_nodes(nodes);
return status;
}
int ares__parse_into_addrinfo(const unsigned char *abuf,
int alen,
struct ares_addrinfo *ai)
{
int status;
char *question_hostname;
status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, ai);
ares_free(question_hostname);
return status;
}

260
deps/cares/src/ares__readaddrinfo.c vendored Normal file
View File

@@ -0,0 +1,260 @@
/* Copyright (C) 2019 by Andrew Selivanov
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#include "ares_setup.h"
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#include "ares.h"
#include "ares_inet_net_pton.h"
#include "ares_nowarn.h"
#include "ares_private.h"
#define MAX_ALIASES 40
int ares__readaddrinfo(FILE *fp,
const char *name,
unsigned short port,
const struct ares_addrinfo_hints *hints,
struct ares_addrinfo *ai)
{
char *line = NULL, *p, *q;
char *txtaddr, *txthost, *txtalias;
char *aliases[MAX_ALIASES];
unsigned int i, alias_count;
int status;
size_t linesize;
ares_sockaddr addr;
struct ares_addrinfo_cname *cname = NULL, *cnames = NULL;
struct ares_addrinfo_node *node = NULL, *nodes = NULL;
int match_with_alias, match_with_canonical;
int want_cname = hints->ai_flags & ARES_AI_CANONNAME;
/* Validate family */
switch (hints->ai_family) {
case AF_INET:
case AF_INET6:
case AF_UNSPEC:
break;
default:
return ARES_EBADFAMILY;
}
while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
{
match_with_alias = 0;
match_with_canonical = 0;
alias_count = 0;
/* Trim line comment. */
p = line;
while (*p && (*p != '#'))
p++;
*p = '\0';
/* Trim trailing whitespace. */
q = p - 1;
while ((q >= line) && ISSPACE(*q))
q--;
*++q = '\0';
/* Skip leading whitespace. */
p = line;
while (*p && ISSPACE(*p))
p++;
if (!*p)
/* Ignore line if empty. */
continue;
/* Pointer to start of IPv4 or IPv6 address part. */
txtaddr = p;
/* Advance past address part. */
while (*p && !ISSPACE(*p))
p++;
if (!*p)
/* Ignore line if reached end of line. */
continue;
/* Null terminate address part. */
*p = '\0';
/* Advance to host name */
p++;
while (*p && ISSPACE(*p))
p++;
if (!*p)
/* Ignore line if reached end of line. */
continue; /* LCOV_EXCL_LINE: trailing whitespace already stripped */
/* Pointer to start of host name. */
txthost = p;
/* Advance past host name. */
while (*p && !ISSPACE(*p))
p++;
/* Pointer to start of first alias. */
txtalias = NULL;
if (*p)
{
q = p + 1;
while (*q && ISSPACE(*q))
q++;
if (*q)
txtalias = q;
}
/* Null terminate host name. */
*p = '\0';
/* Find out if host name matches with canonical host name. */
if (strcasecmp(txthost, name) == 0)
{
match_with_canonical = 1;
}
/* Find out if host name matches with one of the aliases. */
while (txtalias)
{
p = txtalias;
while (*p && !ISSPACE(*p))
p++;
q = p;
while (*q && ISSPACE(*q))
q++;
*p = '\0';
if (strcasecmp(txtalias, name) == 0)
{
match_with_alias = 1;
if (!want_cname)
break;
}
if (alias_count < MAX_ALIASES)
{
aliases[alias_count++] = txtalias;
}
txtalias = *q ? q : NULL;
}
/* Try next line if host does not match. */
if (!match_with_alias && !match_with_canonical)
{
continue;
}
/*
* Convert address string to network address for the requested families.
* Actual address family possible values are AF_INET and AF_INET6 only.
*/
if ((hints->ai_family == AF_INET) || (hints->ai_family == AF_UNSPEC))
{
addr.sa4.sin_port = htons(port);
if (ares_inet_pton(AF_INET, txtaddr, &addr.sa4.sin_addr) > 0)
{
node = ares__append_addrinfo_node(&nodes);
if(!node)
{
goto enomem;
}
node->ai_family = addr.sa.sa_family = AF_INET;
node->ai_addrlen = sizeof(sizeof(addr.sa4));
node->ai_addr = ares_malloc(sizeof(addr.sa4));
if (!node->ai_addr)
{
goto enomem;
}
memcpy(node->ai_addr, &addr.sa4, sizeof(addr.sa4));
}
}
if ((hints->ai_family == AF_INET6) || (hints->ai_family == AF_UNSPEC))
{
addr.sa6.sin6_port = htons(port);
if (ares_inet_pton(AF_INET6, txtaddr, &addr.sa6.sin6_addr) > 0)
{
node = ares__append_addrinfo_node(&nodes);
if (!node)
{
goto enomem;
}
node->ai_family = addr.sa.sa_family = AF_INET6;
node->ai_addrlen = sizeof(sizeof(addr.sa6));
node->ai_addr = ares_malloc(sizeof(addr.sa6));
if (!node->ai_addr)
{
goto enomem;
}
memcpy(node->ai_addr, &addr.sa6, sizeof(addr.sa6));
}
}
if (!node)
/* Ignore line if invalid address string for the requested family. */
continue;
if (want_cname)
{
for (i = 0; i < alias_count; ++i)
{
cname = ares__append_addrinfo_cname(&cnames);
if (!cname)
{
goto enomem;
}
cname->alias = ares_strdup(aliases[i]);
cname->name = ares_strdup(txthost);
}
/* No aliases, cname only. */
if(!alias_count)
{
cname = ares__append_addrinfo_cname(&cnames);
if (!cname)
{
goto enomem;
}
cname->name = ares_strdup(txthost);
}
}
}
/* Last read failed. */
if (status == ARES_ENOMEM)
{
goto enomem;
}
/* Free line buffer. */
ares_free(line);
ares__addrinfo_cat_cnames(&ai->cnames, cnames);
ares__addrinfo_cat_nodes(&ai->nodes, nodes);
return node ? ARES_SUCCESS : ARES_ENOTFOUND;
enomem:
ares_free(line);
ares__freeaddrinfo_cnames(cnames);
ares__freeaddrinfo_nodes(nodes);
return ARES_ENOMEM;
}

494
deps/cares/src/ares__sortaddrinfo.c vendored Normal file
View File

@@ -0,0 +1,494 @@
/*
* Original file name getaddrinfo.c
* Lifted from the 'Android Bionic' project with the BSD license.
*/
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* Copyright (C) 2018 The Android Open Source Project
* Copyright (C) 2019 by Andrew Selivanov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "ares_setup.h"
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <assert.h>
#include <limits.h>
#include "ares.h"
#include "ares_private.h"
struct addrinfo_sort_elem
{
struct ares_addrinfo_node *ai;
int has_src_addr;
ares_sockaddr src_addr;
int original_order;
};
#define ARES_IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
#define ARES_IPV6_ADDR_SCOPE_NODELOCAL 0x01
#define ARES_IPV6_ADDR_SCOPE_INTFACELOCAL 0x01
#define ARES_IPV6_ADDR_SCOPE_LINKLOCAL 0x02
#define ARES_IPV6_ADDR_SCOPE_SITELOCAL 0x05
#define ARES_IPV6_ADDR_SCOPE_ORGLOCAL 0x08
#define ARES_IPV6_ADDR_SCOPE_GLOBAL 0x0e
#define ARES_IN_LOOPBACK(a) ((((long int)(a)) & 0xff000000) == 0x7f000000)
/* RFC 4193. */
#define ARES_IN6_IS_ADDR_ULA(a) (((a)->s6_addr[0] & 0xfe) == 0xfc)
/* These macros are modelled after the ones in <netinet/in6.h>. */
/* RFC 4380, section 2.6 */
#define ARES_IN6_IS_ADDR_TEREDO(a) \
((*(const unsigned int *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000)))
/* RFC 3056, section 2. */
#define ARES_IN6_IS_ADDR_6TO4(a) \
(((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
/* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */
#define ARES_IN6_IS_ADDR_6BONE(a) \
(((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe))
static int get_scope(const struct sockaddr *addr)
{
if (addr->sa_family == AF_INET6)
{
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr))
{
return ARES_IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr);
}
else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) ||
IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr))
{
/*
* RFC 4291 section 2.5.3 says loopback is to be treated as having
* link-local scope.
*/
return ARES_IPV6_ADDR_SCOPE_LINKLOCAL;
}
else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr))
{
return ARES_IPV6_ADDR_SCOPE_SITELOCAL;
}
else
{
return ARES_IPV6_ADDR_SCOPE_GLOBAL;
}
}
else if (addr->sa_family == AF_INET)
{
const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
unsigned long int na = ntohl(addr4->sin_addr.s_addr);
if (ARES_IN_LOOPBACK(na) || /* 127.0.0.0/8 */
(na & 0xffff0000) == 0xa9fe0000) /* 169.254.0.0/16 */
{
return ARES_IPV6_ADDR_SCOPE_LINKLOCAL;
}
else
{
/*
* RFC 6724 section 3.2. Other IPv4 addresses, including private
* addresses and shared addresses (100.64.0.0/10), are assigned global
* scope.
*/
return ARES_IPV6_ADDR_SCOPE_GLOBAL;
}
}
else
{
/*
* This should never happen.
* Return a scope with low priority as a last resort.
*/
return ARES_IPV6_ADDR_SCOPE_NODELOCAL;
}
}
static int get_label(const struct sockaddr *addr)
{
if (addr->sa_family == AF_INET)
{
return 4;
}
else if (addr->sa_family == AF_INET6)
{
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr))
{
return 0;
}
else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr))
{
return 4;
}
else if (ARES_IN6_IS_ADDR_6TO4(&addr6->sin6_addr))
{
return 2;
}
else if (ARES_IN6_IS_ADDR_TEREDO(&addr6->sin6_addr))
{
return 5;
}
else if (ARES_IN6_IS_ADDR_ULA(&addr6->sin6_addr))
{
return 13;
}
else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr))
{
return 3;
}
else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr))
{
return 11;
}
else if (ARES_IN6_IS_ADDR_6BONE(&addr6->sin6_addr))
{
return 12;
}
else
{
/* All other IPv6 addresses, including global unicast addresses. */
return 1;
}
}
else
{
/*
* This should never happen.
* Return a semi-random label as a last resort.
*/
return 1;
}
}
/*
* Get the precedence for a given IPv4/IPv6 address.
* RFC 6724, section 2.1.
*/
static int get_precedence(const struct sockaddr *addr)
{
if (addr->sa_family == AF_INET)
{
return 35;
}
else if (addr->sa_family == AF_INET6)
{
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr))
{
return 50;
}
else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr))
{
return 35;
}
else if (ARES_IN6_IS_ADDR_6TO4(&addr6->sin6_addr))
{
return 30;
}
else if (ARES_IN6_IS_ADDR_TEREDO(&addr6->sin6_addr))
{
return 5;
}
else if (ARES_IN6_IS_ADDR_ULA(&addr6->sin6_addr))
{
return 3;
}
else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) ||
IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) ||
ARES_IN6_IS_ADDR_6BONE(&addr6->sin6_addr))
{
return 1;
}
else
{
/* All other IPv6 addresses, including global unicast addresses. */
return 40;
}
}
else
{
return 1;
}
}
/*
* Find number of matching initial bits between the two addresses a1 and a2.
*/
static int common_prefix_len(const struct in6_addr *a1,
const struct in6_addr *a2)
{
const char *p1 = (const char *)a1;
const char *p2 = (const char *)a2;
unsigned i;
for (i = 0; i < sizeof(*a1); ++i)
{
int x, j;
if (p1[i] == p2[i])
{
continue;
}
x = p1[i] ^ p2[i];
for (j = 0; j < CHAR_BIT; ++j)
{
if (x & (1 << (CHAR_BIT - 1)))
{
return i * CHAR_BIT + j;
}
x <<= 1;
}
}
return sizeof(*a1) * CHAR_BIT;
}
/*
* Compare two source/destination address pairs.
* RFC 6724, section 6.
*/
static int rfc6724_compare(const void *ptr1, const void *ptr2)
{
const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1;
const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2;
int scope_src1, scope_dst1, scope_match1;
int scope_src2, scope_dst2, scope_match2;
int label_src1, label_dst1, label_match1;
int label_src2, label_dst2, label_match2;
int precedence1, precedence2;
int prefixlen1, prefixlen2;
/* Rule 1: Avoid unusable destinations. */
if (a1->has_src_addr != a2->has_src_addr)
{
return a2->has_src_addr - a1->has_src_addr;
}
/* Rule 2: Prefer matching scope. */
scope_src1 = get_scope(&a1->src_addr.sa);
scope_dst1 = get_scope(a1->ai->ai_addr);
scope_match1 = (scope_src1 == scope_dst1);
scope_src2 = get_scope(&a2->src_addr.sa);
scope_dst2 = get_scope(a2->ai->ai_addr);
scope_match2 = (scope_src2 == scope_dst2);
if (scope_match1 != scope_match2)
{
return scope_match2 - scope_match1;
}
/* Rule 3: Avoid deprecated addresses. */
/* Rule 4: Prefer home addresses. */
/* Rule 5: Prefer matching label. */
label_src1 = get_label(&a1->src_addr.sa);
label_dst1 = get_label(a1->ai->ai_addr);
label_match1 = (label_src1 == label_dst1);
label_src2 = get_label(&a2->src_addr.sa);
label_dst2 = get_label(a2->ai->ai_addr);
label_match2 = (label_src2 == label_dst2);
if (label_match1 != label_match2)
{
return label_match2 - label_match1;
}
/* Rule 6: Prefer higher precedence. */
precedence1 = get_precedence(a1->ai->ai_addr);
precedence2 = get_precedence(a2->ai->ai_addr);
if (precedence1 != precedence2)
{
return precedence2 - precedence1;
}
/* Rule 7: Prefer native transport. */
/* Rule 8: Prefer smaller scope. */
if (scope_dst1 != scope_dst2)
{
return scope_dst1 - scope_dst2;
}
/* Rule 9: Use longest matching prefix. */
if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 &&
a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6)
{
const struct sockaddr_in6 *a1_src = &a1->src_addr.sa6;
const struct sockaddr_in6 *a1_dst =
(const struct sockaddr_in6 *)a1->ai->ai_addr;
const struct sockaddr_in6 *a2_src = &a2->src_addr.sa6;
const struct sockaddr_in6 *a2_dst =
(const struct sockaddr_in6 *)a2->ai->ai_addr;
prefixlen1 = common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr);
prefixlen2 = common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr);
if (prefixlen1 != prefixlen2)
{
return prefixlen2 - prefixlen1;
}
}
/*
* Rule 10: Leave the order unchanged.
* We need this since qsort() is not necessarily stable.
*/
return a1->original_order - a2->original_order;
}
/*
* Find the source address that will be used if trying to connect to the given
* address.
*
* Returns 1 if a source address was found, 0 if the address is unreachable,
* and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are
* undefined.
*/
static int find_src_addr(ares_channel channel,
const struct sockaddr *addr,
struct sockaddr *src_addr)
{
int sock;
int ret;
ares_socklen_t len;
switch (addr->sa_family)
{
case AF_INET:
len = sizeof(struct sockaddr_in);
break;
case AF_INET6:
len = sizeof(struct sockaddr_in6);
break;
default:
/* No known usable source address for non-INET families. */
return 0;
}
sock = ares__open_socket(channel, addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1)
{
if (errno == EAFNOSUPPORT)
{
return 0;
}
else
{
return -1;
}
}
do
{
ret = ares__connect_socket(channel, sock, addr, len);
}
while (ret == -1 && errno == EINTR);
if (ret == -1)
{
ares__close_socket(channel, sock);
return 0;
}
if (getsockname(sock, src_addr, &len) == -1)
{
ares__close_socket(channel, sock);
return -1;
}
ares__close_socket(channel, sock);
return 1;
}
/*
* Sort the linked list starting at sentinel->ai_next in RFC6724 order.
* Will leave the list unchanged if an error occurs.
*/
int ares__sortaddrinfo(ares_channel channel, struct ares_addrinfo_node *list_sentinel)
{
struct ares_addrinfo_node *cur;
int nelem = 0, i;
int has_src_addr;
struct addrinfo_sort_elem *elems;
cur = list_sentinel->ai_next;
while (cur)
{
++nelem;
cur = cur->ai_next;
}
elems = (struct addrinfo_sort_elem *)ares_malloc(
nelem * sizeof(struct addrinfo_sort_elem));
if (!elems)
{
return ARES_ENOMEM;
}
/*
* Convert the linked list to an array that also contains the candidate
* source address for each destination address.
*/
for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next)
{
assert(cur != NULL);
elems[i].ai = cur;
elems[i].original_order = i;
has_src_addr = find_src_addr(channel, cur->ai_addr, &elems[i].src_addr.sa);
if (has_src_addr == -1)
{
ares_free(elems);
return ARES_ENOTFOUND;
}
elems[i].has_src_addr = has_src_addr;
}
/* Sort the addresses, and rearrange the linked list so it matches the sorted
* order. */
qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem),
rfc6724_compare);
list_sentinel->ai_next = elems[0].ai;
for (i = 0; i < nelem - 1; ++i)
{
elems[i].ai->ai_next = elems[i + 1].ai;
}
elems[nelem - 1].ai->ai_next = NULL;
ares_free(elems);
return ARES_SUCCESS;
}

View File

@@ -360,8 +360,6 @@ char *ares_get_android_search_domains_list(void)
jstring domains = NULL;
const char *domain;
int res;
size_t i;
size_t cnt = 0;
char *domain_list = NULL;
int need_detatch = 0;

57
deps/cares/src/ares_freeaddrinfo.c vendored Normal file
View File

@@ -0,0 +1,57 @@
/* Copyright 1998 by the Massachusetts Institute of Technology.
* Copyright (C) 2019 by Andrew Selivanov
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#include "ares_setup.h"
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#include "ares.h"
#include "ares_private.h"
void ares__freeaddrinfo_cnames(struct ares_addrinfo_cname *head)
{
struct ares_addrinfo_cname *current;
while (head)
{
current = head;
head = head->next;
ares_free(current->alias);
ares_free(current->name);
ares_free(current);
}
}
void ares__freeaddrinfo_nodes(struct ares_addrinfo_node *head)
{
struct ares_addrinfo_node *current;
while (head)
{
current = head;
head = head->ai_next;
ares_free(current->ai_addr);
ares_free(current);
}
}
void ares_freeaddrinfo(struct ares_addrinfo *ai)
{
ares__freeaddrinfo_cnames(ai->cnames);
ares__freeaddrinfo_nodes(ai->nodes);
ares_free(ai);
}

764
deps/cares/src/ares_getaddrinfo.c vendored Normal file
View File

@@ -0,0 +1,764 @@
/* Copyright 1998, 2011, 2013 by the Massachusetts Institute of Technology.
* Copyright (C) 2017 - 2018 by Christian Ammer
* Copyright (C) 2019 by Andrew Selivanov
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#include "ares_setup.h"
#ifdef HAVE_GETSERVBYNAME_R
# if !defined(GETSERVBYNAME_R_ARGS) || \
(GETSERVBYNAME_R_ARGS < 4) || (GETSERVBYNAME_R_ARGS > 6)
# error "you MUST specifiy a valid number of arguments for getservbyname_r"
# endif
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h>
#else
# include "nameser.h"
#endif
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
# include <arpa/nameser_compat.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <assert.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include "ares.h"
#include "bitncmp.h"
#include "ares_private.h"
#ifdef WATT32
#undef WIN32
#endif
#ifdef WIN32
# include "ares_platform.h"
#endif
struct host_query
{
ares_channel channel;
char *name;
unsigned short port; /* in host order */
ares_addrinfo_callback callback;
void *arg;
struct ares_addrinfo_hints hints;
int sent_family; /* this family is what was is being used */
int timeouts; /* number of timeouts we saw for this request */
const char *remaining_lookups; /* types of lookup we need to perform ("fb" by
default, file and dns respectively) */
struct ares_addrinfo *ai; /* store results between lookups */
int remaining; /* number of DNS answers waiting for */
int next_domain; /* next search domain to try */
};
static const struct ares_addrinfo_hints default_hints = {
0, /* ai_flags */
AF_UNSPEC, /* ai_family */
0, /* ai_socktype */
0, /* ai_protocol */
};
static const struct ares_addrinfo_cname empty_addrinfo_cname = {
INT_MAX, /* ttl */
NULL, /* alias */
NULL, /* name */
NULL, /* next */
};
static const struct ares_addrinfo_node empty_addrinfo_node = {
0, /* ai_ttl */
0, /* ai_flags */
0, /* ai_family */
0, /* ai_socktype */
0, /* ai_protocol */
0, /* ai_addrlen */
NULL, /* ai_addr */
NULL /* ai_next */
};
static const struct ares_addrinfo empty_addrinfo = {
NULL, /* cnames */
NULL /* nodes */
};
/* forward declarations */
static void host_callback(void *arg, int status, int timeouts,
unsigned char *abuf, int alen);
static int as_is_first(const struct host_query *hquery);
static int next_dns_lookup(struct host_query *hquery);
struct ares_addrinfo_cname *ares__malloc_addrinfo_cname()
{
struct ares_addrinfo_cname *cname = ares_malloc(sizeof(struct ares_addrinfo_cname));
if (!cname)
return NULL;
*cname = empty_addrinfo_cname;
return cname;
}
struct ares_addrinfo_cname *ares__append_addrinfo_cname(struct ares_addrinfo_cname **head)
{
struct ares_addrinfo_cname *tail = ares__malloc_addrinfo_cname();
struct ares_addrinfo_cname *last = *head;
if (!last)
{
*head = tail;
return tail;
}
while (last->next)
{
last = last->next;
}
last->next = tail;
return tail;
}
void ares__addrinfo_cat_cnames(struct ares_addrinfo_cname **head,
struct ares_addrinfo_cname *tail)
{
struct ares_addrinfo_cname *last = *head;
if (!last)
{
*head = tail;
return;
}
while (last->next)
{
last = last->next;
}
last->next = tail;
}
struct ares_addrinfo *ares__malloc_addrinfo()
{
struct ares_addrinfo *ai = ares_malloc(sizeof(struct ares_addrinfo));
if (!ai)
return NULL;
*ai = empty_addrinfo;
return ai;
}
struct ares_addrinfo_node *ares__malloc_addrinfo_node()
{
struct ares_addrinfo_node *node =
ares_malloc(sizeof(struct ares_addrinfo_node));
if (!node)
return NULL;
*node = empty_addrinfo_node;
return node;
}
/* Allocate new addrinfo and append to the tail. */
struct ares_addrinfo_node *ares__append_addrinfo_node(struct ares_addrinfo_node **head)
{
struct ares_addrinfo_node *tail = ares__malloc_addrinfo_node();
struct ares_addrinfo_node *last = *head;
if (!last)
{
*head = tail;
return tail;
}
while (last->ai_next)
{
last = last->ai_next;
}
last->ai_next = tail;
return tail;
}
void ares__addrinfo_cat_nodes(struct ares_addrinfo_node **head,
struct ares_addrinfo_node *tail)
{
struct ares_addrinfo_node *last = *head;
if (!last)
{
*head = tail;
return;
}
while (last->ai_next)
{
last = last->ai_next;
}
last->ai_next = tail;
}
/* Resolve service name into port number given in host byte order.
* If not resolved, return 0.
*/
static unsigned short lookup_service(const char *service, int flags)
{
const char *proto;
struct servent *sep;
#ifdef HAVE_GETSERVBYNAME_R
struct servent se;
char tmpbuf[4096];
#endif
if (service)
{
if (flags & ARES_NI_UDP)
proto = "udp";
else if (flags & ARES_NI_SCTP)
proto = "sctp";
else if (flags & ARES_NI_DCCP)
proto = "dccp";
else
proto = "tcp";
#ifdef HAVE_GETSERVBYNAME_R
memset(&se, 0, sizeof(se));
sep = &se;
memset(tmpbuf, 0, sizeof(tmpbuf));
#if GETSERVBYNAME_R_ARGS == 6
if (getservbyname_r(service, proto, &se, (void *)tmpbuf, sizeof(tmpbuf),
&sep) != 0)
sep = NULL; /* LCOV_EXCL_LINE: buffer large so this never fails */
#elif GETSERVBYNAME_R_ARGS == 5
sep =
getservbyname_r(service, proto, &se, (void *)tmpbuf, sizeof(tmpbuf));
#elif GETSERVBYNAME_R_ARGS == 4
if (getservbyname_r(service, proto, &se, (void *)tmpbuf) != 0)
sep = NULL;
#else
/* Lets just hope the OS uses TLS! */
sep = getservbyname(service, proto);
#endif
#else
/* Lets just hope the OS uses TLS! */
#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
sep = getservbyname(service, (char *)proto);
#else
sep = getservbyname(service, proto);
#endif
#endif
return (sep ? ntohs((unsigned short)sep->s_port) : 0);
}
return 0;
}
/* If the name looks like an IP address or an error occured,
* fake up a host entry, end the query immediately, and return true.
* Otherwise return false.
*/
static int fake_addrinfo(const char *name,
unsigned short port,
const struct ares_addrinfo_hints *hints,
struct ares_addrinfo *ai,
ares_addrinfo_callback callback,
void *arg)
{
struct ares_addrinfo_cname *cname;
struct ares_addrinfo_node *node;
ares_sockaddr addr;
size_t addrlen;
int result = 0;
int family = hints->ai_family;
if (family == AF_INET || family == AF_INET6 || family == AF_UNSPEC)
{
/* It only looks like an IP address if it's all numbers and dots. */
int numdots = 0, valid = 1;
const char *p;
for (p = name; *p; p++)
{
if (!ISDIGIT(*p) && *p != '.')
{
valid = 0;
break;
}
else if (*p == '.')
{
numdots++;
}
}
memset(&addr, 0, sizeof(addr));
/* if we don't have 3 dots, it is illegal
* (although inet_pton doesn't think so).
*/
if (numdots != 3 || !valid)
result = 0;
else
result =
(ares_inet_pton(AF_INET, name, &addr.sa4.sin_addr) < 1 ? 0 : 1);
if (result)
{
family = addr.sa.sa_family = AF_INET;
addr.sa4.sin_port = htons(port);
addrlen = sizeof(addr.sa4);
}
}
if (family == AF_INET6 || family == AF_UNSPEC)
{
result =
(ares_inet_pton(AF_INET6, name, &addr.sa6.sin6_addr) < 1 ? 0 : 1);
addr.sa6.sin6_family = AF_INET6;
addr.sa6.sin6_port = htons(port);
addrlen = sizeof(addr.sa6);
}
if (!result)
return 0;
node = ares__malloc_addrinfo_node();
if (!node)
{
ares_freeaddrinfo(ai);
callback(arg, ARES_ENOMEM, 0, NULL);
return 1;
}
ai->nodes = node;
node->ai_addr = ares_malloc(addrlen);
if (!node->ai_addr)
{
ares_freeaddrinfo(ai);
callback(arg, ARES_ENOMEM, 0, NULL);
return 1;
}
node->ai_addrlen = (unsigned int)addrlen;
node->ai_family = addr.sa.sa_family;
if (addr.sa.sa_family == AF_INET)
memcpy(node->ai_addr, &addr.sa4, sizeof(addr.sa4));
else
memcpy(node->ai_addr, &addr.sa6, sizeof(addr.sa6));
if (hints->ai_flags & ARES_AI_CANONNAME)
{
cname = ares__append_addrinfo_cname(&ai->cnames);
if (!cname)
{
ares_freeaddrinfo(ai);
callback(arg, ARES_ENOMEM, 0, NULL);
return 1;
}
/* Duplicate the name, to avoid a constness violation. */
cname->name = ares_strdup(name);
if (!cname->name)
{
ares_freeaddrinfo(ai);
callback(arg, ARES_ENOMEM, 0, NULL);
return 1;
}
}
callback(arg, ARES_SUCCESS, 0, ai);
return 1;
}
static void end_hquery(struct host_query *hquery, int status)
{
struct ares_addrinfo_node sentinel;
struct ares_addrinfo_node *next;
if (status == ARES_SUCCESS)
{
if (!(hquery->hints.ai_flags & ARES_AI_NOSORT))
{
sentinel.ai_next = hquery->ai->nodes;
ares__sortaddrinfo(hquery->channel, &sentinel);
hquery->ai->nodes = sentinel.ai_next;
}
next = hquery->ai->nodes;
/* Set port into each address (resolved separately). */
while (next)
{
if (next->ai_family == AF_INET)
{
((struct sockaddr_in *)next->ai_addr)->sin_port = htons(hquery->port);
}
else
{
((struct sockaddr_in6 *)next->ai_addr)->sin6_port = htons(hquery->port);
}
next = next->ai_next;
}
}
else
{
/* Clean up what we have collected by so far. */
ares_freeaddrinfo(hquery->ai);
hquery->ai = NULL;
}
hquery->callback(hquery->arg, status, hquery->timeouts, hquery->ai);
ares_free(hquery->name);
ares_free(hquery);
}
static int file_lookup(struct host_query *hquery)
{
FILE *fp;
int error;
int status;
const char *path_hosts = NULL;
if (hquery->hints.ai_flags & ARES_AI_ENVHOSTS)
{
path_hosts = getenv("CARES_HOSTS");
}
if (!path_hosts)
{
#ifdef WIN32
char PATH_HOSTS[MAX_PATH];
win_platform platform;
PATH_HOSTS[0] = '\0';
platform = ares__getplatform();
if (platform == WIN_NT)
{
char tmp[MAX_PATH];
HKEY hkeyHosts;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ,
&hkeyHosts) == ERROR_SUCCESS)
{
DWORD dwLength = MAX_PATH;
RegQueryValueEx(hkeyHosts, DATABASEPATH, NULL, NULL, (LPBYTE)tmp,
&dwLength);
ExpandEnvironmentStrings(tmp, PATH_HOSTS, MAX_PATH);
RegCloseKey(hkeyHosts);
}
}
else if (platform == WIN_9X)
GetWindowsDirectory(PATH_HOSTS, MAX_PATH);
else
return ARES_ENOTFOUND;
strcat(PATH_HOSTS, WIN_PATH_HOSTS);
path_hosts = PATH_HOSTS;
#elif defined(WATT32)
const char *PATH_HOSTS = _w32_GetHostsFile();
if (!PATH_HOSTS)
return ARES_ENOTFOUND;
#endif
path_hosts = PATH_HOSTS;
}
fp = fopen(path_hosts, "r");
if (!fp)
{
error = ERRNO;
switch (error)
{
case ENOENT:
case ESRCH:
return ARES_ENOTFOUND;
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", error,
strerror(error)));
DEBUGF(fprintf(stderr, "Error opening file: %s\n", path_hosts));
return ARES_EFILE;
}
}
status = ares__readaddrinfo(fp, hquery->name, hquery->port, &hquery->hints, hquery->ai);
fclose(fp);
return status;
}
static void next_lookup(struct host_query *hquery, int status)
{
switch (*hquery->remaining_lookups)
{
case 'b':
/* DNS lookup */
if (next_dns_lookup(hquery))
break;
hquery->remaining_lookups++;
next_lookup(hquery, status);
break;
case 'f':
/* Host file lookup */
if (file_lookup(hquery) == ARES_SUCCESS)
{
end_hquery(hquery, ARES_SUCCESS);
break;
}
hquery->remaining_lookups++;
next_lookup(hquery, status);
break;
default:
/* No lookup left */
end_hquery(hquery, status);
break;
}
}
static void host_callback(void *arg, int status, int timeouts,
unsigned char *abuf, int alen)
{
struct host_query *hquery = (struct host_query*)arg;
int addinfostatus = ARES_SUCCESS;
hquery->timeouts += timeouts;
hquery->remaining--;
if (status == ARES_SUCCESS)
{
addinfostatus = ares__parse_into_addrinfo(abuf, alen, hquery->ai);
}
else if (status == ARES_EDESTRUCTION)
{
end_hquery(hquery, status);
}
if (!hquery->remaining)
{
if (addinfostatus != ARES_SUCCESS)
{
/* error in parsing result e.g. no memory */
end_hquery(hquery, addinfostatus);
}
else if (hquery->ai->nodes)
{
/* at least one query ended with ARES_SUCCESS */
end_hquery(hquery, ARES_SUCCESS);
}
else if (status == ARES_ENOTFOUND)
{
next_lookup(hquery, status);
}
else
{
end_hquery(hquery, status);
}
}
/* at this point we keep on waiting for the next query to finish */
}
void ares_getaddrinfo(ares_channel channel,
const char* name, const char* service,
const struct ares_addrinfo_hints* hints,
ares_addrinfo_callback callback, void* arg)
{
struct host_query *hquery;
unsigned short port = 0;
int family;
struct ares_addrinfo *ai;
if (!hints)
{
hints = &default_hints;
}
family = hints->ai_family;
/* Right now we only know how to look up Internet addresses
and unspec means try both basically. */
if (family != AF_INET &&
family != AF_INET6 &&
family != AF_UNSPEC)
{
callback(arg, ARES_ENOTIMP, 0, NULL);
return;
}
if (ares__is_onion_domain(name))
{
callback(arg, ARES_ENOTFOUND, 0, NULL);
return;
}
if (service)
{
if (hints->ai_flags & ARES_AI_NUMERICSERV)
{
port = (unsigned short)strtoul(service, NULL, 0);
if (!port)
{
callback(arg, ARES_ESERVICE, 0, NULL);
return;
}
}
else
{
port = lookup_service(service, 0);
if (!port)
{
port = (unsigned short)strtoul(service, NULL, 0);
if (!port)
{
callback(arg, ARES_ESERVICE, 0, NULL);
return;
}
}
}
}
ai = ares__malloc_addrinfo();
if (!ai)
{
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
if (fake_addrinfo(name, port, hints, ai, callback, arg))
{
return;
}
/* Allocate and fill in the host query structure. */
hquery = ares_malloc(sizeof(struct host_query));
if (!hquery)
{
ares_freeaddrinfo(ai);
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
hquery->name = ares_strdup(name);
if (!hquery->name)
{
ares_free(hquery);
ares_freeaddrinfo(ai);
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
hquery->port = port;
hquery->channel = channel;
hquery->hints = *hints;
hquery->sent_family = -1; /* nothing is sent yet */
hquery->callback = callback;
hquery->arg = arg;
hquery->remaining_lookups = channel->lookups;
hquery->timeouts = 0;
hquery->ai = ai;
hquery->next_domain = -1;
hquery->remaining = 0;
/* Start performing lookups according to channel->lookups. */
next_lookup(hquery, ARES_ECONNREFUSED /* initial error code */);
}
static int next_dns_lookup(struct host_query *hquery)
{
char *s = NULL;
int is_s_allocated = 0;
int status;
/* if next_domain == -1 and as_is_first is true, try hquery->name */
if (hquery->next_domain == -1)
{
if (as_is_first(hquery))
{
s = hquery->name;
}
hquery->next_domain = 0;
}
/* if as_is_first is false, try hquery->name at last */
if (!s && hquery->next_domain == hquery->channel->ndomains) {
if (!as_is_first(hquery))
{
s = hquery->name;
}
hquery->next_domain++;
}
if (!s && hquery->next_domain < hquery->channel->ndomains)
{
status = ares__cat_domain(
hquery->name,
hquery->channel->domains[hquery->next_domain++],
&s);
if (status == ARES_SUCCESS)
{
is_s_allocated = 1;
}
}
if (s)
{
switch (hquery->hints.ai_family)
{
case AF_INET:
hquery->remaining += 1;
ares_query(hquery->channel, s, C_IN, T_A, host_callback, hquery);
break;
case AF_INET6:
hquery->remaining += 1;
ares_query(hquery->channel, s, C_IN, T_AAAA, host_callback, hquery);
break;
case AF_UNSPEC:
hquery->remaining += 2;
ares_query(hquery->channel, s, C_IN, T_A, host_callback, hquery);
ares_query(hquery->channel, s, C_IN, T_AAAA, host_callback, hquery);
break;
default: break;
}
if (is_s_allocated)
{
ares_free(s);
}
return 1;
}
else
{
assert(!hquery->ai->nodes);
return 0;
}
}
static int as_is_first(const struct host_query* hquery)
{
char* p;
int ndots = 0;
for (p = hquery->name; *p; p++)
{
if (*p == '.')
{
ndots++;
}
}
return ndots >= hquery->channel->ndots;
}

View File

@@ -22,9 +22,7 @@
char *ares_getenv(const char *name)
{
#ifdef _WIN32_WCE
return NULL;
#endif
}
#endif

View File

@@ -211,6 +211,13 @@ static void host_callback(void *arg, int status, int timeouts,
if (host && channel->nsort)
sort6_addresses(host, channel->sortlist, channel->nsort);
}
if (status == ARES_SUCCESS && host && host->h_addr_list[0] == NULL)
{
/* The query returned something but had no A/AAAA record
(even after potentially retrying AAAA with A)
so we should treat this as an error */
status = ARES_ENODATA;
}
end_hquery(hquery, status, host);
}
else if ((status == ARES_ENODATA || status == ARES_EBADRESP ||
@@ -267,12 +274,12 @@ static int fake_hostent(const char *name, int family,
}
/* if we don't have 3 dots, it is illegal
* (although inet_addr doesn't think so).
* (although inet_pton doesn't think so).
*/
if (numdots != 3 || !valid)
result = 0;
else
result = ((in.s_addr = inet_addr(name)) == INADDR_NONE ? 0 : 1);
result = (ares_inet_pton(AF_INET, name, &in) < 1 ? 0 : 1);
if (result)
family = AF_INET;
@@ -346,10 +353,6 @@ static int file_lookup(const char *name, int family, struct hostent **host)
int status;
int error;
/* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */
if (ares__is_onion_domain(name))
return ARES_ENOTFOUND;
#ifdef WIN32
char PATH_HOSTS[MAX_PATH];
win_platform platform;
@@ -387,6 +390,11 @@ static int file_lookup(const char *name, int family, struct hostent **host)
return ARES_ENOTFOUND;
#endif
/* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */
if (ares__is_onion_domain(name))
return ARES_ENOTFOUND;
fp = fopen(PATH_HOSTS, "r");
if (!fp)
{

View File

@@ -1543,8 +1543,6 @@ static int init_by_resolv_conf(ares_channel channel)
#elif defined(ANDROID) || defined(__ANDROID__)
unsigned int i;
char propname[PROP_NAME_MAX];
char propvalue[PROP_VALUE_MAX]="";
char **dns_servers;
char *domains;
size_t num_servers;
@@ -1587,6 +1585,8 @@ static int init_by_resolv_conf(ares_channel channel)
* We'll only run this if we don't have any dns servers
* because this will get the same ones (if it works). */
if (status != ARES_EOF) {
char propname[PROP_NAME_MAX];
char propvalue[PROP_VALUE_MAX]="";
for (i = 1; i <= MAX_DNS_PROPERTIES; i++) {
snprintf(propname, sizeof(propname), "%s%u", DNS_PROP_NAME_PREFIX, i);
if (__system_property_get(propname, propvalue) < 1) {
@@ -2024,6 +2024,7 @@ static int config_lookup(ares_channel channel, const char *str,
{
char lookups[3], *l;
const char *vqualifier p;
int found;
if (altbindch == NULL)
altbindch = bindch;
@@ -2034,17 +2035,21 @@ static int config_lookup(ares_channel channel, const char *str,
*/
l = lookups;
p = str;
found = 0;
while (*p)
{
if ((*p == *bindch || *p == *altbindch || *p == *filech) && l < lookups + 2) {
if (*p == *bindch || *p == *altbindch) *l++ = 'b';
else *l++ = 'f';
found = 1;
}
while (*p && !ISSPACE(*p) && (*p != ','))
p++;
while (*p && (ISSPACE(*p) || (*p == ',')))
p++;
}
if (!found)
return ARES_ENOTINITIALIZED;
*l = '\0';
channel->lookups = ares_strdup(lookups);
return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
@@ -2418,9 +2423,9 @@ static int ip_addr(const char *ipbuf, ares_ssize_t len, struct in_addr *addr)
if (len > 15)
return -1;
addr->s_addr = inet_addr(ipbuf);
if (addr->s_addr == INADDR_NONE && strcmp(ipbuf, "255.255.255.255") != 0)
if (ares_inet_pton(AF_INET, ipbuf, addr) < 1)
return -1;
return 0;
}

View File

@@ -32,6 +32,13 @@ struct sockaddr_in6
};
#endif
typedef union
{
struct sockaddr sa;
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
} ares_sockaddr;
#ifndef HAVE_STRUCT_ADDRINFO
struct addrinfo
{

View File

@@ -1,5 +1,6 @@
/* Copyright 1998 by the Massachusetts Institute of Technology.
* Copyright (C) 2019 by Andrew Selivanov
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -50,215 +51,164 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
struct hostent **host,
struct ares_addrttl *addrttls, int *naddrttls)
{
unsigned int qdcount, ancount;
int status, i, rr_type, rr_class, rr_len, rr_ttl, naddrs;
int cname_ttl = INT_MAX; /* the TTL imposed by the CNAME chain */
int naliases;
long len;
const unsigned char *aptr;
char *hostname, *rr_name, *rr_data, **aliases;
struct in_addr *addrs;
struct hostent *hostent;
const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0;
struct ares_addrinfo ai;
struct ares_addrinfo_node *next;
struct ares_addrinfo_cname *next_cname;
char **aliases = NULL;
char *question_hostname = NULL;
struct hostent *hostent = NULL;
struct in_addr *addrs = NULL;
int naliases = 0, naddrs = 0, alias = 0, i;
int cname_ttl = INT_MAX;
int status;
/* Set *host to NULL for all failure cases. */
if (host)
*host = NULL;
/* Same with *naddrttls. */
if (naddrttls)
*naddrttls = 0;
memset(&ai, 0, sizeof(ai));
/* Give up if abuf doesn't have room for a header. */
if (alen < HFIXEDSZ)
return ARES_EBADRESP;
/* Fetch the question and answer count from the header. */
qdcount = DNS_HEADER_QDCOUNT(abuf);
ancount = DNS_HEADER_ANCOUNT(abuf);
if (qdcount != 1)
return ARES_EBADRESP;
/* Expand the name from the question, and skip past the question. */
aptr = abuf + HFIXEDSZ;
status = ares__expand_name_for_response(aptr, abuf, alen, &hostname, &len);
status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, &ai);
if (status != ARES_SUCCESS)
return status;
if (aptr + len + QFIXEDSZ > abuf + alen)
{
ares_free(hostname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
ares_free(question_hostname);
if (host)
if (naddrttls)
{
*naddrttls = 0;
}
return status;
}
hostent = ares_malloc(sizeof(struct hostent));
if (!hostent)
{
/* Allocate addresses and aliases; ancount gives an upper bound for
both. */
addrs = ares_malloc(ancount * sizeof(struct in_addr));
if (!addrs)
goto enomem;
}
next = ai.nodes;
while (next)
{
if (next->ai_family == AF_INET)
{
ares_free(hostname);
return ARES_ENOMEM;
++naddrs;
}
aliases = ares_malloc((ancount + 1) * sizeof(char *));
if (!aliases)
next = next->ai_next;
}
next_cname = ai.cnames;
while (next_cname)
{
if(next_cname->alias)
++naliases;
next_cname = next_cname->next;
}
aliases = ares_malloc((naliases + 1) * sizeof(char *));
if (!aliases)
{
goto enomem;
}
if (naliases)
{
next_cname = ai.cnames;
while (next_cname)
{
ares_free(hostname);
ares_free(addrs);
return ARES_ENOMEM;
if(next_cname->alias)
aliases[alias++] = strdup(next_cname->alias);
if(next_cname->ttl < cname_ttl)
cname_ttl = next_cname->ttl;
next_cname = next_cname->next;
}
}
aliases[alias] = NULL;
hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
if (!hostent->h_addr_list)
{
goto enomem;
}
for (i = 0; i < naddrs + 1; ++i)
{
hostent->h_addr_list[i] = NULL;
}
if (ai.cnames)
{
hostent->h_name = strdup(ai.cnames->name);
ares_free(question_hostname);
}
else
{
addrs = NULL;
aliases = NULL;
hostent->h_name = question_hostname;
}
naddrs = 0;
naliases = 0;
hostent->h_aliases = aliases;
hostent->h_addrtype = AF_INET;
hostent->h_length = sizeof(struct in_addr);
/* Examine each answer resource record (RR) in turn. */
for (i = 0; i < (int)ancount; i++)
if (naddrs)
{
/* Decode the RR up to the data field. */
status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
if (status != ARES_SUCCESS)
break;
aptr += len;
if (aptr + RRFIXEDSZ > abuf + alen)
addrs = ares_malloc(naddrs * sizeof(struct in_addr));
if (!addrs)
{
ares_free(rr_name);
status = ARES_EBADRESP;
break;
}
rr_type = DNS_RR_TYPE(aptr);
rr_class = DNS_RR_CLASS(aptr);
rr_len = DNS_RR_LEN(aptr);
rr_ttl = DNS_RR_TTL(aptr);
aptr += RRFIXEDSZ;
if (aptr + rr_len > abuf + alen)
{
ares_free(rr_name);
status = ARES_EBADRESP;
break;
goto enomem;
}
if (rr_class == C_IN && rr_type == T_A
&& rr_len == sizeof(struct in_addr)
&& strcasecmp(rr_name, hostname) == 0)
i = 0;
next = ai.nodes;
while (next)
{
if (addrs)
if (next->ai_family == AF_INET)
{
if (aptr + sizeof(struct in_addr) > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
ares_free(rr_name);
status = ARES_EBADRESP;
break;
} /* LCOV_EXCL_STOP */
memcpy(&addrs[naddrs], aptr, sizeof(struct in_addr));
}
if (naddrs < max_addr_ttls)
{
struct ares_addrttl * const at = &addrttls[naddrs];
if (aptr + sizeof(struct in_addr) > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
ares_free(rr_name);
status = ARES_EBADRESP;
break;
} /* LCOV_EXCL_STOP */
memcpy(&at->ipaddr, aptr, sizeof(struct in_addr));
at->ttl = rr_ttl;
}
naddrs++;
status = ARES_SUCCESS;
}
if (rr_class == C_IN && rr_type == T_CNAME)
{
/* Record the RR name as an alias. */
if (aliases)
aliases[naliases] = rr_name;
else
ares_free(rr_name);
naliases++;
/* Decode the RR data and replace the hostname with it. */
status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
&len);
if (status != ARES_SUCCESS)
break;
ares_free(hostname);
hostname = rr_data;
/* Take the min of the TTLs we see in the CNAME chain. */
if (cname_ttl > rr_ttl)
cname_ttl = rr_ttl;
}
else
ares_free(rr_name);
aptr += rr_len;
if (aptr > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
break;
} /* LCOV_EXCL_STOP */
}
if (status == ARES_SUCCESS && naddrs == 0 && naliases == 0)
/* the check for naliases to be zero is to make sure CNAME responses
don't get caught here */
status = ARES_ENODATA;
if (status == ARES_SUCCESS)
{
/* We got our answer. */
if (naddrttls)
{
const int n = naddrs < max_addr_ttls ? naddrs : max_addr_ttls;
for (i = 0; i < n; i++)
{
/* Ensure that each A TTL is no larger than the CNAME TTL. */
if (addrttls[i].ttl > cname_ttl)
addrttls[i].ttl = cname_ttl;
}
*naddrttls = n;
}
if (aliases)
aliases[naliases] = NULL;
if (host)
{
/* Allocate memory to build the host entry. */
hostent = ares_malloc(sizeof(struct hostent));
if (hostent)
{
hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
if (hostent->h_addr_list)
hostent->h_addr_list[i] = (char *)&addrs[i];
memcpy(hostent->h_addr_list[i],
&(((struct sockaddr_in *)next->ai_addr)->sin_addr),
sizeof(struct in_addr));
if (naddrttls && i < *naddrttls)
{
/* Fill in the hostent and return successfully. */
hostent->h_name = hostname;
hostent->h_aliases = aliases;
hostent->h_addrtype = AF_INET;
hostent->h_length = sizeof(struct in_addr);
for (i = 0; i < naddrs; i++)
hostent->h_addr_list[i] = (char *) &addrs[i];
hostent->h_addr_list[naddrs] = NULL;
if (!naddrs && addrs)
ares_free(addrs);
*host = hostent;
return ARES_SUCCESS;
if (next->ai_ttl > cname_ttl)
addrttls[i].ttl = cname_ttl;
else
addrttls[i].ttl = next->ai_ttl;
memcpy(&addrttls[i].ipaddr,
&(((struct sockaddr_in *)next->ai_addr)->sin_addr),
sizeof(struct in_addr));
}
ares_free(hostent);
++i;
}
status = ARES_ENOMEM;
next = next->ai_next;
}
if (i == 0)
{
ares_free(addrs);
}
}
if (aliases)
{
for (i = 0; i < naliases; i++)
ares_free(aliases[i]);
ares_free(aliases);
}
ares_free(addrs);
ares_free(hostname);
return status;
if (host)
{
*host = hostent;
}
else
{
ares_free_hostent(hostent);
}
if (naddrttls)
{
*naddrttls = naddrs;
}
ares__freeaddrinfo_cnames(ai.cnames);
ares__freeaddrinfo_nodes(ai.nodes);
return ARES_SUCCESS;
enomem:
ares_free(aliases);
ares_free(hostent);
ares__freeaddrinfo_cnames(ai.cnames);
ares__freeaddrinfo_nodes(ai.nodes);
ares_free(question_hostname);
return ARES_ENOMEM;
}

View File

@@ -1,6 +1,7 @@
/* Copyright 1998 by the Massachusetts Institute of Technology.
* Copyright 2005 Dominick Meglio
* Copyright (C) 2019 by Andrew Selivanov
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -52,213 +53,165 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
struct hostent **host, struct ares_addr6ttl *addrttls,
int *naddrttls)
{
unsigned int qdcount, ancount;
int status, i, rr_type, rr_class, rr_len, rr_ttl, naddrs;
int cname_ttl = INT_MAX; /* the TTL imposed by the CNAME chain */
int naliases;
long len;
const unsigned char *aptr;
char *hostname, *rr_name, *rr_data, **aliases;
struct ares_in6_addr *addrs;
struct hostent *hostent;
const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0;
struct ares_addrinfo ai;
struct ares_addrinfo_node *next;
struct ares_addrinfo_cname *next_cname;
char **aliases = NULL;
char *question_hostname = NULL;
struct hostent *hostent = NULL;
struct ares_in6_addr *addrs = NULL;
int naliases = 0, naddrs = 0, alias = 0, i;
int cname_ttl = INT_MAX;
int status;
/* Set *host to NULL for all failure cases. */
if (host)
*host = NULL;
/* Same with *naddrttls. */
if (naddrttls)
*naddrttls = 0;
memset(&ai, 0, sizeof(ai));
/* Give up if abuf doesn't have room for a header. */
if (alen < HFIXEDSZ)
return ARES_EBADRESP;
/* Fetch the question and answer count from the header. */
qdcount = DNS_HEADER_QDCOUNT(abuf);
ancount = DNS_HEADER_ANCOUNT(abuf);
if (qdcount != 1)
return ARES_EBADRESP;
/* Expand the name from the question, and skip past the question. */
aptr = abuf + HFIXEDSZ;
status = ares__expand_name_for_response(aptr, abuf, alen, &hostname, &len);
status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, &ai);
if (status != ARES_SUCCESS)
return status;
if (aptr + len + QFIXEDSZ > abuf + alen)
{
ares_free(hostname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
ares_free(question_hostname);
/* Allocate addresses and aliases; ancount gives an upper bound for both. */
if (host)
if (naddrttls)
{
*naddrttls = 0;
}
return status;
}
hostent = ares_malloc(sizeof(struct hostent));
if (!hostent)
{
addrs = ares_malloc(ancount * sizeof(struct ares_in6_addr));
if (!addrs)
goto enomem;
}
next = ai.nodes;
while (next)
{
if(next->ai_family == AF_INET6)
{
ares_free(hostname);
return ARES_ENOMEM;
++naddrs;
}
aliases = ares_malloc((ancount + 1) * sizeof(char *));
if (!aliases)
next = next->ai_next;
}
next_cname = ai.cnames;
while (next_cname)
{
if(next_cname->alias)
++naliases;
next_cname = next_cname->next;
}
aliases = ares_malloc((naliases + 1) * sizeof(char *));
if (!aliases)
{
goto enomem;
}
if (naliases)
{
next_cname = ai.cnames;
while (next_cname)
{
ares_free(hostname);
ares_free(addrs);
return ARES_ENOMEM;
if(next_cname->alias)
aliases[alias++] = strdup(next_cname->alias);
if(next_cname->ttl < cname_ttl)
cname_ttl = next_cname->ttl;
next_cname = next_cname->next;
}
}
aliases[alias] = NULL;
hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
if (!hostent->h_addr_list)
{
goto enomem;
}
for (i = 0; i < naddrs + 1; ++i)
{
hostent->h_addr_list[i] = NULL;
}
if (ai.cnames)
{
hostent->h_name = strdup(ai.cnames->name);
ares_free(question_hostname);
}
else
{
addrs = NULL;
aliases = NULL;
}
naddrs = 0;
naliases = 0;
/* Examine each answer resource record (RR) in turn. */
for (i = 0; i < (int)ancount; i++)
{
/* Decode the RR up to the data field. */
status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
if (status != ARES_SUCCESS)
break;
aptr += len;
if (aptr + RRFIXEDSZ > abuf + alen)
{
ares_free(rr_name);
status = ARES_EBADRESP;
break;
}
rr_type = DNS_RR_TYPE(aptr);
rr_class = DNS_RR_CLASS(aptr);
rr_len = DNS_RR_LEN(aptr);
rr_ttl = DNS_RR_TTL(aptr);
aptr += RRFIXEDSZ;
if (aptr + rr_len > abuf + alen)
{
ares_free(rr_name);
status = ARES_EBADRESP;
break;
}
if (rr_class == C_IN && rr_type == T_AAAA
&& rr_len == sizeof(struct ares_in6_addr)
&& strcasecmp(rr_name, hostname) == 0)
{
if (addrs)
{
if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
ares_free(rr_name);
status = ARES_EBADRESP;
break;
} /* LCOV_EXCL_STOP */
memcpy(&addrs[naddrs], aptr, sizeof(struct ares_in6_addr));
}
if (naddrs < max_addr_ttls)
{
struct ares_addr6ttl * const at = &addrttls[naddrs];
if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
ares_free(rr_name);
status = ARES_EBADRESP;
break;
} /* LCOV_EXCL_STOP */
memcpy(&at->ip6addr, aptr, sizeof(struct ares_in6_addr));
at->ttl = rr_ttl;
}
naddrs++;
status = ARES_SUCCESS;
}
if (rr_class == C_IN && rr_type == T_CNAME)
{
/* Record the RR name as an alias. */
if (aliases)
aliases[naliases] = rr_name;
else
ares_free(rr_name);
naliases++;
/* Decode the RR data and replace the hostname with it. */
status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
&len);
if (status != ARES_SUCCESS)
break;
ares_free(hostname);
hostname = rr_data;
/* Take the min of the TTLs we see in the CNAME chain. */
if (cname_ttl > rr_ttl)
cname_ttl = rr_ttl;
}
else
ares_free(rr_name);
aptr += rr_len;
if (aptr > abuf + alen)
{ /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
break;
} /* LCOV_EXCL_STOP */
hostent->h_name = question_hostname;
}
/* the check for naliases to be zero is to make sure CNAME responses
don't get caught here */
if (status == ARES_SUCCESS && naddrs == 0 && naliases == 0)
status = ARES_ENODATA;
if (status == ARES_SUCCESS)
hostent->h_aliases = aliases;
hostent->h_addrtype = AF_INET6;
hostent->h_length = sizeof(struct ares_in6_addr);
if (naddrs)
{
/* We got our answer. */
if (naddrttls)
addrs = ares_malloc(naddrs * sizeof(struct ares_in6_addr));
if (!addrs)
{
const int n = naddrs < max_addr_ttls ? naddrs : max_addr_ttls;
for (i = 0; i < n; i++)
{
/* Ensure that each A TTL is no larger than the CNAME TTL. */
if (addrttls[i].ttl > cname_ttl)
addrttls[i].ttl = cname_ttl;
}
*naddrttls = n;
goto enomem;
}
if (aliases)
aliases[naliases] = NULL;
if (host)
i = 0;
next = ai.nodes;
while (next)
{
/* Allocate memory to build the host entry. */
hostent = ares_malloc(sizeof(struct hostent));
if (hostent)
if(next->ai_family == AF_INET6)
{
hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
if (hostent->h_addr_list)
hostent->h_addr_list[i] = (char*)&addrs[i];
memcpy(hostent->h_addr_list[i],
&(((struct sockaddr_in6 *)next->ai_addr)->sin6_addr),
sizeof(struct ares_in6_addr));
if (naddrttls && i < *naddrttls)
{
/* Fill in the hostent and return successfully. */
hostent->h_name = hostname;
hostent->h_aliases = aliases;
hostent->h_addrtype = AF_INET6;
hostent->h_length = sizeof(struct ares_in6_addr);
for (i = 0; i < naddrs; i++)
hostent->h_addr_list[i] = (char *) &addrs[i];
hostent->h_addr_list[naddrs] = NULL;
if (!naddrs && addrs)
ares_free(addrs);
*host = hostent;
return ARES_SUCCESS;
if(next->ai_ttl > cname_ttl)
addrttls[i].ttl = cname_ttl;
else
addrttls[i].ttl = next->ai_ttl;
memcpy(&addrttls[i].ip6addr,
&(((struct sockaddr_in6 *)next->ai_addr)->sin6_addr),
sizeof(struct ares_in6_addr));
}
ares_free(hostent);
++i;
}
status = ARES_ENOMEM;
next = next->ai_next;
}
if (i == 0)
{
ares_free(addrs);
}
}
if (aliases)
if (host)
{
for (i = 0; i < naliases; i++)
ares_free(aliases[i]);
ares_free(aliases);
*host = hostent;
}
ares_free(addrs);
ares_free(hostname);
return status;
else
{
ares_free_hostent(hostent);
}
if (naddrttls)
{
*naddrttls = naddrs;
}
ares__freeaddrinfo_cnames(ai.cnames);
ares__freeaddrinfo_nodes(ai.nodes);
return ARES_SUCCESS;
enomem:
ares_free(aliases);
ares_free(hostent);
ares__freeaddrinfo_cnames(ai.cnames);
ares__freeaddrinfo_nodes(ai.nodes);
ares_free(question_hostname);
return ARES_ENOMEM;
}

View File

@@ -48,8 +48,8 @@ ares_parse_soa_reply(const unsigned char *abuf, int alen,
long len;
char *qname = NULL, *rr_name = NULL;
struct ares_soa_reply *soa = NULL;
int qdcount, ancount;
int status;
int qdcount, ancount, qclass;
int status, i, rr_type, rr_class, rr_len;
if (alen < HFIXEDSZ)
return ARES_EBADRESP;
@@ -57,8 +57,12 @@ ares_parse_soa_reply(const unsigned char *abuf, int alen,
/* parse message header */
qdcount = DNS_HEADER_QDCOUNT(abuf);
ancount = DNS_HEADER_ANCOUNT(abuf);
if (qdcount != 1 || ancount != 1)
if (qdcount != 1)
return ARES_EBADRESP;
if (ancount == 0)
return ARES_EBADRESP;
aptr = abuf + HFIXEDSZ;
/* query name */
@@ -67,67 +71,112 @@ ares_parse_soa_reply(const unsigned char *abuf, int alen,
goto failed_stat;
aptr += len;
qclass = DNS_QUESTION_TYPE(aptr);
/* skip qtype & qclass */
if (aptr + QFIXEDSZ > abuf + alen)
goto failed;
aptr += QFIXEDSZ;
/* rr_name */
status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
if (status != ARES_SUCCESS)
goto failed_stat;
aptr += len;
/* skip rr_type, rr_class, rr_ttl, rr_rdlen */
if (aptr + RRFIXEDSZ > abuf + alen)
/* qclass of SOA with multiple answers */
if (qclass == T_SOA && ancount > 1)
goto failed;
aptr += RRFIXEDSZ;
/* allocate result struct */
soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY);
if (!soa)
/* examine all the records, break and return if found soa */
for (i = 0; i < ancount; i++)
{
rr_name = NULL;
status = ares__expand_name_for_response (aptr, abuf, alen, &rr_name, &len);
if (status != ARES_SUCCESS)
{
ares_free(rr_name);
goto failed_stat;
}
aptr += len;
if ( aptr + RRFIXEDSZ > abuf + alen )
{
status = ARES_ENOMEM;
ares_free(rr_name);
status = ARES_EBADRESP;
goto failed_stat;
}
rr_type = DNS_RR_TYPE( aptr );
rr_class = DNS_RR_CLASS( aptr );
rr_len = DNS_RR_LEN( aptr );
aptr += RRFIXEDSZ;
if (aptr + rr_len > abuf + alen)
{
ares_free(rr_name);
status = ARES_EBADRESP;
goto failed_stat;
}
if ( rr_class == C_IN && rr_type == T_SOA )
{
/* allocate result struct */
soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY);
if (!soa)
{
ares_free(rr_name);
status = ARES_ENOMEM;
goto failed_stat;
}
/* nsname */
status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname, &len);
if (status != ARES_SUCCESS)
goto failed_stat;
aptr += len;
/* nsname */
status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname,
&len);
if (status != ARES_SUCCESS)
{
ares_free(rr_name);
goto failed_stat;
}
aptr += len;
/* hostmaster */
status = ares__expand_name_for_response(aptr, abuf, alen, &soa->hostmaster, &len);
if (status != ARES_SUCCESS)
goto failed_stat;
aptr += len;
/* hostmaster */
status = ares__expand_name_for_response(aptr, abuf, alen,
&soa->hostmaster, &len);
if (status != ARES_SUCCESS)
{
ares_free(rr_name);
goto failed_stat;
}
aptr += len;
/* integer fields */
if (aptr + 5 * 4 > abuf + alen)
goto failed;
soa->serial = DNS__32BIT(aptr + 0 * 4);
soa->refresh = DNS__32BIT(aptr + 1 * 4);
soa->retry = DNS__32BIT(aptr + 2 * 4);
soa->expire = DNS__32BIT(aptr + 3 * 4);
soa->minttl = DNS__32BIT(aptr + 4 * 4);
/* integer fields */
if (aptr + 5 * 4 > abuf + alen)
{
ares_free(rr_name);
goto failed;
}
soa->serial = DNS__32BIT(aptr + 0 * 4);
soa->refresh = DNS__32BIT(aptr + 1 * 4);
soa->retry = DNS__32BIT(aptr + 2 * 4);
soa->expire = DNS__32BIT(aptr + 3 * 4);
soa->minttl = DNS__32BIT(aptr + 4 * 4);
ares_free(qname);
ares_free(rr_name);
ares_free(qname);
ares_free(rr_name);
*soa_out = soa;
*soa_out = soa;
return ARES_SUCCESS;
return ARES_SUCCESS;
}
aptr += rr_len;
ares_free(rr_name);
if (aptr > abuf + alen)
goto failed_stat;
}
/* no SOA record found */
status = ARES_EBADRESP;
goto failed_stat;
failed:
status = ARES_EBADRESP;
failed_stat:
ares_free_data(soa);
if (soa)
ares_free_data(soa);
if (qname)
ares_free(qname);
if (rr_name)
ares_free(rr_name);
return status;
}

View File

@@ -355,11 +355,51 @@ int ares__expand_name_for_response(const unsigned char *encoded,
char **s, long *enclen);
void ares__init_servers_state(ares_channel channel);
void ares__destroy_servers_state(ares_channel channel);
int ares__parse_qtype_reply(const unsigned char* abuf, int alen, int* qtype);
int ares__single_domain(ares_channel channel, const char *name, char **s);
int ares__cat_domain(const char *name, const char *domain, char **s);
int ares__sortaddrinfo(ares_channel channel, struct ares_addrinfo_node *ai_node);
int ares__readaddrinfo(FILE *fp, const char *name, unsigned short port,
const struct ares_addrinfo_hints *hints,
struct ares_addrinfo *ai);
struct ares_addrinfo *ares__malloc_addrinfo(void);
struct ares_addrinfo_node *ares__malloc_addrinfo_node(void);
void ares__freeaddrinfo_nodes(struct ares_addrinfo_node *ai_node);
struct ares_addrinfo_node *ares__append_addrinfo_node(struct ares_addrinfo_node **ai_node);
void ares__addrinfo_cat_nodes(struct ares_addrinfo_node **head,
struct ares_addrinfo_node *tail);
struct ares_addrinfo_cname *ares__malloc_addrinfo_cname(void);
void ares__freeaddrinfo_cnames(struct ares_addrinfo_cname *ai_cname);
struct ares_addrinfo_cname *ares__append_addrinfo_cname(struct ares_addrinfo_cname **ai_cname);
void ares__addrinfo_cat_cnames(struct ares_addrinfo_cname **head,
struct ares_addrinfo_cname *tail);
int ares__parse_into_addrinfo(const unsigned char *abuf,
int alen,
struct ares_addrinfo *ai);
int ares__parse_into_addrinfo2(const unsigned char *abuf,
int alen,
char **question_hostname,
struct ares_addrinfo *ai);
#if 0 /* Not used */
long ares__tvdiff(struct timeval t1, struct timeval t2);
#endif
void ares__socket_close(ares_channel, ares_socket_t);
ares_socket_t ares__open_socket(ares_channel channel,
int af, int type, int protocol);
void ares__close_socket(ares_channel, ares_socket_t);
int ares__connect_socket(ares_channel channel,
ares_socket_t sockfd,
const struct sockaddr *addr,
ares_socklen_t addrlen);
#define ARES_SWAP_BYTE(a,b) \
{ unsigned char swapByte = *(a); *(a) = *(b); *(b) = swapByte; }

View File

@@ -1039,30 +1039,6 @@ static int configure_socket(ares_socket_t s, int family, ares_channel channel)
return 0;
}
static ares_socket_t open_socket(ares_channel channel, int af, int type, int protocol)
{
if (channel->sock_funcs != 0)
return channel->sock_funcs->asocket(af,
type,
protocol,
channel->sock_func_cb_data);
return socket(af, type, protocol);
}
static int connect_socket(ares_channel channel, ares_socket_t sockfd,
const struct sockaddr * addr,
ares_socklen_t addrlen)
{
if (channel->sock_funcs != 0)
return channel->sock_funcs->aconnect(sockfd,
addr,
addrlen,
channel->sock_func_cb_data);
return connect(sockfd, addr, addrlen);
}
static int open_tcp_socket(ares_channel channel, struct server_state *server)
{
ares_socket_t s;
@@ -1107,14 +1083,14 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
}
/* Acquire a socket. */
s = open_socket(channel, server->addr.family, SOCK_STREAM, 0);
s = ares__open_socket(channel, server->addr.family, SOCK_STREAM, 0);
if (s == ARES_SOCKET_BAD)
return -1;
/* Configure it. */
if (configure_socket(s, server->addr.family, channel) < 0)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return -1;
}
@@ -1131,7 +1107,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
(void *)&opt, sizeof(opt)) == -1)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return -1;
}
#endif
@@ -1142,19 +1118,19 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
channel->sock_config_cb_data);
if (err < 0)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return err;
}
}
/* Connect to the server. */
if (connect_socket(channel, s, sa, salen) == -1)
if (ares__connect_socket(channel, s, sa, salen) == -1)
{
int err = SOCKERRNO;
if (err != EINPROGRESS && err != EWOULDBLOCK)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return -1;
}
}
@@ -1165,7 +1141,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
channel->sock_create_cb_data);
if (err < 0)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return err;
}
}
@@ -1220,14 +1196,14 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
}
/* Acquire a socket. */
s = open_socket(channel, server->addr.family, SOCK_DGRAM, 0);
s = ares__open_socket(channel, server->addr.family, SOCK_DGRAM, 0);
if (s == ARES_SOCKET_BAD)
return -1;
/* Set the socket non-blocking. */
if (configure_socket(s, server->addr.family, channel) < 0)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return -1;
}
@@ -1237,19 +1213,19 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
channel->sock_config_cb_data);
if (err < 0)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return err;
}
}
/* Connect to the server. */
if (connect_socket(channel, s, sa, salen) == -1)
if (ares__connect_socket(channel, s, sa, salen) == -1)
{
int err = SOCKERRNO;
if (err != EINPROGRESS && err != EWOULDBLOCK)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return -1;
}
}
@@ -1260,7 +1236,7 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
channel->sock_create_cb_data);
if (err < 0)
{
ares__socket_close(channel, s);
ares__close_socket(channel, s);
return err;
}
}
@@ -1464,7 +1440,33 @@ void ares__free_query(struct query *query)
ares_free(query);
}
void ares__socket_close(ares_channel channel, ares_socket_t s)
ares_socket_t ares__open_socket(ares_channel channel,
int af, int type, int protocol)
{
if (channel->sock_funcs)
return channel->sock_funcs->asocket(af,
type,
protocol,
channel->sock_func_cb_data);
else
return socket(af, type, protocol);
}
int ares__connect_socket(ares_channel channel,
ares_socket_t sockfd,
const struct sockaddr *addr,
ares_socklen_t addrlen)
{
if (channel->sock_funcs)
return channel->sock_funcs->aconnect(sockfd,
addr,
addrlen,
channel->sock_func_cb_data);
else
return connect(sockfd, addr, addrlen);
}
void ares__close_socket(ares_channel channel, ares_socket_t s)
{
if (channel->sock_funcs)
channel->sock_funcs->aclose(s, channel->sock_func_cb_data);

View File

@@ -43,8 +43,6 @@ static void search_callback(void *arg, int status, int timeouts,
unsigned char *abuf, int alen);
static void end_squery(struct search_query *squery, int status,
unsigned char *abuf, int alen);
static int cat_domain(const char *name, const char *domain, char **s);
STATIC_TESTABLE int single_domain(ares_channel channel, const char *name, char **s);
void ares_search(ares_channel channel, const char *name, int dnsclass,
int type, ares_callback callback, void *arg)
@@ -64,7 +62,7 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
/* If name only yields one domain to search, then we don't have
* to keep extra state, so just do an ares_query().
*/
status = single_domain(channel, name, &s);
status = ares__single_domain(channel, name, &s);
if (status != ARES_SUCCESS)
{
callback(arg, status, 0, NULL, 0);
@@ -126,7 +124,7 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
/* Try the name as-is last; start with the first search domain. */
squery->next_domain = 1;
squery->trying_as_is = 0;
status = cat_domain(name, channel->domains[0], &s);
status = ares__cat_domain(name, channel->domains[0], &s);
if (status == ARES_SUCCESS)
{
ares_query(channel, s, dnsclass, type, search_callback, squery);
@@ -174,7 +172,7 @@ static void search_callback(void *arg, int status, int timeouts,
if (squery->next_domain < channel->ndomains)
{
/* Try the next domain. */
status = cat_domain(squery->name,
status = ares__cat_domain(squery->name,
channel->domains[squery->next_domain], &s);
if (status != ARES_SUCCESS)
end_squery(squery, status, NULL, 0);
@@ -213,7 +211,7 @@ static void end_squery(struct search_query *squery, int status,
}
/* Concatenate two domains. */
static int cat_domain(const char *name, const char *domain, char **s)
int ares__cat_domain(const char *name, const char *domain, char **s)
{
size_t nlen = strlen(name);
size_t dlen = strlen(domain);
@@ -232,7 +230,7 @@ static int cat_domain(const char *name, const char *domain, char **s)
* the string we should query, in an allocated buffer. If not, set *s
* to NULL.
*/
STATIC_TESTABLE int single_domain(ares_channel channel, const char *name, char **s)
int ares__single_domain(ares_channel channel, const char *name, char **s)
{
size_t len = strlen(name);
const char *hostaliases;