diff --git a/deps/cares/cares.gyp b/deps/cares/cares.gyp index 0b5cd02c21dde1..02b2774c02683e 100644 --- a/deps/cares/cares.gyp +++ b/deps/cares/cares.gyp @@ -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', diff --git a/deps/cares/include/ares.h b/deps/cares/include/ares.h index 06f60b33304b80..91dc754dfb6a18 100644 --- a/deps/cares/include/ares.h +++ b/deps/cares/include/ares.h @@ -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. diff --git a/deps/cares/include/ares_version.h b/deps/cares/include/ares_version.h index 3fe5b00a1171c2..7758a48148a804 100644 --- a/deps/cares/include/ares_version.h +++ b/deps/cares/include/ares_version.h @@ -3,15 +3,15 @@ #define ARES__VERSION_H /* This is the global package copyright */ -#define ARES_COPYRIGHT "2004 - 2018 Daniel Stenberg, ." +#define ARES_COPYRIGHT "2004 - 2020 Daniel Stenberg, ." #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 diff --git a/deps/cares/src/README.md b/deps/cares/src/README.md index 93c1f5f812de4c..148338f9e18081 100644 --- a/deps/cares/src/README.md +++ b/deps/cares/src/README.md @@ -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 diff --git a/deps/cares/src/RELEASE-NOTES b/deps/cares/src/RELEASE-NOTES index 62276fdf4e38c6..0d8573ae8dd933 100644 --- a/deps/cares/src/RELEASE-NOTES +++ b/deps/cares/src/RELEASE-NOTES @@ -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 diff --git a/deps/cares/src/ares__close_sockets.c b/deps/cares/src/ares__close_sockets.c index f07904e8735bcd..0477174e3e1187 100644 --- a/deps/cares/src/ares__close_sockets.c +++ b/deps/cares/src/ares__close_sockets.c @@ -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; } } diff --git a/deps/cares/src/ares__get_hostent.c b/deps/cares/src/ares__get_hostent.c index d2f95034934708..367f39037b168c 100644 --- a/deps/cares/src/ares__get_hostent.c +++ b/deps/cares/src/ares__get_hostent.c @@ -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; diff --git a/deps/cares/src/ares__parse_into_addrinfo.c b/deps/cares/src/ares__parse_into_addrinfo.c new file mode 100644 index 00000000000000..b0801632b4008f --- /dev/null +++ b/deps/cares/src/ares__parse_into_addrinfo.c @@ -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 +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_STRINGS_H +# include +#endif + +#ifdef HAVE_LIMITS_H +# include +#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; +} diff --git a/deps/cares/src/ares__readaddrinfo.c b/deps/cares/src/ares__readaddrinfo.c new file mode 100644 index 00000000000000..dd3abe2e9f8778 --- /dev/null +++ b/deps/cares/src/ares__readaddrinfo.c @@ -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 +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#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; +} diff --git a/deps/cares/src/ares__sortaddrinfo.c b/deps/cares/src/ares__sortaddrinfo.c new file mode 100644 index 00000000000000..7a90270a2a6b92 --- /dev/null +++ b/deps/cares/src/ares__sortaddrinfo.c @@ -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 +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#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 . */ +/* 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; +} \ No newline at end of file diff --git a/deps/cares/src/ares_android.c b/deps/cares/src/ares_android.c index bf77131b58cf84..5b00b8065c56b9 100644 --- a/deps/cares/src/ares_android.c +++ b/deps/cares/src/ares_android.c @@ -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; diff --git a/deps/cares/src/ares_freeaddrinfo.c b/deps/cares/src/ares_freeaddrinfo.c new file mode 100644 index 00000000000000..128f5daec4d39f --- /dev/null +++ b/deps/cares/src/ares_freeaddrinfo.c @@ -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 +#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); +} diff --git a/deps/cares/src/ares_getaddrinfo.c b/deps/cares/src/ares_getaddrinfo.c new file mode 100644 index 00000000000000..8265e4afc20f60 --- /dev/null +++ b/deps/cares/src/ares_getaddrinfo.c @@ -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 +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif +#include + +#ifdef HAVE_LIMITS_H +#include +#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; +} diff --git a/deps/cares/src/ares_getenv.c b/deps/cares/src/ares_getenv.c index 1b2e85d2bee9c5..f6e4dc29526218 100644 --- a/deps/cares/src/ares_getenv.c +++ b/deps/cares/src/ares_getenv.c @@ -22,9 +22,7 @@ char *ares_getenv(const char *name) { -#ifdef _WIN32_WCE return NULL; -#endif } #endif diff --git a/deps/cares/src/ares_gethostbyname.c b/deps/cares/src/ares_gethostbyname.c index 8187746bb14c7f..ecd03e79310c63 100644 --- a/deps/cares/src/ares_gethostbyname.c +++ b/deps/cares/src/ares_gethostbyname.c @@ -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) { diff --git a/deps/cares/src/ares_init.c b/deps/cares/src/ares_init.c index c2c00d65237072..dffa518171b29c 100644 --- a/deps/cares/src/ares_init.c +++ b/deps/cares/src/ares_init.c @@ -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; } diff --git a/deps/cares/src/ares_ipv6.h b/deps/cares/src/ares_ipv6.h index b0017f16c79d20..fdbc21fe8f9fa5 100644 --- a/deps/cares/src/ares_ipv6.h +++ b/deps/cares/src/ares_ipv6.h @@ -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 { diff --git a/deps/cares/src/ares_parse_a_reply.c b/deps/cares/src/ares_parse_a_reply.c index 0422bd3828a765..920ba24af42129 100644 --- a/deps/cares/src/ares_parse_a_reply.c +++ b/deps/cares/src/ares_parse_a_reply.c @@ -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; - - /* Set *host to NULL for all failure cases. */ - if (host) - *host = NULL; - /* Same with *naddrttls. */ - if (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; + + memset(&ai, 0, sizeof(ai)); + + status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, &ai); + if (status != ARES_SUCCESS) + { + ares_free(question_hostname); - /* Give up if abuf doesn't have room for a header. */ - if (alen < HFIXEDSZ) - return ARES_EBADRESP; + if (naddrttls) + { + *naddrttls = 0; + } - /* 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; + return status; + } - /* 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); - if (status != ARES_SUCCESS) - return status; - if (aptr + len + QFIXEDSZ > abuf + alen) + hostent = ares_malloc(sizeof(struct hostent)); + if (!hostent) { - ares_free(hostname); - return ARES_EBADRESP; + goto enomem; } - aptr += len + QFIXEDSZ; - if (host) + next = ai.nodes; + while (next) { - /* Allocate addresses and aliases; ancount gives an upper bound for - both. */ - addrs = ares_malloc(ancount * sizeof(struct in_addr)); - if (!addrs) + if (next->ai_family == AF_INET) { - ares_free(hostname); - return ARES_ENOMEM; - } - aliases = ares_malloc((ancount + 1) * sizeof(char *)); - if (!aliases) - { - ares_free(hostname); - ares_free(addrs); - return ARES_ENOMEM; + ++naddrs; } + next = next->ai_next; } - else + + next_cname = ai.cnames; + while (next_cname) { - addrs = NULL; - aliases = NULL; + if(next_cname->alias) + ++naliases; + next_cname = next_cname->next; } - naddrs = 0; - naliases = 0; - - /* Examine each answer resource record (RR) in turn. */ - for (i = 0; i < (int)ancount; i++) + aliases = ares_malloc((naliases + 1) * sizeof(char *)); + if (!aliases) { - /* 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; - } + goto enomem; + } - if (rr_class == C_IN && rr_type == T_A - && rr_len == sizeof(struct in_addr) - && strcasecmp(rr_name, hostname) == 0) + if (naliases) + { + next_cname = ai.cnames; + while (next_cname) { - if (addrs) - { - 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(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; } + } - 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++; + aliases[alias] = NULL; - /* 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; + hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *)); + if (!hostent->h_addr_list) + { + goto enomem; + } - /* 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); + for (i = 0; i < naddrs + 1; ++i) + { + hostent->h_addr_list[i] = NULL; + } - aptr += rr_len; - if (aptr > abuf + alen) - { /* LCOV_EXCL_START: already checked above */ - status = ARES_EBADRESP; - break; - } /* LCOV_EXCL_STOP */ + if (ai.cnames) + { + hostent->h_name = strdup(ai.cnames->name); + ares_free(question_hostname); } + else + { + hostent->h_name = question_hostname; + } + + hostent->h_aliases = aliases; + hostent->h_addrtype = AF_INET; + hostent->h_length = sizeof(struct in_addr); - 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) + if (naddrs) { - /* We got our answer. */ - if (naddrttls) + addrs = ares_malloc(naddrs * sizeof(struct in_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_INET) { - 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 (aliases) + if (i == 0) + { + ares_free(addrs); + } + } + + if (host) + { + *host = hostent; + } + else { - for (i = 0; i < naliases; i++) - ares_free(aliases[i]); - ares_free(aliases); + ares_free_hostent(hostent); } - ares_free(addrs); - ares_free(hostname); - return status; + + 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; } diff --git a/deps/cares/src/ares_parse_aaaa_reply.c b/deps/cares/src/ares_parse_aaaa_reply.c index 5b38bb571e1d65..d39e138d4c3304 100644 --- a/deps/cares/src/ares_parse_aaaa_reply.c +++ b/deps/cares/src/ares_parse_aaaa_reply.c @@ -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; - - /* Set *host to NULL for all failure cases. */ - if (host) - *host = NULL; - /* Same with *naddrttls. */ - if (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; + + memset(&ai, 0, sizeof(ai)); + + status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, &ai); + if (status != ARES_SUCCESS) + { + ares_free(question_hostname); - /* Give up if abuf doesn't have room for a header. */ - if (alen < HFIXEDSZ) - return ARES_EBADRESP; + if (naddrttls) + { + *naddrttls = 0; + } - /* 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; + return status; + } - /* 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); - if (status != ARES_SUCCESS) - return status; - if (aptr + len + QFIXEDSZ > abuf + alen) + hostent = ares_malloc(sizeof(struct hostent)); + if (!hostent) { - ares_free(hostname); - return ARES_EBADRESP; + goto enomem; } - aptr += len + QFIXEDSZ; - /* Allocate addresses and aliases; ancount gives an upper bound for both. */ - if (host) + next = ai.nodes; + while (next) { - addrs = ares_malloc(ancount * sizeof(struct ares_in6_addr)); - if (!addrs) + if(next->ai_family == AF_INET6) { - ares_free(hostname); - return ARES_ENOMEM; - } - aliases = ares_malloc((ancount + 1) * sizeof(char *)); - if (!aliases) - { - ares_free(hostname); - ares_free(addrs); - return ARES_ENOMEM; + ++naddrs; } + next = next->ai_next; } - else + + next_cname = ai.cnames; + while (next_cname) { - addrs = NULL; - aliases = NULL; + if(next_cname->alias) + ++naliases; + next_cname = next_cname->next; } - naddrs = 0; - naliases = 0; - /* Examine each answer resource record (RR) in turn. */ - for (i = 0; i < (int)ancount; i++) + aliases = ares_malloc((naliases + 1) * sizeof(char *)); + if (!aliases) { - /* 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; - } + goto enomem; + } - if (rr_class == C_IN && rr_type == T_AAAA - && rr_len == sizeof(struct ares_in6_addr) - && strcasecmp(rr_name, hostname) == 0) + if (naliases) + { + next_cname = ai.cnames; + while (next_cname) { - 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(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; } + } - 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++; + aliases[alias] = NULL; - /* 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; + hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *)); + if (!hostent->h_addr_list) + { + goto enomem; + } - /* 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); + for (i = 0; i < naddrs + 1; ++i) + { + hostent->h_addr_list[i] = NULL; + } - aptr += rr_len; - if (aptr > abuf + alen) - { /* LCOV_EXCL_START: already checked above */ - status = ARES_EBADRESP; - break; - } /* LCOV_EXCL_STOP */ + if (ai.cnames) + { + hostent->h_name = strdup(ai.cnames->name); + ares_free(question_hostname); } + else + { + hostent->h_name = question_hostname; + } + + hostent->h_aliases = aliases; + hostent->h_addrtype = AF_INET6; + hostent->h_length = sizeof(struct ares_in6_addr); - /* 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) + 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 (host) + { + *host = hostent; } - if (aliases) + else { - for (i = 0; i < naliases; i++) - ares_free(aliases[i]); - ares_free(aliases); + ares_free_hostent(hostent); } - ares_free(addrs); - ares_free(hostname); - return status; + + 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; } diff --git a/deps/cares/src/ares_parse_soa_reply.c b/deps/cares/src/ares_parse_soa_reply.c index 35af0a75c00451..d72eeb94148e27 100644 --- a/deps/cares/src/ares_parse_soa_reply.c +++ b/deps/cares/src/ares_parse_soa_reply.c @@ -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) + { + 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) + { + ares_free(rr_name); + goto failed_stat; + } + aptr += len; + + /* 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); + + *soa_out = soa; + + return ARES_SUCCESS; + } + aptr += rr_len; - /* nsname */ - status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname, &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) - 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); - - ares_free(qname); - ares_free(rr_name); - - *soa_out = soa; - - return ARES_SUCCESS; + 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; } - diff --git a/deps/cares/src/ares_private.h b/deps/cares/src/ares_private.h index 1990f6902fc75e..2ee54e5ecd8e21 100644 --- a/deps/cares/src/ares_private.h +++ b/deps/cares/src/ares_private.h @@ -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; } diff --git a/deps/cares/src/ares_process.c b/deps/cares/src/ares_process.c index df9f290bb133a6..c86d3f2026b20b 100644 --- a/deps/cares/src/ares_process.c +++ b/deps/cares/src/ares_process.c @@ -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); diff --git a/deps/cares/src/ares_search.c b/deps/cares/src/ares_search.c index 001c3482a7dd5d..c4b0424f5bab75 100644 --- a/deps/cares/src/ares_search.c +++ b/deps/cares/src/ares_search.c @@ -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;