aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErwin Jansen <jansene@google.com>2019-04-04 11:24:54 -0700
committerErwin Jansen <jansene@google.com>2019-04-05 14:28:33 -0700
commit42ca08a52a1b458cac8cbc6d097c1ae17299ccad (patch)
tree65d700375fe7d71f9a1ddfc496c8b264f5c3dbe6
parent24e124e42be81e5a2e3438cb4f6fa946bc8f8d99 (diff)
downloadc-ares-42ca08a52a1b458cac8cbc6d097c1ae17299ccad.tar.gz
Merge c-ares 1.13.0.
Version od grpc we are building (1.16.0) needs this version of c-ares.
-rw-r--r--CMakeLists.txt100
-rw-r--r--acountry.c31
-rw-r--r--adig.c40
-rw-r--r--ahost.c38
-rw-r--r--ares.h142
-rw-r--r--ares__close_sockets.c15
-rw-r--r--ares__get_hostent.c42
-rw-r--r--ares__read_line.c14
-rw-r--r--ares__timeval.c2
-rw-r--r--ares_android.c446
-rw-r--r--ares_android.h27
-rw-r--r--ares_build.h91
-rw-r--r--ares_cancel.c42
-rw-r--r--ares_create_query.c202
-rw-r--r--ares_data.c107
-rw-r--r--ares_data.h19
-rw-r--r--ares_destroy.c29
-rw-r--r--ares_dns.h35
-rw-r--r--ares_expand_name.c43
-rw-r--r--ares_expand_string.c9
-rw-r--r--ares_fds.c4
-rw-r--r--ares_free_hostent.c13
-rw-r--r--ares_free_string.c4
-rw-r--r--ares_gethostbyaddr.c13
-rw-r--r--ares_gethostbyname.c45
-rw-r--r--ares_getnameinfo.c91
-rw-r--r--ares_getsock.c12
-rw-r--r--ares_inet_net_pton.h25
-rw-r--r--ares_init.c1648
-rw-r--r--ares_ipv6.h8
-rw-r--r--ares_library_init.c47
-rw-r--r--ares_library_init.h3
-rw-r--r--ares_llist.c23
-rw-r--r--ares_llist.h3
-rw-r--r--ares_mkquery.c169
-rw-r--r--ares_nowarn.c124
-rw-r--r--ares_nowarn.h14
-rw-r--r--ares_options.c222
-rw-r--r--ares_parse_a_reply.c63
-rw-r--r--ares_parse_aaaa_reply.c69
-rw-r--r--ares_parse_mx_reply.c18
-rw-r--r--ares_parse_naptr_reply.c193
-rw-r--r--ares_parse_ns_reply.c47
-rw-r--r--ares_parse_ptr_reply.c74
-rw-r--r--ares_parse_soa_reply.c133
-rw-r--r--ares_parse_srv_reply.c18
-rw-r--r--ares_parse_txt_reply.c133
-rw-r--r--ares_private.h65
-rw-r--r--ares_process.c527
-rw-r--r--ares_query.c23
-rw-r--r--ares_rules.h21
-rw-r--r--ares_search.c43
-rw-r--r--ares_send.c29
-rw-r--r--ares_setup.h22
-rw-r--r--ares_strdup.c35
-rw-r--r--ares_strdup.h2
-rw-r--r--ares_strsplit.c174
-rw-r--r--ares_strsplit.h43
-rw-r--r--ares_timeout.c38
-rw-r--r--ares_version.h8
-rw-r--r--ares_writev.c8
-rw-r--r--ares_writev.h2
-rw-r--r--bitncmp.c42
-rw-r--r--bitncmp.h6
-rw-r--r--config-dos.h12
-rw-r--r--config-win32.h72
-rw-r--r--inet_net_pton.c23
-rw-r--r--inet_ntop.c28
-rw-r--r--nameser.h8
-rw-r--r--setup_once.h94
70 files changed, 4196 insertions, 1819 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7bcd932..65b36be 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,56 +8,56 @@ if(WINDOWS)
endif()
set(cares_src
- acountry.c
- adig.c
- ahost.c
- ares__close_sockets.c
- ares__get_hostent.c
- ares__read_line.c
- ares__timeval.c
- ares_cancel.c
- ares_data.c
- ares_destroy.c
- ares_expand_name.c
- ares_expand_string.c
- ares_fds.c
- ares_free_hostent.c
- ares_free_string.c
- ares_getenv.c
- ares_gethostbyaddr.c
- ares_gethostbyname.c
- ares_getnameinfo.c
- ares_getopt.c
- ares_getsock.c
- ares_init.c
- ares_library_init.c
- ares_llist.c
- ares_mkquery.c
- ares_nowarn.c
- ares_options.c
- ares_parse_a_reply.c
- ares_parse_aaaa_reply.c
- ares_parse_mx_reply.c
- ares_parse_ns_reply.c
- ares_parse_ptr_reply.c
- ares_parse_srv_reply.c
- ares_parse_txt_reply.c
- ares_platform.c
- ares_process.c
- ares_query.c
- ares_search.c
- ares_send.c
- ares_strcasecmp.c
- ares_strdup.c
- ares_strerror.c
- ares_timeout.c
- ares_version.c
- ares_writev.c
- bitncmp.c
- inet_net_pton.c
- inet_ntop.c
- windows_port.c)
-
+ ares__close_sockets.c
+ ares__get_hostent.c
+ ares__read_line.c
+ ares__timeval.c
+ ares_cancel.c
+ ares_create_query.c
+ ares_data.c
+ ares_destroy.c
+ ares_expand_name.c
+ ares_expand_string.c
+ ares_fds.c
+ ares_free_hostent.c
+ ares_free_string.c
+ ares_getenv.c
+ ares_gethostbyaddr.c
+ ares_gethostbyname.c
+ ares_getnameinfo.c
+ ares_getopt.c
+ ares_getsock.c
+ ares_init.c
+ ares_library_init.c
+ ares_llist.c
+ ares_mkquery.c
+ ares_nowarn.c
+ ares_options.c
+ ares_parse_a_reply.c
+ ares_parse_aaaa_reply.c
+ ares_parse_mx_reply.c
+ ares_parse_naptr_reply.c
+ ares_parse_ns_reply.c
+ ares_parse_ptr_reply.c
+ ares_parse_soa_reply.c
+ ares_parse_srv_reply.c
+ ares_parse_txt_reply.c
+ ares_platform.c
+ ares_process.c
+ ares_query.c
+ ares_search.c
+ ares_send.c
+ ares_strcasecmp.c
+ ares_strdup.c
+ ares_strerror.c
+ ares_timeout.c
+ ares_version.c
+ ares_writev.c
+ bitncmp.c
+ inet_net_pton.c
+ inet_ntop.c
+ windows_port.c
+ )
android_add_library(cares)
target_compile_definitions(cares
diff --git a/acountry.c b/acountry.c
index d989018..2f20ff4 100644
--- a/acountry.c
+++ b/acountry.c
@@ -15,7 +15,7 @@
*
* Ref: http://countries.nerd.dk/more.html
*
- * Written by G. Vanem <gvanem@broadpark.no> 2006, 2007
+ * Written by G. Vanem <gvanem@yahoo.no> 2006, 2007
*
* NB! This program may not be big-endian aware.
*
@@ -34,14 +34,6 @@
#include "ares_setup.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
@@ -49,7 +41,6 @@
#if defined(WIN32) && !defined(WATT32)
#include <winsock.h>
#else
- #include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
@@ -57,8 +48,6 @@
#include "ares.h"
#include "ares_getopt.h"
-#include "inet_net_pton.h"
-#include "inet_ntop.h"
#include "ares_nowarn.h"
#ifndef HAVE_STRDUP
@@ -82,14 +71,14 @@
static const char *usage = "acountry [-vh?] {host|addr} ...\n";
static const char nerd_fmt[] = "%u.%u.%u.%u.zz.countries.nerd.dk";
-static const char *nerd_ver1 = nerd_fmt + 14;
-static const char *nerd_ver2 = nerd_fmt + 11;
+static const char *nerd_ver1 = nerd_fmt + 14; /* .countries.nerd.dk */
+static const char *nerd_ver2 = nerd_fmt + 11; /* .zz.countries.nerd.dk */
static int verbose = 0;
#define TRACE(fmt) do { \
if (verbose > 0) \
printf fmt ; \
- } while (0)
+ } WHILE_FALSE
static void wait_ares(ares_channel channel);
static void callback(void *arg, int status, int timeouts, struct hostent *host);
@@ -211,7 +200,9 @@ static void wait_ares(ares_channel channel)
if (nfds == 0)
break;
tvp = ares_timeout(channel, NULL, &tv);
- select(nfds, &read_fds, &write_fds, NULL, tvp);
+ nfds = select(nfds, &read_fds, &write_fds, NULL, tvp);
+ if (nfds < 0)
+ continue;
ares_process(channel, &read_fds, &write_fds);
}
}
@@ -282,7 +273,7 @@ static const struct search_list *list_lookup(int number, const struct search_lis
*/
static const struct search_list country_list[] = {
{ 4, "af", "Afghanistan" },
- { 248, "ax", "Åland Island" },
+ { 248, "ax", "Ã…land Island" },
{ 8, "al", "Albania" },
{ 12, "dz", "Algeria" },
{ 16, "as", "American Samoa" },
@@ -570,9 +561,10 @@ static void find_country_from_cname(const char *cname, struct in_addr addr)
if (ver_1)
{
const char *dot = strchr(cname, '.');
- if ((z0 != 'z' && z1 != 'z') || dot != cname+4)
+ if (dot != cname+4)
{
printf("Unexpected CNAME %s (ver_1)\n", cname);
+ free(ccopy);
return;
}
}
@@ -583,12 +575,14 @@ static void find_country_from_cname(const char *cname, struct in_addr addr)
if (z0 != 'z' && z1 != 'z')
{
printf("Unexpected CNAME %s (ver_2)\n", cname);
+ free(ccopy);
return;
}
}
else
{
printf("Unexpected CNAME %s (ver?)\n", cname);
+ free(ccopy);
return;
}
@@ -625,4 +619,3 @@ static void find_country_from_cname(const char *cname, struct in_addr addr)
}
free(ccopy);
}
-
diff --git a/adig.c b/adig.c
index 9e3c553..e112dc0 100644
--- a/adig.c
+++ b/adig.c
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -37,25 +34,12 @@
# include <arpa/nameser_compat.h>
#endif
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
#include "ares.h"
#include "ares_dns.h"
-#include "inet_ntop.h"
-#include "inet_net_pton.h"
#include "ares_getopt.h"
#include "ares_nowarn.h"
@@ -390,9 +374,9 @@ int main(int argc, char **argv)
break;
tvp = ares_timeout(channel, NULL, &tv);
count = select(nfds, &read_fds, &write_fds, NULL, tvp);
- if (count < 0 && SOCKERRNO != EINVAL)
+ if (count < 0 && (status = SOCKERRNO) != EINVAL)
{
- perror("select");
+ printf("select fail: %d", status);
return 1;
}
ares_process(channel, &read_fds, &write_fds);
@@ -649,7 +633,7 @@ static const unsigned char *display_rr(const unsigned char *aptr,
*/
if (dlen < 2)
return NULL;
- printf("\t%d", DNS__16BIT(aptr));
+ printf("\t%d", (int)DNS__16BIT(aptr));
status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len);
if (status != ARES_SUCCESS)
return NULL;
@@ -676,10 +660,10 @@ static const unsigned char *display_rr(const unsigned char *aptr,
p += len;
if (p + 20 > aptr + dlen)
return NULL;
- printf("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )",
- (unsigned long)DNS__32BIT(p), (unsigned long)DNS__32BIT(p+4),
- (unsigned long)DNS__32BIT(p+8), (unsigned long)DNS__32BIT(p+12),
- (unsigned long)DNS__32BIT(p+16));
+ printf("\t\t\t\t\t\t( %u %u %u %u %u )",
+ DNS__32BIT(p), DNS__32BIT(p+4),
+ DNS__32BIT(p+8), DNS__32BIT(p+12),
+ DNS__32BIT(p+16));
break;
case T_TXT:
@@ -723,9 +707,9 @@ static const unsigned char *display_rr(const unsigned char *aptr,
* priority, weight, and port, followed by a domain name.
*/
- printf("\t%d", DNS__16BIT(aptr));
- printf(" %d", DNS__16BIT(aptr + 2));
- printf(" %d", DNS__16BIT(aptr + 4));
+ printf("\t%d", (int)DNS__16BIT(aptr));
+ printf(" %d", (int)DNS__16BIT(aptr + 2));
+ printf(" %d", (int)DNS__16BIT(aptr + 4));
status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len);
if (status != ARES_SUCCESS)
@@ -736,8 +720,8 @@ static const unsigned char *display_rr(const unsigned char *aptr,
case T_NAPTR:
- printf("\t%d", DNS__16BIT(aptr)); /* order */
- printf(" %d\n", DNS__16BIT(aptr + 2)); /* preference */
+ printf("\t%d", (int)DNS__16BIT(aptr)); /* order */
+ printf(" %d\n", (int)DNS__16BIT(aptr + 2)); /* preference */
p = aptr + 4;
status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
diff --git a/ahost.c b/ahost.c
index fb67f1f..7fbfd64 100644
--- a/ahost.c
+++ b/ahost.c
@@ -17,29 +17,17 @@
#include "ares_setup.h"
#if !defined(WIN32) || defined(WATT32)
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
#endif
+
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "ares.h"
#include "ares_dns.h"
-#include "inet_ntop.h"
-#include "inet_net_pton.h"
#include "ares_getopt.h"
#include "ares_ipv6.h"
#include "ares_nowarn.h"
@@ -64,6 +52,8 @@ static void usage(void);
int main(int argc, char **argv)
{
+ struct ares_options options;
+ int optmask = 0;
ares_channel channel;
int status, nfds, c, addr_family = AF_INET;
fd_set read_fds, write_fds;
@@ -77,6 +67,8 @@ int main(int argc, char **argv)
WSAStartup(wVersionRequested, &wsaData);
#endif
+ memset(&options, 0, sizeof(options));
+
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS)
{
@@ -84,7 +76,7 @@ int main(int argc, char **argv)
return 1;
}
- while ((c = ares_getopt(argc,argv,"dt:h")) != -1)
+ while ((c = ares_getopt(argc,argv,"dt:hs:")) != -1)
{
switch (c)
{
@@ -93,11 +85,20 @@ int main(int argc, char **argv)
dbug_init();
#endif
break;
+ case 's':
+ optmask |= ARES_OPT_DOMAINS;
+ options.ndomains++;
+ options.domains = (char **)realloc(options.domains,
+ options.ndomains * sizeof(char *));
+ options.domains[options.ndomains - 1] = strdup(optarg);
+ break;
case 't':
if (!strcasecmp(optarg,"a"))
addr_family = AF_INET;
else if (!strcasecmp(optarg,"aaaa"))
addr_family = AF_INET6;
+ else if (!strcasecmp(optarg,"u"))
+ addr_family = AF_UNSPEC;
else
usage();
break;
@@ -113,7 +114,7 @@ int main(int argc, char **argv)
if (argc < 1)
usage();
- status = ares_init(&channel);
+ status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS)
{
fprintf(stderr, "ares_init: %s\n", ares_strerror(status));
@@ -142,13 +143,16 @@ int main(int argc, char **argv)
/* Wait for all queries to complete. */
for (;;)
{
+ int res;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = ares_fds(channel, &read_fds, &write_fds);
if (nfds == 0)
break;
tvp = ares_timeout(channel, NULL, &tv);
- select(nfds, &read_fds, &write_fds, NULL, tvp);
+ res = select(nfds, &read_fds, &write_fds, NULL, tvp);
+ if (-1 == res)
+ break;
ares_process(channel, &read_fds, &write_fds);
}
@@ -197,6 +201,6 @@ static void callback(void *arg, int status, int timeouts, struct hostent *host)
static void usage(void)
{
- fprintf(stderr, "usage: ahost [-t {a|aaaa}] {host|addr} ...\n");
+ fprintf(stderr, "usage: ahost [-t {a|aaaa|u}] {host|addr} ...\n");
exit(1);
}
diff --git a/ares.h b/ares.h
index ccf6987..cfd72b0 100644
--- a/ares.h
+++ b/ares.h
@@ -1,6 +1,6 @@
-/* Copyright 1998, 2009 by the Massachusetts Institute of Technology.
- * Copyright (C) 2007-2011 by Daniel Stenberg
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2007-2013 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -38,7 +38,8 @@
require it! */
#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
- defined(__ANDROID__)
+ defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
+ defined(__QNXNTO__)
#include <sys/select.h>
#endif
#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
@@ -75,22 +76,18 @@ extern "C" {
** c-ares external API function linkage decorations.
*/
-#if !defined(CARES_STATICLIB) && \
- (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
- /* __declspec function decoration for Win32 and Symbian DLL's */
+#ifdef CARES_STATICLIB
+# define CARES_EXTERN
+#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)
# if defined(CARES_BUILDING_LIBRARY)
# define CARES_EXTERN __declspec(dllexport)
# else
# define CARES_EXTERN __declspec(dllimport)
# endif
+#elif defined(CARES_BUILDING_LIBRARY) && defined(CARES_SYMBOL_HIDING)
+# define CARES_EXTERN CARES_SYMBOL_SCOPE_EXTERN
#else
- /* visibility function decoration for other cases */
-# if !defined(CARES_SYMBOL_HIDING) || \
- defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)
-# define CARES_EXTERN
-# else
-# define CARES_EXTERN CARES_SYMBOL_SCOPE_EXTERN
-# endif
+# define CARES_EXTERN
#endif
@@ -143,6 +140,7 @@ extern "C" {
#define ARES_FLAG_NOSEARCH (1 << 5)
#define ARES_FLAG_NOALIASES (1 << 6)
#define ARES_FLAG_NOCHECKRESP (1 << 7)
+#define ARES_FLAG_EDNS (1 << 8)
/* Option mask values */
#define ARES_OPT_FLAGS (1 << 0)
@@ -160,6 +158,8 @@ extern "C" {
#define ARES_OPT_SOCK_RCVBUF (1 << 12)
#define ARES_OPT_TIMEOUTMS (1 << 13)
#define ARES_OPT_ROTATE (1 << 14)
+#define ARES_OPT_EDNSPSZ (1 << 15)
+#define ARES_OPT_NOROTATE (1 << 16)
/* Nameinfo flag values */
#define ARES_NI_NOFQDN (1 << 0)
@@ -265,6 +265,7 @@ struct ares_options {
void *sock_state_cb_data;
struct apattern *sortlist;
int nsort;
+ int ednspsz;
};
struct hostent;
@@ -295,8 +296,19 @@ typedef int (*ares_sock_create_callback)(ares_socket_t socket_fd,
int type,
void *data);
+typedef int (*ares_sock_config_callback)(ares_socket_t socket_fd,
+ int type,
+ void *data);
+
CARES_EXTERN int ares_library_init(int flags);
+CARES_EXTERN int ares_library_init_mem(int flags,
+ void *(*amalloc)(size_t size),
+ void (*afree)(void *ptr),
+ void *(*arealloc)(void *ptr, size_t size));
+
+CARES_EXTERN int ares_library_initialized(void);
+
CARES_EXTERN void ares_library_cleanup(void);
CARES_EXTERN const char *ares_version(int *version);
@@ -338,6 +350,34 @@ CARES_EXTERN void ares_set_socket_callback(ares_channel channel,
ares_sock_create_callback callback,
void *user_data);
+CARES_EXTERN void ares_set_socket_configure_callback(ares_channel channel,
+ ares_sock_config_callback callback,
+ void *user_data);
+
+CARES_EXTERN int ares_set_sortlist(ares_channel channel,
+ const char *sortstr);
+
+/*
+ * Virtual function set to have user-managed socket IO.
+ * Note that all functions need to be defined, and when
+ * set, the library will not do any bind nor set any
+ * socket options, assuming the client handles these
+ * through either socket creation or the
+ * ares_sock_config_callback call.
+ */
+struct iovec;
+struct ares_socket_functions {
+ ares_socket_t(*asocket)(int, int, int, void *);
+ int(*aclose)(ares_socket_t, void *);
+ int(*aconnect)(ares_socket_t, const struct sockaddr *, ares_socklen_t, void *);
+ ares_ssize_t(*arecvfrom)(ares_socket_t, void *, size_t, int, struct sockaddr *, ares_socklen_t *, void *);
+ ares_ssize_t(*asendv)(ares_socket_t, const struct iovec *, int, void *);
+};
+
+CARES_EXTERN void ares_set_socket_functions(ares_channel channel,
+ const struct ares_socket_functions * funcs,
+ void *user_data);
+
CARES_EXTERN void ares_send(ares_channel channel,
const unsigned char *qbuf,
int qlen,
@@ -403,6 +443,15 @@ CARES_EXTERN void ares_process_fd(ares_channel channel,
ares_socket_t read_fd,
ares_socket_t write_fd);
+CARES_EXTERN int ares_create_query(const char *name,
+ int dnsclass,
+ int type,
+ unsigned short id,
+ int rd,
+ unsigned char **buf,
+ int *buflen,
+ int max_udp_size);
+
CARES_EXTERN int ares_mkquery(const char *name,
int dnsclass,
int type,
@@ -466,6 +515,37 @@ struct ares_txt_reply {
size_t length; /* length excludes null termination */
};
+/* NOTE: This structure is a superset of ares_txt_reply
+ */
+struct ares_txt_ext {
+ struct ares_txt_ext *next;
+ unsigned char *txt;
+ size_t length;
+ /* 1 - if start of new record
+ * 0 - if a chunk in the same record */
+ unsigned char record_start;
+};
+
+struct ares_naptr_reply {
+ struct ares_naptr_reply *next;
+ unsigned char *flags;
+ unsigned char *service;
+ unsigned char *regexp;
+ char *replacement;
+ unsigned short order;
+ unsigned short preference;
+};
+
+struct ares_soa_reply {
+ char *nsname;
+ char *hostmaster;
+ unsigned int serial;
+ unsigned int refresh;
+ unsigned int retry;
+ unsigned int expire;
+ unsigned int minttl;
+};
+
/*
** 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.
@@ -509,6 +589,18 @@ CARES_EXTERN int ares_parse_txt_reply(const unsigned char* abuf,
int alen,
struct ares_txt_reply** txt_out);
+CARES_EXTERN int ares_parse_txt_reply_ext(const unsigned char* abuf,
+ int alen,
+ struct ares_txt_ext** txt_out);
+
+CARES_EXTERN int ares_parse_naptr_reply(const unsigned char* abuf,
+ int alen,
+ struct ares_naptr_reply** naptr_out);
+
+CARES_EXTERN int ares_parse_soa_reply(const unsigned char* abuf,
+ int alen,
+ struct ares_soa_reply** soa_out);
+
CARES_EXTERN void ares_free_string(void *str);
CARES_EXTERN void ares_free_hostent(struct hostent *host);
@@ -517,7 +609,6 @@ CARES_EXTERN void ares_free_data(void *dataptr);
CARES_EXTERN const char *ares_strerror(int code);
-/* TODO: Hold port here as well. */
struct ares_addr_node {
struct ares_addr_node *next;
int family;
@@ -527,15 +618,38 @@ struct ares_addr_node {
} addr;
};
+struct ares_addr_port_node {
+ struct ares_addr_port_node *next;
+ int family;
+ union {
+ struct in_addr addr4;
+ struct ares_in6_addr addr6;
+ } addr;
+ int udp_port;
+ int tcp_port;
+};
+
CARES_EXTERN int ares_set_servers(ares_channel channel,
struct ares_addr_node *servers);
+CARES_EXTERN int ares_set_servers_ports(ares_channel channel,
+ struct ares_addr_port_node *servers);
/* Incomming string format: host[:port][,host[:port]]... */
CARES_EXTERN int ares_set_servers_csv(ares_channel channel,
const char* servers);
+CARES_EXTERN int ares_set_servers_ports_csv(ares_channel channel,
+ const char* servers);
CARES_EXTERN int ares_get_servers(ares_channel channel,
struct ares_addr_node **servers);
+CARES_EXTERN int ares_get_servers_ports(ares_channel channel,
+ struct ares_addr_port_node **servers);
+
+CARES_EXTERN const char *ares_inet_ntop(int af, const void *src, char *dst,
+ ares_socklen_t size);
+
+CARES_EXTERN int ares_inet_pton(int af, const char *src, void *dst);
+
#ifdef __cplusplus
}
diff --git a/ares__close_sockets.c b/ares__close_sockets.c
index 5d391a9..f07904e 100644
--- a/ares__close_sockets.c
+++ b/ares__close_sockets.c
@@ -16,11 +16,6 @@
#include "ares_setup.h"
-#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
#include "ares.h"
#include "ares_private.h"
@@ -35,14 +30,14 @@ void ares__close_sockets(ares_channel channel, struct server_state *server)
sendreq = server->qhead;
server->qhead = sendreq->next;
if (sendreq->data_storage != NULL)
- free(sendreq->data_storage);
- free(sendreq);
+ ares_free(sendreq->data_storage);
+ ares_free(sendreq);
}
server->qtail = NULL;
/* Reset any existing input buffer. */
if (server->tcp_buffer)
- free(server->tcp_buffer);
+ ares_free(server->tcp_buffer);
server->tcp_buffer = NULL;
server->tcp_lenbuf_pos = 0;
@@ -53,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);
- sclose(server->tcp_socket);
+ ares__socket_close(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);
- sclose(server->udp_socket);
+ ares__socket_close(channel, server->udp_socket);
server->udp_socket = ARES_SOCKET_BAD;
}
}
diff --git a/ares__get_hostent.c b/ares__get_hostent.c
index 298df09..d2f9503 100644
--- a/ares__get_hostent.c
+++ b/ares__get_hostent.c
@@ -1,5 +1,5 @@
-/* Copyright 1998, 2010 by the Massachusetts Institute of Technology.
+/* Copyright 1998, 2011 by the Massachusetts Institute of Technology.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -30,7 +27,8 @@
#endif
#include "ares.h"
-#include "inet_net_pton.h"
+#include "ares_inet_net_pton.h"
+#include "ares_nowarn.h"
#include "ares_private.h"
int ares__get_hostent(FILE *fp, int family, struct hostent **host)
@@ -96,7 +94,7 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
p++;
if (!*p)
/* Ignore line if reached end of line. */
- continue;
+ continue; /* LCOV_EXCL_LINE: trailing whitespace already stripped */
/* Pointer to start of host name. */
txthost = p;
@@ -166,7 +164,7 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
*/
/* Allocate memory for the hostent structure. */
- hostent = malloc(sizeof(struct hostent));
+ hostent = ares_malloc(sizeof(struct hostent));
if (!hostent)
break;
@@ -175,16 +173,16 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
hostent->h_addr_list = NULL;
/* Copy official host name. */
- hostent->h_name = strdup(txthost);
+ hostent->h_name = ares_strdup(txthost);
if (!hostent->h_name)
break;
/* Copy network address. */
- hostent->h_addr_list = malloc(2 * sizeof(char *));
+ hostent->h_addr_list = ares_malloc(2 * sizeof(char *));
if (!hostent->h_addr_list)
break;
hostent->h_addr_list[1] = NULL;
- hostent->h_addr_list[0] = malloc(addrlen);
+ hostent->h_addr_list[0] = ares_malloc(addrlen);
if (!hostent->h_addr_list[0])
break;
if (addr.family == AF_INET)
@@ -193,7 +191,7 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(addr.addrV6));
/* Copy aliases. */
- hostent->h_aliases = malloc((naliases + 1) * sizeof(char *));
+ hostent->h_aliases = ares_malloc((naliases + 1) * sizeof(char *));
if (!hostent->h_aliases)
break;
alias = hostent->h_aliases;
@@ -209,7 +207,7 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
while (*q && ISSPACE(*q))
q++;
*p = '\0';
- if ((*alias = strdup(txtalias)) == NULL)
+ if ((*alias = ares_strdup(txtalias)) == NULL)
break;
alias++;
txtalias = *q ? q : NULL;
@@ -219,11 +217,11 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
break;
/* Copy actual network address family and length. */
- hostent->h_addrtype = addr.family;
- hostent->h_length = (int)addrlen;
+ hostent->h_addrtype = aresx_sitoss(addr.family);
+ hostent->h_length = aresx_uztoss(addrlen);
/* Free line buffer. */
- free(line);
+ ares_free(line);
/* Return hostent successfully */
*host = hostent;
@@ -233,7 +231,7 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
/* If allocated, free line buffer. */
if (line)
- free(line);
+ ares_free(line);
if (status == ARES_SUCCESS)
{
@@ -241,20 +239,20 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
if (hostent)
{
if (hostent->h_name)
- free((char *) hostent->h_name);
+ ares_free((char *) hostent->h_name);
if (hostent->h_aliases)
{
for (alias = hostent->h_aliases; *alias; alias++)
- free(*alias);
- free(hostent->h_aliases);
+ ares_free(*alias);
+ ares_free(hostent->h_aliases);
}
if (hostent->h_addr_list)
{
if (hostent->h_addr_list[0])
- free(hostent->h_addr_list[0]);
- free(hostent->h_addr_list);
+ ares_free(hostent->h_addr_list[0]);
+ ares_free(hostent->h_addr_list);
}
- free(hostent);
+ ares_free(hostent);
}
return ARES_ENOMEM;
}
diff --git a/ares__read_line.c b/ares__read_line.c
index ca01803..c62ad2a 100644
--- a/ares__read_line.c
+++ b/ares__read_line.c
@@ -15,9 +15,7 @@
*/
#include "ares_setup.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+
#include "ares.h"
#include "ares_nowarn.h"
#include "ares_private.h"
@@ -38,7 +36,7 @@ int ares__read_line(FILE *fp, char **buf, size_t *bufsize)
if (*buf == NULL)
{
- *buf = malloc(128);
+ *buf = ares_malloc(128);
if (!*buf)
return ARES_ENOMEM;
*bufsize = 128;
@@ -61,9 +59,13 @@ int ares__read_line(FILE *fp, char **buf, size_t *bufsize)
continue;
/* Allocate more space. */
- newbuf = realloc(*buf, *bufsize * 2);
+ newbuf = ares_realloc(*buf, *bufsize * 2);
if (!newbuf)
- return ARES_ENOMEM;
+ {
+ ares_free(*buf);
+ *buf = NULL;
+ return ARES_ENOMEM;
+ }
*buf = newbuf;
*bufsize *= 2;
}
diff --git a/ares__timeval.c b/ares__timeval.c
index f7aa788..94efb7d 100644
--- a/ares__timeval.c
+++ b/ares__timeval.c
@@ -56,7 +56,7 @@ struct timeval ares__tvnow(void)
*/
#ifdef HAVE_GETTIMEOFDAY
else
- (void)gettimeofday(&now, NULL);
+ (void)gettimeofday(&now, NULL); /* LCOV_EXCL_LINE */
#else
else {
now.tv_sec = (long)time(NULL);
diff --git a/ares_android.c b/ares_android.c
new file mode 100644
index 0000000..bf77131
--- /dev/null
+++ b/ares_android.c
@@ -0,0 +1,446 @@
+/* Copyright (C) 2017 by John Schember <john@nachtimwald.com>
+ *
+ * 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.
+ */
+#if defined(ANDROID) || defined(__ANDROID__)
+
+#include <jni.h>
+
+#include "ares_setup.h"
+#include "ares.h"
+#include "ares_android.h"
+#include "ares_private.h"
+
+static JavaVM *android_jvm = NULL;
+static jobject android_connectivity_manager = NULL;
+
+/* ConnectivityManager.getActiveNetwork */
+static jmethodID android_cm_active_net_mid = NULL;
+/* ConnectivityManager.getLinkProperties */
+static jmethodID android_cm_link_props_mid = NULL;
+/* LinkProperties.getDnsServers */
+static jmethodID android_lp_dns_servers_mid = NULL;
+/* LinkProperties.getDomains */
+static jmethodID android_lp_domains_mid = NULL;
+/* List.size */
+static jmethodID android_list_size_mid = NULL;
+/* List.get */
+static jmethodID android_list_get_mid = NULL;
+/* InetAddress.getHostAddress */
+static jmethodID android_ia_host_addr_mid = NULL;
+
+static jclass jni_get_class(JNIEnv *env, const char *path)
+{
+ jclass cls = NULL;
+
+ if (env == NULL || path == NULL || *path == '\0')
+ return NULL;
+
+ cls = (*env)->FindClass(env, path);
+ if ((*env)->ExceptionOccurred(env)) {
+ (*env)->ExceptionClear(env);
+ return NULL;
+ }
+ return cls;
+}
+
+static jmethodID jni_get_method_id(JNIEnv *env, jclass cls,
+ const char *func_name, const char *signature)
+{
+ jmethodID mid = NULL;
+
+ if (env == NULL || cls == NULL || func_name == NULL || *func_name == '\0' ||
+ signature == NULL || *signature == '\0')
+ {
+ return NULL;
+ }
+
+ mid = (*env)->GetMethodID(env, cls, func_name, signature);
+ if ((*env)->ExceptionOccurred(env))
+ {
+ (*env)->ExceptionClear(env);
+ return NULL;
+ }
+
+ return mid;
+}
+
+void ares_library_init_jvm(JavaVM *jvm)
+{
+ android_jvm = jvm;
+}
+
+int ares_library_init_android(jobject connectivity_manager)
+{
+ JNIEnv *env = NULL;
+ int need_detatch = 0;
+ int res;
+ int ret = ARES_ENOTINITIALIZED;
+ jclass obj_cls = NULL;
+
+ if (android_jvm == NULL)
+ goto cleanup;
+
+ res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
+ if (res == JNI_EDETACHED)
+ {
+ env = NULL;
+ res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL);
+ need_detatch = 1;
+ }
+ if (res != JNI_OK || env == NULL)
+ goto cleanup;
+
+ android_connectivity_manager =
+ (*env)->NewGlobalRef(env, connectivity_manager);
+ if (android_connectivity_manager == NULL)
+ goto cleanup;
+
+ /* Initialization has succeeded. Now attempt to cache the methods that will be
+ * called by ares_get_android_server_list. */
+ ret = ARES_SUCCESS;
+
+ /* ConnectivityManager in API 1. */
+ obj_cls = jni_get_class(env, "android/net/ConnectivityManager");
+ if (obj_cls == NULL)
+ goto cleanup;
+
+ /* ConnectivityManager.getActiveNetwork in API 23. */
+ android_cm_active_net_mid =
+ jni_get_method_id(env, obj_cls, "getActiveNetwork",
+ "()Landroid/net/Network;");
+ if (android_cm_active_net_mid == NULL)
+ goto cleanup;
+
+ /* ConnectivityManager.getLinkProperties in API 21. */
+ android_cm_link_props_mid =
+ jni_get_method_id(env, obj_cls, "getLinkProperties",
+ "(Landroid/net/Network;)Landroid/net/LinkProperties;");
+ if (android_cm_link_props_mid == NULL)
+ goto cleanup;
+
+ /* LinkProperties in API 21. */
+ (*env)->DeleteLocalRef(env, obj_cls);
+ obj_cls = jni_get_class(env, "android/net/LinkProperties");
+ if (obj_cls == NULL)
+ goto cleanup;
+
+ /* getDnsServers in API 21. */
+ android_lp_dns_servers_mid = jni_get_method_id(env, obj_cls, "getDnsServers",
+ "()Ljava/util/List;");
+ if (android_lp_dns_servers_mid == NULL)
+ goto cleanup;
+
+ /* getDomains in API 21. */
+ android_lp_domains_mid = jni_get_method_id(env, obj_cls, "getDomains",
+ "()Ljava/lang/String;");
+ if (android_lp_domains_mid == NULL)
+ goto cleanup;
+
+ (*env)->DeleteLocalRef(env, obj_cls);
+ obj_cls = jni_get_class(env, "java/util/List");
+ if (obj_cls == NULL)
+ goto cleanup;
+
+ android_list_size_mid = jni_get_method_id(env, obj_cls, "size", "()I");
+ if (android_list_size_mid == NULL)
+ goto cleanup;
+
+ android_list_get_mid = jni_get_method_id(env, obj_cls, "get",
+ "(I)Ljava/lang/Object;");
+ if (android_list_get_mid == NULL)
+ goto cleanup;
+
+ (*env)->DeleteLocalRef(env, obj_cls);
+ obj_cls = jni_get_class(env, "java/net/InetAddress");
+ if (obj_cls == NULL)
+ goto cleanup;
+
+ android_ia_host_addr_mid = jni_get_method_id(env, obj_cls, "getHostAddress",
+ "()Ljava/lang/String;");
+ if (android_ia_host_addr_mid == NULL)
+ goto cleanup;
+
+ (*env)->DeleteLocalRef(env, obj_cls);
+ goto done;
+
+cleanup:
+ if (obj_cls != NULL)
+ (*env)->DeleteLocalRef(env, obj_cls);
+
+ android_cm_active_net_mid = NULL;
+ android_cm_link_props_mid = NULL;
+ android_lp_dns_servers_mid = NULL;
+ android_lp_domains_mid = NULL;
+ android_list_size_mid = NULL;
+ android_list_get_mid = NULL;
+ android_ia_host_addr_mid = NULL;
+
+done:
+ if (need_detatch)
+ (*android_jvm)->DetachCurrentThread(android_jvm);
+
+ return ret;
+}
+
+int ares_library_android_initialized(void)
+{
+ if (android_jvm == NULL || android_connectivity_manager == NULL)
+ return ARES_ENOTINITIALIZED;
+ return ARES_SUCCESS;
+}
+
+void ares_library_cleanup_android(void)
+{
+ JNIEnv *env = NULL;
+ int need_detatch = 0;
+ int res;
+
+ if (android_jvm == NULL || android_connectivity_manager == NULL)
+ return;
+
+ res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
+ if (res == JNI_EDETACHED)
+ {
+ env = NULL;
+ res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL);
+ need_detatch = 1;
+ }
+ if (res != JNI_OK || env == NULL)
+ return;
+
+ android_cm_active_net_mid = NULL;
+ android_cm_link_props_mid = NULL;
+ android_lp_dns_servers_mid = NULL;
+ android_lp_domains_mid = NULL;
+ android_list_size_mid = NULL;
+ android_list_get_mid = NULL;
+ android_ia_host_addr_mid = NULL;
+
+ (*env)->DeleteGlobalRef(env, android_connectivity_manager);
+ android_connectivity_manager = NULL;
+
+ if (need_detatch)
+ (*android_jvm)->DetachCurrentThread(android_jvm);
+}
+
+char **ares_get_android_server_list(size_t max_servers,
+ size_t *num_servers)
+{
+ JNIEnv *env = NULL;
+ jobject active_network = NULL;
+ jobject link_properties = NULL;
+ jobject server_list = NULL;
+ jobject server = NULL;
+ jstring str = NULL;
+ jint nserv;
+ const char *ch_server_address;
+ int res;
+ size_t i;
+ char **dns_list = NULL;
+ int need_detatch = 0;
+
+ if (android_jvm == NULL || android_connectivity_manager == NULL ||
+ max_servers == 0 || num_servers == NULL)
+ {
+ return NULL;
+ }
+
+ if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL ||
+ android_lp_dns_servers_mid == NULL || android_list_size_mid == NULL ||
+ android_list_get_mid == NULL || android_ia_host_addr_mid == NULL)
+ {
+ return NULL;
+ }
+
+ res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
+ if (res == JNI_EDETACHED)
+ {
+ env = NULL;
+ res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL);
+ need_detatch = 1;
+ }
+ if (res != JNI_OK || env == NULL)
+ goto done;
+
+ /* JNI below is equivalent to this Java code.
+ import android.content.Context;
+ import android.net.ConnectivityManager;
+ import android.net.LinkProperties;
+ import android.net.Network;
+ import java.net.InetAddress;
+ import java.util.List;
+
+ ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext()
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ Network an = cm.getActiveNetwork();
+ LinkProperties lp = cm.getLinkProperties(an);
+ List<InetAddress> dns = lp.getDnsServers();
+ for (InetAddress ia: dns) {
+ String ha = ia.getHostAddress();
+ }
+
+ Note: The JNI ConnectivityManager object and all method IDs were previously
+ initialized in ares_library_init_android.
+ */
+
+ active_network = (*env)->CallObjectMethod(env, android_connectivity_manager,
+ android_cm_active_net_mid);
+ if (active_network == NULL)
+ goto done;
+
+ link_properties =
+ (*env)->CallObjectMethod(env, android_connectivity_manager,
+ android_cm_link_props_mid, active_network);
+ if (link_properties == NULL)
+ goto done;
+
+ server_list = (*env)->CallObjectMethod(env, link_properties,
+ android_lp_dns_servers_mid);
+ if (server_list == NULL)
+ goto done;
+
+ nserv = (*env)->CallIntMethod(env, server_list, android_list_size_mid);
+ if (nserv > (jint)max_servers)
+ nserv = (jint)max_servers;
+ if (nserv <= 0)
+ goto done;
+ *num_servers = (size_t)nserv;
+
+ dns_list = ares_malloc(sizeof(*dns_list)*(*num_servers));
+ for (i=0; i<*num_servers; i++)
+ {
+ server = (*env)->CallObjectMethod(env, server_list, android_list_get_mid,
+ (jint)i);
+ dns_list[i] = ares_malloc(64);
+ dns_list[i][0] = 0;
+ if (server == NULL)
+ {
+ continue;
+ }
+ str = (*env)->CallObjectMethod(env, server, android_ia_host_addr_mid);
+ ch_server_address = (*env)->GetStringUTFChars(env, str, 0);
+ strncpy(dns_list[i], ch_server_address, 64);
+ (*env)->ReleaseStringUTFChars(env, str, ch_server_address);
+ (*env)->DeleteLocalRef(env, str);
+ (*env)->DeleteLocalRef(env, server);
+ }
+
+done:
+ if ((*env)->ExceptionOccurred(env))
+ (*env)->ExceptionClear(env);
+
+ if (server_list != NULL)
+ (*env)->DeleteLocalRef(env, server_list);
+ if (link_properties != NULL)
+ (*env)->DeleteLocalRef(env, link_properties);
+ if (active_network != NULL)
+ (*env)->DeleteLocalRef(env, active_network);
+
+ if (need_detatch)
+ (*android_jvm)->DetachCurrentThread(android_jvm);
+ return dns_list;
+}
+
+char *ares_get_android_search_domains_list(void)
+{
+ JNIEnv *env = NULL;
+ jobject active_network = NULL;
+ jobject link_properties = NULL;
+ jstring domains = NULL;
+ const char *domain;
+ int res;
+ size_t i;
+ size_t cnt = 0;
+ char *domain_list = NULL;
+ int need_detatch = 0;
+
+ if (android_jvm == NULL || android_connectivity_manager == NULL)
+ {
+ return NULL;
+ }
+
+ if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL ||
+ android_lp_domains_mid == NULL)
+ {
+ return NULL;
+ }
+
+ res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
+ if (res == JNI_EDETACHED)
+ {
+ env = NULL;
+ res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL);
+ need_detatch = 1;
+ }
+ if (res != JNI_OK || env == NULL)
+ goto done;
+
+ /* JNI below is equivalent to this Java code.
+ import android.content.Context;
+ import android.net.ConnectivityManager;
+ import android.net.LinkProperties;
+
+ ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext()
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ Network an = cm.getActiveNetwork();
+ LinkProperties lp = cm.getLinkProperties(an);
+ String domains = lp.getDomains();
+ for (String domain: domains.split(",")) {
+ String d = domain;
+ }
+
+ Note: The JNI ConnectivityManager object and all method IDs were previously
+ initialized in ares_library_init_android.
+ */
+
+ active_network = (*env)->CallObjectMethod(env, android_connectivity_manager,
+ android_cm_active_net_mid);
+ if (active_network == NULL)
+ goto done;
+
+ link_properties =
+ (*env)->CallObjectMethod(env, android_connectivity_manager,
+ android_cm_link_props_mid, active_network);
+ if (link_properties == NULL)
+ goto done;
+
+ /* Get the domains. It is a common separated list of domains to search. */
+ domains = (*env)->CallObjectMethod(env, link_properties,
+ android_lp_domains_mid);
+ if (domains == NULL)
+ goto done;
+
+ /* Split on , */
+ domain = (*env)->GetStringUTFChars(env, domains, 0);
+ domain_list = ares_strdup(domain);
+ (*env)->ReleaseStringUTFChars(env, domains, domain);
+ (*env)->DeleteLocalRef(env, domains);
+
+done:
+ if ((*env)->ExceptionOccurred(env))
+ (*env)->ExceptionClear(env);
+
+ if (link_properties != NULL)
+ (*env)->DeleteLocalRef(env, link_properties);
+ if (active_network != NULL)
+ (*env)->DeleteLocalRef(env, active_network);
+
+ if (need_detatch)
+ (*android_jvm)->DetachCurrentThread(android_jvm);
+ return domain_list;
+}
+#else
+/* warning: ISO C forbids an empty translation unit */
+typedef int dummy_make_iso_compilers_happy;
+#endif
diff --git a/ares_android.h b/ares_android.h
new file mode 100644
index 0000000..93fb75f
--- /dev/null
+++ b/ares_android.h
@@ -0,0 +1,27 @@
+/* Copyright (C) 2017 by John Schember <john@nachtimwald.com>
+ *
+ * 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.
+ */
+
+#ifndef __ARES_ANDROID_H__
+#define __ARES_ANDROID_H__
+
+#if defined(ANDROID) || defined(__ANDROID__)
+
+char **ares_get_android_server_list(size_t max_servers, size_t *num_servers);
+char *ares_get_android_search_domains_list(void);
+void ares_library_cleanup_android(void);
+
+#endif
+
+#endif /* __ARES_ANDROID_H__ */
diff --git a/ares_build.h b/ares_build.h
index e2c14c6..e5988cf 100644
--- a/ares_build.h
+++ b/ares_build.h
@@ -2,7 +2,7 @@
#define __CARES_BUILD_H
-/* Copyright (C) 2009 - 2010 by Daniel Stenberg et al
+/* Copyright (C) 2009 - 2013 by Daniel Stenberg et al
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
@@ -83,148 +83,88 @@
/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */
/* ================================================================ */
-#ifdef CARES_SIZEOF_LONG
-# error "CARES_SIZEOF_LONG shall not be defined except in ares_build.h"
- Error Compilation_aborted_CARES_SIZEOF_LONG_already_defined
-#endif
-
#ifdef CARES_TYPEOF_ARES_SOCKLEN_T
# error "CARES_TYPEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h"
Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_already_defined
#endif
-#ifdef CARES_SIZEOF_ARES_SOCKLEN_T
-# error "CARES_SIZEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h"
- Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_already_defined
-#endif
-
/* ================================================================ */
/* EXTERNAL INTERFACE SETTINGS FOR NON-CONFIGURE SYSTEMS ONLY */
/* ================================================================ */
#if defined(__DJGPP__) || defined(__GO32__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__SALFORDC__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__BORLANDC__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__TURBOC__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__WATCOMC__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__POCC__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__LCC__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__SYMBIAN32__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T unsigned int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__MWERKS__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(_WIN32_WCE)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__MINGW32__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__VMS)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T unsigned int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
#elif defined(__OS400__)
# if defined(__ILEC400__)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
# define CARES_PULL_SYS_TYPES_H 1
# define CARES_PULL_SYS_SOCKET_H 1
# endif
#elif defined(__MVS__)
# if defined(__IBMC__) || defined(__IBMCPP__)
-# if defined(_ILP32)
-# define CARES_SIZEOF_LONG 4
-# elif defined(_LP64)
-# define CARES_SIZEOF_LONG 8
-# endif
# define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
# define CARES_PULL_SYS_TYPES_H 1
# define CARES_PULL_SYS_SOCKET_H 1
# endif
#elif defined(__370__)
# if defined(__IBMC__) || defined(__IBMCPP__)
-# if defined(_ILP32)
-# define CARES_SIZEOF_LONG 4
-# elif defined(_LP64)
-# define CARES_SIZEOF_LONG 8
-# endif
# define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
# define CARES_PULL_SYS_TYPES_H 1
# define CARES_PULL_SYS_SOCKET_H 1
# endif
#elif defined(TPF)
-# define CARES_SIZEOF_LONG 8
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
/* ===================================== */
/* KEEP MSVC THE PENULTIMATE ENTRY */
/* ===================================== */
#elif defined(_MSC_VER)
-# define CARES_SIZEOF_LONG 4
# define CARES_TYPEOF_ARES_SOCKLEN_T int
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
/* ===================================== */
/* KEEP GENERIC GCC THE LAST ENTRY */
/* ===================================== */
#elif defined(__GNUC__)
-# if defined(__i386__) || defined(__ppc__)
-# define CARES_SIZEOF_LONG 4
-# elif defined(__x86_64__) || defined(__ppc64__)
-# define CARES_SIZEOF_LONG 8
-# else
-# define CARES_SIZEOF_LONG sizeof(long)
-# endif
# define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
-# define CARES_SIZEOF_ARES_SOCKLEN_T 4
# define CARES_PULL_SYS_TYPES_H 1
# define CARES_PULL_SYS_SOCKET_H 1
@@ -251,4 +191,33 @@
typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t;
#endif
+/* Data type definition of ares_ssize_t. */
+/* gRPC Manuel edit here!
+ * Possibly include <_mingw.h> header to define __int64 type under mingw */
+#ifdef _WIN32
+# ifdef _WIN64
+# ifdef __MINGW32__
+# include <_mingw.h>
+# endif
+# define CARES_TYPEOF_ARES_SSIZE_T __int64
+# else
+# define CARES_TYPEOF_ARES_SSIZE_T long
+# endif
+#else
+# define CARES_TYPEOF_ARES_SSIZE_T ssize_t
+#endif
+
+typedef CARES_TYPEOF_ARES_SSIZE_T ares_ssize_t;
+
+/* IMPORTANT: gRPC MANUAL EDIT HERE!
+ * Undefine UNICODE, as c-ares does not use the ANSI version of functions
+ * explicitly. */
+#ifdef UNICODE
+# undef UNICODE
+#endif
+
+#ifdef _UNICODE
+# undef _UNICODE
+#endif
+
#endif /* __CARES_BUILD_H */
diff --git a/ares_cancel.c b/ares_cancel.c
index eb790ae..465cc9e 100644
--- a/ares_cancel.c
+++ b/ares_cancel.c
@@ -14,7 +14,7 @@
#include "ares_setup.h"
#include <assert.h>
-#include <stdlib.h>
+
#include "ares.h"
#include "ares_private.h"
@@ -26,33 +26,33 @@
void ares_cancel(ares_channel channel)
{
struct query *query;
+ struct list_node list_head_copy;
struct list_node* list_head;
struct list_node* list_node;
int i;
- list_head = &(channel->all_queries);
- for (list_node = list_head->next; list_node != list_head; )
+ if (!ares__is_list_empty(&(channel->all_queries)))
{
- query = list_node->data;
- list_node = list_node->next; /* since we're deleting the query */
- query->callback(query->arg, ARES_ECANCELLED, 0, NULL, 0);
- ares__free_query(query);
- }
-#ifndef NDEBUG
- /* Freeing the query should remove it from all the lists in which it sits,
- * so all query lists should be empty now.
- */
- assert(ares__is_list_empty(&(channel->all_queries)));
- for (i = 0; i < ARES_QID_TABLE_SIZE; i++)
+ /* Swap list heads, so that only those queries which were present on entry
+ * into this function are cancelled. New queries added by callbacks of
+ * queries being cancelled will not be cancelled themselves.
+ */
+ list_head = &(channel->all_queries);
+ list_head_copy.prev = list_head->prev;
+ list_head_copy.next = list_head->next;
+ list_head_copy.prev->next = &list_head_copy;
+ list_head_copy.next->prev = &list_head_copy;
+ list_head->prev = list_head;
+ list_head->next = list_head;
+ for (list_node = list_head_copy.next; list_node != &list_head_copy; )
{
- assert(ares__is_list_empty(&(channel->queries_by_qid[i])));
+ query = list_node->data;
+ list_node = list_node->next; /* since we're deleting the query */
+ query->callback(query->arg, ARES_ECANCELLED, 0, NULL, 0);
+ ares__free_query(query);
}
- for (i = 0; i < ARES_TIMEOUT_TABLE_SIZE; i++)
- {
- assert(ares__is_list_empty(&(channel->queries_by_timeout[i])));
- }
-#endif
- if (!(channel->flags & ARES_FLAG_STAYOPEN))
+ }
+ if (!(channel->flags & ARES_FLAG_STAYOPEN) && ares__is_list_empty(&(channel->all_queries)))
{
if (channel->servers)
{
diff --git a/ares_create_query.c b/ares_create_query.c
new file mode 100644
index 0000000..07d7570
--- /dev/null
+++ b/ares_create_query.c
@@ -0,0 +1,202 @@
+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#include "ares_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#else
+# include "nameser.h"
+#endif
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+# include <arpa/nameser_compat.h>
+#endif
+
+#include "ares.h"
+#include "ares_dns.h"
+#include "ares_private.h"
+
+#ifndef T_OPT
+# define T_OPT 41 /* EDNS0 option (meta-RR) */
+#endif
+
+/* Header format, from RFC 1035:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ID |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QDCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ANCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | NSCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ARCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *
+ * AA, TC, RA, and RCODE are only set in responses. Brief description
+ * of the remaining fields:
+ * ID Identifier to match responses with queries
+ * QR Query (0) or response (1)
+ * Opcode For our purposes, always QUERY
+ * RD Recursion desired
+ * Z Reserved (zero)
+ * QDCOUNT Number of queries
+ * ANCOUNT Number of answers
+ * NSCOUNT Number of name server records
+ * ARCOUNT Number of additional records
+ *
+ * Question format, from RFC 1035:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | |
+ * / QNAME /
+ * / /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QTYPE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QCLASS |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *
+ * The query name is encoded as a series of labels, each represented
+ * as a one-byte length (maximum 63) followed by the text of the
+ * label. The list is terminated by a label of length zero (which can
+ * be thought of as the root domain).
+ */
+
+int ares_create_query(const char *name, int dnsclass, int type,
+ unsigned short id, int rd, unsigned char **bufp,
+ int *buflenp, int max_udp_size)
+{
+ size_t len;
+ unsigned char *q;
+ const char *p;
+ size_t buflen;
+ unsigned char *buf;
+
+ /* Set our results early, in case we bail out early with an error. */
+ *buflenp = 0;
+ *bufp = NULL;
+
+ /* Allocate a memory area for the maximum size this packet might need. +2
+ * is for the length byte and zero termination if no dots or ecscaping is
+ * used.
+ */
+ len = strlen(name) + 2 + HFIXEDSZ + QFIXEDSZ +
+ (max_udp_size ? EDNSFIXEDSZ : 0);
+ buf = ares_malloc(len);
+ if (!buf)
+ return ARES_ENOMEM;
+
+ /* Set up the header. */
+ q = buf;
+ memset(q, 0, HFIXEDSZ);
+ DNS_HEADER_SET_QID(q, id);
+ DNS_HEADER_SET_OPCODE(q, QUERY);
+ if (rd) {
+ DNS_HEADER_SET_RD(q, 1);
+ }
+ else {
+ DNS_HEADER_SET_RD(q, 0);
+ }
+ DNS_HEADER_SET_QDCOUNT(q, 1);
+
+ if (max_udp_size) {
+ DNS_HEADER_SET_ARCOUNT(q, 1);
+ }
+
+ /* A name of "." is a screw case for the loop below, so adjust it. */
+ if (strcmp(name, ".") == 0)
+ name++;
+
+ /* Start writing out the name after the header. */
+ q += HFIXEDSZ;
+ while (*name)
+ {
+ if (*name == '.') {
+ ares_free (buf);
+ return ARES_EBADNAME;
+ }
+
+ /* Count the number of bytes in this label. */
+ len = 0;
+ for (p = name; *p && *p != '.'; p++)
+ {
+ if (*p == '\\' && *(p + 1) != 0)
+ p++;
+ len++;
+ }
+ if (len > MAXLABEL) {
+ ares_free (buf);
+ return ARES_EBADNAME;
+ }
+
+ /* Encode the length and copy the data. */
+ *q++ = (unsigned char)len;
+ for (p = name; *p && *p != '.'; p++)
+ {
+ if (*p == '\\' && *(p + 1) != 0)
+ p++;
+ *q++ = *p;
+ }
+
+ /* Go to the next label and repeat, unless we hit the end. */
+ if (!*p)
+ break;
+ name = p + 1;
+ }
+
+ /* Add the zero-length label at the end. */
+ *q++ = 0;
+
+ /* Finish off the question with the type and class. */
+ DNS_QUESTION_SET_TYPE(q, type);
+ DNS_QUESTION_SET_CLASS(q, dnsclass);
+
+ q += QFIXEDSZ;
+ if (max_udp_size)
+ {
+ memset(q, 0, EDNSFIXEDSZ);
+ q++;
+ DNS_RR_SET_TYPE(q, T_OPT);
+ DNS_RR_SET_CLASS(q, max_udp_size);
+ q += (EDNSFIXEDSZ-1);
+ }
+ buflen = (q - buf);
+
+ /* Reject names that are longer than the maximum of 255 bytes that's
+ * specified in RFC 1035 ("To simplify implementations, the total length of
+ * a domain name (i.e., label octets and label length octets) is restricted
+ * to 255 octets or less."). */
+ if (buflen > (MAXCDNAME + HFIXEDSZ + QFIXEDSZ +
+ (max_udp_size ? EDNSFIXEDSZ : 0))) {
+ ares_free (buf);
+ return ARES_EBADNAME;
+ }
+
+ /* we know this fits in an int at this point */
+ *buflenp = (int) buflen;
+ *bufp = buf;
+
+ return ARES_SUCCESS;
+}
diff --git a/ares_data.c b/ares_data.c
index a2477be..f891113 100644
--- a/ares_data.c
+++ b/ares_data.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2009-2010 by Daniel Stenberg
+/* Copyright (C) 2009-2013 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -67,7 +67,7 @@ void ares_free_data(void *dataptr)
if (ptr->data.mx_reply.next)
ares_free_data(ptr->data.mx_reply.next);
if (ptr->data.mx_reply.host)
- free(ptr->data.mx_reply.host);
+ ares_free(ptr->data.mx_reply.host);
break;
case ARES_DATATYPE_SRV_REPLY:
@@ -75,15 +75,16 @@ void ares_free_data(void *dataptr)
if (ptr->data.srv_reply.next)
ares_free_data(ptr->data.srv_reply.next);
if (ptr->data.srv_reply.host)
- free(ptr->data.srv_reply.host);
+ ares_free(ptr->data.srv_reply.host);
break;
case ARES_DATATYPE_TXT_REPLY:
+ case ARES_DATATYPE_TXT_EXT:
if (ptr->data.txt_reply.next)
ares_free_data(ptr->data.txt_reply.next);
if (ptr->data.txt_reply.txt)
- free(ptr->data.txt_reply.txt);
+ ares_free(ptr->data.txt_reply.txt);
break;
case ARES_DATATYPE_ADDR_NODE:
@@ -92,11 +93,38 @@ void ares_free_data(void *dataptr)
ares_free_data(ptr->data.addr_node.next);
break;
+ case ARES_DATATYPE_ADDR_PORT_NODE:
+
+ if (ptr->data.addr_port_node.next)
+ ares_free_data(ptr->data.addr_port_node.next);
+ break;
+
+ case ARES_DATATYPE_NAPTR_REPLY:
+
+ if (ptr->data.naptr_reply.next)
+ ares_free_data(ptr->data.naptr_reply.next);
+ if (ptr->data.naptr_reply.flags)
+ ares_free(ptr->data.naptr_reply.flags);
+ if (ptr->data.naptr_reply.service)
+ ares_free(ptr->data.naptr_reply.service);
+ if (ptr->data.naptr_reply.regexp)
+ ares_free(ptr->data.naptr_reply.regexp);
+ if (ptr->data.naptr_reply.replacement)
+ ares_free(ptr->data.naptr_reply.replacement);
+ break;
+
+ case ARES_DATATYPE_SOA_REPLY:
+ if (ptr->data.soa_reply.nsname)
+ ares_free(ptr->data.soa_reply.nsname);
+ if (ptr->data.soa_reply.hostmaster)
+ ares_free(ptr->data.soa_reply.hostmaster);
+ break;
+
default:
return;
}
- free(ptr);
+ ares_free(ptr);
}
@@ -115,7 +143,7 @@ void *ares_malloc_data(ares_datatype type)
{
struct ares_data *ptr;
- ptr = malloc(sizeof(struct ares_data));
+ ptr = ares_malloc(sizeof(struct ares_data));
if (!ptr)
return NULL;
@@ -135,10 +163,14 @@ void *ares_malloc_data(ares_datatype type)
ptr->data.srv_reply.port = 0;
break;
+ case ARES_DATATYPE_TXT_EXT:
+ ptr->data.txt_ext.record_start = 0;
+ /* FALLTHROUGH */
+
case ARES_DATATYPE_TXT_REPLY:
ptr->data.txt_reply.next = NULL;
ptr->data.txt_reply.txt = NULL;
- ptr->data.txt_reply.length = 0;
+ ptr->data.txt_reply.length = 0;
break;
case ARES_DATATYPE_ADDR_NODE:
@@ -148,8 +180,37 @@ void *ares_malloc_data(ares_datatype type)
sizeof(ptr->data.addr_node.addrV6));
break;
+ case ARES_DATATYPE_ADDR_PORT_NODE:
+ ptr->data.addr_port_node.next = NULL;
+ ptr->data.addr_port_node.family = 0;
+ ptr->data.addr_port_node.udp_port = 0;
+ ptr->data.addr_port_node.tcp_port = 0;
+ memset(&ptr->data.addr_port_node.addrV6, 0,
+ sizeof(ptr->data.addr_port_node.addrV6));
+ break;
+
+ case ARES_DATATYPE_NAPTR_REPLY:
+ ptr->data.naptr_reply.next = NULL;
+ ptr->data.naptr_reply.flags = NULL;
+ ptr->data.naptr_reply.service = NULL;
+ ptr->data.naptr_reply.regexp = NULL;
+ ptr->data.naptr_reply.replacement = NULL;
+ ptr->data.naptr_reply.order = 0;
+ ptr->data.naptr_reply.preference = 0;
+ break;
+
+ case ARES_DATATYPE_SOA_REPLY:
+ ptr->data.soa_reply.nsname = NULL;
+ ptr->data.soa_reply.hostmaster = NULL;
+ ptr->data.soa_reply.serial = 0;
+ ptr->data.soa_reply.refresh = 0;
+ ptr->data.soa_reply.retry = 0;
+ ptr->data.soa_reply.expire = 0;
+ ptr->data.soa_reply.minttl = 0;
+ break;
+
default:
- free(ptr);
+ ares_free(ptr);
return NULL;
}
@@ -158,33 +219,3 @@ void *ares_malloc_data(ares_datatype type)
return &ptr->data;
}
-
-
-/*
-** ares_get_datatype() - c-ares internal helper function.
-**
-** This function returns the ares_datatype of the data stored in a
-** private ares_data struct when given the public API pointer.
-*/
-
-ares_datatype ares_get_datatype(void * dataptr)
-{
- struct ares_data *ptr;
-
-#ifdef __INTEL_COMPILER
-# pragma warning(push)
-# pragma warning(disable:1684)
- /* 1684: conversion from pointer to same-sized integral type */
-#endif
-
- ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data));
-
-#ifdef __INTEL_COMPILER
-# pragma warning(pop)
-#endif
-
- if (ptr->mark == ARES_DATATYPE_MARK)
- return ptr->type;
-
- return ARES_DATATYPE_UNKNOWN;
-}
diff --git a/ares_data.h b/ares_data.h
index de1608b..ffee2be 100644
--- a/ares_data.h
+++ b/ares_data.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2009-2010 by Daniel Stenberg
+/* Copyright (C) 2009-2013 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -18,14 +18,18 @@ typedef enum {
ARES_DATATYPE_UNKNOWN = 1, /* unknown data type - introduced in 1.7.0 */
ARES_DATATYPE_SRV_REPLY, /* struct ares_srv_reply - introduced in 1.7.0 */
ARES_DATATYPE_TXT_REPLY, /* struct ares_txt_reply - introduced in 1.7.0 */
+ ARES_DATATYPE_TXT_EXT, /* struct ares_txt_ext - introduced in 1.11.0 */
ARES_DATATYPE_ADDR_NODE, /* struct ares_addr_node - introduced in 1.7.1 */
ARES_DATATYPE_MX_REPLY, /* struct ares_mx_reply - introduced in 1.7.2 */
+ ARES_DATATYPE_NAPTR_REPLY,/* struct ares_naptr_reply - introduced in 1.7.6 */
+ ARES_DATATYPE_SOA_REPLY, /* struct ares_soa_reply - introduced in 1.9.0 */
#if 0
ARES_DATATYPE_ADDR6TTL, /* struct ares_addrttl */
ARES_DATATYPE_ADDRTTL, /* struct ares_addr6ttl */
ARES_DATATYPE_HOSTENT, /* struct hostent */
ARES_DATATYPE_OPTIONS, /* struct ares_options */
#endif
+ ARES_DATATYPE_ADDR_PORT_NODE, /* struct ares_addr_port_node - introduced in 1.11.0 */
ARES_DATATYPE_LAST /* not used - introduced in 1.7.0 */
} ares_datatype;
@@ -53,13 +57,16 @@ struct ares_data {
ares_datatype type; /* Actual data type identifier. */
unsigned int mark; /* Private ares_data signature. */
union {
- struct ares_txt_reply txt_reply;
- struct ares_srv_reply srv_reply;
- struct ares_addr_node addr_node;
- struct ares_mx_reply mx_reply;
+ struct ares_txt_reply txt_reply;
+ struct ares_txt_ext txt_ext;
+ struct ares_srv_reply srv_reply;
+ struct ares_addr_node addr_node;
+ struct ares_addr_port_node addr_port_node;
+ struct ares_mx_reply mx_reply;
+ struct ares_naptr_reply naptr_reply;
+ struct ares_soa_reply soa_reply;
} data;
};
void *ares_malloc_data(ares_datatype type);
-ares_datatype ares_get_datatype(void * dataptr);
diff --git a/ares_destroy.c b/ares_destroy.c
index 5e274da..8aa4223 100644
--- a/ares_destroy.c
+++ b/ares_destroy.c
@@ -1,6 +1,6 @@
/* Copyright 1998 by the Massachusetts Institute of Technology.
- * Copyright (C) 2004-2010 by Daniel Stenberg
+ * Copyright (C) 2004-2011 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -16,8 +16,9 @@
*/
#include "ares_setup.h"
+
#include <assert.h>
-#include <stdlib.h>
+
#include "ares.h"
#include "ares_private.h"
@@ -26,13 +27,15 @@ void ares_destroy_options(struct ares_options *options)
int i;
if(options->servers)
- free(options->servers);
+ ares_free(options->servers);
for (i = 0; i < options->ndomains; i++)
- free(options->domains[i]);
- free(options->domains);
+ ares_free(options->domains[i]);
+ if(options->domains)
+ ares_free(options->domains);
if(options->sortlist)
- free(options->sortlist);
- free(options->lookups);
+ ares_free(options->sortlist);
+ if(options->lookups)
+ ares_free(options->lookups);
}
void ares_destroy(ares_channel channel)
@@ -72,17 +75,17 @@ void ares_destroy(ares_channel channel)
if (channel->domains) {
for (i = 0; i < channel->ndomains; i++)
- free(channel->domains[i]);
- free(channel->domains);
+ ares_free(channel->domains[i]);
+ ares_free(channel->domains);
}
if(channel->sortlist)
- free(channel->sortlist);
+ ares_free(channel->sortlist);
if (channel->lookups)
- free(channel->lookups);
+ ares_free(channel->lookups);
- free(channel);
+ ares_free(channel);
}
void ares__destroy_servers_state(ares_channel channel)
@@ -98,7 +101,7 @@ void ares__destroy_servers_state(ares_channel channel)
ares__close_sockets(channel, server);
assert(ares__is_list_empty(&server->queries_to_server));
}
- free(channel->servers);
+ ares_free(channel->servers);
channel->servers = NULL;
}
channel->nservers = -1;
diff --git a/ares_dns.h b/ares_dns.h
index 6893c02..79f993b 100644
--- a/ares_dns.h
+++ b/ares_dns.h
@@ -1,5 +1,7 @@
+#ifndef HEADER_CARES_DNS_H
+#define HEADER_CARES_DNS_H
-/* Copyright 1998 by the Massachusetts Institute of Technology.
+/* Copyright 1998, 2011 by the Massachusetts Institute of Technology.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -14,12 +16,23 @@
* without express or implied warranty.
*/
-#ifndef ARES__DNS_H
-#define ARES__DNS_H
+/*
+ * Macro DNS__16BIT reads a network short (16 bit) given in network
+ * byte order, and returns its value as an unsigned short.
+ */
+#define DNS__16BIT(p) ((unsigned short)((unsigned int) 0xffff & \
+ (((unsigned int)((unsigned char)(p)[0]) << 8U) | \
+ ((unsigned int)((unsigned char)(p)[1])))))
-#define DNS__16BIT(p) (((p)[0] << 8) | (p)[1])
-#define DNS__32BIT(p) (((p)[0] << 24) | ((p)[1] << 16) | \
- ((p)[2] << 8) | (p)[3])
+/*
+ * Macro DNS__32BIT reads a network long (32 bit) given in network
+ * byte order, and returns its value as an unsigned int.
+ */
+#define DNS__32BIT(p) ((unsigned int) \
+ (((unsigned int)((unsigned char)(p)[0]) << 24U) | \
+ ((unsigned int)((unsigned char)(p)[1]) << 16U) | \
+ ((unsigned int)((unsigned char)(p)[2]) << 8U) | \
+ ((unsigned int)((unsigned char)(p)[3]))))
#define DNS__SET16BIT(p, v) (((p)[0] = (unsigned char)(((v) >> 8) & 0xff)), \
((p)[1] = (unsigned char)((v) & 0xff)))
@@ -82,9 +95,9 @@
#define DNS_RR_LEN(r) DNS__16BIT((r) + 8)
/* Macros for constructing the fixed part of a DNS resource record */
-#define DNS_RR_SET_TYPE(r) DNS__SET16BIT(r, v)
-#define DNS_RR_SET_CLASS(r) DNS__SET16BIT((r) + 2, v)
-#define DNS_RR_SET_TTL(r) DNS__SET32BIT((r) + 4, v)
-#define DNS_RR_SET_LEN(r) DNS__SET16BIT((r) + 8, v)
+#define DNS_RR_SET_TYPE(r, v) DNS__SET16BIT(r, v)
+#define DNS_RR_SET_CLASS(r, v) DNS__SET16BIT((r) + 2, v)
+#define DNS_RR_SET_TTL(r, v) DNS__SET32BIT((r) + 4, v)
+#define DNS_RR_SET_LEN(r, v) DNS__SET16BIT((r) + 8, v)
-#endif /* ARES__DNS_H */
+#endif /* HEADER_CARES_DNS_H */
diff --git a/ares_expand_name.c b/ares_expand_name.c
index e3eccd2..3a38e67 100644
--- a/ares_expand_name.c
+++ b/ares_expand_name.c
@@ -1,5 +1,5 @@
-/* Copyright 1998 by the Massachusetts Institute of Technology.
+/* Copyright 1998, 2011 by the Massachusetts Institute of Technology.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -31,10 +28,13 @@
# include <arpa/nameser_compat.h>
#endif
-#include <stdlib.h>
#include "ares.h"
+#include "ares_nowarn.h"
#include "ares_private.h" /* for the memdebug */
+/* Maximum number of indirections allowed for a name */
+#define MAX_INDIRS 50
+
static int name_length(const unsigned char *encoded, const unsigned char *abuf,
int alen);
@@ -69,7 +69,7 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
char *q;
const unsigned char *p;
union {
- ssize_t sig;
+ ares_ssize_t sig;
size_t uns;
} nlen;
@@ -77,7 +77,7 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
if (nlen.sig < 0)
return ARES_EBADNAME;
- *s = malloc(nlen.uns + 1);
+ *s = ares_malloc(nlen.uns + 1);
if (!*s)
return ARES_ENOMEM;
q = *s;
@@ -91,9 +91,9 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
/* indirect root label (like 0xc0 0x0c) is 2 bytes long (stupid, but
valid) */
if ((*encoded & INDIR_MASK) == INDIR_MASK)
- *enclen = 2;
+ *enclen = 2L;
else
- *enclen = 1; /* the caller should move one byte to get past this */
+ *enclen = 1L; /* the caller should move one byte to get past this */
return ARES_SUCCESS;
}
@@ -106,7 +106,7 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
{
if (!indir)
{
- *enclen = p + 2 - encoded;
+ *enclen = aresx_uztosl(p + 2U - encoded);
indir = 1;
}
p = abuf + ((*p & ~INDIR_MASK) << 8 | *(p + 1));
@@ -126,13 +126,13 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
}
}
if (!indir)
- *enclen = p + 1 - encoded;
+ *enclen = aresx_uztosl(p + 1U - encoded);
/* Nuke the trailing period if we wrote one. */
if (q > *s)
*(q - 1) = 0;
else
- *q = 0; /* zero terminate */
+ *q = 0; /* zero terminate; LCOV_EXCL_LINE: empty names exit above */
return ARES_SUCCESS;
}
@@ -143,15 +143,16 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
static int name_length(const unsigned char *encoded, const unsigned char *abuf,
int alen)
{
- int n = 0, offset, indir = 0;
+ int n = 0, offset, indir = 0, top;
/* Allow the caller to pass us abuf + alen and have us check for it. */
- if (encoded == abuf + alen)
+ if (encoded >= abuf + alen)
return -1;
while (*encoded)
{
- if ((*encoded & INDIR_MASK) == INDIR_MASK)
+ top = (*encoded & INDIR_MASK);
+ if (top == INDIR_MASK)
{
/* Check the offset and go there. */
if (encoded + 1 >= abuf + alen)
@@ -164,10 +165,11 @@ static int name_length(const unsigned char *encoded, const unsigned char *abuf,
/* If we've seen more indirects than the message length,
* then there's a loop.
*/
- if (++indir > alen)
+ ++indir;
+ if (indir > alen || indir > MAX_INDIRS)
return -1;
}
- else
+ else if (top == 0x00)
{
offset = *encoded;
if (encoded + offset + 1 >= abuf + alen)
@@ -180,6 +182,13 @@ static int name_length(const unsigned char *encoded, const unsigned char *abuf,
}
n++;
}
+ else
+ {
+ /* RFC 1035 4.1.4 says other options (01, 10) for top 2
+ * bits are reserved.
+ */
+ return -1;
+ }
}
/* If there were any labels at all, then the number of dots is one
diff --git a/ares_expand_string.c b/ares_expand_string.c
index f24cccf..d35df75 100644
--- a/ares_expand_string.c
+++ b/ares_expand_string.c
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -28,8 +25,6 @@
# include "nameser.h"
#endif
-#include <string.h>
-#include <stdlib.h>
#include "ares.h"
#include "ares_private.h" /* for the memdebug */
@@ -46,7 +41,7 @@ int ares_expand_string(const unsigned char *encoded,
{
unsigned char *q;
union {
- ssize_t sig;
+ ares_ssize_t sig;
size_t uns;
} elen;
@@ -59,7 +54,7 @@ int ares_expand_string(const unsigned char *encoded,
encoded++;
- *s = malloc(elen.uns+1);
+ *s = ares_malloc(elen.uns+1);
if (*s == NULL)
return ARES_ENOMEM;
q = *s;
diff --git a/ares_fds.c b/ares_fds.c
index ac5eedb..f405fc0 100644
--- a/ares_fds.c
+++ b/ares_fds.c
@@ -16,10 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
#include "ares.h"
#include "ares_nowarn.h"
#include "ares_private.h"
diff --git a/ares_free_hostent.c b/ares_free_hostent.c
index 349d379..cfc5f81 100644
--- a/ares_free_hostent.c
+++ b/ares_free_hostent.c
@@ -15,7 +15,6 @@
*/
#include "ares_setup.h"
-#include <stdlib.h>
#ifdef HAVE_NETDB_H
#include <netdb.h>
@@ -31,12 +30,12 @@ void ares_free_hostent(struct hostent *host)
if (!host)
return;
- free((char *)(host->h_name));
+ ares_free((char *)(host->h_name));
for (p = host->h_aliases; *p; p++)
- free(*p);
- free(host->h_aliases);
- free(host->h_addr_list[0]); /* no matter if there is one or many entries,
+ ares_free(*p);
+ ares_free(host->h_aliases);
+ ares_free(host->h_addr_list[0]); /* no matter if there is one or many entries,
there is only one malloc for all of them */
- free(host->h_addr_list);
- free(host);
+ ares_free(host->h_addr_list);
+ ares_free(host);
}
diff --git a/ares_free_string.c b/ares_free_string.c
index e0545c1..024992e 100644
--- a/ares_free_string.c
+++ b/ares_free_string.c
@@ -15,11 +15,11 @@
*/
#include "ares_setup.h"
-#include <stdlib.h>
+
#include "ares.h"
#include "ares_private.h"
void ares_free_string(void *str)
{
- free(str);
+ ares_free(str);
}
diff --git a/ares_gethostbyaddr.c b/ares_gethostbyaddr.c
index 4b4c8a7..9258919 100644
--- a/ares_gethostbyaddr.c
+++ b/ares_gethostbyaddr.c
@@ -15,9 +15,6 @@
*/
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -36,12 +33,8 @@
# include <arpa/nameser_compat.h>
#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "ares.h"
-#include "inet_net_pton.h"
+#include "ares_inet_net_pton.h"
#include "ares_platform.h"
#include "ares_private.h"
@@ -86,7 +79,7 @@ void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
return;
}
- aquery = malloc(sizeof(struct addr_query));
+ aquery = ares_malloc(sizeof(struct addr_query));
if (!aquery)
{
callback(arg, ARES_ENOMEM, 0, NULL);
@@ -176,7 +169,7 @@ static void end_aquery(struct addr_query *aquery, int status,
aquery->callback(aquery->arg, status, aquery->timeouts, host);
if (host)
ares_free_hostent(host);
- free(aquery);
+ ares_free(aquery);
}
static int file_lookup(struct ares_addr *addr, struct hostent **host)
diff --git a/ares_gethostbyname.c b/ares_gethostbyname.c
index ad89dc2..caab6ae 100644
--- a/ares_gethostbyname.c
+++ b/ares_gethostbyname.c
@@ -1,5 +1,5 @@
-/* Copyright 1998 by the Massachusetts Institute of Technology.
+/* Copyright 1998, 2011, 2013 by the Massachusetts Institute of Technology.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -37,18 +34,15 @@
# include <arpa/nameser_compat.h>
#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include "ares.h"
-#include "inet_net_pton.h"
+#include "ares_inet_net_pton.h"
#include "bitncmp.h"
#include "ares_platform.h"
+#include "ares_nowarn.h"
#include "ares_private.h"
#ifdef WATT32
@@ -105,18 +99,18 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
return;
/* Allocate and fill in the host query structure. */
- hquery = malloc(sizeof(struct host_query));
+ hquery = ares_malloc(sizeof(struct host_query));
if (!hquery)
{
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
hquery->channel = channel;
- hquery->name = strdup(name);
+ hquery->name = ares_strdup(name);
hquery->want_family = family;
hquery->sent_family = -1; /* nothing is sent yet */
if (!hquery->name) {
- free(hquery);
+ ares_free(hquery);
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
@@ -194,11 +188,14 @@ static void host_callback(void *arg, int status, int timeouts,
else if (hquery->sent_family == AF_INET6)
{
status = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL);
- if ((status == ARES_ENODATA || status == ARES_EBADRESP) &&
- hquery->want_family == AF_UNSPEC) {
+ if ((status == ARES_ENODATA || status == ARES_EBADRESP ||
+ (status == ARES_SUCCESS && host && host->h_addr_list[0] == NULL)) &&
+ hquery->want_family == AF_UNSPEC) {
/* The query returned something but either there were no AAAA
records (e.g. just CNAME) or the response was malformed. Try
looking up A instead. */
+ if (host)
+ ares_free_hostent(host);
hquery->sent_family = AF_INET;
ares_search(hquery->channel, hquery->name, C_IN, T_A,
host_callback, hquery);
@@ -230,8 +227,8 @@ static void end_hquery(struct host_query *hquery, int status,
hquery->callback(hquery->arg, status, hquery->timeouts, host);
if (host)
ares_free_hostent(host);
- free(hquery->name);
- free(hquery);
+ ares_free(hquery->name);
+ ares_free(hquery);
}
/* If the name looks like an IP address, fake up a host entry, end the
@@ -290,7 +287,7 @@ static int fake_hostent(const char *name, int family,
addrs[0] = (char *)&in6;
}
/* Duplicate the name, to avoid a constness violation. */
- hostent.h_name = strdup(name);
+ hostent.h_name = ares_strdup(name);
if (!hostent.h_name)
{
callback(arg, ARES_ENOMEM, 0, NULL);
@@ -300,11 +297,11 @@ static int fake_hostent(const char *name, int family,
/* Fill in the rest of the host structure and terminate the query. */
addrs[1] = NULL;
hostent.h_aliases = aliases;
- hostent.h_addrtype = family;
+ hostent.h_addrtype = aresx_sitoss(family);
hostent.h_addr_list = addrs;
callback(arg, ARES_SUCCESS, 0, &hostent);
- free((char *)(hostent.h_name));
+ ares_free((char *)(hostent.h_name));
return 1;
}
@@ -466,8 +463,8 @@ static int get_address_index(const struct in_addr *addr,
}
else
{
- if (!ares_bitncmp(&addr->s_addr, &sortlist[i].addrV4.s_addr,
- sortlist[i].mask.bits))
+ if (!ares__bitncmp(&addr->s_addr, &sortlist[i].addrV4.s_addr,
+ sortlist[i].mask.bits))
break;
}
}
@@ -514,10 +511,8 @@ static int get6_address_index(const struct ares_in6_addr *addr,
{
if (sortlist[i].family != AF_INET6)
continue;
- if (!ares_bitncmp(addr,
- &sortlist[i].addrV6,
- sortlist[i].mask.bits))
- break;
+ if (!ares__bitncmp(addr, &sortlist[i].addrV6, sortlist[i].mask.bits))
+ break;
}
return i;
}
diff --git a/ares_getnameinfo.c b/ares_getnameinfo.c
index 82e261d..c77b1f8 100644
--- a/ares_getnameinfo.c
+++ b/ares_getnameinfo.c
@@ -22,9 +22,6 @@
# endif
#endif
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -47,17 +44,8 @@
#include <net/if.h>
#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "ares.h"
#include "ares_ipv6.h"
-#include "inet_ntop.h"
#include "ares_nowarn.h"
#include "ares_private.h"
@@ -89,7 +77,7 @@ static char *lookup_service(unsigned short port, int flags,
static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int scopeid,
char *buf, size_t buflen);
#endif
-static char *ares_striendstr(const char *s1, const char *s2);
+STATIC_TESTABLE char *ares_striendstr(const char *s1, const char *s2);
void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa,
ares_socklen_t salen,
@@ -175,7 +163,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa,
/* This is where a DNS lookup becomes necessary */
else
{
- niquery = malloc(sizeof(struct nameinfo_query));
+ niquery = ares_malloc(sizeof(struct nameinfo_query));
if (!niquery)
{
callback(arg, ARES_ENOMEM, 0, NULL, NULL);
@@ -188,7 +176,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa,
if (sa->sa_family == AF_INET)
{
niquery->family = AF_INET;
- memcpy(&niquery->addr.addr4, addr, sizeof(struct in_addr));
+ memcpy(&niquery->addr.addr4, addr, sizeof(niquery->addr.addr4));
ares_gethostbyaddr(channel, &addr->sin_addr,
sizeof(struct in_addr), AF_INET,
nameinfo_callback, niquery);
@@ -196,7 +184,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa,
else
{
niquery->family = AF_INET6;
- memcpy(&niquery->addr.addr6, addr6, sizeof(struct ares_in6_addr));
+ memcpy(&niquery->addr.addr6, addr6, sizeof(niquery->addr.addr6));
ares_gethostbyaddr(channel, &addr6->sin6_addr,
sizeof(struct ares_in6_addr), AF_INET6,
nameinfo_callback, niquery);
@@ -246,7 +234,7 @@ static void nameinfo_callback(void *arg, int status, int timeouts,
niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts,
(char *)(host->h_name),
service);
- free(niquery);
+ ares_free(niquery);
return;
}
/* We couldn't find the host, but it's OK, we can use the IP */
@@ -277,11 +265,11 @@ static void nameinfo_callback(void *arg, int status, int timeouts,
}
niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts, ipbuf,
service);
- free(niquery);
+ ares_free(niquery);
return;
}
niquery->callback(niquery->arg, status, niquery->timeouts, NULL, NULL);
- free(niquery);
+ ares_free(niquery);
}
static char *lookup_service(unsigned short port, int flags,
@@ -293,6 +281,8 @@ static char *lookup_service(unsigned short port, int flags,
struct servent se;
#endif
char tmpbuf[4096];
+ char *name;
+ size_t name_len;
if (port)
{
@@ -309,12 +299,13 @@ static char *lookup_service(unsigned short port, int flags,
else
proto = "tcp";
#ifdef HAVE_GETSERVBYPORT_R
+ memset(&se, 0, sizeof(se));
sep = &se;
memset(tmpbuf, 0, sizeof(tmpbuf));
#if GETSERVBYPORT_R_ARGS == 6
if (getservbyport_r(port, proto, &se, (void *)tmpbuf,
sizeof(tmpbuf), &sep) != 0)
- sep = NULL;
+ sep = NULL; /* LCOV_EXCL_LINE: buffer large so this never fails */
#elif GETSERVBYPORT_R_ARGS == 5
sep = getservbyport_r(port, proto, &se, (void *)tmpbuf,
sizeof(tmpbuf));
@@ -335,17 +326,23 @@ static char *lookup_service(unsigned short port, int flags,
#endif
}
if (sep && sep->s_name)
- /* get service name */
- strcpy(tmpbuf, sep->s_name);
+ {
+ /* get service name */
+ name = sep->s_name;
+ }
else
- /* get port as a string */
- sprintf(tmpbuf, "%u", (unsigned int)ntohs(port));
- if (strlen(tmpbuf) < buflen)
+ {
+ /* get port as a string */
+ sprintf(tmpbuf, "%u", (unsigned int)ntohs(port));
+ name = tmpbuf;
+ }
+ name_len = strlen(name);
+ if (name_len < buflen)
/* return it if buffer big enough */
- strcpy(buf, tmpbuf);
+ memcpy(buf, name, name_len + 1);
else
/* avoid reusing previous one */
- buf[0] = '\0';
+ buf[0] = '\0'; /* LCOV_EXCL_LINE: no real service names are too big */
return buf;
}
buf[0] = '\0';
@@ -359,12 +356,9 @@ static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int flags,
#ifdef HAVE_IF_INDEXTONAME
int is_ll, is_mcll;
#endif
- static const char fmt_u[] = "%u";
- static const char fmt_lu[] = "%lu";
char tmpbuf[IF_NAMESIZE + 2];
size_t bufl;
- const char *fmt = (sizeof(addr6->sin6_scope_id) > sizeof(unsigned int))?
- fmt_lu:fmt_u;
+ int is_scope_long = sizeof(addr6->sin6_scope_id) > sizeof(unsigned int);
tmpbuf[0] = '%';
@@ -374,15 +368,38 @@ static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int flags,
if ((flags & ARES_NI_NUMERICSCOPE) ||
(!is_ll && !is_mcll))
{
- sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id);
+ if (is_scope_long)
+ {
+ sprintf(&tmpbuf[1], "%lu", (unsigned long)addr6->sin6_scope_id);
+ }
+ else
+ {
+ sprintf(&tmpbuf[1], "%u", (unsigned int)addr6->sin6_scope_id);
+ }
}
else
{
if (if_indextoname(addr6->sin6_scope_id, &tmpbuf[1]) == NULL)
- sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id);
+ {
+ if (is_scope_long)
+ {
+ sprintf(&tmpbuf[1], "%lu", (unsigned long)addr6->sin6_scope_id);
+ }
+ else
+ {
+ sprintf(&tmpbuf[1], "%u", (unsigned int)addr6->sin6_scope_id);
+ }
+ }
}
#else
- sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id);
+ if (is_scope_long)
+ {
+ sprintf(&tmpbuf[1], "%lu", (unsigned long)addr6->sin6_scope_id);
+ }
+ else
+ {
+ sprintf(&tmpbuf[1], "%u", (unsigned int)addr6->sin6_scope_id);
+ }
(void) flags;
#endif
tmpbuf[IF_NAMESIZE + 1] = '\0';
@@ -395,7 +412,7 @@ static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int flags,
#endif
/* Determines if s1 ends with the string in s2 (case-insensitive) */
-static char *ares_striendstr(const char *s1, const char *s2)
+STATIC_TESTABLE char *ares_striendstr(const char *s1, const char *s2)
{
const char *c1, *c2, *c1_begin;
int lo1, lo2;
@@ -421,7 +438,5 @@ static char *ares_striendstr(const char *s1, const char *s2)
c2++;
}
}
- if (c2 == c1 && c2 == NULL)
- return (char *)c1_begin;
- return NULL;
+ return (char *)c1_begin;
}
diff --git a/ares_getsock.c b/ares_getsock.c
index 72e467f..22d3446 100644
--- a/ares_getsock.c
+++ b/ares_getsock.c
@@ -14,10 +14,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
#include "ares.h"
#include "ares_private.h"
@@ -34,9 +30,7 @@ int ares_getsock(ares_channel channel,
/* Are there any active queries? */
int active_queries = !ares__is_list_empty(&(channel->all_queries));
- for (i = 0;
- (i < channel->nservers) && (sockindex < ARES_GETSOCK_MAXNUM);
- i++)
+ for (i = 0; i < channel->nservers; i++)
{
server = &channel->servers[i];
/* We only need to register interest in UDP sockets if we have
@@ -44,7 +38,7 @@ int ares_getsock(ares_channel channel,
*/
if (active_queries && server->udp_socket != ARES_SOCKET_BAD)
{
- if(sockindex >= numsocks)
+ if(sockindex >= numsocks || sockindex >= ARES_GETSOCK_MAXNUM)
break;
socks[sockindex] = server->udp_socket;
bitmap |= ARES_GETSOCK_READABLE(setbits, sockindex);
@@ -56,7 +50,7 @@ int ares_getsock(ares_channel channel,
*/
if (server->tcp_socket != ARES_SOCKET_BAD)
{
- if(sockindex >= numsocks)
+ if(sockindex >= numsocks || sockindex >= ARES_GETSOCK_MAXNUM)
break;
socks[sockindex] = server->tcp_socket;
bitmap |= ARES_GETSOCK_READABLE(setbits, sockindex);
diff --git a/ares_inet_net_pton.h b/ares_inet_net_pton.h
new file mode 100644
index 0000000..90da2cc
--- /dev/null
+++ b/ares_inet_net_pton.h
@@ -0,0 +1,25 @@
+#ifndef HEADER_CARES_INET_NET_PTON_H
+#define HEADER_CARES_INET_NET_PTON_H
+
+/* Copyright (C) 2005-2013 by Daniel Stenberg et al
+ *
+ * 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.
+ */
+
+#ifdef HAVE_INET_NET_PTON
+#define ares_inet_net_pton(w,x,y,z) inet_net_pton(w,x,y,z)
+#else
+int ares_inet_net_pton(int af, const char *src, void *dst, size_t size);
+#endif
+
+#endif /* HEADER_CARES_INET_NET_PTON_H */
diff --git a/ares_init.c b/ares_init.c
index 44d4cf9..f7b700b 100644
--- a/ares_init.c
+++ b/ares_init.c
@@ -1,6 +1,6 @@
/* Copyright 1998 by the Massachusetts Institute of Technology.
- * Copyright (C) 2007-2011 by Daniel Stenberg
+ * Copyright (C) 2007-2013 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -21,14 +21,6 @@
#include <sys/param.h>
#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -50,33 +42,30 @@
# include <arpa/nameser_compat.h>
#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+#if defined(ANDROID) || defined(__ANDROID__)
+#include <sys/system_properties.h>
+/* From the Bionic sources */
+#define DNS_PROP_NAME_PREFIX "net.dns"
+#define MAX_DNS_PROPERTIES 8
#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-
-#ifdef ANDROID
-#include <sys/system_properties.h>
+#if defined(CARES_USE_LIBRESOLV)
+#include <resolv.h>
#endif
#include "ares.h"
-#include "inet_net_pton.h"
+#include "ares_inet_net_pton.h"
#include "ares_library_init.h"
#include "ares_nowarn.h"
#include "ares_platform.h"
-#include "inet_ntop.h"
#include "ares_private.h"
#ifdef WATT32
#undef WIN32 /* Redefined in MingW/MSVC headers */
#endif
-static int init_by_options(ares_channel channel, const struct ares_options *options,
+static int init_by_options(ares_channel channel,
+ const struct ares_options *options,
int optmask);
static int init_by_environment(ares_channel channel);
static int init_by_resolv_conf(ares_channel channel);
@@ -91,15 +80,18 @@ static int set_options(ares_channel channel, const char *str);
static const char *try_option(const char *p, const char *q, const char *opt);
static int init_id_key(rc4_key* key,int key_data_len);
-#if !defined(WIN32) && !defined(WATT32)
-static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat);
-static int ip_addr(const char *s, ssize_t len, struct in_addr *addr);
+static int config_sortlist(struct apattern **sortlist, int *nsort,
+ const char *str);
+static int sortlist_alloc(struct apattern **sortlist, int *nsort,
+ struct apattern *pat);
+static int ip_addr(const char *s, ares_ssize_t len, struct in_addr *addr);
static void natural_mask(struct apattern *pat);
+#if !defined(WIN32) && !defined(WATT32) && \
+ !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV)
static int config_domain(ares_channel channel, char *str);
static int config_lookup(ares_channel channel, const char *str,
- const char *bindch, const char *filech);
-static int config_sortlist(struct apattern **sortlist, int *nsort,
- const char *str);
+ const char *bindch, const char *altbindch,
+ const char *filech);
static char *try_config(char *s, const char *opt, char scc);
#endif
@@ -137,9 +129,9 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
#endif
if (ares_library_initialized() != ARES_SUCCESS)
- return ARES_ENOTINITIALIZED;
+ return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
- channel = malloc(sizeof(struct ares_channeldata));
+ channel = ares_malloc(sizeof(struct ares_channeldata));
if (!channel) {
*channelptr = NULL;
return ARES_ENOMEM;
@@ -157,6 +149,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
channel->rotate = -1;
channel->udp_port = -1;
channel->tcp_port = -1;
+ channel->ednspsz = -1;
channel->socket_send_buffer_size = -1;
channel->socket_receive_buffer_size = -1;
channel->nservers = -1;
@@ -171,6 +164,10 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
channel->sock_state_cb_data = NULL;
channel->sock_create_cb = NULL;
channel->sock_create_cb_data = NULL;
+ channel->sock_config_cb = NULL;
+ channel->sock_config_cb_data = NULL;
+ channel->sock_funcs = NULL;
+ channel->sock_func_cb_data = NULL;
channel->last_server = 0;
channel->last_timeout_processed = (time_t)now.tv_sec;
@@ -194,18 +191,17 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
* precedence to lowest.
*/
- if (status == ARES_SUCCESS) {
- status = init_by_options(channel, options, optmask);
- if (status != ARES_SUCCESS)
- DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
- ares_strerror(status)));
- }
- if (status == ARES_SUCCESS) {
- status = init_by_environment(channel);
- if (status != ARES_SUCCESS)
- DEBUGF(fprintf(stderr, "Error: init_by_environment failed: %s\n",
- ares_strerror(status)));
+ status = init_by_options(channel, options, optmask);
+ if (status != ARES_SUCCESS) {
+ DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
+ ares_strerror(status)));
+ /* If we fail to apply user-specified options, fail the whole init process */
+ goto done;
}
+ status = init_by_environment(channel);
+ if (status != ARES_SUCCESS)
+ DEBUGF(fprintf(stderr, "Error: init_by_environment failed: %s\n",
+ ares_strerror(status)));
if (status == ARES_SUCCESS) {
status = init_by_resolv_conf(channel);
if (status != ARES_SUCCESS)
@@ -233,22 +229,23 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
ares_strerror(status)));
}
+done:
if (status != ARES_SUCCESS)
{
/* Something failed; clean up memory we may have allocated. */
if (channel->servers)
- free(channel->servers);
+ ares_free(channel->servers);
if (channel->domains)
{
for (i = 0; i < channel->ndomains; i++)
- free(channel->domains[i]);
- free(channel->domains);
+ ares_free(channel->domains[i]);
+ ares_free(channel->domains);
}
if (channel->sortlist)
- free(channel->sortlist);
+ ares_free(channel->sortlist);
if(channel->lookups)
- free(channel->lookups);
- free(channel);
+ ares_free(channel->lookups);
+ ares_free(channel);
return status;
}
@@ -267,8 +264,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
int ares_dup(ares_channel *dest, ares_channel src)
{
struct ares_options opts;
- struct ares_addr_node *servers;
- int ipv6_nservers = 0;
+ struct ares_addr_port_node *servers;
+ int non_v4_default_port = 0;
int i, rc;
int optmask;
@@ -278,7 +275,10 @@ int ares_dup(ares_channel *dest, ares_channel src)
which is most of them */
rc = ares_save_options(src, &opts, &optmask);
if(rc)
+ {
+ ares_destroy_options(&opts);
return rc;
+ }
/* Then create the new channel with those options */
rc = ares_init_options(dest, &opts, optmask);
@@ -292,27 +292,40 @@ int ares_dup(ares_channel *dest, ares_channel src)
/* Now clone the options that ares_save_options() doesn't support. */
(*dest)->sock_create_cb = src->sock_create_cb;
(*dest)->sock_create_cb_data = src->sock_create_cb_data;
+ (*dest)->sock_config_cb = src->sock_config_cb;
+ (*dest)->sock_config_cb_data = src->sock_config_cb_data;
+ (*dest)->sock_funcs = src->sock_funcs;
+ (*dest)->sock_func_cb_data = src->sock_func_cb_data;
- strncpy((*dest)->local_dev_name, src->local_dev_name, sizeof(src->local_dev_name));
+ strncpy((*dest)->local_dev_name, src->local_dev_name,
+ sizeof(src->local_dev_name));
(*dest)->local_ip4 = src->local_ip4;
memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
- /* Full name server cloning required when not all are IPv4 */
+ /* Full name server cloning required if there is a non-IPv4, or non-default port, nameserver */
for (i = 0; i < src->nservers; i++)
{
- if (src->servers[i].addr.family != AF_INET) {
- ipv6_nservers++;
+ if ((src->servers[i].addr.family != AF_INET) ||
+ (src->servers[i].addr.udp_port != 0) ||
+ (src->servers[i].addr.tcp_port != 0)) {
+ non_v4_default_port++;
break;
}
}
- if (ipv6_nservers) {
- rc = ares_get_servers(src, &servers);
- if (rc != ARES_SUCCESS)
+ if (non_v4_default_port) {
+ rc = ares_get_servers_ports(src, &servers);
+ if (rc != ARES_SUCCESS) {
+ ares_destroy(*dest);
+ *dest = NULL;
return rc;
- rc = ares_set_servers(*dest, servers);
+ }
+ rc = ares_set_servers_ports(*dest, servers);
ares_free_data(servers);
- if (rc != ARES_SUCCESS)
+ if (rc != ARES_SUCCESS) {
+ ares_destroy(*dest);
+ *dest = NULL;
return rc;
+ }
}
return ARES_SUCCESS; /* everything went fine */
@@ -337,8 +350,8 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
(*optmask) = (ARES_OPT_FLAGS|ARES_OPT_TRIES|ARES_OPT_NDOTS|
ARES_OPT_UDP_PORT|ARES_OPT_TCP_PORT|ARES_OPT_SOCK_STATE_CB|
ARES_OPT_SERVERS|ARES_OPT_DOMAINS|ARES_OPT_LOOKUPS|
- ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS) |
- (channel->optmask & ARES_OPT_ROTATE);
+ ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS);
+ (*optmask) |= (channel->rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE);
/* Copy easy stuff */
options->flags = channel->flags;
@@ -348,25 +361,29 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
options->timeout = channel->timeout;
options->tries = channel->tries;
options->ndots = channel->ndots;
- options->udp_port = (unsigned short)channel->udp_port;
- options->tcp_port = (unsigned short)channel->tcp_port;
+ options->udp_port = ntohs(aresx_sitous(channel->udp_port));
+ options->tcp_port = ntohs(aresx_sitous(channel->tcp_port));
options->sock_state_cb = channel->sock_state_cb;
options->sock_state_cb_data = channel->sock_state_cb_data;
- /* Copy IPv4 servers */
+ /* Copy IPv4 servers that use the default port */
if (channel->nservers) {
for (i = 0; i < channel->nservers; i++)
{
- if (channel->servers[i].addr.family == AF_INET)
+ if ((channel->servers[i].addr.family == AF_INET) &&
+ (channel->servers[i].addr.udp_port == 0) &&
+ (channel->servers[i].addr.tcp_port == 0))
ipv4_nservers++;
}
if (ipv4_nservers) {
- options->servers = malloc(ipv4_nservers * sizeof(struct in_addr));
+ options->servers = ares_malloc(ipv4_nservers * sizeof(struct in_addr));
if (!options->servers)
return ARES_ENOMEM;
for (i = j = 0; i < channel->nservers; i++)
{
- if (channel->servers[i].addr.family == AF_INET)
+ if ((channel->servers[i].addr.family == AF_INET) &&
+ (channel->servers[i].addr.udp_port == 0) &&
+ (channel->servers[i].addr.tcp_port == 0))
memcpy(&options->servers[j++],
&channel->servers[i].addr.addrV4,
sizeof(channel->servers[i].addr.addrV4));
@@ -377,14 +394,14 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
/* copy domains */
if (channel->ndomains) {
- options->domains = malloc(channel->ndomains * sizeof(char *));
+ options->domains = ares_malloc(channel->ndomains * sizeof(char *));
if (!options->domains)
return ARES_ENOMEM;
for (i = 0; i < channel->ndomains; i++)
{
options->ndomains = i;
- options->domains[i] = strdup(channel->domains[i]);
+ options->domains[i] = ares_strdup(channel->domains[i]);
if (!options->domains[i])
return ARES_ENOMEM;
}
@@ -393,14 +410,14 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
/* copy lookups */
if (channel->lookups) {
- options->lookups = strdup(channel->lookups);
+ options->lookups = ares_strdup(channel->lookups);
if (!options->lookups && channel->lookups)
return ARES_ENOMEM;
}
/* copy sortlist */
if (channel->nsort) {
- options->sortlist = malloc(channel->nsort * sizeof(struct apattern));
+ options->sortlist = ares_malloc(channel->nsort * sizeof(struct apattern));
if (!options->sortlist)
return ARES_ENOMEM;
for (i = 0; i < channel->nsort; i++)
@@ -430,10 +447,12 @@ static int init_by_options(ares_channel channel,
channel->ndots = options->ndots;
if ((optmask & ARES_OPT_ROTATE) && channel->rotate == -1)
channel->rotate = 1;
+ if ((optmask & ARES_OPT_NOROTATE) && channel->rotate == -1)
+ channel->rotate = 0;
if ((optmask & ARES_OPT_UDP_PORT) && channel->udp_port == -1)
- channel->udp_port = options->udp_port;
+ channel->udp_port = htons(options->udp_port);
if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
- channel->tcp_port = options->tcp_port;
+ channel->tcp_port = htons(options->tcp_port);
if ((optmask & ARES_OPT_SOCK_STATE_CB) && channel->sock_state_cb == NULL)
{
channel->sock_state_cb = options->sock_state_cb;
@@ -446,6 +465,9 @@ static int init_by_options(ares_channel channel,
&& channel->socket_receive_buffer_size == -1)
channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
+ if ((optmask & ARES_OPT_EDNSPSZ) && channel->ednspsz == -1)
+ channel->ednspsz = options->ednspsz;
+
/* Copy the IPv4 servers, if given. */
if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
{
@@ -453,12 +475,14 @@ static int init_by_options(ares_channel channel,
if (options->nservers > 0)
{
channel->servers =
- malloc(options->nservers * sizeof(struct server_state));
+ ares_malloc(options->nservers * sizeof(struct server_state));
if (!channel->servers)
return ARES_ENOMEM;
for (i = 0; i < options->nservers; i++)
{
channel->servers[i].addr.family = AF_INET;
+ channel->servers[i].addr.udp_port = 0;
+ channel->servers[i].addr.tcp_port = 0;
memcpy(&channel->servers[i].addr.addrV4,
&options->servers[i],
sizeof(channel->servers[i].addr.addrV4));
@@ -475,13 +499,13 @@ static int init_by_options(ares_channel channel,
/* Avoid zero size allocations at any cost */
if (options->ndomains > 0)
{
- channel->domains = malloc(options->ndomains * sizeof(char *));
+ channel->domains = ares_malloc(options->ndomains * sizeof(char *));
if (!channel->domains)
return ARES_ENOMEM;
for (i = 0; i < options->ndomains; i++)
{
channel->ndomains = i;
- channel->domains[i] = strdup(options->domains[i]);
+ channel->domains[i] = ares_strdup(options->domains[i]);
if (!channel->domains[i])
return ARES_ENOMEM;
}
@@ -492,19 +516,20 @@ static int init_by_options(ares_channel channel,
/* Set lookups, if given. */
if ((optmask & ARES_OPT_LOOKUPS) && !channel->lookups)
{
- channel->lookups = strdup(options->lookups);
+ channel->lookups = ares_strdup(options->lookups);
if (!channel->lookups)
return ARES_ENOMEM;
}
/* copy sortlist */
- if ((optmask & ARES_OPT_SORTLIST) && (channel->nsort == -1) &&
- (options->nsort>0)) {
- channel->sortlist = malloc(options->nsort * sizeof(struct apattern));
- if (!channel->sortlist)
- return ARES_ENOMEM;
- for (i = 0; i < options->nsort; i++)
- channel->sortlist[i] = options->sortlist[i];
+ if ((optmask & ARES_OPT_SORTLIST) && (channel->nsort == -1)) {
+ if (options->nsort > 0) {
+ channel->sortlist = ares_malloc(options->nsort * sizeof(struct apattern));
+ if (!channel->sortlist)
+ return ARES_ENOMEM;
+ for (i = 0; i < options->nsort; i++)
+ channel->sortlist[i] = options->sortlist[i];
+ }
channel->nsort = options->nsort;
}
@@ -531,7 +556,7 @@ static int init_by_environment(ares_channel channel)
{
status = set_options(channel, res_options);
if (status != ARES_SUCCESS)
- return status;
+ return status; /* LCOV_EXCL_LINE: set_options() never fails */
}
return ARES_SUCCESS;
@@ -539,255 +564,891 @@ static int init_by_environment(ares_channel channel)
#ifdef WIN32
/*
- * Warning: returns a dynamically allocated buffer, the user MUST
- * use free() if the function returns 1
+ * get_REG_SZ()
+ *
+ * Given a 'hKey' handle to an open registry key and a 'leafKeyName' pointer
+ * to the name of the registry leaf key to be queried, fetch it's string
+ * value and return a pointer in *outptr to a newly allocated memory area
+ * holding it as a null-terminated string.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return a string value.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Supported on Windows NT 3.5 and newer.
*/
-static int get_res_nt(HKEY hKey, const char *subkey, char **obuf)
+static int get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr)
{
- /* Test for the size we need */
DWORD size = 0;
- int result;
+ int res;
- result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size);
- if ((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size)
+ *outptr = NULL;
+
+ /* Find out size of string stored in registry */
+ res = RegQueryValueEx(hKey, leafKeyName, 0, NULL, NULL, &size);
+ if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size)
return 0;
- *obuf = malloc(size+1);
- if (!*obuf)
+
+ /* Allocate buffer of indicated size plus one given that string
+ might have been stored without null termination */
+ *outptr = ares_malloc(size+1);
+ if (!*outptr)
return 0;
- if (RegQueryValueEx(hKey, subkey, 0, NULL,
- (LPBYTE)*obuf, &size) != ERROR_SUCCESS)
+ /* Get the value for real */
+ res = RegQueryValueEx(hKey, leafKeyName, 0, NULL,
+ (unsigned char *)*outptr, &size);
+ if ((res != ERROR_SUCCESS) || (size == 1))
{
- free(*obuf);
+ ares_free(*outptr);
+ *outptr = NULL;
return 0;
}
- if (size == 1)
+
+ /* Null terminate buffer allways */
+ *(*outptr + size) = '\0';
+
+ return 1;
+}
+
+/*
+ * get_REG_SZ_9X()
+ *
+ * Functionally identical to get_REG_SZ()
+ *
+ * Supported on Windows 95, 98 and ME.
+ */
+static int get_REG_SZ_9X(HKEY hKey, const char *leafKeyName, char **outptr)
+{
+ DWORD dataType = 0;
+ DWORD size = 0;
+ int res;
+
+ *outptr = NULL;
+
+ /* Find out size of string stored in registry */
+ res = RegQueryValueEx(hKey, leafKeyName, 0, &dataType, NULL, &size);
+ if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size)
+ return 0;
+
+ /* Allocate buffer of indicated size plus one given that string
+ might have been stored without null termination */
+ *outptr = ares_malloc(size+1);
+ if (!*outptr)
+ return 0;
+
+ /* Get the value for real */
+ res = RegQueryValueEx(hKey, leafKeyName, 0, &dataType,
+ (unsigned char *)*outptr, &size);
+ if ((res != ERROR_SUCCESS) || (size == 1))
{
- free(*obuf);
+ ares_free(*outptr);
+ *outptr = NULL;
return 0;
}
+
+ /* Null terminate buffer allways */
+ *(*outptr + size) = '\0';
+
return 1;
}
-static int get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf)
+/*
+ * get_enum_REG_SZ()
+ *
+ * Given a 'hKeyParent' handle to an open registry key and a 'leafKeyName'
+ * pointer to the name of the registry leaf key to be queried, parent key
+ * is enumerated searching in child keys for given leaf key name and its
+ * associated string value. When located, this returns a pointer in *outptr
+ * to a newly allocated memory area holding it as a null-terminated string.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return a string value.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Supported on Windows NT 3.5 and newer.
+ */
+static int get_enum_REG_SZ(HKEY hKeyParent, const char *leafKeyName,
+ char **outptr)
{
- char enumbuf[39]; /* GUIDs are 38 chars + 1 for NULL */
- DWORD enum_size = 39;
- int idx = 0;
- HKEY hVal;
+ char enumKeyName[256];
+ DWORD enumKeyNameBuffSize;
+ DWORD enumKeyIdx = 0;
+ HKEY hKeyEnum;
+ int gotString;
+ int res;
- while (RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0,
- NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
- {
- int rc;
+ *outptr = NULL;
- enum_size = 39;
- if (RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) !=
- ERROR_SUCCESS)
+ for(;;)
+ {
+ enumKeyNameBuffSize = sizeof(enumKeyName);
+ res = RegEnumKeyEx(hKeyParent, enumKeyIdx++, enumKeyName,
+ &enumKeyNameBuffSize, 0, NULL, NULL, NULL);
+ if (res != ERROR_SUCCESS)
+ break;
+ res = RegOpenKeyEx(hKeyParent, enumKeyName, 0, KEY_QUERY_VALUE,
+ &hKeyEnum);
+ if (res != ERROR_SUCCESS)
continue;
- rc = get_res_nt(hVal, subkey, obuf);
- RegCloseKey(hVal);
- if (rc)
- return 1;
- }
- return 0;
+ gotString = get_REG_SZ(hKeyEnum, leafKeyName, outptr);
+ RegCloseKey(hKeyEnum);
+ if (gotString)
+ break;
+ }
+
+ if (!*outptr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * get_DNS_Registry_9X()
+ *
+ * Functionally identical to get_DNS_Registry()
+ *
+ * Implementation supports Windows 95, 98 and ME.
+ */
+static int get_DNS_Registry_9X(char **outptr)
+{
+ HKEY hKey_VxD_MStcp;
+ int gotString;
+ int res;
+
+ *outptr = NULL;
+
+ res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X, 0, KEY_READ,
+ &hKey_VxD_MStcp);
+ if (res != ERROR_SUCCESS)
+ return 0;
+
+ gotString = get_REG_SZ_9X(hKey_VxD_MStcp, NAMESERVER, outptr);
+ RegCloseKey(hKey_VxD_MStcp);
+
+ if (!gotString || !*outptr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * get_DNS_Registry_NT()
+ *
+ * Functionally identical to get_DNS_Registry()
+ *
+ * Refs: Microsoft Knowledge Base articles KB120642 and KB314053.
+ *
+ * Implementation supports Windows NT 3.5 and newer.
+ */
+static int get_DNS_Registry_NT(char **outptr)
+{
+ HKEY hKey_Interfaces = NULL;
+ HKEY hKey_Tcpip_Parameters;
+ int gotString;
+ int res;
+
+ *outptr = NULL;
+
+ res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ,
+ &hKey_Tcpip_Parameters);
+ if (res != ERROR_SUCCESS)
+ return 0;
+
+ /*
+ ** Global DNS settings override adapter specific parameters when both
+ ** are set. Additionally static DNS settings override DHCP-configured
+ ** parameters when both are set.
+ */
+
+ /* Global DNS static parameters */
+ gotString = get_REG_SZ(hKey_Tcpip_Parameters, NAMESERVER, outptr);
+ if (gotString)
+ goto done;
+
+ /* Global DNS DHCP-configured parameters */
+ gotString = get_REG_SZ(hKey_Tcpip_Parameters, DHCPNAMESERVER, outptr);
+ if (gotString)
+ goto done;
+
+ /* Try adapter specific parameters */
+ res = RegOpenKeyEx(hKey_Tcpip_Parameters, "Interfaces", 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &hKey_Interfaces);
+ if (res != ERROR_SUCCESS)
+ {
+ hKey_Interfaces = NULL;
+ goto done;
+ }
+
+ /* Adapter specific DNS static parameters */
+ gotString = get_enum_REG_SZ(hKey_Interfaces, NAMESERVER, outptr);
+ if (gotString)
+ goto done;
+
+ /* Adapter specific DNS DHCP-configured parameters */
+ gotString = get_enum_REG_SZ(hKey_Interfaces, DHCPNAMESERVER, outptr);
+
+done:
+ if (hKey_Interfaces)
+ RegCloseKey(hKey_Interfaces);
+
+ RegCloseKey(hKey_Tcpip_Parameters);
+
+ if (!gotString || !*outptr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * get_DNS_Registry()
+ *
+ * Locates DNS info in the registry. When located, this returns a pointer
+ * in *outptr to a newly allocated memory area holding a null-terminated
+ * string with a space or comma seperated list of DNS IP addresses.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return DNSes string.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ */
+static int get_DNS_Registry(char **outptr)
+{
+ win_platform platform;
+ int gotString = 0;
+
+ *outptr = NULL;
+
+ platform = ares__getplatform();
+
+ if (platform == WIN_NT)
+ gotString = get_DNS_Registry_NT(outptr);
+ else if (platform == WIN_9X)
+ gotString = get_DNS_Registry_9X(outptr);
+
+ if (!gotString)
+ return 0;
+
+ return 1;
}
-/**
- * The desired output for this method is that we set "ret_buf" to
- * something like:
+static void commanjoin(char** dst, const char* const src, const size_t len)
+{
+ char *newbuf;
+ size_t newsize;
+
+ /* 1 for terminating 0 and 2 for , and terminating 0 */
+ newsize = len + (*dst ? (strlen(*dst) + 2) : 1);
+ newbuf = ares_realloc(*dst, newsize);
+ if (!newbuf)
+ return;
+ if (*dst == NULL)
+ *newbuf = '\0';
+ *dst = newbuf;
+ if (strlen(*dst) != 0)
+ strcat(*dst, ",");
+ strncat(*dst, src, len);
+}
+
+/*
+ * commajoin()
+ *
+ * RTF code.
+ */
+static void commajoin(char **dst, const char *src)
+{
+ commanjoin(dst, src, strlen(src));
+}
+
+/*
+ * get_DNS_NetworkParams()
+ *
+ * Locates DNS info using GetNetworkParams() function from the Internet
+ * Protocol Helper (IP Helper) API. When located, this returns a pointer
+ * in *outptr to a newly allocated memory area holding a null-terminated
+ * string with a space or comma seperated list of DNS IP addresses.
*
- * 192.168.0.1,dns01.my.domain,fe80::200:f8ff:fe21:67cf
+ * Returns 0 and nullifies *outptr upon inability to return DNSes string.
*
- * The only ordering requirement is that primary servers are listed
- * before secondary. There is no requirement that IPv4 addresses should
- * necessarily be before IPv6.
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
*
- * Note that ret_size should ideally be big enough to hold around
- * 2-3 IPv4 and 2-3 IPv6 addresses.
+ * Implementation supports Windows 98 and newer.
*
- * Finally, we need to return the total number of DNS servers located.
+ * Note: Ancient PSDK required in order to build a W98 target.
*/
-static int get_iphlpapi_dns_info (char *ret_buf, size_t ret_size)
+static int get_DNS_NetworkParams(char **outptr)
{
- const size_t ipv4_size = INET_ADDRSTRLEN + 1; /* +1 for ',' at end */
- const size_t ipv6_size = INET6_ADDRSTRLEN + 12; /* +12 for "%0123456789," at end */
- size_t left = ret_size;
- char *ret = ret_buf;
- int count = 0;
-
- /* Use the GetAdaptersAddresses method if it's available, otherwise
- fall back to GetNetworkParams. */
- if (ares_fpGetAdaptersAddresses != ZERO_NULL)
+ FIXED_INFO *fi, *newfi;
+ struct ares_addr namesrvr;
+ char *txtaddr;
+ IP_ADDR_STRING *ipAddr;
+ int res;
+ DWORD size = sizeof (*fi);
+
+ *outptr = NULL;
+
+ /* Verify run-time availability of GetNetworkParams() */
+ if (ares_fpGetNetworkParams == ZERO_NULL)
+ return 0;
+
+ fi = ares_malloc(size);
+ if (!fi)
+ return 0;
+
+ res = (*ares_fpGetNetworkParams) (fi, &size);
+ if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
+ goto done;
+
+ newfi = ares_realloc(fi, size);
+ if (!newfi)
+ goto done;
+
+ fi = newfi;
+ res = (*ares_fpGetNetworkParams) (fi, &size);
+ if (res != ERROR_SUCCESS)
+ goto done;
+
+ for (ipAddr = &fi->DnsServerList; ipAddr; ipAddr = ipAddr->Next)
{
- const ULONG working_buf_size = 15000;
- IP_ADAPTER_ADDRESSES *pFirstEntry = NULL;
- IP_ADAPTER_ADDRESSES *pEntry = NULL;
- ULONG bufSize = 0;
- ULONG result = 0;
-
- /* According to MSDN, the recommended way to do this is to use a temporary
- buffer of 15K, to "dramatically reduce the chance that the GetAdaptersAddresses
- method returns ERROR_BUFFER_OVERFLOW" */
- pFirstEntry = ( IP_ADAPTER_ADDRESSES * ) malloc( working_buf_size );
- bufSize = working_buf_size;
- if( !pFirstEntry )
- return 0;
-
- /* Call the method one time */
- result = ( *ares_fpGetAdaptersAddresses )( AF_UNSPEC, 0, 0, pFirstEntry, &bufSize );
- if( result == ERROR_BUFFER_OVERFLOW )
+ txtaddr = &ipAddr->IpAddress.String[0];
+
+ /* Validate converting textual address to binary format. */
+ if (ares_inet_pton(AF_INET, txtaddr, &namesrvr.addrV4) == 1)
{
- /* Reallocate, bufSize should now be set to the required size */
- pFirstEntry = ( IP_ADAPTER_ADDRESSES * ) realloc( pFirstEntry, bufSize );
- if( !pFirstEntry )
- return 0;
-
- /* Call the method a second time */
- result = ( *ares_fpGetAdaptersAddresses )( AF_UNSPEC, 0, 0, pFirstEntry, &bufSize );
- if( result == ERROR_BUFFER_OVERFLOW )
- {
- /* Reallocate, bufSize should now be set to the required size */
- pFirstEntry = ( IP_ADAPTER_ADDRESSES * ) realloc( pFirstEntry, bufSize );
- if( !pFirstEntry )
- return 0;
-
- /* Call the method a third time. The maximum number of times we're going to do
- this is 3. Three shall be the number thou shalt count, and the number of the
- counting shall be three. Five is right out. */
- result = ( *ares_fpGetAdaptersAddresses )( AF_UNSPEC, 0, 0, pFirstEntry, &bufSize );
- }
+ if ((namesrvr.addrV4.S_un.S_addr == INADDR_ANY) ||
+ (namesrvr.addrV4.S_un.S_addr == INADDR_NONE))
+ continue;
+ }
+ else if (ares_inet_pton(AF_INET6, txtaddr, &namesrvr.addrV6) == 1)
+ {
+ if (memcmp(&namesrvr.addrV6, &ares_in6addr_any,
+ sizeof(namesrvr.addrV6)) == 0)
+ continue;
}
+ else
+ continue;
+
+ commajoin(outptr, txtaddr);
+
+ if (!*outptr)
+ break;
+ }
+
+done:
+ if (fi)
+ ares_free(fi);
+
+ if (!*outptr)
+ return 0;
+
+ return 1;
+}
+
+static BOOL ares_IsWindowsVistaOrGreater(void)
+{
+ OSVERSIONINFO vinfo;
+ memset(&vinfo, 0, sizeof(vinfo));
+ vinfo.dwOSVersionInfoSize = sizeof(vinfo);
+ if (!GetVersionEx(&vinfo) || vinfo.dwMajorVersion < 6)
+ return FALSE;
+ return TRUE;
+}
- /* Check the current result for failure */
- if( result != ERROR_SUCCESS )
+/* A structure to hold the string form of IPv4 and IPv6 addresses so we can
+ * sort them by a metric.
+ */
+typedef struct
+{
+ /* The metric we sort them by. */
+ ULONG metric;
+
+ /* Room enough for the string form of any IPv4 or IPv6 address that
+ * ares_inet_ntop() will create. Based on the existing c-ares practice.
+ */
+ char text[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+} Address;
+
+/* Sort Address values \a left and \a right by metric, returning the usual
+ * indicators for qsort().
+ */
+static int compareAddresses(const void *arg1,
+ const void *arg2)
+{
+ const Address * const left = arg1;
+ const Address * const right = arg2;
+ if(left->metric < right->metric) return -1;
+ if(left->metric > right->metric) return 1;
+ return 0;
+}
+
+/* There can be multiple routes to "the Internet". And there can be different
+ * DNS servers associated with each of the interfaces that offer those routes.
+ * We have to assume that any DNS server can serve any request. But, some DNS
+ * servers may only respond if requested over their associated interface. But
+ * we also want to use "the preferred route to the Internet" whenever possible
+ * (and not use DNS servers on a non-preferred route even by forcing request
+ * to go out on the associated non-preferred interface). i.e. We want to use
+ * the DNS servers associated with the same interface that we would use to
+ * make a general request to anything else.
+ *
+ * But, Windows won't sort the DNS servers by the metrics associated with the
+ * routes and interfaces _even_ though it obviously sends IP packets based on
+ * those same routes and metrics. So, we must do it ourselves.
+ *
+ * So, we sort the DNS servers by the same metric values used to determine how
+ * an outgoing IP packet will go, thus effectively using the DNS servers
+ * associated with the interface that the DNS requests themselves will
+ * travel. This gives us optimal routing and avoids issues where DNS servers
+ * won't respond to requests that don't arrive via some specific subnetwork
+ * (and thus some specific interface).
+ *
+ * This function computes the metric we use to sort. On the interface
+ * identified by \a luid, it determines the best route to \a dest and combines
+ * that route's metric with \a interfaceMetric to compute a metric for the
+ * destination address on that interface. This metric can be used as a weight
+ * to sort the DNS server addresses associated with each interface (lower is
+ * better).
+ *
+ * Note that by restricting the route search to the specific interface with
+ * which the DNS servers are associated, this function asks the question "What
+ * is the metric for sending IP packets to this DNS server?" which allows us
+ * to sort the DNS servers correctly.
+ */
+static ULONG getBestRouteMetric(IF_LUID * const luid, /* Can't be const :( */
+ const SOCKADDR_INET * const dest,
+ const ULONG interfaceMetric)
+{
+ /* On this interface, get the best route to that destination. */
+ MIB_IPFORWARD_ROW2 row;
+ SOCKADDR_INET ignored;
+ if(!ares_fpGetBestRoute2 ||
+ ares_fpGetBestRoute2(/* The interface to use. The index is ignored since we are
+ * passing a LUID.
+ */
+ luid, 0,
+ /* No specific source address. */
+ NULL,
+ /* Our destination address. */
+ dest,
+ /* No options. */
+ 0,
+ /* The route row. */
+ &row,
+ /* The best source address, which we don't need. */
+ &ignored) != NO_ERROR
+ /* If the metric is "unused" (-1) or too large for us to add the two
+ * metrics, use the worst possible, thus sorting this last.
+ */
+ || row.Metric == (ULONG)-1
+ || row.Metric > ((ULONG)-1) - interfaceMetric) {
+ /* Return the worst possible metric. */
+ return (ULONG)-1;
+ }
+
+ /* Return the metric value from that row, plus the interface metric.
+ *
+ * See
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa814494(v=vs.85).aspx
+ * which describes the combination as a "sum".
+ */
+ return row.Metric + interfaceMetric;
+}
+
+/*
+ * get_DNS_AdaptersAddresses()
+ *
+ * Locates DNS info using GetAdaptersAddresses() function from the Internet
+ * Protocol Helper (IP Helper) API. When located, this returns a pointer
+ * in *outptr to a newly allocated memory area holding a null-terminated
+ * string with a space or comma seperated list of DNS IP addresses.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return DNSes string.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Implementation supports Windows XP and newer.
+ */
+#define IPAA_INITIAL_BUF_SZ 15 * 1024
+#define IPAA_MAX_TRIES 3
+static int get_DNS_AdaptersAddresses(char **outptr)
+{
+ IP_ADAPTER_DNS_SERVER_ADDRESS *ipaDNSAddr;
+ IP_ADAPTER_ADDRESSES *ipaa, *newipaa, *ipaaEntry;
+ ULONG ReqBufsz = IPAA_INITIAL_BUF_SZ;
+ ULONG Bufsz = IPAA_INITIAL_BUF_SZ;
+ ULONG AddrFlags = 0;
+ int trying = IPAA_MAX_TRIES;
+ int res;
+
+ /* The capacity of addresses, in elements. */
+ size_t addressesSize;
+ /* The number of elements in addresses. */
+ size_t addressesIndex = 0;
+ /* The addresses we will sort. */
+ Address *addresses;
+
+ union {
+ struct sockaddr *sa;
+ struct sockaddr_in *sa4;
+ struct sockaddr_in6 *sa6;
+ } namesrvr;
+
+ *outptr = NULL;
+
+ /* Verify run-time availability of GetAdaptersAddresses() */
+ if (ares_fpGetAdaptersAddresses == ZERO_NULL)
+ return 0;
+
+ ipaa = ares_malloc(Bufsz);
+ if (!ipaa)
+ return 0;
+
+ /* Start with enough room for a few DNS server addresses and we'll grow it
+ * as we encounter more.
+ */
+ addressesSize = 4;
+ addresses = (Address*)ares_malloc(sizeof(Address) * addressesSize);
+ if(addresses == NULL) {
+ /* We need room for at least some addresses to function. */
+ ares_free(ipaa);
+ return 0;
+ }
+
+ /* Usually this call suceeds with initial buffer size */
+ res = (*ares_fpGetAdaptersAddresses) (AF_UNSPEC, AddrFlags, NULL,
+ ipaa, &ReqBufsz);
+ if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
+ goto done;
+
+ while ((res == ERROR_BUFFER_OVERFLOW) && (--trying))
+ {
+ if (Bufsz < ReqBufsz)
{
- free( pFirstEntry );
- return 0;
+ newipaa = ares_realloc(ipaa, ReqBufsz);
+ if (!newipaa)
+ goto done;
+ Bufsz = ReqBufsz;
+ ipaa = newipaa;
}
+ res = (*ares_fpGetAdaptersAddresses) (AF_UNSPEC, AddrFlags, NULL,
+ ipaa, &ReqBufsz);
+ if (res == ERROR_SUCCESS)
+ break;
+ }
+ if (res != ERROR_SUCCESS)
+ goto done;
- /* process the results */
- for( pEntry = pFirstEntry ; pEntry != NULL ; pEntry = pEntry->Next )
+ for (ipaaEntry = ipaa; ipaaEntry; ipaaEntry = ipaaEntry->Next)
+ {
+ if(ipaaEntry->OperStatus != IfOperStatusUp)
+ continue;
+
+ /* For each interface, find any associated DNS servers as IPv4 or IPv6
+ * addresses. For each found address, find the best route to that DNS
+ * server address _on_ _that_ _interface_ (at this moment in time) and
+ * compute the resulting total metric, just as Windows routing will do.
+ * Then, sort all the addresses found by the metric.
+ */
+ for (ipaDNSAddr = ipaaEntry->FirstDnsServerAddress;
+ ipaDNSAddr;
+ ipaDNSAddr = ipaDNSAddr->Next)
{
- IP_ADAPTER_DNS_SERVER_ADDRESS* pDNSAddr = pEntry->FirstDnsServerAddress;
- for( ; pDNSAddr != NULL ; pDNSAddr = pDNSAddr->Next )
+ namesrvr.sa = ipaDNSAddr->Address.lpSockaddr;
+
+ if (namesrvr.sa->sa_family == AF_INET)
{
- struct sockaddr *pGenericAddr = pDNSAddr->Address.lpSockaddr;
- size_t stringlen = 0;
+ if ((namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_ANY) ||
+ (namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_NONE))
+ continue;
+
+ /* Allocate room for another address, if necessary, else skip. */
+ if(addressesIndex == addressesSize) {
+ const size_t newSize = addressesSize + 4;
+ Address * const newMem =
+ (Address*)ares_realloc(addresses, sizeof(Address) * newSize);
+ if(newMem == NULL) {
+ continue;
+ }
+ addresses = newMem;
+ addressesSize = newSize;
+ }
- if( pGenericAddr->sa_family == AF_INET && left > ipv4_size )
+ /* Vista required for Luid or Ipv4Metric */
+ if (ares_IsWindowsVistaOrGreater())
{
- /* Handle the v4 case */
- struct sockaddr_in *pIPv4Addr = ( struct sockaddr_in * ) pGenericAddr;
- ares_inet_ntop( AF_INET, &pIPv4Addr->sin_addr, ret, ipv4_size - 1 ); /* -1 for comma */
-
- /* Append a comma to the end, THEN NULL. Should be OK because we
- already tested the size at the top of the if statement. */
- stringlen = strlen( ret );
- ret[ stringlen ] = ',';
- ret[ stringlen + 1 ] = '\0';
- ret += stringlen + 1;
- left -= ret - ret_buf;
- ++count;
+ /* Save the address as the next element in addresses. */
+ addresses[addressesIndex].metric =
+ getBestRouteMetric(&ipaaEntry->Luid,
+ (SOCKADDR_INET*)(namesrvr.sa),
+ ipaaEntry->Ipv4Metric);
}
- else if( pGenericAddr->sa_family == AF_INET6 && left > ipv6_size )
+ else
{
- /* Handle the v6 case */
- struct sockaddr_in6 *pIPv6Addr = ( struct sockaddr_in6 * ) pGenericAddr;
- ares_inet_ntop( AF_INET6, &pIPv6Addr->sin6_addr, ret, ipv6_size - 1 ); /* -1 for comma */
-
- /* Append a comma to the end, THEN NULL. Should be OK because we
- already tested the size at the top of the if statement. */
- stringlen = strlen( ret );
- ret[ stringlen ] = ',';
- ret[ stringlen + 1 ] = '\0';
- ret += stringlen + 1;
- left -= ret - ret_buf;
- ++count;
-
- /* NB on Windows this also returns stuff in the fec0::/10 range,
- seems to be hard-coded somehow. Do we need to ignore them? */
+ addresses[addressesIndex].metric = -1;
+ }
+
+ if (! ares_inet_ntop(AF_INET, &namesrvr.sa4->sin_addr,
+ addresses[addressesIndex].text,
+ sizeof(addresses[0].text))) {
+ continue;
+ }
+ ++addressesIndex;
+ }
+ else if (namesrvr.sa->sa_family == AF_INET6)
+ {
+ if (memcmp(&namesrvr.sa6->sin6_addr, &ares_in6addr_any,
+ sizeof(namesrvr.sa6->sin6_addr)) == 0)
+ continue;
+
+ /* Allocate room for another address, if necessary, else skip. */
+ if(addressesIndex == addressesSize) {
+ const size_t newSize = addressesSize + 4;
+ Address * const newMem =
+ (Address*)ares_realloc(addresses, sizeof(Address) * newSize);
+ if(newMem == NULL) {
+ continue;
+ }
+ addresses = newMem;
+ addressesSize = newSize;
+ }
+
+ /* Vista required for Luid or Ipv4Metric */
+ if (ares_IsWindowsVistaOrGreater())
+ {
+ /* Save the address as the next element in addresses. */
+ addresses[addressesIndex].metric =
+ getBestRouteMetric(&ipaaEntry->Luid,
+ (SOCKADDR_INET*)(namesrvr.sa),
+ ipaaEntry->Ipv6Metric);
+ }
+ else
+ {
+ addresses[addressesIndex].metric = -1;
+ }
+
+ if (! ares_inet_ntop(AF_INET6, &namesrvr.sa6->sin6_addr,
+ addresses[addressesIndex].text,
+ sizeof(addresses[0].text))) {
+ continue;
+ }
+ ++addressesIndex;
+ }
+ else {
+ /* Skip non-IPv4/IPv6 addresses completely. */
+ continue;
+ }
+ }
+ }
+
+ /* Sort all of the textual addresses by their metric. */
+ qsort(addresses, addressesIndex, sizeof(*addresses), compareAddresses);
+
+ /* Join them all into a single string, removing duplicates. */
+ {
+ size_t i;
+ for(i = 0; i < addressesIndex; ++i) {
+ size_t j;
+ /* Look for this address text appearing previously in the results. */
+ for(j = 0; j < i; ++j) {
+ if(strcmp(addresses[j].text, addresses[i].text) == 0) {
+ break;
}
}
+ /* Iff we didn't emit this address already, emit it now. */
+ if(j == i) {
+ /* Add that to outptr (if we can). */
+ commajoin(outptr, addresses[i].text);
+ }
}
+ }
+
+done:
+ ares_free(addresses);
+
+ if (ipaa)
+ ares_free(ipaa);
- if( pFirstEntry )
- free( pFirstEntry );
- if (ret > ret_buf)
- ret[-1] = '\0';
- return count;
+ if (!*outptr) {
+ return 0;
}
- else
+
+ return 1;
+}
+
+/*
+ * get_DNS_Windows()
+ *
+ * Locates DNS info from Windows employing most suitable methods available at
+ * run-time no matter which Windows version it is. When located, this returns
+ * a pointer in *outptr to a newly allocated memory area holding a string with
+ * a space or comma seperated list of DNS IP addresses, null-terminated.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return DNSes string.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Implementation supports Windows 95 and newer.
+ */
+static int get_DNS_Windows(char **outptr)
+{
+ /* Try using IP helper API GetAdaptersAddresses(). IPv4 + IPv6, also sorts
+ * DNS servers by interface route metrics to try to use the best DNS server. */
+ if (get_DNS_AdaptersAddresses(outptr))
+ return 1;
+
+ /* Try using IP helper API GetNetworkParams(). IPv4 only. */
+ if (get_DNS_NetworkParams(outptr))
+ return 1;
+
+ /* Fall-back to registry information */
+ return get_DNS_Registry(outptr);
+}
+
+static void replace_comma_by_space(char* str)
+{
+ /* replace ',' by ' ' to coincide with resolv.conf search parameter */
+ char *p;
+ for (p = str; *p != '\0'; p++)
{
- FIXED_INFO *fi, *newfi;
- DWORD size = sizeof (*fi);
- IP_ADDR_STRING *ipAddr;
- int i;
- int debug = 0;
- HRESULT res;
-
- fi = malloc(size);
- if (!fi)
- return 0;
-
- res = (*ares_fpGetNetworkParams) (fi, &size);
- if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
- goto quit;
-
- newfi = realloc(fi, size);
- if (!newfi)
- goto quit;
-
- fi = newfi;
- res = (*ares_fpGetNetworkParams) (fi, &size);
- if (res != ERROR_SUCCESS)
- goto quit;
+ if (*p == ',')
+ *p = ' ';
+ }
+}
- if (debug)
- {
- printf ("Host Name: %s\n", fi->HostName);
- printf ("Domain Name: %s\n", fi->DomainName);
- printf ("DNS Servers:\n"
- " %s (primary)\n", fi->DnsServerList.IpAddress.String);
- }
- if (strlen(fi->DnsServerList.IpAddress.String) > 0 &&
- inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE &&
- left > ipv4_size)
- {
- ret += sprintf (ret, "%s,", fi->DnsServerList.IpAddress.String);
- left -= ret - ret_buf;
- ++count;
- }
+/* Search if 'suffix' is containted in the 'searchlist'. Returns true if yes,
+ * otherwise false. 'searchlist' is a comma separated list of domain suffixes,
+ * 'suffix' is one domain suffix, 'len' is the length of 'suffix'.
+ * The search ignores case. E.g.:
+ * contains_suffix("abc.def,ghi.jkl", "ghi.JKL") returns true */
+static bool contains_suffix(const char* const searchlist,
+ const char* const suffix, const size_t len)
+{
+ const char* beg = searchlist;
+ const char* end;
+ if (!*suffix)
+ return true;
+ for (;;)
+ {
+ while (*beg && (ISSPACE(*beg) || (*beg == ',')))
+ ++beg;
+ if (!*beg)
+ return false;
+ end = beg;
+ while (*end && !ISSPACE(*end) && (*end != ','))
+ ++end;
+ if (len == (end - beg) && !strnicmp(beg, suffix, len))
+ return true;
+ beg = end;
+ }
+}
- for (i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ipv4_size;
- ipAddr = ipAddr->Next, i++)
+/* advances list to the next suffix within a comma separated search list.
+ * len is the length of the next suffix. */
+static size_t next_suffix(const char** list, const size_t advance)
+{
+ const char* beg = *list + advance;
+ const char* end;
+ while (*beg && (ISSPACE(*beg) || (*beg == ',')))
+ ++beg;
+ end = beg;
+ while (*end && !ISSPACE(*end) && (*end != ','))
+ ++end;
+ *list = beg;
+ return end - beg;
+}
+
+/*
+ * get_SuffixList_Windows()
+ *
+ * Reads the "DNS Suffix Search List" from registry and writes the list items
+ * whitespace separated to outptr. If the Search List is empty, the
+ * "Primary Dns Suffix" is written to outptr.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return the suffix list.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Implementation supports Windows Server 2003 and newer
+ */
+static int get_SuffixList_Windows(char **outptr)
+{
+ HKEY hKey, hKeyEnum;
+ char keyName[256];
+ DWORD keyNameBuffSize;
+ DWORD keyIdx = 0;
+ char *p = NULL;
+ char *pp;
+ size_t len = 0;
+
+ *outptr = NULL;
+
+ if (ares__getplatform() != WIN_NT)
+ return 0;
+
+ /* 1. Global DNS Suffix Search List */
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
+ KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ if (get_REG_SZ(hKey, SEARCHLIST_KEY, outptr))
+ replace_comma_by_space(*outptr);
+ RegCloseKey(hKey);
+ if (*outptr)
+ return 1;
+ }
+
+ /* 2. Connection Specific Search List composed of:
+ * a. Primary DNS Suffix */
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_DNSCLIENT, 0,
+ KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, outptr);
+ RegCloseKey(hKey);
+ }
+ if (!*outptr)
+ return 0;
+
+ /* b. Interface SearchList, Domain, DhcpDomain */
+ if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0,
+ KEY_READ, &hKey) == ERROR_SUCCESS)
+ return 0;
+ for(;;)
+ {
+ keyNameBuffSize = sizeof(keyName);
+ if (RegEnumKeyEx(hKey, keyIdx++, keyName, &keyNameBuffSize,
+ 0, NULL, NULL, NULL)
+ != ERROR_SUCCESS)
+ break;
+ if (RegOpenKeyEx(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum)
+ != ERROR_SUCCESS)
+ continue;
+ if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p) ||
+ get_REG_SZ(hKeyEnum, DOMAIN_KEY, &p) ||
+ get_REG_SZ(hKeyEnum, DHCPDOMAIN_KEY, &p))
{
- if (inet_addr(ipAddr->IpAddress.String) != INADDR_NONE)
+ /* p can be comma separated (SearchList) */
+ pp = p;
+ while (len = next_suffix(&pp, len))
{
- ret += sprintf (ret, "%s,", ipAddr->IpAddress.String);
- left -= ret - ret_buf;
- ++count;
+ if (!contains_suffix(*outptr, pp, len))
+ commanjoin(outptr, pp, len);
}
- if (debug)
- printf (" %s (secondary %d)\n", ipAddr->IpAddress.String, i+1);
+ ares_free(p);
+ p = NULL;
}
-
-quit:
- if (fi)
- free(fi);
-
- if (debug && left <= ipv4_size)
- printf ("Too many nameservers. Truncating to %d addressess", count);
- if (ret > ret_buf)
- ret[-1] = '\0';
- return count;
+ RegCloseKey(hKeyEnum);
}
+ RegCloseKey(hKey);
+ if (*outptr)
+ replace_comma_by_space(*outptr);
+ return *outptr != NULL;
}
+
#endif
static int init_by_resolv_conf(ares_channel channel)
{
-#ifndef WATT32
+#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(WATT32) && \
+ !defined(CARES_USE_LIBRESOLV)
char *line = NULL;
#endif
int status = -1, nservers = 0, nsort = 0;
@@ -796,111 +1457,19 @@ static int init_by_resolv_conf(ares_channel channel)
#ifdef WIN32
- /*
- NameServer info via IPHLPAPI (IP helper API):
- GetNetworkParams() should be the trusted source for this.
- Available in Win-98/2000 and later. If that fail, fall-back to
- registry information.
-
- NameServer Registry:
-
- On Windows 9X, the DNS server can be found in:
-HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer
-
- On Windows NT/2000/XP/2003:
-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer
- or
-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer
- or
-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
-NameServer
- or
-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
-DhcpNameServer
- */
-
- HKEY mykey;
- HKEY subkey;
- DWORD data_type;
- DWORD bytes;
- DWORD result;
- char buf[512];
- win_platform platform;
-
if (channel->nservers > -1) /* don't override ARES_OPT_SERVER */
return ARES_SUCCESS;
- if (get_iphlpapi_dns_info(buf,sizeof(buf)) > 0)
+ if (get_DNS_Windows(&line))
{
- status = config_nameserver(&servers, &nservers, buf);
- if (status == ARES_SUCCESS)
- goto okay;
+ status = config_nameserver(&servers, &nservers, line);
+ ares_free(line);
}
- platform = ares__getplatform();
-
- if (platform == WIN_NT)
- {
- if (RegOpenKeyEx(
- HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
- KEY_READ, &mykey
- ) == ERROR_SUCCESS)
- {
- RegOpenKeyEx(mykey, "Interfaces", 0,
- KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &subkey);
- if (get_res_nt(mykey, NAMESERVER, &line))
- {
- status = config_nameserver(&servers, &nservers, line);
- free(line);
- }
- else if (get_res_nt(mykey, DHCPNAMESERVER, &line))
- {
- status = config_nameserver(&servers, &nservers, line);
- free(line);
- }
- /* Try the interfaces */
- else if (get_res_interfaces_nt(subkey, NAMESERVER, &line))
- {
- status = config_nameserver(&servers, &nservers, line);
- free(line);
- }
- else if (get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line))
- {
- status = config_nameserver(&servers, &nservers, line);
- free(line);
- }
- RegCloseKey(subkey);
- RegCloseKey(mykey);
- }
- }
- else if (platform == WIN_9X)
+ if (channel->ndomains == -1 && get_SuffixList_Windows(&line))
{
- if (RegOpenKeyEx(
- HKEY_LOCAL_MACHINE, WIN_NS_9X, 0,
- KEY_READ, &mykey
- ) == ERROR_SUCCESS)
- {
- if ((result = RegQueryValueEx(
- mykey, NAMESERVER, NULL, &data_type,
- NULL, &bytes
- )
- ) == ERROR_SUCCESS ||
- result == ERROR_MORE_DATA)
- {
- if (bytes)
- {
- line = malloc(bytes+1);
- if (RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
- (unsigned char *)line, &bytes) ==
- ERROR_SUCCESS)
- {
- status = config_nameserver(&servers, &nservers, line);
- }
- free(line);
- }
- }
- }
- RegCloseKey(mykey);
+ status = set_search(channel, line);
+ ares_free(line);
}
if (status == ARES_SUCCESS)
@@ -918,7 +1487,7 @@ DhcpNameServer
line = getenv("Inet$Resolvers");
status = ARES_EOF;
if (line) {
- char *resolvers = strdup(line), *pos, *space;
+ char *resolvers = ares_strdup(line), *pos, *space;
if (!resolvers)
return ARES_ENOMEM;
@@ -937,7 +1506,7 @@ DhcpNameServer
if (status == ARES_SUCCESS)
status = ARES_EOF;
- free(resolvers);
+ ares_free(resolvers);
}
#elif defined(WATT32)
@@ -950,43 +1519,117 @@ DhcpNameServer
return ARES_SUCCESS; /* use localhost DNS server */
nservers = i;
- servers = calloc(i, sizeof(struct server_state));
+ servers = ares_malloc(sizeof(struct server_state));
if (!servers)
return ARES_ENOMEM;
+ memset(servers, 0, sizeof(struct server_state));
for (i = 0; def_nameservers[i]; i++)
{
servers[i].addr.addrV4.s_addr = htonl(def_nameservers[i]);
servers[i].addr.family = AF_INET;
+ servers[i].addr.udp_port = 0;
+ servers[i].addr.tcp_port = 0;
}
status = ARES_EOF;
-#elif defined(ANDROID)
- char value[PROP_VALUE_MAX]="";
- __system_property_get("net.dns1", value);
- status = config_nameserver(&servers, &nservers, value);
- if (status == ARES_SUCCESS)
+#elif defined(ANDROID) || defined(__ANDROID__)
+ unsigned int i;
+ 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) {
+ status = ARES_EOF;
+ break;
+ }
+ status = config_nameserver(&servers, &nservers, propvalue);
+ if (status != ARES_SUCCESS)
+ break;
+ status = ARES_EOF;
+ }
+#elif defined(CARES_USE_LIBRESOLV)
+ struct __res_state res;
+ memset(&res, 0, sizeof(res));
+ int result = res_ninit(&res);
+ if (result == 0 && (res.options & RES_INIT)) {
status = ARES_EOF;
+
+ if (channel->nservers == -1) {
+ union res_sockaddr_union addr[MAXNS];
+ int nscount = res_getservers(&res, addr, MAXNS);
+ for (int i = 0; i < nscount; ++i) {
+ char str[INET6_ADDRSTRLEN];
+ int config_status;
+ sa_family_t family = addr[i].sin.sin_family;
+ if (family == AF_INET) {
+ ares_inet_ntop(family, &addr[i].sin.sin_addr, str, sizeof(str));
+ } else if (family == AF_INET6) {
+ ares_inet_ntop(family, &addr[i].sin6.sin6_addr, str, sizeof(str));
+ } else {
+ continue;
+ }
+
+ config_status = config_nameserver(&servers, &nservers, str);
+ if (config_status != ARES_SUCCESS) {
+ status = config_status;
+ break;
+ }
+ }
+ }
+ if (channel->ndomains == -1) {
+ int entries = 0;
+ while ((entries < MAXDNSRCH) && res.dnsrch[entries])
+ entries++;
+
+ channel->domains = ares_malloc(entries * sizeof(char *));
+ if (!channel->domains) {
+ status = ARES_ENOMEM;
+ } else {
+ channel->ndomains = entries;
+ for (int i = 0; i < channel->ndomains; ++i) {
+ channel->domains[i] = ares_strdup(res.dnsrch[i]);
+ if (!channel->domains[i])
+ status = ARES_ENOMEM;
+ }
+ }
+ }
+ if (channel->ndots == -1)
+ channel->ndots = res.ndots;
+ if (channel->tries == -1)
+ channel->tries = res.retry;
+ if (channel->rotate == -1)
+ channel->rotate = res.options & RES_ROTATE;
+ if (channel->timeout == -1)
+ channel->timeout = res.retrans * 1000;
+
+ res_ndestroy(&res);
+ }
#else
{
char *p;
FILE *fp;
size_t linesize;
int error;
+ int update_domains;
/* Don't read resolv.conf and friends if we don't have to */
if (ARES_CONFIG_CHECK(channel))
return ARES_SUCCESS;
+ /* Only update search domains if they're not already specified */
+ update_domains = (channel->ndomains == -1);
+
fp = fopen(PATH_RESOLV_CONF, "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
{
- if ((p = try_config(line, "domain", ';')))
+ if ((p = try_config(line, "domain", ';')) && update_domains)
status = config_domain(channel, p);
else if ((p = try_config(line, "lookup", ';')) && !channel->lookups)
- status = config_lookup(channel, p, "bind", "file");
- else if ((p = try_config(line, "search", ';')))
+ status = config_lookup(channel, p, "bind", NULL, "file");
+ else if ((p = try_config(line, "search", ';')) && update_domains)
status = set_search(channel, p);
else if ((p = try_config(line, "nameserver", ';')) &&
channel->nservers == -1)
@@ -1022,11 +1665,11 @@ DhcpNameServer
/* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */
fp = fopen("/etc/nsswitch.conf", "r");
if (fp) {
- while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
+ while ((status = ares__read_line(fp, &line, &linesize)) ==
+ ARES_SUCCESS)
{
if ((p = try_config(line, "hosts:", '\0')) && !channel->lookups)
- /* ignore errors */
- (void)config_lookup(channel, p, "dns", "files");
+ (void)config_lookup(channel, p, "dns", "resolve", "files");
}
fclose(fp);
}
@@ -1035,14 +1678,16 @@ DhcpNameServer
switch(error) {
case ENOENT:
case ESRCH:
- status = ARES_EOF;
break;
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
- DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/nsswitch.conf"));
- status = ARES_EFILE;
+ DEBUGF(fprintf(stderr, "Error opening file: %s\n",
+ "/etc/nsswitch.conf"));
}
+
+ /* ignore error, maybe we will get luck in next if clause */
+ status = ARES_EOF;
}
}
@@ -1050,11 +1695,12 @@ DhcpNameServer
/* Linux / GNU libc 2.x and possibly others have host.conf */
fp = fopen("/etc/host.conf", "r");
if (fp) {
- while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
+ while ((status = ares__read_line(fp, &line, &linesize)) ==
+ ARES_SUCCESS)
{
if ((p = try_config(line, "order", '\0')) && !channel->lookups)
/* ignore errors */
- (void)config_lookup(channel, p, "bind", "hosts");
+ (void)config_lookup(channel, p, "bind", NULL, "hosts");
}
fclose(fp);
}
@@ -1063,14 +1709,16 @@ DhcpNameServer
switch(error) {
case ENOENT:
case ESRCH:
- status = ARES_EOF;
break;
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
- DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/host.conf"));
- status = ARES_EFILE;
+ DEBUGF(fprintf(stderr, "Error opening file: %s\n",
+ "/etc/host.conf"));
}
+
+ /* ignore error, maybe we will get luck in next if clause */
+ status = ARES_EOF;
}
}
@@ -1078,11 +1726,12 @@ DhcpNameServer
/* Tru64 uses /etc/svc.conf */
fp = fopen("/etc/svc.conf", "r");
if (fp) {
- while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
+ while ((status = ares__read_line(fp, &line, &linesize)) ==
+ ARES_SUCCESS)
{
if ((p = try_config(line, "hosts=", '\0')) && !channel->lookups)
/* ignore errors */
- (void)config_lookup(channel, p, "bind", "local");
+ (void)config_lookup(channel, p, "bind", NULL, "local");
}
fclose(fp);
}
@@ -1091,19 +1740,20 @@ DhcpNameServer
switch(error) {
case ENOENT:
case ESRCH:
- status = ARES_EOF;
break;
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/svc.conf"));
- status = ARES_EFILE;
}
+
+ /* ignore error, default value will be chosen for `channel->lookups` */
+ status = ARES_EOF;
}
}
if(line)
- free(line);
+ ares_free(line);
}
#endif
@@ -1112,16 +1762,13 @@ DhcpNameServer
if (status != ARES_EOF)
{
if (servers != NULL)
- free(servers);
+ ares_free(servers);
if (sortlist != NULL)
- free(sortlist);
+ ares_free(sortlist);
return status;
}
/* If we got any name server entries, fill them in. */
-#ifdef WIN32
-okay:
-#endif
if (servers)
{
channel->servers = servers;
@@ -1161,15 +1808,20 @@ static int init_by_defaults(ares_channel channel)
if (channel->tcp_port == -1)
channel->tcp_port = htons(NAMESERVER_PORT);
+ if (channel->ednspsz == -1)
+ channel->ednspsz = EDNSPACKETSZ;
+
if (channel->nservers == -1) {
/* If nobody specified servers, try a local named. */
- channel->servers = malloc(sizeof(struct server_state));
+ channel->servers = ares_malloc(sizeof(struct server_state));
if (!channel->servers) {
rc = ARES_ENOMEM;
goto error;
}
channel->servers[0].addr.family = AF_INET;
channel->servers[0].addr.addrV4.s_addr = htonl(INADDR_LOOPBACK);
+ channel->servers[0].addr.udp_port = 0;
+ channel->servers[0].addr.tcp_port = 0;
channel->nservers = 1;
}
@@ -1186,24 +1838,28 @@ static int init_by_defaults(ares_channel channel)
/* Derive a default domain search list from the kernel hostname,
* or set it to empty if the hostname isn't helpful.
*/
+#ifndef HAVE_GETHOSTNAME
+ channel->ndomains = 0; /* default to none */
+#else
+ GETHOSTNAME_TYPE_ARG2 lenv = 64;
size_t len = 64;
int res;
channel->ndomains = 0; /* default to none */
-#ifdef HAVE_GETHOSTNAME
- hostname = malloc(len);
+ hostname = ares_malloc(len);
if(!hostname) {
rc = ARES_ENOMEM;
goto error;
}
do {
- res = gethostname(hostname, len);
+ res = gethostname(hostname, lenv);
if(toolong(res)) {
char *p;
len *= 2;
- p = realloc(hostname, len);
+ lenv *= 2;
+ p = ares_realloc(hostname, len);
if(!p) {
rc = ARES_ENOMEM;
goto error;
@@ -1216,17 +1872,17 @@ static int init_by_defaults(ares_channel channel)
goto error;
}
- } while(0);
+ } while (res != 0);
dot = strchr(hostname, '.');
if (dot) {
/* a dot was found */
- channel->domains = malloc(sizeof(char *));
+ channel->domains = ares_malloc(sizeof(char *));
if (!channel->domains) {
rc = ARES_ENOMEM;
goto error;
}
- channel->domains[0] = strdup(dot + 1);
+ channel->domains[0] = ares_strdup(dot + 1);
if (!channel->domains[0]) {
rc = ARES_ENOMEM;
goto error;
@@ -1242,31 +1898,39 @@ static int init_by_defaults(ares_channel channel)
}
if (!channel->lookups) {
- channel->lookups = strdup("fb");
+ channel->lookups = ares_strdup("fb");
if (!channel->lookups)
rc = ARES_ENOMEM;
}
error:
if(rc) {
- if(channel->servers)
- free(channel->servers);
+ if(channel->servers) {
+ ares_free(channel->servers);
+ channel->servers = NULL;
+ }
if(channel->domains && channel->domains[0])
- free(channel->domains[0]);
- if(channel->domains)
- free(channel->domains);
- if(channel->lookups)
- free(channel->lookups);
+ ares_free(channel->domains[0]);
+ if(channel->domains) {
+ ares_free(channel->domains);
+ channel->domains = NULL;
+ }
+
+ if(channel->lookups) {
+ ares_free(channel->lookups);
+ channel->lookups = NULL;
+ }
}
if(hostname)
- free(hostname);
+ ares_free(hostname);
return rc;
}
-#if !defined(WIN32) && !defined(WATT32)
+#if !defined(WIN32) && !defined(WATT32) && \
+ !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV)
static int config_domain(ares_channel channel, char *str)
{
char *q;
@@ -1288,11 +1952,15 @@ static int config_domain(ares_channel channel, char *str)
#endif
static int config_lookup(ares_channel channel, const char *str,
- const char *bindch, const char *filech)
+ const char *bindch, const char *altbindch,
+ const char *filech)
{
char lookups[3], *l;
const char *vqualifier p;
+ if (altbindch == NULL)
+ altbindch = bindch;
+
/* Set the lookup order. Only the first letter of each work
* is relevant, and it has to be "b" for DNS or "f" for the
* host file. Ignore everything else.
@@ -1301,8 +1969,8 @@ static int config_lookup(ares_channel channel, const char *str,
p = str;
while (*p)
{
- if ((*p == *bindch || *p == *filech) && l < lookups + 2) {
- if (*p == *bindch) *l++ = 'b';
+ if ((*p == *bindch || *p == *altbindch || *p == *filech) && l < lookups + 2) {
+ if (*p == *bindch || *p == *altbindch) *l++ = 'b';
else *l++ = 'f';
}
while (*p && !ISSPACE(*p) && (*p != ','))
@@ -1311,10 +1979,10 @@ static int config_lookup(ares_channel channel, const char *str,
p++;
}
*l = '\0';
- channel->lookups = strdup(lookups);
+ channel->lookups = ares_strdup(lookups);
return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
}
-#endif /* !WIN32 & !WATT32 */
+#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ & !CARES_USE_LIBRESOLV */
#ifndef WATT32
static int config_nameserver(struct server_state **servers, int *nservers,
@@ -1357,13 +2025,15 @@ static int config_nameserver(struct server_state **servers, int *nservers,
continue;
/* Resize servers state array. */
- newserv = realloc(*servers, (*nservers + 1) *
- sizeof(struct server_state));
+ newserv = ares_realloc(*servers, (*nservers + 1) *
+ sizeof(struct server_state));
if (!newserv)
return ARES_ENOMEM;
/* Store address data. */
newserv[*nservers].addr.family = host.family;
+ newserv[*nservers].addr.udp_port = 0;
+ newserv[*nservers].addr.tcp_port = 0;
if (host.family == AF_INET)
memcpy(&newserv[*nservers].addr.addrV4, &host.addrV4,
sizeof(host.addrV4));
@@ -1378,8 +2048,8 @@ static int config_nameserver(struct server_state **servers, int *nservers,
return ARES_SUCCESS;
}
+#endif /* !WATT32 */
-#ifndef WIN32
static int config_sortlist(struct apattern **sortlist, int *nsort,
const char *str)
{
@@ -1418,8 +2088,11 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
pat.type = PATTERN_CIDR;
pat.mask.bits = (unsigned short)bits;
pat.family = AF_INET6;
- if (!sortlist_alloc(sortlist, nsort, &pat))
+ if (!sortlist_alloc(sortlist, nsort, &pat)) {
+ ares_free(*sortlist);
+ *sortlist = NULL;
return ARES_ENOMEM;
+ }
}
else if (ipbufpfx[0] &&
(bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addrV4,
@@ -1428,8 +2101,11 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
pat.type = PATTERN_CIDR;
pat.mask.bits = (unsigned short)bits;
pat.family = AF_INET;
- if (!sortlist_alloc(sortlist, nsort, &pat))
+ if (!sortlist_alloc(sortlist, nsort, &pat)) {
+ ares_free(*sortlist);
+ *sortlist = NULL;
return ARES_ENOMEM;
+ }
}
/* See if it is just a regular IP */
else if (ip_addr(ipbuf, q-str, &pat.addrV4) == 0)
@@ -1445,8 +2121,11 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
natural_mask(&pat);
pat.family = AF_INET;
pat.type = PATTERN_MASK;
- if (!sortlist_alloc(sortlist, nsort, &pat))
+ if (!sortlist_alloc(sortlist, nsort, &pat)) {
+ ares_free(*sortlist);
+ *sortlist = NULL;
return ARES_ENOMEM;
+ }
}
else
{
@@ -1460,8 +2139,6 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
return ARES_SUCCESS;
}
-#endif /* !WIN32 */
-#endif /* !WATT32 */
static int set_search(ares_channel channel, const char *str)
{
@@ -1469,13 +2146,14 @@ static int set_search(ares_channel channel, const char *str)
const char *p, *q;
if(channel->ndomains != -1) {
+ /* LCOV_EXCL_START: all callers check ndomains == -1 */
/* if we already have some domains present, free them first */
for(n=0; n < channel->ndomains; n++)
- free(channel->domains[n]);
- free(channel->domains);
+ ares_free(channel->domains[n]);
+ ares_free(channel->domains);
channel->domains = NULL;
channel->ndomains = -1;
- }
+ } /* LCOV_EXCL_STOP */
/* Count the domains given. */
n = 0;
@@ -1495,7 +2173,7 @@ static int set_search(ares_channel channel, const char *str)
return ARES_SUCCESS;
}
- channel->domains = malloc(n * sizeof(char *));
+ channel->domains = ares_malloc(n * sizeof(char *));
if (!channel->domains)
return ARES_ENOMEM;
@@ -1508,7 +2186,7 @@ static int set_search(ares_channel channel, const char *str)
q = p;
while (*q && !ISSPACE(*q))
q++;
- channel->domains[n] = malloc(q - p + 1);
+ channel->domains[n] = ares_malloc(q - p + 1);
if (!channel->domains[n])
return ARES_ENOMEM;
memcpy(channel->domains[n], p, q - p);
@@ -1559,7 +2237,8 @@ static const char *try_option(const char *p, const char *q, const char *opt)
return ((size_t)(q - p) >= len && !strncmp(p, opt, len)) ? &p[len] : NULL;
}
-#if !defined(WIN32) && !defined(WATT32)
+#if !defined(WIN32) && !defined(WATT32) && \
+ !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV)
static char *try_config(char *s, const char *opt, char scc)
{
size_t len;
@@ -1568,7 +2247,7 @@ static char *try_config(char *s, const char *opt, char scc)
if (!s || !opt)
/* no line or no option */
- return NULL;
+ return NULL; /* LCOV_EXCL_LINE */
/* Hash '#' character is always used as primary comment char, additionally
a not-NUL secondary comment char will be considered when specified. */
@@ -1600,7 +2279,7 @@ static char *try_config(char *s, const char *opt, char scc)
if ((len = strlen(opt)) == 0)
/* empty option */
- return NULL;
+ return NULL; /* LCOV_EXCL_LINE */
if (strncmp(p, opt, len) != 0)
/* line and option do not match */
@@ -1611,7 +2290,7 @@ static char *try_config(char *s, const char *opt, char scc)
if (!*p)
/* no option value */
- return NULL;
+ return NULL; /* LCOV_EXCL_LINE */
if ((opt[len-1] != ':') && (opt[len-1] != '=') && !ISSPACE(*p))
/* whitespace between option name and value is mandatory
@@ -1629,21 +2308,9 @@ static char *try_config(char *s, const char *opt, char scc)
/* return pointer to option value */
return p;
}
+#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ */
-static int sortlist_alloc(struct apattern **sortlist, int *nsort,
- struct apattern *pat)
-{
- struct apattern *newsort;
- newsort = realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
- if (!newsort)
- return 0;
- newsort[*nsort] = *pat;
- *sortlist = newsort;
- (*nsort)++;
- return 1;
-}
-
-static int ip_addr(const char *ipbuf, ssize_t len, struct in_addr *addr)
+static int ip_addr(const char *ipbuf, ares_ssize_t len, struct in_addr *addr)
{
/* Four octets and three periods yields at most 15 characters. */
@@ -1675,7 +2342,19 @@ static void natural_mask(struct apattern *pat)
else
pat->mask.addr4.s_addr = htonl(IN_CLASSC_NET);
}
-#endif /* !WIN32 && !WATT32 */
+
+static int sortlist_alloc(struct apattern **sortlist, int *nsort,
+ struct apattern *pat)
+{
+ struct apattern *newsort;
+ newsort = ares_realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
+ if (!newsort)
+ return 0;
+ newsort[*nsort] = *pat;
+ *sortlist = newsort;
+ (*nsort)++;
+ return 1;
+}
/* initialize an rc4 key. If possible a cryptographically secure random key
is generated using a suitable function (for example win32's RtlGenRandom as
@@ -1706,9 +2385,9 @@ static void randomize_key(unsigned char* key,int key_data_len)
#endif
#endif /* WIN32 */
- if ( !randomized ) {
+ if (!randomized) {
for (;counter<key_data_len;counter++)
- key[counter]=(unsigned char)(rand() % 256);
+ key[counter]=(unsigned char)(rand() % 256); /* LCOV_EXCL_LINE */
}
}
@@ -1720,9 +2399,10 @@ static int init_id_key(rc4_key* key,int key_data_len)
short counter;
unsigned char *key_data_ptr = 0;
- key_data_ptr = calloc(1,key_data_len);
+ key_data_ptr = ares_malloc(key_data_len);
if (!key_data_ptr)
return ARES_ENOMEM;
+ memset(key_data_ptr, 0, key_data_len);
state = &key->state[0];
for(counter = 0; counter < 256; counter++)
@@ -1741,17 +2421,10 @@ static int init_id_key(rc4_key* key,int key_data_len)
index1 = (unsigned char)((index1 + 1) % key_data_len);
}
- free(key_data_ptr);
+ ares_free(key_data_ptr);
return ARES_SUCCESS;
}
-unsigned short ares__generate_new_id(rc4_key* key)
-{
- unsigned short r=0;
- ares__rc4(key, (unsigned char *)&r, sizeof(r));
- return r;
-}
-
void ares_set_local_ip4(ares_channel channel, unsigned int local_ip)
{
channel->local_ip4 = local_ip;
@@ -1782,6 +2455,41 @@ void ares_set_socket_callback(ares_channel channel,
channel->sock_create_cb_data = data;
}
+void ares_set_socket_configure_callback(ares_channel channel,
+ ares_sock_config_callback cb,
+ void *data)
+{
+ channel->sock_config_cb = cb;
+ channel->sock_config_cb_data = data;
+}
+
+void ares_set_socket_functions(ares_channel channel,
+ const struct ares_socket_functions * funcs,
+ void *data)
+{
+ channel->sock_funcs = funcs;
+ channel->sock_func_cb_data = data;
+}
+
+int ares_set_sortlist(ares_channel channel, const char *sortstr)
+{
+ int nsort = 0;
+ struct apattern *sortlist = NULL;
+ int status;
+
+ if (!channel)
+ return ARES_ENODATA;
+
+ status = config_sortlist(&sortlist, &nsort, sortstr);
+ if (status == ARES_SUCCESS && sortlist) {
+ if (channel->sortlist)
+ ares_free(channel->sortlist);
+ channel->sortlist = sortlist;
+ channel->nsort = nsort;
+ }
+ return status;
+}
+
void ares__init_servers_state(ares_channel channel)
{
struct server_state *server;
diff --git a/ares_ipv6.h b/ares_ipv6.h
index 6f1022a..b0017f1 100644
--- a/ares_ipv6.h
+++ b/ares_ipv6.h
@@ -47,16 +47,16 @@ struct addrinfo
#endif
#ifndef NS_IN6ADDRSZ
-#if SIZEOF_STRUCT_IN6_ADDR == 0
+#ifndef HAVE_STRUCT_IN6_ADDR
/* We cannot have it set to zero, so we pick a fixed value here */
#define NS_IN6ADDRSZ 16
#else
-#define NS_IN6ADDRSZ SIZEOF_STRUCT_IN6_ADDR
+#define NS_IN6ADDRSZ sizeof(struct in6_addr)
#endif
#endif
#ifndef NS_INADDRSZ
-#define NS_INADDRSZ SIZEOF_STRUCT_IN_ADDR
+#define NS_INADDRSZ sizeof(struct in_addr)
#endif
#ifndef NS_INT16SZ
@@ -71,7 +71,7 @@ struct addrinfo
#endif
#endif
-/* Defined in ares_net_pton.c for no particular reason. */
+/* Defined in inet_net_pton.c for no particular reason. */
extern const struct ares_in6_addr ares_in6addr_any; /* :: */
diff --git a/ares_library_init.c b/ares_library_init.c
index f0137a1..0a853d7 100644
--- a/ares_library_init.c
+++ b/ares_library_init.c
@@ -27,6 +27,7 @@
fpGetNetworkParams_t ares_fpGetNetworkParams = ZERO_NULL;
fpSystemFunction036_t ares_fpSystemFunction036 = ZERO_NULL;
fpGetAdaptersAddresses_t ares_fpGetAdaptersAddresses = ZERO_NULL;
+fpGetBestRoute2_t ares_fpGetBestRoute2 = ZERO_NULL;
#endif
/* library-private global vars with source visibility restricted to this file */
@@ -34,6 +35,11 @@ fpGetAdaptersAddresses_t ares_fpGetAdaptersAddresses = ZERO_NULL;
static unsigned int ares_initialized;
static int ares_init_flags;
+/* library-private global vars with visibility across the whole library */
+void *(*ares_malloc)(size_t size) = malloc;
+void *(*ares_realloc)(void *ptr, size_t size) = realloc;
+void (*ares_free)(void *ptr) = free;
+
#ifdef USE_WINSOCK
static HMODULE hnd_iphlpapi;
static HMODULE hnd_advapi32;
@@ -45,7 +51,7 @@ static int ares_win32_init(void)
#ifdef USE_WINSOCK
hnd_iphlpapi = 0;
- hnd_iphlpapi = LoadLibrary("iphlpapi.dll");
+ hnd_iphlpapi = LoadLibraryW(L"iphlpapi.dll");
if (!hnd_iphlpapi)
return ARES_ELOADIPHLPAPI;
@@ -66,6 +72,15 @@ static int ares_win32_init(void)
support Windows 2000 anymore */
}
+ ares_fpGetBestRoute2 = (fpGetBestRoute2_t)
+ GetProcAddress(hnd_iphlpapi, "GetBestRoute2");
+ if (!ares_fpGetBestRoute2)
+ {
+ /* This can happen on clients before Vista, I don't
+ think it should be an error, unless we don't want to
+ support Windows XP anymore */
+ }
+
/*
* When advapi32.dll is unavailable or advapi32.dll has no SystemFunction036,
* also known as RtlGenRandom, which is the case for Windows versions prior
@@ -73,7 +88,7 @@ static int ares_win32_init(void)
*/
hnd_advapi32 = 0;
- hnd_advapi32 = LoadLibrary("advapi32.dll");
+ hnd_advapi32 = LoadLibraryW(L"advapi32.dll");
if (hnd_advapi32)
{
ares_fpSystemFunction036 = (fpSystemFunction036_t)
@@ -101,14 +116,17 @@ int ares_library_init(int flags)
int res;
if (ares_initialized)
- return ARES_SUCCESS;
+ {
+ ares_initialized++;
+ return ARES_SUCCESS;
+ }
ares_initialized++;
if (flags & ARES_LIB_INIT_WIN32)
{
res = ares_win32_init();
if (res != ARES_SUCCESS)
- return res;
+ return res; /* LCOV_EXCL_LINE: can't test Win32 init failure */
}
ares_init_flags = flags;
@@ -116,17 +134,36 @@ int ares_library_init(int flags)
return ARES_SUCCESS;
}
+int ares_library_init_mem(int flags,
+ void *(*amalloc)(size_t size),
+ void (*afree)(void *ptr),
+ void *(*arealloc)(void *ptr, size_t size))
+{
+ if (amalloc)
+ ares_malloc = amalloc;
+ if (arealloc)
+ ares_realloc = arealloc;
+ if (afree)
+ ares_free = afree;
+ return ares_library_init(flags);
+}
+
void ares_library_cleanup(void)
{
if (!ares_initialized)
return;
ares_initialized--;
+ if (ares_initialized)
+ return;
if (ares_init_flags & ARES_LIB_INIT_WIN32)
ares_win32_cleanup();
ares_init_flags = ARES_LIB_INIT_NONE;
+ ares_malloc = malloc;
+ ares_realloc = realloc;
+ ares_free = free;
}
@@ -138,5 +175,3 @@ int ares_library_initialized(void)
#endif
return ARES_SUCCESS;
}
-
-
diff --git a/ares_library_init.h b/ares_library_init.h
index 59e5cc5..2a2ba11 100644
--- a/ares_library_init.h
+++ b/ares_library_init.h
@@ -28,13 +28,14 @@
typedef DWORD (WINAPI *fpGetNetworkParams_t) (FIXED_INFO*, DWORD*);
typedef BOOLEAN (APIENTRY *fpSystemFunction036_t) (void*, ULONG);
typedef ULONG (WINAPI *fpGetAdaptersAddresses_t) ( ULONG, ULONG, void*, IP_ADAPTER_ADDRESSES*, ULONG* );
-
+typedef NETIO_STATUS (WINAPI *fpGetBestRoute2_t) ( NET_LUID *, NET_IFINDEX, const SOCKADDR_INET *, const SOCKADDR_INET *, ULONG, PMIB_IPFORWARD_ROW2, SOCKADDR_INET * );
/* Forward-declaration of variables defined in ares_library_init.c */
/* that are global and unique instances for whole c-ares library. */
extern fpGetNetworkParams_t ares_fpGetNetworkParams;
extern fpSystemFunction036_t ares_fpSystemFunction036;
extern fpGetAdaptersAddresses_t ares_fpGetAdaptersAddresses;
+extern fpGetBestRoute2_t ares_fpGetBestRoute2;
#endif /* USE_WINSOCK */
diff --git a/ares_llist.c b/ares_llist.c
index c0acd90..36ca84c 100644
--- a/ares_llist.c
+++ b/ares_llist.c
@@ -61,26 +61,3 @@ void ares__remove_from_list(struct list_node* node) {
}
}
-/* Swap the contents of two lists */
-void ares__swap_lists(struct list_node* head_a,
- struct list_node* head_b) {
- int is_a_empty = ares__is_list_empty(head_a);
- int is_b_empty = ares__is_list_empty(head_b);
- struct list_node old_a = *head_a;
- struct list_node old_b = *head_b;
-
- if (is_a_empty) {
- ares__init_list_head(head_b);
- } else {
- *head_b = old_a;
- old_a.next->prev = head_b;
- old_a.prev->next = head_b;
- }
- if (is_b_empty) {
- ares__init_list_head(head_a);
- } else {
- *head_a = old_b;
- old_b.next->prev = head_a;
- old_b.prev->next = head_a;
- }
-}
diff --git a/ares_llist.h b/ares_llist.h
index b09f0de..20f4d1c 100644
--- a/ares_llist.h
+++ b/ares_llist.h
@@ -36,7 +36,4 @@ void ares__insert_in_list(struct list_node* new_node,
void ares__remove_from_list(struct list_node* node);
-void ares__swap_lists(struct list_node* head_a,
- struct list_node* head_b);
-
#endif /* __ARES_LLIST_H */
diff --git a/ares_mkquery.c b/ares_mkquery.c
index aa41e6b..5aea914 100644
--- a/ares_mkquery.c
+++ b/ares_mkquery.c
@@ -15,175 +15,10 @@
*/
#include "ares_setup.h"
-
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_NAMESER_H
-# include <arpa/nameser.h>
-#else
-# include "nameser.h"
-#endif
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
-# include <arpa/nameser_compat.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
#include "ares.h"
-#include "ares_dns.h"
-#include "ares_private.h"
-
-/* Header format, from RFC 1035:
- * 1 1 1 1 1 1
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | ID |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | QDCOUNT |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | ANCOUNT |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | NSCOUNT |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | ARCOUNT |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *
- * AA, TC, RA, and RCODE are only set in responses. Brief description
- * of the remaining fields:
- * ID Identifier to match responses with queries
- * QR Query (0) or response (1)
- * Opcode For our purposes, always QUERY
- * RD Recursion desired
- * Z Reserved (zero)
- * QDCOUNT Number of queries
- * ANCOUNT Number of answers
- * NSCOUNT Number of name server records
- * ARCOUNT Number of additional records
- *
- * Question format, from RFC 1035:
- * 1 1 1 1 1 1
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | |
- * / QNAME /
- * / /
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | QTYPE |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | QCLASS |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *
- * The query name is encoded as a series of labels, each represented
- * as a one-byte length (maximum 63) followed by the text of the
- * label. The list is terminated by a label of length zero (which can
- * be thought of as the root domain).
- */
int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
- int rd, unsigned char **bufp, int *buflenp)
+ int rd, unsigned char **buf, int *buflen)
{
- size_t len;
- unsigned char *q;
- const char *p;
- size_t buflen;
- unsigned char *buf;
-
- /* Set our results early, in case we bail out early with an error. */
- *buflenp = 0;
- *bufp = NULL;
-
- /* Allocate a memory area for the maximum size this packet might need. +2
- * is for the length byte and zero termination if no dots or ecscaping is
- * used.
- */
- len = strlen(name) + 2 + HFIXEDSZ + QFIXEDSZ;
- buf = malloc(len);
- if (!buf)
- return ARES_ENOMEM;
-
- /* Set up the header. */
- q = buf;
- memset(q, 0, HFIXEDSZ);
- DNS_HEADER_SET_QID(q, id);
- DNS_HEADER_SET_OPCODE(q, QUERY);
- if (rd) {
- DNS_HEADER_SET_RD(q, 1);
- }
- else {
- DNS_HEADER_SET_RD(q, 0);
- }
- DNS_HEADER_SET_QDCOUNT(q, 1);
-
- /* A name of "." is a screw case for the loop below, so adjust it. */
- if (strcmp(name, ".") == 0)
- name++;
-
- /* Start writing out the name after the header. */
- q += HFIXEDSZ;
- while (*name)
- {
- if (*name == '.') {
- free(buf);
- return ARES_EBADNAME;
- }
-
- /* Count the number of bytes in this label. */
- len = 0;
- for (p = name; *p && *p != '.'; p++)
- {
- if (*p == '\\' && *(p + 1) != 0)
- p++;
- len++;
- }
- if (len > MAXLABEL) {
- free(buf);
- return ARES_EBADNAME;
- }
-
- /* Encode the length and copy the data. */
- *q++ = (unsigned char)len;
- for (p = name; *p && *p != '.'; p++)
- {
- if (*p == '\\' && *(p + 1) != 0)
- p++;
- *q++ = *p;
- }
-
- /* Go to the next label and repeat, unless we hit the end. */
- if (!*p)
- break;
- name = p + 1;
- }
-
- /* Add the zero-length label at the end. */
- *q++ = 0;
-
- /* Finish off the question with the type and class. */
- DNS_QUESTION_SET_TYPE(q, type);
- DNS_QUESTION_SET_CLASS(q, dnsclass);
-
- q += QFIXEDSZ;
-
- buflen = (q - buf);
-
- /* Reject names that are longer than the maximum of 255 bytes that's
- * specified in RFC 1035 ("To simplify implementations, the total length of
- * a domain name (i.e., label octets and label length octets) is restricted
- * to 255 octets or less."). */
- if (buflen > (MAXCDNAME + HFIXEDSZ + QFIXEDSZ)) {
- free(buf);
- return ARES_EBADNAME;
- }
-
- /* we know this fits in an int at this point */
- *buflenp = (int) buflen;
- *bufp = buf;
-
- return ARES_SUCCESS;
+ return ares_create_query(name, dnsclass, type, id, rd, buf, buflen, 0);
}
diff --git a/ares_nowarn.c b/ares_nowarn.c
index 0ed015c..f63d913 100644
--- a/ares_nowarn.c
+++ b/ares_nowarn.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2010-2011 by Daniel Stenberg
+/* Copyright (C) 2010-2013 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -22,14 +22,11 @@
#endif
#ifdef HAVE_LIMITS_H
-# include <limits.h>
+#include <limits.h>
#endif
#if defined(__INTEL_COMPILER) && defined(__unix__)
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -43,24 +40,43 @@
#include "ares_nowarn.h"
-#if (SIZEOF_INT == 2)
-# define CARES_MASK_SINT 0x7FFF
-# define CARES_MASK_UINT 0xFFFF
-#elif (SIZEOF_INT == 4)
-# define CARES_MASK_SINT 0x7FFFFFFF
-# define CARES_MASK_UINT 0xFFFFFFFF
-#elif (SIZEOF_INT == 8)
-# define CARES_MASK_SINT 0x7FFFFFFFFFFFFFFF
-# define CARES_MASK_UINT 0xFFFFFFFFFFFFFFFF
-#elif (SIZEOF_INT == 16)
-# define CARES_MASK_SINT 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-# define CARES_MASK_UINT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-#elif defined(HAVE_LIMITS_H)
-# define CARES_MASK_SINT INT_MAX
-# define CARES_MASK_UINT UINT_MAX
+#ifndef HAVE_LIMITS_H
+/* systems without <limits.h> we guess have 16 bit shorts, 32bit ints and
+ 32bit longs */
+# define CARES_MASK_SSHORT 0x7FFF
+# define CARES_MASK_USHORT 0xFFFF
+# define CARES_MASK_SINT 0x7FFFFFFF
+# define CARES_MASK_UINT 0xFFFFFFFF
+# define CARES_MASK_SLONG 0x7FFFFFFFL
+# define CARES_MASK_ULONG 0xFFFFFFFFUL
+#else
+# define CARES_MASK_SSHORT SHRT_MAX
+# define CARES_MASK_USHORT USHRT_MAX
+# define CARES_MASK_SINT INT_MAX
+# define CARES_MASK_UINT UINT_MAX
+# define CARES_MASK_SLONG LONG_MAX
+# define CARES_MASK_ULONG ULONG_MAX
#endif
/*
+** unsigned size_t to signed long
+*/
+
+long aresx_uztosl(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ return (long)(uznum & (size_t) CARES_MASK_SLONG);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
** unsigned size_t to signed int
*/
@@ -79,6 +95,43 @@ int aresx_uztosi(size_t uznum)
}
/*
+** unsigned size_t to signed short
+*/
+
+short aresx_uztoss(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ return (short)(uznum & (size_t) CARES_MASK_SSHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed int to signed short
+*/
+
+short aresx_sitoss(int sinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sinum >= 0);
+ return (short)(sinum & (int) CARES_MASK_SSHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
** signed long to signed int
*/
@@ -98,10 +151,10 @@ int aresx_sltosi(long slnum)
}
/*
-** signed ssize_t to signed int
+** signed ares_ssize_t to signed int
*/
-int aresx_sztosi(ssize_t sznum)
+int aresx_sztosi(ares_ssize_t sznum)
{
#ifdef __INTEL_COMPILER
# pragma warning(push)
@@ -109,7 +162,7 @@ int aresx_sztosi(ssize_t sznum)
#endif
DEBUGASSERT(sznum >= 0);
- return (int)(sznum & (ssize_t) CARES_MASK_SINT);
+ return (int)(sznum & (ares_ssize_t) CARES_MASK_SINT);
#ifdef __INTEL_COMPILER
# pragma warning(pop)
@@ -117,10 +170,10 @@ int aresx_sztosi(ssize_t sznum)
}
/*
-** signed ssize_t to unsigned int
+** signed ares_ssize_t to unsigned int
*/
-unsigned int aresx_sztoui(ssize_t sznum)
+unsigned int aresx_sztoui(ares_ssize_t sznum)
{
#ifdef __INTEL_COMPILER
# pragma warning(push)
@@ -128,7 +181,26 @@ unsigned int aresx_sztoui(ssize_t sznum)
#endif
DEBUGASSERT(sznum >= 0);
- return (unsigned int)(sznum & (ssize_t) CARES_MASK_UINT);
+ return (unsigned int)(sznum & (ares_ssize_t) CARES_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed int to unsigned short
+*/
+
+unsigned short aresx_sitous(int sinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sinum >= 0);
+ return (unsigned short)(sinum & (int) CARES_MASK_USHORT);
#ifdef __INTEL_COMPILER
# pragma warning(pop)
diff --git a/ares_nowarn.h b/ares_nowarn.h
index bcaa227..505e622 100644
--- a/ares_nowarn.h
+++ b/ares_nowarn.h
@@ -2,7 +2,7 @@
#define HEADER_CARES_NOWARN_H
-/* Copyright (C) 2010-2011 by Daniel Stenberg
+/* Copyright (C) 2010-2012 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -17,13 +17,19 @@
* without express or implied warranty.
*/
-int aresx_uztosi(size_t uznum);
+long aresx_uztosl(size_t uznum);
+int aresx_uztosi(size_t uznum);
+short aresx_uztoss(size_t uznum);
+
+short aresx_sitoss(int sinum);
int aresx_sltosi(long slnum);
-int aresx_sztosi(ssize_t sznum);
+int aresx_sztosi(ares_ssize_t sznum);
+
+unsigned int aresx_sztoui(ares_ssize_t sznum);
-unsigned int aresx_sztoui(ssize_t sznum);
+unsigned short aresx_sitous(int sinum);
#if defined(__INTEL_COMPILER) && defined(__unix__)
diff --git a/ares_options.c b/ares_options.c
index 5174ef2..c3cbd1d 100644
--- a/ares_options.c
+++ b/ares_options.c
@@ -1,6 +1,6 @@
/* Copyright 1998 by the Massachusetts Institute of Technology.
- * Copyright (C) 2008-2011 by Daniel Stenberg
+ * Copyright (C) 2008-2013 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -24,7 +24,7 @@
#include "ares.h"
#include "ares_data.h"
-#include "inet_net_pton.h"
+#include "ares_inet_net_pton.h"
#include "ares_private.h"
@@ -83,6 +83,62 @@ int ares_get_servers(ares_channel channel,
return status;
}
+int ares_get_servers_ports(ares_channel channel,
+ struct ares_addr_port_node **servers)
+{
+ struct ares_addr_port_node *srvr_head = NULL;
+ struct ares_addr_port_node *srvr_last = NULL;
+ struct ares_addr_port_node *srvr_curr;
+ int status = ARES_SUCCESS;
+ int i;
+
+ if (!channel)
+ return ARES_ENODATA;
+
+ for (i = 0; i < channel->nservers; i++)
+ {
+ /* Allocate storage for this server node appending it to the list */
+ srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_PORT_NODE);
+ if (!srvr_curr)
+ {
+ status = ARES_ENOMEM;
+ break;
+ }
+ if (srvr_last)
+ {
+ srvr_last->next = srvr_curr;
+ }
+ else
+ {
+ srvr_head = srvr_curr;
+ }
+ srvr_last = srvr_curr;
+
+ /* Fill this server node data */
+ srvr_curr->family = channel->servers[i].addr.family;
+ srvr_curr->udp_port = ntohs((unsigned short)channel->servers[i].addr.udp_port);
+ srvr_curr->tcp_port = ntohs((unsigned short)channel->servers[i].addr.tcp_port);
+ if (srvr_curr->family == AF_INET)
+ memcpy(&srvr_curr->addrV4, &channel->servers[i].addr.addrV4,
+ sizeof(srvr_curr->addrV4));
+ else
+ memcpy(&srvr_curr->addrV6, &channel->servers[i].addr.addrV6,
+ sizeof(srvr_curr->addrV6));
+ }
+
+ if (status != ARES_SUCCESS)
+ {
+ if (srvr_head)
+ {
+ ares_free_data(srvr_head);
+ srvr_head = NULL;
+ }
+ }
+
+ *servers = srvr_head;
+
+ return status;
+}
int ares_set_servers(ares_channel channel,
struct ares_addr_node *servers)
@@ -92,7 +148,7 @@ int ares_set_servers(ares_channel channel,
int i;
if (ares_library_initialized() != ARES_SUCCESS)
- return ARES_ENOTINITIALIZED;
+ return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
if (!channel)
return ARES_ENODATA;
@@ -107,7 +163,7 @@ int ares_set_servers(ares_channel channel,
if (num_srvrs > 0)
{
/* Allocate storage for servers state */
- channel->servers = malloc(num_srvrs * sizeof(struct server_state));
+ channel->servers = ares_malloc(num_srvrs * sizeof(struct server_state));
if (!channel->servers)
{
return ARES_ENOMEM;
@@ -117,6 +173,57 @@ int ares_set_servers(ares_channel channel,
for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
{
channel->servers[i].addr.family = srvr->family;
+ channel->servers[i].addr.udp_port = 0;
+ channel->servers[i].addr.tcp_port = 0;
+ if (srvr->family == AF_INET)
+ memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
+ sizeof(srvr->addrV4));
+ else
+ memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6,
+ sizeof(srvr->addrV6));
+ }
+ /* Initialize servers state remaining data */
+ ares__init_servers_state(channel);
+ }
+
+ return ARES_SUCCESS;
+}
+
+int ares_set_servers_ports(ares_channel channel,
+ struct ares_addr_port_node *servers)
+{
+ struct ares_addr_port_node *srvr;
+ int num_srvrs = 0;
+ int i;
+
+ if (ares_library_initialized() != ARES_SUCCESS)
+ return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
+
+ if (!channel)
+ return ARES_ENODATA;
+
+ ares__destroy_servers_state(channel);
+
+ for (srvr = servers; srvr; srvr = srvr->next)
+ {
+ num_srvrs++;
+ }
+
+ if (num_srvrs > 0)
+ {
+ /* Allocate storage for servers state */
+ channel->servers = ares_malloc(num_srvrs * sizeof(struct server_state));
+ if (!channel->servers)
+ {
+ return ARES_ENOMEM;
+ }
+ channel->nservers = num_srvrs;
+ /* Fill servers state address data */
+ for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
+ {
+ channel->servers[i].addr.family = srvr->family;
+ channel->servers[i].addr.udp_port = htons((unsigned short)srvr->udp_port);
+ channel->servers[i].addr.tcp_port = htons((unsigned short)srvr->tcp_port);
if (srvr->family == AF_INET)
memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
sizeof(srvr->addrV4));
@@ -132,19 +239,21 @@ int ares_set_servers(ares_channel channel,
}
/* Incomming string format: host[:port][,host[:port]]... */
-int ares_set_servers_csv(ares_channel channel,
- const char* _csv)
+/* IPv6 addresses with ports require square brackets [fe80::1%lo0]:53 */
+static int set_servers_csv(ares_channel channel,
+ const char* _csv, int use_port)
{
size_t i;
char* csv = NULL;
char* ptr;
char* start_host;
+ int cc = 0;
int rv = ARES_SUCCESS;
- struct ares_addr_node *servers = NULL;
- struct ares_addr_node *last = NULL;
+ struct ares_addr_port_node *servers = NULL;
+ struct ares_addr_port_node *last = NULL;
if (ares_library_initialized() != ARES_SUCCESS)
- return ARES_ENOTINITIALIZED;
+ return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
if (!channel)
return ARES_ENODATA;
@@ -155,7 +264,10 @@ int ares_set_servers_csv(ares_channel channel,
if (i == 0)
return ARES_SUCCESS; /* blank all servers */
- csv = malloc(i + 2);
+ csv = ares_malloc(i + 2);
+ if (!csv)
+ return ARES_ENOMEM;
+
strcpy(csv, _csv);
if (csv[i-1] != ',') { /* make parsing easier by ensuring ending ',' */
csv[i] = ',';
@@ -164,28 +276,54 @@ int ares_set_servers_csv(ares_channel channel,
start_host = csv;
for (ptr = csv; *ptr; ptr++) {
- if (*ptr == ',') {
+ if (*ptr == ':') {
+ /* count colons to determine if we have an IPv6 number or IPv4 with
+ port */
+ cc++;
+ }
+ else if (*ptr == '[') {
+ /* move start_host if an open square bracket is found wrapping an IPv6
+ address */
+ start_host = ptr + 1;
+ }
+ else if (*ptr == ',') {
char* pp = ptr - 1;
+ char* p = ptr;
+ int port = 0;
struct in_addr in4;
struct ares_in6_addr in6;
- struct ares_addr_node *s = NULL;
+ struct ares_addr_port_node *s = NULL;
*ptr = 0; /* null terminate host:port string */
- /* Got an entry..see if port was specified. */
- while (pp > start_host) {
- if (*pp == ':')
- break; /* yes */
- if (!ISDIGIT(*pp)) {
- /* Found end of digits before we found :, so wasn't a port */
- pp = ptr;
- break;
+ /* Got an entry..see if the port was specified. */
+ if (cc > 0) {
+ while (pp > start_host) {
+ /* a single close square bracket followed by a colon, ']:' indicates
+ an IPv6 address with port */
+ if ((*pp == ']') && (*p == ':'))
+ break; /* found port */
+ /* a single colon, ':' indicates an IPv4 address with port */
+ if ((*pp == ':') && (cc == 1))
+ break; /* found port */
+ if (!(ISDIGIT(*pp) || (*pp == ':'))) {
+ /* Found end of digits before we found :, so wasn't a port */
+ /* must allow ':' for IPv6 case of ']:' indicates we found a port */
+ pp = p = ptr;
+ break;
+ }
+ pp--;
+ p--;
+ }
+ if ((pp != start_host) && ((pp + 1) < ptr)) {
+ /* Found it. Parse over the port number */
+ /* when an IPv6 address is wrapped with square brackets the port
+ starts at pp + 2 */
+ if (*pp == ']')
+ p++; /* move p before ':' */
+ /* p will point to the start of the port */
+ port = (int)strtol(p, NULL, 10);
+ *pp = 0; /* null terminate host */
}
- pp--;
- }
- if ((pp != start_host) && ((pp + 1) < ptr)) {
- /* Found it. Parse over the port number */
- (void)strtol(pp + 1, NULL, 10);
- *pp = 0; /* null terminate host */
}
/* resolve host, try ipv4 first, rslt is in network byte order */
rv = ares_inet_pton(AF_INET, start_host, &in4);
@@ -197,7 +335,7 @@ int ares_set_servers_csv(ares_channel channel,
goto out;
}
/* was ipv6, add new server */
- s = malloc(sizeof(*s));
+ s = ares_malloc(sizeof(*s));
if (!s) {
rv = ARES_ENOMEM;
goto out;
@@ -207,7 +345,7 @@ int ares_set_servers_csv(ares_channel channel,
}
else {
/* was ipv4, add new server */
- s = malloc(sizeof(*s));
+ s = ares_malloc(sizeof(*s));
if (!s) {
rv = ARES_ENOMEM;
goto out;
@@ -216,11 +354,13 @@ int ares_set_servers_csv(ares_channel channel,
memcpy(&s->addr, &in4, sizeof(struct in_addr));
}
if (s) {
- /* TODO: Add port to ares_addr_node and assign it here. */
-
+ s->udp_port = use_port ? port: 0;
+ s->tcp_port = s->udp_port;
s->next = NULL;
if (last) {
last->next = s;
+ /* need to move last to maintain the linked list */
+ last = last->next;
}
else {
servers = s;
@@ -230,19 +370,33 @@ int ares_set_servers_csv(ares_channel channel,
/* Set up for next one */
start_host = ptr + 1;
+ cc = 0;
}
}
- rv = ares_set_servers(channel, servers);
+ rv = ares_set_servers_ports(channel, servers);
out:
if (csv)
- free(csv);
+ ares_free(csv);
while (servers) {
- struct ares_addr_node *s = servers;
+ struct ares_addr_port_node *s = servers;
servers = servers->next;
- free(s);
+ ares_free(s);
}
return rv;
}
+
+int ares_set_servers_csv(ares_channel channel,
+ const char* _csv)
+{
+ return set_servers_csv(channel, _csv, FALSE);
+}
+
+int ares_set_servers_ports_csv(ares_channel channel,
+ const char* _csv)
+{
+ return set_servers_csv(channel, _csv, TRUE);
+}
+
diff --git a/ares_parse_a_reply.c b/ares_parse_a_reply.c
index 4bd0845..0422bd3 100644
--- a/ares_parse_a_reply.c
+++ b/ares_parse_a_reply.c
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -41,8 +38,6 @@
# include <strings.h>
#endif
-#include <stdlib.h>
-#include <string.h>
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
@@ -90,7 +85,7 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
return status;
if (aptr + len + QFIXEDSZ > abuf + alen)
{
- free(hostname);
+ ares_free(hostname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
@@ -99,17 +94,17 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
{
/* Allocate addresses and aliases; ancount gives an upper bound for
both. */
- addrs = malloc(ancount * sizeof(struct in_addr));
+ addrs = ares_malloc(ancount * sizeof(struct in_addr));
if (!addrs)
{
- free(hostname);
+ ares_free(hostname);
return ARES_ENOMEM;
}
- aliases = malloc((ancount + 1) * sizeof(char *));
+ aliases = ares_malloc((ancount + 1) * sizeof(char *));
if (!aliases)
{
- free(hostname);
- free(addrs);
+ ares_free(hostname);
+ ares_free(addrs);
return ARES_ENOMEM;
}
}
@@ -132,7 +127,7 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
aptr += len;
if (aptr + RRFIXEDSZ > abuf + alen)
{
- free(rr_name);
+ ares_free(rr_name);
status = ARES_EBADRESP;
break;
}
@@ -141,6 +136,12 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
rr_len = DNS_RR_LEN(aptr);
rr_ttl = DNS_RR_TTL(aptr);
aptr += RRFIXEDSZ;
+ if (aptr + rr_len > abuf + alen)
+ {
+ ares_free(rr_name);
+ status = ARES_EBADRESP;
+ break;
+ }
if (rr_class == C_IN && rr_type == T_A
&& rr_len == sizeof(struct in_addr)
@@ -149,22 +150,22 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
if (addrs)
{
if (aptr + sizeof(struct in_addr) > abuf + alen)
- {
- free(rr_name);
+ { /* 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)
- {
- free(rr_name);
+ { /* 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;
}
@@ -178,7 +179,7 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
if (aliases)
aliases[naliases] = rr_name;
else
- free(rr_name);
+ ares_free(rr_name);
naliases++;
/* Decode the RR data and replace the hostname with it. */
@@ -186,7 +187,7 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
&len);
if (status != ARES_SUCCESS)
break;
- free(hostname);
+ ares_free(hostname);
hostname = rr_data;
/* Take the min of the TTLs we see in the CNAME chain. */
@@ -194,14 +195,14 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
cname_ttl = rr_ttl;
}
else
- free(rr_name);
+ ares_free(rr_name);
aptr += rr_len;
if (aptr > abuf + alen)
- {
+ { /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
break;
- }
+ } /* LCOV_EXCL_STOP */
}
if (status == ARES_SUCCESS && naddrs == 0 && naliases == 0)
@@ -227,10 +228,10 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
if (host)
{
/* Allocate memory to build the host entry. */
- hostent = malloc(sizeof(struct hostent));
+ hostent = ares_malloc(sizeof(struct hostent));
if (hostent)
{
- hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *));
+ hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
if (hostent->h_addr_list)
{
/* Fill in the hostent and return successfully. */
@@ -242,11 +243,11 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
hostent->h_addr_list[i] = (char *) &addrs[i];
hostent->h_addr_list[naddrs] = NULL;
if (!naddrs && addrs)
- free(addrs);
+ ares_free(addrs);
*host = hostent;
return ARES_SUCCESS;
}
- free(hostent);
+ ares_free(hostent);
}
status = ARES_ENOMEM;
}
@@ -254,10 +255,10 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
if (aliases)
{
for (i = 0; i < naliases; i++)
- free(aliases[i]);
- free(aliases);
+ ares_free(aliases[i]);
+ ares_free(aliases);
}
- free(addrs);
- free(hostname);
+ ares_free(addrs);
+ ares_free(hostname);
return status;
}
diff --git a/ares_parse_aaaa_reply.c b/ares_parse_aaaa_reply.c
index 1fbe838..5b38bb5 100644
--- a/ares_parse_aaaa_reply.c
+++ b/ares_parse_aaaa_reply.c
@@ -17,9 +17,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -42,15 +39,13 @@
# include <strings.h>
#endif
-#include <stdlib.h>
-#include <string.h>
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#include "ares.h"
#include "ares_dns.h"
-#include "inet_net_pton.h"
+#include "ares_inet_net_pton.h"
#include "ares_private.h"
int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
@@ -92,7 +87,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
return status;
if (aptr + len + QFIXEDSZ > abuf + alen)
{
- free(hostname);
+ ares_free(hostname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
@@ -100,17 +95,17 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
/* Allocate addresses and aliases; ancount gives an upper bound for both. */
if (host)
{
- addrs = malloc(ancount * sizeof(struct ares_in6_addr));
+ addrs = ares_malloc(ancount * sizeof(struct ares_in6_addr));
if (!addrs)
{
- free(hostname);
+ ares_free(hostname);
return ARES_ENOMEM;
}
- aliases = malloc((ancount + 1) * sizeof(char *));
+ aliases = ares_malloc((ancount + 1) * sizeof(char *));
if (!aliases)
{
- free(hostname);
- free(addrs);
+ ares_free(hostname);
+ ares_free(addrs);
return ARES_ENOMEM;
}
}
@@ -132,7 +127,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
aptr += len;
if (aptr + RRFIXEDSZ > abuf + alen)
{
- free(rr_name);
+ ares_free(rr_name);
status = ARES_EBADRESP;
break;
}
@@ -141,6 +136,12 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
rr_len = DNS_RR_LEN(aptr);
rr_ttl = DNS_RR_TTL(aptr);
aptr += RRFIXEDSZ;
+ if (aptr + rr_len > abuf + alen)
+ {
+ ares_free(rr_name);
+ status = ARES_EBADRESP;
+ break;
+ }
if (rr_class == C_IN && rr_type == T_AAAA
&& rr_len == sizeof(struct ares_in6_addr)
@@ -149,22 +150,22 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
if (addrs)
{
if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
- {
- free(rr_name);
+ { /* 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)
- {
- free(rr_name);
+ { /* 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;
}
@@ -178,7 +179,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
if (aliases)
aliases[naliases] = rr_name;
else
- free(rr_name);
+ ares_free(rr_name);
naliases++;
/* Decode the RR data and replace the hostname with it. */
@@ -186,7 +187,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
&len);
if (status != ARES_SUCCESS)
break;
- free(hostname);
+ ares_free(hostname);
hostname = rr_data;
/* Take the min of the TTLs we see in the CNAME chain. */
@@ -194,17 +195,19 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
cname_ttl = rr_ttl;
}
else
- free(rr_name);
+ ares_free(rr_name);
aptr += rr_len;
if (aptr > abuf + alen)
- {
+ { /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
break;
- }
+ } /* LCOV_EXCL_STOP */
}
- if (status == ARES_SUCCESS && naddrs == 0)
+ /* 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)
{
@@ -225,10 +228,10 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
if (host)
{
/* Allocate memory to build the host entry. */
- hostent = malloc(sizeof(struct hostent));
+ hostent = ares_malloc(sizeof(struct hostent));
if (hostent)
{
- hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *));
+ hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
if (hostent->h_addr_list)
{
/* Fill in the hostent and return successfully. */
@@ -239,10 +242,12 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
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;
}
- free(hostent);
+ ares_free(hostent);
}
status = ARES_ENOMEM;
}
@@ -250,10 +255,10 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
if (aliases)
{
for (i = 0; i < naliases; i++)
- free(aliases[i]);
- free(aliases);
+ ares_free(aliases[i]);
+ ares_free(aliases);
}
- free(addrs);
- free(hostname);
+ ares_free(addrs);
+ ares_free(hostname);
return status;
}
diff --git a/ares_parse_mx_reply.c b/ares_parse_mx_reply.c
index 2180054..e633647 100644
--- a/ares_parse_mx_reply.c
+++ b/ares_parse_mx_reply.c
@@ -17,9 +17,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -38,8 +35,6 @@
# include <arpa/nameser_compat.h>
#endif
-#include <stdlib.h>
-#include <string.h>
#include "ares.h"
#include "ares_dns.h"
#include "ares_data.h"
@@ -81,7 +76,7 @@ ares_parse_mx_reply (const unsigned char *abuf, int alen,
if (aptr + len + QFIXEDSZ > abuf + alen)
{
- free (hostname);
+ ares_free (hostname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
@@ -105,6 +100,11 @@ ares_parse_mx_reply (const unsigned char *abuf, int alen,
rr_class = DNS_RR_CLASS (aptr);
rr_len = DNS_RR_LEN (aptr);
aptr += RRFIXEDSZ;
+ if (aptr + rr_len > abuf + alen)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
/* Check if we are really looking at a MX record */
if (rr_class == C_IN && rr_type == T_MX)
@@ -143,7 +143,7 @@ ares_parse_mx_reply (const unsigned char *abuf, int alen,
}
/* Don't lose memory in the next iteration */
- free (rr_name);
+ ares_free (rr_name);
rr_name = NULL;
/* Move on to the next record */
@@ -151,9 +151,9 @@ ares_parse_mx_reply (const unsigned char *abuf, int alen,
}
if (hostname)
- free (hostname);
+ ares_free (hostname);
if (rr_name)
- free (rr_name);
+ ares_free (rr_name);
/* clean up on error */
if (status != ARES_SUCCESS)
diff --git a/ares_parse_naptr_reply.c b/ares_parse_naptr_reply.c
new file mode 100644
index 0000000..717d355
--- /dev/null
+++ b/ares_parse_naptr_reply.c
@@ -0,0 +1,193 @@
+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2009 by Jakub Hrozek <jhrozek@redhat.com>
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#include "ares_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#else
+# include "nameser.h"
+#endif
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+# include <arpa/nameser_compat.h>
+#endif
+
+#include "ares.h"
+#include "ares_dns.h"
+#include "ares_data.h"
+#include "ares_private.h"
+
+/* AIX portability check */
+#ifndef T_NAPTR
+ #define T_NAPTR 35 /* naming authority pointer */
+#endif
+
+int
+ares_parse_naptr_reply (const unsigned char *abuf, int alen,
+ struct ares_naptr_reply **naptr_out)
+{
+ unsigned int qdcount, ancount, i;
+ const unsigned char *aptr, *vptr;
+ int status, rr_type, rr_class, rr_len;
+ long len;
+ char *hostname = NULL, *rr_name = NULL;
+ struct ares_naptr_reply *naptr_head = NULL;
+ struct ares_naptr_reply *naptr_last = NULL;
+ struct ares_naptr_reply *naptr_curr;
+
+ /* Set *naptr_out to NULL for all failure cases. */
+ *naptr_out = 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;
+ if (ancount == 0)
+ return ARES_ENODATA;
+
+ /* Expand the name from the question, and skip past the question. */
+ aptr = abuf + HFIXEDSZ;
+ status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
+ if (status != ARES_SUCCESS)
+ return status;
+
+ if (aptr + len + QFIXEDSZ > abuf + alen)
+ {
+ ares_free (hostname);
+ return ARES_EBADRESP;
+ }
+ aptr += len + QFIXEDSZ;
+
+ /* Examine each answer resource record (RR) in turn. */
+ for (i = 0; i < ancount; i++)
+ {
+ /* Decode the RR up to the data field. */
+ status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
+ if (status != ARES_SUCCESS)
+ {
+ break;
+ }
+ aptr += len;
+ if (aptr + RRFIXEDSZ > abuf + alen)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
+ 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)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
+ /* RR must contain at least 7 bytes = 2 x int16 + 3 x name */
+ if (rr_len < 7)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
+
+ /* Check if we are really looking at a NAPTR record */
+ if (rr_class == C_IN && rr_type == T_NAPTR)
+ {
+ /* parse the NAPTR record itself */
+
+ /* Allocate storage for this NAPTR answer appending it to the list */
+ naptr_curr = ares_malloc_data(ARES_DATATYPE_NAPTR_REPLY);
+ if (!naptr_curr)
+ {
+ status = ARES_ENOMEM;
+ break;
+ }
+ if (naptr_last)
+ {
+ naptr_last->next = naptr_curr;
+ }
+ else
+ {
+ naptr_head = naptr_curr;
+ }
+ naptr_last = naptr_curr;
+
+ vptr = aptr;
+ naptr_curr->order = DNS__16BIT(vptr);
+ vptr += sizeof(unsigned short);
+ naptr_curr->preference = DNS__16BIT(vptr);
+ vptr += sizeof(unsigned short);
+
+ status = ares_expand_string(vptr, abuf, alen, &naptr_curr->flags, &len);
+ if (status != ARES_SUCCESS)
+ break;
+ vptr += len;
+
+ status = ares_expand_string(vptr, abuf, alen, &naptr_curr->service, &len);
+ if (status != ARES_SUCCESS)
+ break;
+ vptr += len;
+
+ status = ares_expand_string(vptr, abuf, alen, &naptr_curr->regexp, &len);
+ if (status != ARES_SUCCESS)
+ break;
+ vptr += len;
+
+ status = ares_expand_name(vptr, abuf, alen, &naptr_curr->replacement, &len);
+ if (status != ARES_SUCCESS)
+ break;
+ }
+
+ /* Don't lose memory in the next iteration */
+ ares_free (rr_name);
+ rr_name = NULL;
+
+ /* Move on to the next record */
+ aptr += rr_len;
+ }
+
+ if (hostname)
+ ares_free (hostname);
+ if (rr_name)
+ ares_free (rr_name);
+
+ /* clean up on error */
+ if (status != ARES_SUCCESS)
+ {
+ if (naptr_head)
+ ares_free_data (naptr_head);
+ return status;
+ }
+
+ /* everything looks fine, return the data */
+ *naptr_out = naptr_head;
+
+ return ARES_SUCCESS;
+}
diff --git a/ares_parse_ns_reply.c b/ares_parse_ns_reply.c
index 5e9af71..7bb5142 100644
--- a/ares_parse_ns_reply.c
+++ b/ares_parse_ns_reply.c
@@ -20,9 +20,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -41,8 +38,6 @@
# include <arpa/nameser_compat.h>
#endif
-#include <stdlib.h>
-#include <string.h>
#include "ares.h"
#include "ares_dns.h"
#include "ares_private.h"
@@ -78,16 +73,16 @@ int ares_parse_ns_reply( const unsigned char* abuf, int alen,
return status;
if ( aptr + len + QFIXEDSZ > abuf + alen )
{
- free( hostname );
+ ares_free( hostname );
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
/* Allocate nameservers array; ancount gives an upper bound */
- nameservers = malloc( ( ancount + 1 ) * sizeof( char * ) );
+ nameservers = ares_malloc( ( ancount + 1 ) * sizeof( char * ) );
if ( !nameservers )
{
- free( hostname );
+ ares_free( hostname );
return ARES_ENOMEM;
}
nameservers_num = 0;
@@ -103,13 +98,19 @@ int ares_parse_ns_reply( const unsigned char* abuf, int alen,
if ( aptr + RRFIXEDSZ > abuf + alen )
{
status = ARES_EBADRESP;
- free(rr_name);
+ ares_free(rr_name);
break;
}
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;
+ break;
+ }
if ( rr_class == C_IN && rr_type == T_NS )
{
@@ -118,33 +119,33 @@ int ares_parse_ns_reply( const unsigned char* abuf, int alen,
&len);
if ( status != ARES_SUCCESS )
{
- free(rr_name);
+ ares_free(rr_name);
break;
}
- nameservers[nameservers_num] = malloc(strlen(rr_data)+1);
+ nameservers[nameservers_num] = ares_malloc(strlen(rr_data)+1);
if (nameservers[nameservers_num]==NULL)
{
- free(rr_name);
- free(rr_data);
+ ares_free(rr_name);
+ ares_free(rr_data);
status=ARES_ENOMEM;
break;
}
strcpy(nameservers[nameservers_num],rr_data);
- free(rr_data);
+ ares_free(rr_data);
nameservers_num++;
}
- free( rr_name );
+ ares_free( rr_name );
aptr += rr_len;
if ( aptr > abuf + alen )
- {
+ { /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
break;
- }
+ } /* LCOV_EXCL_STOP */
}
if ( status == ARES_SUCCESS && nameservers_num == 0 )
@@ -155,10 +156,10 @@ int ares_parse_ns_reply( const unsigned char* abuf, int alen,
{
/* We got our answer. Allocate memory to build the host entry. */
nameservers[nameservers_num] = NULL;
- hostent = malloc( sizeof( struct hostent ) );
+ hostent = ares_malloc( sizeof( struct hostent ) );
if ( hostent )
{
- hostent->h_addr_list = malloc( 1 * sizeof( char * ) );
+ hostent->h_addr_list = ares_malloc( 1 * sizeof( char * ) );
if ( hostent->h_addr_list )
{
/* Fill in the hostent and return successfully. */
@@ -170,13 +171,13 @@ int ares_parse_ns_reply( const unsigned char* abuf, int alen,
*host = hostent;
return ARES_SUCCESS;
}
- free( hostent );
+ ares_free( hostent );
}
status = ARES_ENOMEM;
}
for ( i = 0; i < nameservers_num; i++ )
- free( nameservers[i] );
- free( nameservers );
- free( hostname );
+ ares_free( nameservers[i] );
+ ares_free( nameservers );
+ ares_free( hostname );
return status;
}
diff --git a/ares_parse_ptr_reply.c b/ares_parse_ptr_reply.c
index 3b6dbc3..976a531 100644
--- a/ares_parse_ptr_reply.c
+++ b/ares_parse_ptr_reply.c
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -38,10 +35,9 @@
# include <strings.h>
#endif
-#include <stdlib.h>
-#include <string.h>
#include "ares.h"
#include "ares_dns.h"
+#include "ares_nowarn.h"
#include "ares_private.h"
int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
@@ -77,17 +73,17 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
return status;
if (aptr + len + QFIXEDSZ > abuf + alen)
{
- free(ptrname);
+ ares_free(ptrname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
/* Examine each answer resource record (RR) in turn. */
hostname = NULL;
- aliases = malloc(alias_alloc * sizeof(char *));
+ aliases = ares_malloc(alias_alloc * sizeof(char *));
if (!aliases)
{
- free(ptrname);
+ ares_free(ptrname);
return ARES_ENOMEM;
}
for (i = 0; i < (int)ancount; i++)
@@ -99,7 +95,7 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
aptr += len;
if (aptr + RRFIXEDSZ > abuf + alen)
{
- free(rr_name);
+ ares_free(rr_name);
status = ARES_EBADRESP;
break;
}
@@ -107,6 +103,12 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
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;
+ break;
+ }
if (rr_class == C_IN && rr_type == T_PTR
&& strcasecmp(rr_name, ptrname) == 0)
@@ -116,16 +118,16 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
&len);
if (status != ARES_SUCCESS)
{
- free(rr_name);
+ ares_free(rr_name);
break;
}
if (hostname)
- free(hostname);
+ ares_free(hostname);
hostname = rr_data;
- aliases[aliascnt] = malloc((strlen(rr_data)+1) * sizeof(char));
+ aliases[aliascnt] = ares_malloc((strlen(rr_data)+1) * sizeof(char));
if (!aliases[aliascnt])
{
- free(rr_name);
+ ares_free(rr_name);
status = ARES_ENOMEM;
break;
}
@@ -134,9 +136,9 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
if (aliascnt >= alias_alloc) {
char **ptr;
alias_alloc *= 2;
- ptr = realloc(aliases, alias_alloc * sizeof(char *));
+ ptr = ares_realloc(aliases, alias_alloc * sizeof(char *));
if(!ptr) {
- free(rr_name);
+ ares_free(rr_name);
status = ARES_ENOMEM;
break;
}
@@ -151,20 +153,20 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
&len);
if (status != ARES_SUCCESS)
{
- free(rr_name);
+ ares_free(rr_name);
break;
}
- free(ptrname);
+ ares_free(ptrname);
ptrname = rr_data;
}
- free(rr_name);
+ ares_free(rr_name);
aptr += rr_len;
if (aptr > abuf + alen)
- {
+ { /* LCOV_EXCL_START: already checked above */
status = ARES_EBADRESP;
break;
- }
+ } /* LCOV_EXCL_STOP */
}
if (status == ARES_SUCCESS && !hostname)
@@ -172,16 +174,16 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
if (status == ARES_SUCCESS)
{
/* We got our answer. Allocate memory to build the host entry. */
- hostent = malloc(sizeof(struct hostent));
+ hostent = ares_malloc(sizeof(struct hostent));
if (hostent)
{
- hostent->h_addr_list = malloc(2 * sizeof(char *));
+ hostent->h_addr_list = ares_malloc(2 * sizeof(char *));
if (hostent->h_addr_list)
{
- hostent->h_addr_list[0] = malloc(addrlen);
+ hostent->h_addr_list[0] = ares_malloc(addrlen);
if (hostent->h_addr_list[0])
{
- hostent->h_aliases = malloc((aliascnt+1) * sizeof (char *));
+ hostent->h_aliases = ares_malloc((aliascnt+1) * sizeof (char *));
if (hostent->h_aliases)
{
/* Fill in the hostent and return successfully. */
@@ -189,29 +191,29 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
for (i=0 ; i<aliascnt ; i++)
hostent->h_aliases[i] = aliases[i];
hostent->h_aliases[aliascnt] = NULL;
- hostent->h_addrtype = family;
- hostent->h_length = addrlen;
+ hostent->h_addrtype = aresx_sitoss(family);
+ hostent->h_length = aresx_sitoss(addrlen);
memcpy(hostent->h_addr_list[0], addr, addrlen);
hostent->h_addr_list[1] = NULL;
*host = hostent;
- free(aliases);
- free(ptrname);
+ ares_free(aliases);
+ ares_free(ptrname);
return ARES_SUCCESS;
}
- free(hostent->h_addr_list[0]);
+ ares_free(hostent->h_addr_list[0]);
}
- free(hostent->h_addr_list);
+ ares_free(hostent->h_addr_list);
}
- free(hostent);
+ ares_free(hostent);
}
status = ARES_ENOMEM;
}
for (i=0 ; i<aliascnt ; i++)
- if (aliases[i])
- free(aliases[i]);
- free(aliases);
+ if (aliases[i])
+ ares_free(aliases[i]);
+ ares_free(aliases);
if (hostname)
- free(hostname);
- free(ptrname);
+ ares_free(hostname);
+ ares_free(ptrname);
return status;
}
diff --git a/ares_parse_soa_reply.c b/ares_parse_soa_reply.c
new file mode 100644
index 0000000..35af0a7
--- /dev/null
+++ b/ares_parse_soa_reply.c
@@ -0,0 +1,133 @@
+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2012 Marko Kreen <markokr@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#include "ares_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#else
+# include "nameser.h"
+#endif
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+# include <arpa/nameser_compat.h>
+#endif
+
+#include "ares.h"
+#include "ares_dns.h"
+#include "ares_data.h"
+#include "ares_private.h"
+
+int
+ares_parse_soa_reply(const unsigned char *abuf, int alen,
+ struct ares_soa_reply **soa_out)
+{
+ const unsigned char *aptr;
+ long len;
+ char *qname = NULL, *rr_name = NULL;
+ struct ares_soa_reply *soa = NULL;
+ int qdcount, ancount;
+ int status;
+
+ if (alen < HFIXEDSZ)
+ return ARES_EBADRESP;
+
+ /* parse message header */
+ qdcount = DNS_HEADER_QDCOUNT(abuf);
+ ancount = DNS_HEADER_ANCOUNT(abuf);
+ if (qdcount != 1 || ancount != 1)
+ return ARES_EBADRESP;
+ aptr = abuf + HFIXEDSZ;
+
+ /* query name */
+ status = ares__expand_name_for_response(aptr, abuf, alen, &qname, &len);
+ if (status != ARES_SUCCESS)
+ goto failed_stat;
+ aptr += len;
+
+ /* 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)
+ goto failed;
+ aptr += RRFIXEDSZ;
+
+ /* allocate result struct */
+ soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY);
+ if (!soa)
+ {
+ status = ARES_ENOMEM;
+ goto failed_stat;
+ }
+
+ /* nsname */
+ status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname, &len);
+ if (status != ARES_SUCCESS)
+ goto failed_stat;
+ aptr += len;
+
+ /* 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;
+
+failed:
+ status = ARES_EBADRESP;
+
+failed_stat:
+ ares_free_data(soa);
+ if (qname)
+ ares_free(qname);
+ if (rr_name)
+ ares_free(rr_name);
+ return status;
+}
+
diff --git a/ares_parse_srv_reply.c b/ares_parse_srv_reply.c
index 9c7eb6e..824ff3a 100644
--- a/ares_parse_srv_reply.c
+++ b/ares_parse_srv_reply.c
@@ -17,9 +17,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -38,8 +35,6 @@
# include <arpa/nameser_compat.h>
#endif
-#include <stdlib.h>
-#include <string.h>
#include "ares.h"
#include "ares_dns.h"
#include "ares_data.h"
@@ -86,7 +81,7 @@ ares_parse_srv_reply (const unsigned char *abuf, int alen,
if (aptr + len + QFIXEDSZ > abuf + alen)
{
- free (hostname);
+ ares_free (hostname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
@@ -110,6 +105,11 @@ ares_parse_srv_reply (const unsigned char *abuf, int alen,
rr_class = DNS_RR_CLASS (aptr);
rr_len = DNS_RR_LEN (aptr);
aptr += RRFIXEDSZ;
+ if (aptr + rr_len > abuf + alen)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
/* Check if we are really looking at a SRV record */
if (rr_class == C_IN && rr_type == T_SRV)
@@ -152,7 +152,7 @@ ares_parse_srv_reply (const unsigned char *abuf, int alen,
}
/* Don't lose memory in the next iteration */
- free (rr_name);
+ ares_free (rr_name);
rr_name = NULL;
/* Move on to the next record */
@@ -160,9 +160,9 @@ ares_parse_srv_reply (const unsigned char *abuf, int alen,
}
if (hostname)
- free (hostname);
+ ares_free (hostname);
if (rr_name)
- free (rr_name);
+ ares_free (rr_name);
/* clean up on error */
if (status != ARES_SUCCESS)
diff --git a/ares_parse_txt_reply.c b/ares_parse_txt_reply.c
index 5165332..4856b4c 100644
--- a/ares_parse_txt_reply.c
+++ b/ares_parse_txt_reply.c
@@ -17,9 +17,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -42,28 +39,25 @@
# include <strings.h>
#endif
-#include <stdlib.h>
-#include <string.h>
-
#include "ares.h"
#include "ares_dns.h"
#include "ares_data.h"
#include "ares_private.h"
-int
-ares_parse_txt_reply (const unsigned char *abuf, int alen,
- struct ares_txt_reply **txt_out)
+static int
+ares__parse_txt_reply (const unsigned char *abuf, int alen,
+ int ex, void **txt_out)
{
- size_t substr_len, str_len;
+ size_t substr_len;
unsigned int qdcount, ancount, i;
const unsigned char *aptr;
const unsigned char *strptr;
int status, rr_type, rr_class, rr_len;
long len;
char *hostname = NULL, *rr_name = NULL;
- struct ares_txt_reply *txt_head = NULL;
- struct ares_txt_reply *txt_last = NULL;
- struct ares_txt_reply *txt_curr;
+ struct ares_txt_ext *txt_head = NULL;
+ struct ares_txt_ext *txt_last = NULL;
+ struct ares_txt_ext *txt_curr;
/* Set *txt_out to NULL for all failure cases. */
*txt_out = NULL;
@@ -88,7 +82,7 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
if (aptr + len + QFIXEDSZ > abuf + alen)
{
- free (hostname);
+ ares_free (hostname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
@@ -112,27 +106,15 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
rr_class = DNS_RR_CLASS (aptr);
rr_len = DNS_RR_LEN (aptr);
aptr += RRFIXEDSZ;
+ if (aptr + rr_len > abuf + alen)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
/* Check if we are really looking at a TXT record */
if (rr_class == C_IN && rr_type == T_TXT)
{
- /* Allocate storage for this TXT answer appending it to the list */
- txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY);
- if (!txt_curr)
- {
- status = ARES_ENOMEM;
- break;
- }
- if (txt_last)
- {
- txt_last->next = txt_curr;
- }
- else
- {
- txt_head = txt_curr;
- }
- txt_last = txt_curr;
-
/*
* There may be multiple substrings in a single TXT record. Each
* substring may be up to 255 characters in length, with a
@@ -141,40 +123,62 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
* substrings contained therein.
*/
- /* Compute total length to allow a single memory allocation */
strptr = aptr;
while (strptr < (aptr + rr_len))
{
substr_len = (unsigned char)*strptr;
- txt_curr->length += substr_len;
- strptr += substr_len + 1;
- }
-
- /* Including null byte */
- txt_curr->txt = malloc (txt_curr->length + 1);
- if (txt_curr->txt == NULL)
- {
- status = ARES_ENOMEM;
- break;
- }
+ if (strptr + substr_len + 1 > aptr + rr_len)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
+
+ /* Allocate storage for this TXT answer appending it to the list */
+ txt_curr = ares_malloc_data(ex ? ARES_DATATYPE_TXT_EXT :
+ ARES_DATATYPE_TXT_REPLY);
+ if (!txt_curr)
+ {
+ status = ARES_ENOMEM;
+ break;
+ }
+ if (txt_last)
+ {
+ txt_last->next = txt_curr;
+ }
+ else
+ {
+ txt_head = txt_curr;
+ }
+ txt_last = txt_curr;
+
+ if (ex)
+ txt_curr->record_start = (strptr == aptr);
+ txt_curr->length = substr_len;
+ txt_curr->txt = ares_malloc (substr_len + 1/* Including null byte */);
+ if (txt_curr->txt == NULL)
+ {
+ status = ARES_ENOMEM;
+ break;
+ }
+
+ ++strptr;
+ memcpy ((char *) txt_curr->txt, strptr, substr_len);
+
+ /* Make sure we NULL-terminate */
+ txt_curr->txt[substr_len] = 0;
- /* Step through the list of substrings, concatenating them */
- str_len = 0;
- strptr = aptr;
- while (strptr < (aptr + rr_len))
- {
- substr_len = (unsigned char)*strptr;
- strptr++;
- memcpy ((char *) txt_curr->txt + str_len, strptr, substr_len);
- str_len += substr_len;
strptr += substr_len;
}
- /* Make sure we NULL-terminate */
- *((char *) txt_curr->txt + txt_curr->length) = '\0';
+ }
+
+ /* Propagate any failures */
+ if (status != ARES_SUCCESS)
+ {
+ break;
}
/* Don't lose memory in the next iteration */
- free (rr_name);
+ ares_free (rr_name);
rr_name = NULL;
/* Move on to the next record */
@@ -182,9 +186,9 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
}
if (hostname)
- free (hostname);
+ ares_free (hostname);
if (rr_name)
- free (rr_name);
+ ares_free (rr_name);
/* clean up on error */
if (status != ARES_SUCCESS)
@@ -199,3 +203,18 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
return ARES_SUCCESS;
}
+
+int
+ares_parse_txt_reply (const unsigned char *abuf, int alen,
+ struct ares_txt_reply **txt_out)
+{
+ return ares__parse_txt_reply(abuf, alen, 0, (void **) txt_out);
+}
+
+
+int
+ares_parse_txt_reply_ext (const unsigned char *abuf, int alen,
+ struct ares_txt_ext **txt_out)
+{
+ return ares__parse_txt_reply(abuf, alen, 1, (void **) txt_out);
+}
diff --git a/ares_private.h b/ares_private.h
index ff45ba7..5d77386 100644
--- a/ares_private.h
+++ b/ares_private.h
@@ -26,9 +26,6 @@
#define WIN32
#endif
-#include <stdio.h>
-#include <sys/types.h>
-
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -40,24 +37,33 @@
#define HAVE_WRITEV 1
#endif
-#ifdef NETWARE
-#include <time.h>
-#endif
-
#define DEFAULT_TIMEOUT 5000 /* milliseconds */
#define DEFAULT_TRIES 4
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
+#ifdef CARES_EXPOSE_STATICS
+/* Make some internal functions visible for testing */
+#define STATIC_TESTABLE
+#else
+#define STATIC_TESTABLE static
+#endif
+
#if defined(WIN32) && !defined(WATT32)
#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP"
#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
+#define WIN_DNSCLIENT "Software\\Policies\\Microsoft\\System\\DNSClient"
#define NAMESERVER "NameServer"
#define DHCPNAMESERVER "DhcpNameServer"
#define DATABASEPATH "DatabasePath"
#define WIN_PATH_HOSTS "\\hosts"
+#define SEARCHLIST_KEY "SearchList"
+#define PRIMARYDNSSUFFIX_KEY "PrimaryDNSSuffix"
+#define INTERFACES_KEY "Interfaces"
+#define DOMAIN_KEY "Domain"
+#define DHCPDOMAIN_KEY "DhcpDomain"
#elif defined(WATT32)
@@ -93,10 +99,7 @@
# define getenv(ptr) ares_getenv(ptr)
#endif
-#ifndef HAVE_STRDUP
-# include "ares_strdup.h"
-# define strdup(ptr) ares_strdup(ptr)
-#endif
+#include "ares_strdup.h"
#ifndef HAVE_STRCASECMP
# include "ares_strcasecmp.h"
@@ -113,12 +116,21 @@
# define writev(s,ptr,cnt) ares_writev(s,ptr,cnt)
#endif
+/********* EDNS defines section ******/
+#define EDNSPACKETSZ 1280 /* Reasonable UDP payload size, as suggested
+ in RFC2671 */
+#define MAXENDSSZ 4096 /* Maximum (local) limit for edns packet size */
+#define EDNSFIXEDSZ 11 /* Size of EDNS header */
+/********* EDNS defines section ******/
+
struct ares_addr {
int family;
union {
struct in_addr addr4;
struct ares_in6_addr addr6;
} addr;
+ int udp_port; /* stored in network order */
+ int tcp_port; /* stored in network order */
};
#define addrV4 addr.addr4
#define addrV6 addr.addr6
@@ -251,8 +263,8 @@ struct ares_channeldata {
int tries;
int ndots;
int rotate; /* if true, all servers specified are used */
- int udp_port;
- int tcp_port;
+ int udp_port; /* stored in network order */
+ int tcp_port; /* stored in network order */
int socket_send_buffer_size;
int socket_receive_buffer_size;
char **domains;
@@ -260,6 +272,7 @@ struct ares_channeldata {
struct apattern *sortlist;
int nsort;
char *lookups;
+ int ednspsz;
/* For binding to local devices and/or IP addresses. Leave
* them null/zero for no binding.
@@ -304,20 +317,23 @@ struct ares_channeldata {
ares_sock_create_callback sock_create_cb;
void *sock_create_cb_data;
+
+ ares_sock_config_callback sock_config_cb;
+ void *sock_config_cb_data;
+
+ const struct ares_socket_functions * sock_funcs;
+ void *sock_func_cb_data;
};
+/* Memory management functions */
+extern void *(*ares_malloc)(size_t size);
+extern void *(*ares_realloc)(void *ptr, size_t size);
+extern void (*ares_free)(void *ptr);
+
/* return true if now is exactly check time or later */
int ares__timedout(struct timeval *now,
struct timeval *check);
-/* add the specific number of milliseconds to the time in the first argument */
-int ares__timeadd(struct timeval *now,
- int millisecs);
-/* return time offset between now and (future) check, in milliseconds */
-long ares__timeoffset(struct timeval *now,
- struct timeval *check);
-/* returns ARES_SUCCESS if library has been initialized */
-int ares_library_initialized(void);
-void ares__rc4(rc4_key* key,unsigned char *buffer_ptr, int buffer_len);
+
void ares__send_query(ares_channel channel, struct query *query,
struct timeval *now);
void ares__close_sockets(ares_channel channel, struct server_state *server);
@@ -335,6 +351,8 @@ void ares__destroy_servers_state(ares_channel channel);
long ares__tvdiff(struct timeval t1, struct timeval t2);
#endif
+void ares__socket_close(ares_channel, ares_socket_t);
+
#define ARES_SWAP_BYTE(a,b) \
{ unsigned char swapByte = *(a); *(a) = *(b); *(b) = swapByte; }
@@ -342,13 +360,14 @@ long ares__tvdiff(struct timeval t1, struct timeval t2);
do { \
if ((c)->sock_state_cb) \
(c)->sock_state_cb((c)->sock_state_cb_data, (s), (r), (w)); \
- } while (0)
+ } WHILE_FALSE
#ifdef CURLDEBUG
/* This is low-level hard-hacking memory leak tracking and similar. Using the
libcurl lowlevel code from within library is ugly and only works when
c-ares is built and linked with a similarly curldebug-enabled libcurl,
but we do this anyway for convenience. */
+#define HEADER_CURL_SETUP_ONCE_H
#include "../lib/memdebug.h"
#endif
diff --git a/ares_process.c b/ares_process.c
index e5efa5f..df85524 100644
--- a/ares_process.c
+++ b/ares_process.c
@@ -1,6 +1,6 @@
/* Copyright 1998 by the Massachusetts Institute of Technology.
- * Copyright (C) 2004-2010 by Daniel Stenberg
+ * Copyright (C) 2004-2017 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -17,9 +17,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
@@ -32,6 +29,9 @@
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h>
#else
@@ -41,16 +41,9 @@
# include <arpa/nameser_compat.h>
#endif
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
@@ -59,10 +52,7 @@
#endif
#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
#include <fcntl.h>
-#include <time.h>
#include "ares.h"
#include "ares_dns.h"
@@ -78,7 +68,7 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds,
static void read_udp_packets(ares_channel channel, fd_set *read_fds,
ares_socket_t read_fd, struct timeval *now);
static void advance_tcp_send_queue(ares_channel channel, int whichserver,
- ssize_t num_bytes);
+ ares_ssize_t num_bytes);
static void process_timeouts(ares_channel channel, struct timeval *now);
static void process_broken_connections(ares_channel channel,
struct timeval *now);
@@ -115,8 +105,7 @@ int ares__timedout(struct timeval *now,
}
/* add the specific number of milliseconds to the time in the first argument */
-int ares__timeadd(struct timeval *now,
- int millisecs)
+static void timeadd(struct timeval *now, int millisecs)
{
now->tv_sec += millisecs/1000;
now->tv_usec += (millisecs%1000)*1000;
@@ -125,19 +114,8 @@ int ares__timeadd(struct timeval *now,
++(now->tv_sec);
now->tv_usec -= 1000000;
}
-
- return 0;
-}
-
-/* return time offset between now and (future) check, in milliseconds */
-long ares__timeoffset(struct timeval *now,
- struct timeval *check)
-{
- return (check->tv_sec - now->tv_sec)*1000 +
- (check->tv_usec - now->tv_usec)/1000;
}
-
/*
* generic process function
*/
@@ -200,6 +178,26 @@ static int try_again(int errnum)
return 0;
}
+static ares_ssize_t socket_writev(ares_channel channel, ares_socket_t s, const struct iovec * vec, int len)
+{
+ if (channel->sock_funcs)
+ return channel->sock_funcs->asendv(s, vec, len, channel->sock_func_cb_data);
+
+ return writev(s, vec, len);
+}
+
+static ares_ssize_t socket_write(ares_channel channel, ares_socket_t s, const void * data, size_t len)
+{
+ if (channel->sock_funcs)
+ {
+ struct iovec vec;
+ vec.iov_base = (void*)data;
+ vec.iov_len = len;
+ return channel->sock_funcs->asendv(s, &vec, 1, channel->sock_func_cb_data);
+ }
+ return swrite(s, data, len);
+}
+
/* If any TCP sockets select true for writing, write out queued data
* we have for them.
*/
@@ -212,8 +210,8 @@ static void write_tcp_data(ares_channel channel,
struct send_request *sendreq;
struct iovec *vec;
int i;
- ssize_t scount;
- ssize_t wcount;
+ ares_ssize_t scount;
+ ares_ssize_t wcount;
size_t n;
if(!write_fds && (write_fd == ARES_SOCKET_BAD))
@@ -252,7 +250,7 @@ static void write_tcp_data(ares_channel channel,
n++;
/* Allocate iovecs so we can send all our data at once. */
- vec = malloc(n * sizeof(struct iovec));
+ vec = ares_malloc(n * sizeof(struct iovec));
if (vec)
{
/* Fill in the iovecs and send. */
@@ -263,12 +261,12 @@ static void write_tcp_data(ares_channel channel,
vec[n].iov_len = sendreq->len;
n++;
}
- wcount = (ssize_t)writev(server->tcp_socket, vec, (int)n);
- free(vec);
+ wcount = socket_writev(channel, server->tcp_socket, vec, (int)n);
+ ares_free(vec);
if (wcount < 0)
{
if (!try_again(SOCKERRNO))
- handle_error(channel, i, now);
+ handle_error(channel, i, now);
continue;
}
@@ -280,11 +278,11 @@ static void write_tcp_data(ares_channel channel,
/* Can't allocate iovecs; just send the first request. */
sendreq = server->qhead;
- scount = swrite(server->tcp_socket, sendreq->data, sendreq->len);
+ scount = socket_write(channel, server->tcp_socket, sendreq->data, sendreq->len);
if (scount < 0)
{
if (!try_again(SOCKERRNO))
- handle_error(channel, i, now);
+ handle_error(channel, i, now);
continue;
}
@@ -296,7 +294,7 @@ static void write_tcp_data(ares_channel channel,
/* Consume the given number of bytes from the head of the TCP send queue. */
static void advance_tcp_send_queue(ares_channel channel, int whichserver,
- ssize_t num_bytes)
+ ares_ssize_t num_bytes)
{
struct send_request *sendreq;
struct server_state *server = &channel->servers[whichserver];
@@ -306,8 +304,8 @@ static void advance_tcp_send_queue(ares_channel channel, int whichserver,
num_bytes -= sendreq->len;
server->qhead = sendreq->next;
if (sendreq->data_storage)
- free(sendreq->data_storage);
- free(sendreq);
+ ares_free(sendreq->data_storage);
+ ares_free(sendreq);
if (server->qhead == NULL) {
SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 0);
server->qtail = NULL;
@@ -324,6 +322,38 @@ static void advance_tcp_send_queue(ares_channel channel, int whichserver,
}
}
+static ares_ssize_t socket_recvfrom(ares_channel channel,
+ ares_socket_t s,
+ void * data,
+ size_t data_len,
+ int flags,
+ struct sockaddr *from,
+ ares_socklen_t *from_len)
+{
+ if (channel->sock_funcs)
+ return channel->sock_funcs->arecvfrom(s, data, data_len,
+ flags, from, from_len,
+ channel->sock_func_cb_data);
+
+#ifdef HAVE_RECVFROM
+ return recvfrom(s, data, data_len, flags, from, from_len);
+#else
+ return sread(s, data, data_len);
+#endif
+}
+
+static ares_ssize_t socket_recv(ares_channel channel,
+ ares_socket_t s,
+ void * data,
+ size_t data_len)
+{
+ if (channel->sock_funcs)
+ return channel->sock_funcs->arecvfrom(s, data, data_len, 0, 0, 0,
+ channel->sock_func_cb_data);
+
+ return sread(s, data, data_len);
+}
+
/* If any TCP socket selects true for reading, read some data,
* allocate a buffer if we finish reading the length word, and process
* a packet if we finish reading one.
@@ -333,7 +363,7 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds,
{
struct server_state *server;
int i;
- ssize_t count;
+ ares_ssize_t count;
if(!read_fds && (read_fd == ARES_SOCKET_BAD))
/* no possible action */
@@ -356,11 +386,11 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds,
}
if(read_fds)
- /* If there's an error and we close this socket, then open
- * another with the same fd to talk to another server, then we
- * don't want to think that it was the new socket that was
- * ready. This is not disastrous, but is likely to result in
- * extra system calls and confusion. */
+ /* If there's an error and we close this socket, then open another
+ * with the same fd to talk to another server, then we don't want to
+ * think that it was the new socket that was ready. This is not
+ * disastrous, but is likely to result in extra system calls and
+ * confusion. */
FD_CLR(server->tcp_socket, read_fds);
if (server->tcp_lenbuf_pos != 2)
@@ -368,13 +398,13 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds,
/* We haven't yet read a length word, so read that (or
* what's left to read of it).
*/
- count = sread(server->tcp_socket,
- server->tcp_lenbuf + server->tcp_lenbuf_pos,
- 2 - server->tcp_lenbuf_pos);
+ count = socket_recv(channel, server->tcp_socket,
+ server->tcp_lenbuf + server->tcp_lenbuf_pos,
+ 2 - server->tcp_lenbuf_pos);
if (count <= 0)
{
if (!(count == -1 && try_again(SOCKERRNO)))
- handle_error(channel, i, now);
+ handle_error(channel, i, now);
continue;
}
@@ -386,22 +416,25 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds,
*/
server->tcp_length = server->tcp_lenbuf[0] << 8
| server->tcp_lenbuf[1];
- server->tcp_buffer = malloc(server->tcp_length);
- if (!server->tcp_buffer)
+ server->tcp_buffer = ares_malloc(server->tcp_length);
+ if (!server->tcp_buffer) {
handle_error(channel, i, now);
+ return; /* bail out on malloc failure. TODO: make this
+ function return error codes */
+ }
server->tcp_buffer_pos = 0;
}
}
else
{
/* Read data into the allocated buffer. */
- count = sread(server->tcp_socket,
- server->tcp_buffer + server->tcp_buffer_pos,
- server->tcp_length - server->tcp_buffer_pos);
+ count = socket_recv(channel, server->tcp_socket,
+ server->tcp_buffer + server->tcp_buffer_pos,
+ server->tcp_length - server->tcp_buffer_pos);
if (count <= 0)
{
if (!(count == -1 && try_again(SOCKERRNO)))
- handle_error(channel, i, now);
+ handle_error(channel, i, now);
continue;
}
@@ -413,8 +446,7 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds,
*/
process_answer(channel, server->tcp_buffer, server->tcp_length,
i, 1, now);
- if (server->tcp_buffer)
- free(server->tcp_buffer);
+ ares_free(server->tcp_buffer);
server->tcp_buffer = NULL;
server->tcp_lenbuf_pos = 0;
server->tcp_buffer_pos = 0;
@@ -429,8 +461,8 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
{
struct server_state *server;
int i;
- ssize_t count;
- unsigned char buf[PACKETSZ + 1];
+ ares_ssize_t count;
+ unsigned char buf[MAXENDSSZ + 1];
#ifdef HAVE_RECVFROM
ares_socklen_t fromlen;
union {
@@ -472,25 +504,27 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
/* To reduce event loop overhead, read and process as many
* packets as we can. */
do {
-#ifdef HAVE_RECVFROM
- if (server->addr.family == AF_INET)
- fromlen = sizeof(from.sa4);
- else
- fromlen = sizeof(from.sa6);
- count = (ssize_t)recvfrom(server->udp_socket, (void *)buf, sizeof(buf),
- 0, &from.sa, &fromlen);
-#else
- count = sread(server->udp_socket, buf, sizeof(buf));
-#endif
+ if (server->udp_socket == ARES_SOCKET_BAD)
+ count = 0;
+
+ else {
+ if (server->addr.family == AF_INET)
+ fromlen = sizeof(from.sa4);
+ else
+ fromlen = sizeof(from.sa6);
+ count = socket_recvfrom(channel, server->udp_socket, (void *)buf,
+ sizeof(buf), 0, &from.sa, &fromlen);
+ }
+
if (count == -1 && try_again(SOCKERRNO))
continue;
else if (count <= 0)
handle_error(channel, i, now);
#ifdef HAVE_RECVFROM
else if (!same_address(&from.sa, &server->addr))
- /* The address the response comes from does not match
- * the address we sent the request to. Someone may be
- * attempting to perform a cache poisoning attack. */
+ /* The address the response comes from does not match the address we
+ * sent the request to. Someone may be attempting to perform a cache
+ * poisoning attack. */
break;
#endif
else
@@ -507,11 +541,10 @@ static void process_timeouts(ares_channel channel, struct timeval *now)
struct list_node* list_head;
struct list_node* list_node;
- /* Process all the timeouts that have fired since the last time we
- * processed timeouts. If things are going well, then we'll have
- * hundreds/thousands of queries that fall into future buckets, and
- * only a handful of requests that fall into the "now" bucket, so
- * this should be quite quick.
+ /* Process all the timeouts that have fired since the last time we processed
+ * timeouts. If things are going well, then we'll have hundreds/thousands of
+ * queries that fall into future buckets, and only a handful of requests
+ * that fall into the "now" bucket, so this should be quite quick.
*/
for (t = channel->last_timeout_processed; t <= now->tv_sec; t++)
{
@@ -536,7 +569,7 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
int alen, int whichserver, int tcp,
struct timeval *now)
{
- int tc, rcode;
+ int tc, rcode, packetsz;
unsigned short id;
struct query *query;
struct list_node* list_head;
@@ -553,11 +586,10 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
rcode = DNS_HEADER_RCODE(abuf);
/* Find the query corresponding to this packet. The queries are
- * hashed/bucketed by query id, so this lookup should be quick.
- * Note that both the query id and the questions must be the same;
- * when the query id wraps around we can have multiple outstanding
- * queries with the same query id, so we need to check both the id and
- * question.
+ * hashed/bucketed by query id, so this lookup should be quick. Note that
+ * both the query id and the questions must be the same; when the query id
+ * wraps around we can have multiple outstanding queries with the same query
+ * id, so we need to check both the id and question.
*/
query = NULL;
list_head = &(channel->queries_by_qid[id % ARES_QID_TABLE_SIZE]);
@@ -574,11 +606,35 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
if (!query)
return;
+ packetsz = PACKETSZ;
+ /* If we use EDNS and server answers with one of these RCODES, the protocol
+ * extension is not understood by the responder. We must retry the query
+ * without EDNS enabled.
+ */
+ if (channel->flags & ARES_FLAG_EDNS)
+ {
+ packetsz = channel->ednspsz;
+ if (rcode == NOTIMP || rcode == FORMERR || rcode == SERVFAIL)
+ {
+ int qlen = (query->tcplen - 2) - EDNSFIXEDSZ;
+ channel->flags ^= ARES_FLAG_EDNS;
+ query->tcplen -= EDNSFIXEDSZ;
+ query->qlen -= EDNSFIXEDSZ;
+ query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
+ query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
+ DNS_HEADER_SET_ARCOUNT(query->tcpbuf + 2, 0);
+ query->tcpbuf = ares_realloc(query->tcpbuf, query->tcplen);
+ query->qbuf = query->tcpbuf + 2;
+ ares__send_query(channel, query, now);
+ return;
+ }
+ }
+
/* If we got a truncated UDP packet and are not ignoring truncation,
* don't accept the packet, and switch the query to TCP if we hadn't
* done so already.
*/
- if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
+ if ((tc || alen > packetsz) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
{
if (!query->using_tcp)
{
@@ -591,8 +647,8 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
/* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
* are ignoring truncation.
*/
- if (alen > PACKETSZ && !tcp)
- alen = PACKETSZ;
+ if (alen > packetsz && !tcp)
+ alen = packetsz;
/* If we aren't passing through all error packets, discard packets
* with SERVFAIL, NOTIMP, or REFUSED response codes.
@@ -626,6 +682,31 @@ static void process_broken_connections(ares_channel channel,
}
}
+/* Swap the contents of two lists */
+static void swap_lists(struct list_node* head_a,
+ struct list_node* head_b)
+{
+ int is_a_empty = ares__is_list_empty(head_a);
+ int is_b_empty = ares__is_list_empty(head_b);
+ struct list_node old_a = *head_a;
+ struct list_node old_b = *head_b;
+
+ if (is_a_empty) {
+ ares__init_list_head(head_b);
+ } else {
+ *head_b = old_a;
+ old_a.next->prev = head_b;
+ old_a.prev->next = head_b;
+ }
+ if (is_b_empty) {
+ ares__init_list_head(head_a);
+ } else {
+ *head_a = old_b;
+ old_b.next->prev = head_a;
+ old_b.prev->next = head_a;
+ }
+}
+
static void handle_error(ares_channel channel, int whichserver,
struct timeval *now)
{
@@ -639,15 +720,14 @@ static void handle_error(ares_channel channel, int whichserver,
/* Reset communications with this server. */
ares__close_sockets(channel, server);
- /* Tell all queries talking to this server to move on and not try
- * this server again. We steal the current list of queries that were
- * in-flight to this server, since when we call next_server this can
- * cause the queries to be re-sent to this server, which will
- * re-insert these queries in that same server->queries_to_server
- * list.
+ /* Tell all queries talking to this server to move on and not try this
+ * server again. We steal the current list of queries that were in-flight to
+ * this server, since when we call next_server this can cause the queries to
+ * be re-sent to this server, which will re-insert these queries in that
+ * same server->queries_to_server list.
*/
ares__init_list_head(&list_head);
- ares__swap_lists(&list_head, &(server->queries_to_server));
+ swap_lists(&list_head, &(server->queries_to_server));
for (list_node = list_head.next; list_node != &list_head; )
{
query = list_node->data;
@@ -663,14 +743,15 @@ static void handle_error(ares_channel channel, int whichserver,
}
static void skip_server(ares_channel channel, struct query *query,
- int whichserver) {
- /* The given server gave us problems with this query, so if we have
- * the luxury of using other servers, then let's skip the
- * potentially broken server and just use the others. If we only
- * have one server and we need to retry then we should just go ahead
- * and re-use that server, since it's our only hope; perhaps we
- * just got unlucky, and retrying will work (eg, the server timed
- * out our TCP connection just as we were sending another request).
+ int whichserver)
+{
+ /* The given server gave us problems with this query, so if we have the
+ * luxury of using other servers, then let's skip the potentially broken
+ * server and just use the others. If we only have one server and we need to
+ * retry then we should just go ahead and re-use that server, since it's our
+ * only hope; perhaps we just got unlucky, and retrying will work (eg, the
+ * server timed out our TCP connection just as we were sending another
+ * request).
*/
if (channel->nservers > 1)
{
@@ -693,11 +774,10 @@ static void next_server(ares_channel channel, struct query *query,
query->server = (query->server + 1) % channel->nservers;
server = &channel->servers[query->server];
- /* We don't want to use this server if (1) we decided this
- * connection is broken, and thus about to be closed, (2)
- * we've decided to skip this server because of earlier
- * errors we encountered, or (3) we already sent this query
- * over this exact connection.
+ /* We don't want to use this server if (1) we decided this connection is
+ * broken, and thus about to be closed, (2) we've decided to skip this
+ * server because of earlier errors we encountered, or (3) we already
+ * sent this query over this exact connection.
*/
if (!server->is_broken &&
!query->server_info[query->server].skip_server &&
@@ -709,11 +789,11 @@ static void next_server(ares_channel channel, struct query *query,
return;
}
- /* You might think that with TCP we only need one try. However,
- * even when using TCP, servers can time-out our connection just
- * as we're sending a request, or close our connection because
- * they die, or never send us a reply because they get wedged or
- * tickle a bug that drops our request.
+ /* You might think that with TCP we only need one try. However, even
+ * when using TCP, servers can time-out our connection just as we're
+ * sending a request, or close our connection because they die, or never
+ * send us a reply because they get wedged or tickle a bug that drops
+ * our request.
*/
}
@@ -743,17 +823,18 @@ void ares__send_query(ares_channel channel, struct query *query,
return;
}
}
- sendreq = calloc(1, sizeof(struct send_request));
+ sendreq = ares_malloc(sizeof(struct send_request));
if (!sendreq)
{
end_query(channel, query, ARES_ENOMEM, NULL, 0);
return;
}
- /* To make the common case fast, we avoid copies by using the
- * query's tcpbuf for as long as the query is alive. In the rare
- * case where the query ends while it's queued for transmission,
- * then we give the sendreq its own copy of the request packet
- * and put it in sendreq->data_storage.
+ memset(sendreq, 0, sizeof(struct send_request));
+ /* To make the common case fast, we avoid copies by using the query's
+ * tcpbuf for as long as the query is alive. In the rare case where the
+ * query ends while it's queued for transmission, then we give the
+ * sendreq its own copy of the request packet and put it in
+ * sendreq->data_storage.
*/
sendreq->data_storage = NULL;
sendreq->data = query->tcpbuf;
@@ -782,7 +863,7 @@ void ares__send_query(ares_channel channel, struct query *query,
return;
}
}
- if (swrite(server->udp_socket, query->qbuf, query->qlen) == -1)
+ if (socket_write(channel, server->udp_socket, query->qbuf, query->qlen) == -1)
{
/* FIXME: Handle EAGAIN here since it likely can happen. */
skip_server(channel, query, query->server);
@@ -793,8 +874,7 @@ void ares__send_query(ares_channel channel, struct query *query,
timeplus = channel->timeout << (query->try_count / channel->nservers);
timeplus = (timeplus * (9 + (rand () & 7))) / 16;
query->timeout = *now;
- ares__timeadd(&query->timeout,
- timeplus);
+ timeadd(&query->timeout, timeplus);
/* Keep track of queries bucketed by timeout, so we can process
* timeout events quickly.
*/
@@ -818,7 +898,7 @@ void ares__send_query(ares_channel channel, struct query *query,
* portable.
*/
static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
- int nonblock /* TRUE or FALSE */)
+ int nonblock /* TRUE or FALSE */)
{
#if defined(USE_BLOCKING_SOCKETS)
@@ -832,35 +912,34 @@ static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
if (FALSE != nonblock)
return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
else
- return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+ return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); /* LCOV_EXCL_LINE */
#elif defined(HAVE_IOCTL_FIONBIO)
/* older unix versions */
- int flags;
- flags = nonblock;
+ int flags = nonblock ? 1 : 0;
return ioctl(sockfd, FIONBIO, &flags);
#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
#ifdef WATT32
- char flags;
+ char flags = nonblock ? 1 : 0;
#else
/* Windows */
- unsigned long flags;
+ unsigned long flags = nonblock ? 1UL : 0UL;
#endif
- flags = nonblock;
return ioctlsocket(sockfd, FIONBIO, &flags);
#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
/* Amiga */
- return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
+ long flags = nonblock ? 1L : 0L;
+ return IoctlSocket(sockfd, FIONBIO, flags);
#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
/* BeOS */
- long b = nonblock ? 1 : 0;
+ long b = nonblock ? 1L : 0L;
return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
#else
@@ -876,12 +955,16 @@ static int configure_socket(ares_socket_t s, int family, ares_channel channel)
struct sockaddr_in6 sa6;
} local;
- setsocknonblock(s, TRUE);
+ /* do not set options for user-managed sockets */
+ if (channel->sock_funcs)
+ return 0;
+
+ (void)setsocknonblock(s, TRUE);
#if defined(FD_CLOEXEC) && !defined(MSDOS)
/* Configure the socket fd as close-on-exec. */
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1)
- return -1;
+ return -1; /* LCOV_EXCL_LINE */
#endif
/* Set the socket's send and receive buffer sizes. */
@@ -917,10 +1000,12 @@ static int configure_socket(ares_socket_t s, int family, ares_channel channel)
}
}
else if (family == AF_INET6) {
- if (memcmp(channel->local_ip6, &ares_in6addr_any, sizeof(channel->local_ip6)) != 0) {
+ if (memcmp(channel->local_ip6, &ares_in6addr_any,
+ sizeof(channel->local_ip6)) != 0) {
memset(&local.sa6, 0, sizeof(local.sa6));
local.sa6.sin6_family = AF_INET6;
- memcpy(&local.sa6.sin6_addr, channel->local_ip6, sizeof(channel->local_ip6));
+ memcpy(&local.sa6.sin6_addr, channel->local_ip6,
+ sizeof(channel->local_ip6));
if (bind(s, &local.sa, sizeof(local.sa6)) < 0)
return -1;
}
@@ -929,6 +1014,30 @@ 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;
@@ -947,7 +1056,11 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
salen = sizeof(saddr.sa4);
memset(sa, 0, salen);
saddr.sa4.sin_family = AF_INET;
- saddr.sa4.sin_port = (unsigned short)(channel->tcp_port & 0xffff);
+ if (server->addr.tcp_port) {
+ saddr.sa4.sin_port = aresx_sitous(server->addr.tcp_port);
+ } else {
+ saddr.sa4.sin_port = aresx_sitous(channel->tcp_port);
+ }
memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
sizeof(server->addr.addrV4));
break;
@@ -956,23 +1069,27 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
salen = sizeof(saddr.sa6);
memset(sa, 0, salen);
saddr.sa6.sin6_family = AF_INET6;
- saddr.sa6.sin6_port = (unsigned short)(channel->tcp_port & 0xffff);
+ if (server->addr.tcp_port) {
+ saddr.sa6.sin6_port = aresx_sitous(server->addr.tcp_port);
+ } else {
+ saddr.sa6.sin6_port = aresx_sitous(channel->tcp_port);
+ }
memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
sizeof(server->addr.addrV6));
break;
default:
- return -1;
+ return -1; /* LCOV_EXCL_LINE */
}
/* Acquire a socket. */
- s = socket(server->addr.family, SOCK_STREAM, 0);
+ s = 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)
{
- sclose(s);
+ ares__socket_close(channel, s);
return -1;
}
@@ -984,22 +1101,35 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
* so batching isn't very interesting.
*/
opt = 1;
- if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
- (void *)&opt, sizeof(opt)) == -1)
+ if (channel->sock_funcs == 0
+ &&
+ setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
+ (void *)&opt, sizeof(opt)) == -1)
{
- sclose(s);
+ ares__socket_close(channel, s);
return -1;
}
#endif
+ if (channel->sock_config_cb)
+ {
+ int err = channel->sock_config_cb(s, SOCK_STREAM,
+ channel->sock_config_cb_data);
+ if (err < 0)
+ {
+ ares__socket_close(channel, s);
+ return err;
+ }
+ }
+
/* Connect to the server. */
- if (connect(s, sa, salen) == -1)
+ if (connect_socket(channel, s, sa, salen) == -1)
{
int err = SOCKERRNO;
if (err != EINPROGRESS && err != EWOULDBLOCK)
{
- sclose(s);
+ ares__socket_close(channel, s);
return -1;
}
}
@@ -1010,7 +1140,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
channel->sock_create_cb_data);
if (err < 0)
{
- sclose(s);
+ ares__socket_close(channel, s);
return err;
}
}
@@ -1039,7 +1169,11 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
salen = sizeof(saddr.sa4);
memset(sa, 0, salen);
saddr.sa4.sin_family = AF_INET;
- saddr.sa4.sin_port = (unsigned short)(channel->udp_port & 0xffff);
+ if (server->addr.udp_port) {
+ saddr.sa4.sin_port = aresx_sitous(server->addr.udp_port);
+ } else {
+ saddr.sa4.sin_port = aresx_sitous(channel->udp_port);
+ }
memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
sizeof(server->addr.addrV4));
break;
@@ -1048,34 +1182,49 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
salen = sizeof(saddr.sa6);
memset(sa, 0, salen);
saddr.sa6.sin6_family = AF_INET6;
- saddr.sa6.sin6_port = (unsigned short)(channel->udp_port & 0xffff);
+ if (server->addr.udp_port) {
+ saddr.sa6.sin6_port = aresx_sitous(server->addr.udp_port);
+ } else {
+ saddr.sa6.sin6_port = aresx_sitous(channel->udp_port);
+ }
memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
sizeof(server->addr.addrV6));
break;
default:
- return -1;
+ return -1; /* LCOV_EXCL_LINE */
}
/* Acquire a socket. */
- s = socket(server->addr.family, SOCK_DGRAM, 0);
+ s = 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)
{
- sclose(s);
+ ares__socket_close(channel, s);
return -1;
}
+ if (channel->sock_config_cb)
+ {
+ int err = channel->sock_config_cb(s, SOCK_DGRAM,
+ channel->sock_config_cb_data);
+ if (err < 0)
+ {
+ ares__socket_close(channel, s);
+ return err;
+ }
+ }
+
/* Connect to the server. */
- if (connect(s, sa, salen) == -1)
+ if (connect_socket(channel, s, sa, salen) == -1)
{
int err = SOCKERRNO;
if (err != EINPROGRESS && err != EWOULDBLOCK)
{
- sclose(s);
+ ares__socket_close(channel, s);
return -1;
}
}
@@ -1086,7 +1235,7 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
channel->sock_create_cb_data);
if (err < 0)
{
- sclose(s);
+ ares__socket_close(channel, s);
return err;
}
}
@@ -1130,7 +1279,7 @@ static int same_questions(const unsigned char *qbuf, int qlen,
q.p += q.namelen;
if (q.p + QFIXEDSZ > qbuf + qlen)
{
- free(q.name);
+ ares_free(q.name);
return 0;
}
q.type = DNS_QUESTION_TYPE(q.p);
@@ -1145,14 +1294,14 @@ static int same_questions(const unsigned char *qbuf, int qlen,
if (ares_expand_name(a.p, abuf, alen, &a.name, &a.namelen)
!= ARES_SUCCESS)
{
- free(q.name);
+ ares_free(q.name);
return 0;
}
a.p += a.namelen;
if (a.p + QFIXEDSZ > abuf + alen)
{
- free(q.name);
- free(a.name);
+ ares_free(q.name);
+ ares_free(a.name);
return 0;
}
a.type = DNS_QUESTION_TYPE(a.p);
@@ -1163,13 +1312,13 @@ static int same_questions(const unsigned char *qbuf, int qlen,
if (strcasecmp(q.name, a.name) == 0 && q.type == a.type
&& q.dnsclass == a.dnsclass)
{
- free(a.name);
+ ares_free(a.name);
break;
}
- free(a.name);
+ ares_free(a.name);
}
- free(q.name);
+ ares_free(q.name);
if (j == a.qdcount)
return 0;
}
@@ -1198,7 +1347,7 @@ static int same_address(struct sockaddr *sa, struct ares_addr *aa)
return 1; /* match */
break;
default:
- break;
+ break; /* LCOV_EXCL_LINE */
}
}
return 0; /* different */
@@ -1223,21 +1372,19 @@ static void end_query (ares_channel channel, struct query *query, int status,
assert(sendreq->data_storage == NULL);
if (status == ARES_SUCCESS)
{
- /* We got a reply for this query, but this queued
- * sendreq points into this soon-to-be-gone query's
- * tcpbuf. Probably this means we timed out and queued
- * the query for retransmission, then received a
- * response before actually retransmitting. This is
- * perfectly fine, so we want to keep the connection
- * running smoothly if we can. But in the worst case
- * we may have sent only some prefix of the query,
- * with some suffix of the query left to send. Also,
- * the buffer may be queued on multiple queues. To
- * prevent dangling pointers to the query's tcpbuf and
- * handle these cases, we just give such sendreqs
- * their own copy of the query packet.
+ /* We got a reply for this query, but this queued sendreq
+ * points into this soon-to-be-gone query's tcpbuf. Probably
+ * this means we timed out and queued the query for
+ * retransmission, then received a response before actually
+ * retransmitting. This is perfectly fine, so we want to keep
+ * the connection running smoothly if we can. But in the worst
+ * case we may have sent only some prefix of the query, with
+ * some suffix of the query left to send. Also, the buffer may
+ * be queued on multiple queues. To prevent dangling pointers
+ * to the query's tcpbuf and handle these cases, we just give
+ * such sendreqs their own copy of the query packet.
*/
- sendreq->data_storage = malloc(sendreq->len);
+ sendreq->data_storage = ares_malloc(sendreq->len);
if (sendreq->data_storage != NULL)
{
memcpy(sendreq->data_storage, sendreq->data, sendreq->len);
@@ -1246,14 +1393,12 @@ static void end_query (ares_channel channel, struct query *query, int status,
}
if ((status != ARES_SUCCESS) || (sendreq->data_storage == NULL))
{
- /* We encountered an error (probably a timeout,
- * suggesting the DNS server we're talking to is
- * probably unreachable, wedged, or severely
- * overloaded) or we couldn't copy the request, so
- * mark the connection as broken. When we get to
- * process_broken_connections() we'll close the
- * connection and try to re-send requests to another
- * server.
+ /* We encountered an error (probably a timeout, suggesting the
+ * DNS server we're talking to is probably unreachable,
+ * wedged, or severely overloaded) or we couldn't copy the
+ * request, so mark the connection as broken. When we get to
+ * process_broken_connections() we'll close the connection and
+ * try to re-send requests to another server.
*/
server->is_broken = 1;
/* Just to be paranoid, zero out this sendreq... */
@@ -1267,8 +1412,8 @@ static void end_query (ares_channel channel, struct query *query, int status,
query->callback(query->arg, status, query->timeouts, abuf, alen);
ares__free_query(query);
- /* Simple cleanup policy: if no queries are remaining, close all
- * network sockets unless STAYOPEN is set.
+ /* Simple cleanup policy: if no queries are remaining, close all network
+ * sockets unless STAYOPEN is set.
*/
if (!(channel->flags & ARES_FLAG_STAYOPEN) &&
ares__is_list_empty(&(channel->all_queries)))
@@ -1289,7 +1434,15 @@ void ares__free_query(struct query *query)
query->callback = NULL;
query->arg = NULL;
/* Deallocate the memory associated with the query */
- free(query->tcpbuf);
- free(query->server_info);
- free(query);
+ ares_free(query->tcpbuf);
+ ares_free(query->server_info);
+ ares_free(query);
+}
+
+void ares__socket_close(ares_channel channel, ares_socket_t s)
+{
+ if (channel->sock_funcs)
+ channel->sock_funcs->aclose(s, channel->sock_func_cb_data);
+ else
+ sclose(s);
}
diff --git a/ares_query.c b/ares_query.c
index 63652e2..b38b8a6 100644
--- a/ares_query.c
+++ b/ares_query.c
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -31,7 +28,6 @@
# include <arpa/nameser_compat.h>
#endif
-#include <stdlib.h>
#include "ares.h"
#include "ares_dns.h"
#include "ares_private.h"
@@ -43,7 +39,7 @@ struct qquery {
static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen);
-void ares__rc4(rc4_key* key, unsigned char *buffer_ptr, int buffer_len)
+static void rc4(rc4_key* key, unsigned char *buffer_ptr, int buffer_len)
{
unsigned char x;
unsigned char y;
@@ -105,6 +101,13 @@ static unsigned short generate_unique_id(ares_channel channel)
return (unsigned short)id;
}
+unsigned short ares__generate_new_id(rc4_key* key)
+{
+ unsigned short r=0;
+ rc4(key, (unsigned char *)&r, sizeof(r));
+ return r;
+}
+
void ares_query(ares_channel channel, const char *name, int dnsclass,
int type, ares_callback callback, void *arg)
{
@@ -114,11 +117,11 @@ void ares_query(ares_channel channel, const char *name, int dnsclass,
/* Compose the query. */
rd = !(channel->flags & ARES_FLAG_NORECURSE);
- status = ares_mkquery(name, dnsclass, type, channel->next_id, rd, &qbuf,
- &qlen);
+ status = ares_create_query(name, dnsclass, type, channel->next_id, rd, &qbuf,
+ &qlen, (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : 0);
if (status != ARES_SUCCESS)
{
- if (qbuf != NULL) free(qbuf);
+ if (qbuf != NULL) ares_free(qbuf);
callback(arg, status, 0, NULL, 0);
return;
}
@@ -126,7 +129,7 @@ void ares_query(ares_channel channel, const char *name, int dnsclass,
channel->next_id = generate_unique_id(channel);
/* Allocate and fill in the query structure. */
- qquery = malloc(sizeof(struct qquery));
+ qquery = ares_malloc(sizeof(struct qquery));
if (!qquery)
{
ares_free_string(qbuf);
@@ -179,5 +182,5 @@ static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf,
}
qquery->callback(qquery->arg, status, timeouts, abuf, alen);
}
- free(qquery);
+ ares_free(qquery);
}
diff --git a/ares_rules.h b/ares_rules.h
index f94c5b5..e617fdc 100644
--- a/ares_rules.h
+++ b/ares_rules.h
@@ -68,21 +68,11 @@
* Verify that some macros are actually defined.
*/
-#ifndef CARES_SIZEOF_LONG
-# error "CARES_SIZEOF_LONG definition is missing!"
- Error Compilation_aborted_CARES_SIZEOF_LONG_is_missing
-#endif
-
#ifndef CARES_TYPEOF_ARES_SOCKLEN_T
# error "CARES_TYPEOF_ARES_SOCKLEN_T definition is missing!"
Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_is_missing
#endif
-#ifndef CARES_SIZEOF_ARES_SOCKLEN_T
-# error "CARES_SIZEOF_ARES_SOCKLEN_T definition is missing!"
- Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_is_missing
-#endif
-
/*
* Macros private to this header file.
*/
@@ -92,15 +82,6 @@
#define CareschkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1
/*
- * Verify that the size previously defined and expected for long
- * is the same as the one reported by sizeof() at compile time.
- */
-
-typedef char
- __cares_rule_01__
- [CareschkszEQ(long, CARES_SIZEOF_LONG)];
-
-/*
* Verify that the size previously defined and expected for
* ares_socklen_t is actually the the same as the one reported
* by sizeof() at compile time.
@@ -108,7 +89,7 @@ typedef char
typedef char
__cares_rule_02__
- [CareschkszEQ(ares_socklen_t, CARES_SIZEOF_ARES_SOCKLEN_T)];
+ [CareschkszEQ(ares_socklen_t, sizeof(CARES_TYPEOF_ARES_SOCKLEN_T))];
/*
* Verify at compile time that the size of ares_socklen_t as reported
diff --git a/ares_search.c b/ares_search.c
index 1877c19..68e8525 100644
--- a/ares_search.c
+++ b/ares_search.c
@@ -16,11 +16,6 @@
#include "ares_setup.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
@@ -49,7 +44,7 @@ static void search_callback(void *arg, int status, int timeouts,
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 int single_domain(ares_channel channel, const char *name, 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)
@@ -71,24 +66,24 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
if (s)
{
ares_query(channel, s, dnsclass, type, callback, arg);
- free(s);
+ ares_free(s);
return;
}
/* Allocate a search_query structure to hold the state necessary for
* doing multiple lookups.
*/
- squery = malloc(sizeof(struct search_query));
+ squery = ares_malloc(sizeof(struct search_query));
if (!squery)
{
callback(arg, ARES_ENOMEM, 0, NULL, 0);
return;
}
squery->channel = channel;
- squery->name = strdup(name);
+ squery->name = ares_strdup(name);
if (!squery->name)
{
- free(squery);
+ ares_free(squery);
callback(arg, ARES_ENOMEM, 0, NULL, 0);
return;
}
@@ -128,13 +123,13 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
if (status == ARES_SUCCESS)
{
ares_query(channel, s, dnsclass, type, search_callback, squery);
- free(s);
+ ares_free(s);
}
else
{
/* failed, free the malloc()ed memory */
- free(squery->name);
- free(squery);
+ ares_free(squery->name);
+ ares_free(squery);
callback(arg, status, 0, NULL, 0);
}
}
@@ -182,7 +177,7 @@ static void search_callback(void *arg, int status, int timeouts,
squery->next_domain++;
ares_query(channel, s, squery->dnsclass, squery->type,
search_callback, squery);
- free(s);
+ ares_free(s);
}
}
else if (squery->status_as_is == -1)
@@ -206,8 +201,8 @@ static void end_squery(struct search_query *squery, int status,
unsigned char *abuf, int alen)
{
squery->callback(squery->arg, status, squery->timeouts, abuf, alen);
- free(squery->name);
- free(squery);
+ ares_free(squery->name);
+ ares_free(squery);
}
/* Concatenate two domains. */
@@ -216,7 +211,7 @@ static int cat_domain(const char *name, const char *domain, char **s)
size_t nlen = strlen(name);
size_t dlen = strlen(domain);
- *s = malloc(nlen + 1 + dlen + 1);
+ *s = ares_malloc(nlen + 1 + dlen + 1);
if (!*s)
return ARES_ENOMEM;
memcpy(*s, name, nlen);
@@ -230,7 +225,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 int single_domain(ares_channel channel, const char *name, char **s)
+STATIC_TESTABLE int single_domain(ares_channel channel, const char *name, char **s)
{
size_t len = strlen(name);
const char *hostaliases;
@@ -244,9 +239,9 @@ static int single_domain(ares_channel channel, const char *name, char **s)
/* If the name contains a trailing dot, then the single query is the name
* sans the trailing dot.
*/
- if (name[len - 1] == '.')
+ if ((len > 0) && (name[len - 1] == '.'))
{
- *s = strdup(name);
+ *s = ares_strdup(name);
return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
}
@@ -273,18 +268,18 @@ static int single_domain(ares_channel channel, const char *name, char **s)
q = p + 1;
while (*q && !ISSPACE(*q))
q++;
- *s = malloc(q - p + 1);
+ *s = ares_malloc(q - p + 1);
if (*s)
{
memcpy(*s, p, q - p);
(*s)[q - p] = 0;
}
- free(line);
+ ares_free(line);
fclose(fp);
return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
}
}
- free(line);
+ ares_free(line);
fclose(fp);
if (status != ARES_SUCCESS && status != ARES_EOF)
return status;
@@ -312,7 +307,7 @@ static int single_domain(ares_channel channel, const char *name, char **s)
if (channel->flags & ARES_FLAG_NOSEARCH || channel->ndomains == 0)
{
/* No domain search to do; just try the name as-is. */
- *s = strdup(name);
+ *s = ares_strdup(name);
return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
}
diff --git a/ares_send.c b/ares_send.c
index 37b0704..88c0035 100644
--- a/ares_send.c
+++ b/ares_send.c
@@ -16,9 +16,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -31,9 +28,6 @@
# include <arpa/nameser_compat.h>
#endif
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
#include "ares.h"
#include "ares_dns.h"
#include "ares_private.h"
@@ -42,7 +36,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
ares_callback callback, void *arg)
{
struct query *query;
- int i;
+ int i, packetsz;
struct timeval now;
/* Verify that the query is at least long enough to hold the header. */
@@ -53,31 +47,31 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
}
/* Allocate space for query and allocated fields. */
- query = malloc(sizeof(struct query));
+ query = ares_malloc(sizeof(struct query));
if (!query)
{
callback(arg, ARES_ENOMEM, 0, NULL, 0);
return;
}
- query->tcpbuf = malloc(qlen + 2);
+ query->tcpbuf = ares_malloc(qlen + 2);
if (!query->tcpbuf)
{
- free(query);
+ ares_free(query);
callback(arg, ARES_ENOMEM, 0, NULL, 0);
return;
}
- query->server_info = malloc(channel->nservers *
- sizeof(query->server_info[0]));
+ query->server_info = ares_malloc(channel->nservers *
+ sizeof(query->server_info[0]));
if (!query->server_info)
{
- free(query->tcpbuf);
- free(query);
+ ares_free(query->tcpbuf);
+ ares_free(query);
callback(arg, ARES_ENOMEM, 0, NULL, 0);
return;
}
/* Compute the query ID. Start with no timeout. */
- query->qid = (unsigned short)DNS_HEADER_QID(qbuf);
+ query->qid = DNS_HEADER_QID(qbuf);
query->timeout.tv_sec = 0;
query->timeout.tv_usec = 0;
@@ -109,7 +103,10 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
query->server_info[i].skip_server = 0;
query->server_info[i].tcp_connection_generation = 0;
}
- query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;
+
+ packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ;
+ query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz;
+
query->error_status = ARES_ECONNREFUSED;
query->timeouts = 0;
diff --git a/ares_setup.h b/ares_setup.h
index a46c510..4df7961 100644
--- a/ares_setup.h
+++ b/ares_setup.h
@@ -2,7 +2,7 @@
#define HEADER_CARES_SETUP_H
-/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al
+/* Copyright (C) 2004 - 2012 by Daniel Stenberg et al
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
@@ -157,6 +157,18 @@
#endif /* HAVE_CONFIG_H */
+/*
+ * Arg 2 type for gethostname in case it hasn't been defined in config file.
+ */
+
+#ifndef GETHOSTNAME_TYPE_ARG2
+# ifdef USE_WINSOCK
+# define GETHOSTNAME_TYPE_ARG2 int
+# else
+# define GETHOSTNAME_TYPE_ARG2 size_t
+# endif
+#endif
+
#ifdef __POCC__
# include <sys/types.h>
# include <unistd.h>
@@ -164,6 +176,14 @@
#endif
/*
+ * Android does have the arpa/nameser.h header which is detected by configure
+ * but it appears to be empty with recent NDK r7b / r7c, so we undefine here.
+ */
+#if (defined(ANDROID) || defined(__ANDROID__)) && defined(HAVE_ARPA_NAMESER_H)
+# undef HAVE_ARPA_NAMESER_H
+#endif
+
+/*
* Recent autoconf versions define these symbols in ares_config.h. We don't
* want them (since they collide with the libcurl ones when we build
* --enable-debug) so we undef them again here.
diff --git a/ares_strdup.c b/ares_strdup.c
index 1804327..0c3dcff 100644
--- a/ares_strdup.c
+++ b/ares_strdup.c
@@ -17,26 +17,33 @@
#include "ares_setup.h"
#include "ares_strdup.h"
+#include "ares.h"
+#include "ares_private.h"
-#ifndef HAVE_STRDUP
char *ares_strdup(const char *s1)
{
- size_t sz;
- char * s2;
+#ifdef HAVE_STRDUP
+ if (ares_malloc == malloc)
+ return strdup(s1);
+ else
+#endif
+ {
+ size_t sz;
+ char * s2;
- if(s1) {
- sz = strlen(s1);
- if(sz < (size_t)-1) {
- sz++;
- if(sz < ((size_t)-1) / sizeof(char)) {
- s2 = malloc(sz * sizeof(char));
- if(s2) {
- memcpy(s2, s1, sz * sizeof(char));
- return s2;
+ if(s1) {
+ sz = strlen(s1);
+ if(sz < (size_t)-1) {
+ sz++;
+ if(sz < ((size_t)-1) / sizeof(char)) {
+ s2 = ares_malloc(sz * sizeof(char));
+ if(s2) {
+ memcpy(s2, s1, sz * sizeof(char));
+ return s2;
+ }
}
}
}
+ return (char *)NULL;
}
- return (char *)NULL;
}
-#endif
diff --git a/ares_strdup.h b/ares_strdup.h
index c413a94..67f2a74 100644
--- a/ares_strdup.h
+++ b/ares_strdup.h
@@ -19,8 +19,6 @@
#include "ares_setup.h"
-#ifndef HAVE_STRDUP
extern char *ares_strdup(const char *s1);
-#endif
#endif /* HEADER_CARES_STRDUP_H */
diff --git a/ares_strsplit.c b/ares_strsplit.c
new file mode 100644
index 0000000..b57a30f
--- /dev/null
+++ b/ares_strsplit.c
@@ -0,0 +1,174 @@
+/* Copyright (C) 2018 by John Schember <john@nachtimwald.com>
+ *
+ * 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"
+#include "ares_strsplit.h"
+#include "ares.h"
+#include "ares_private.h"
+
+static int list_contains(char * const *list, size_t num_elem, const char *str, int insensitive)
+{
+ size_t len;
+ size_t i;
+
+ len = strlen(str);
+ for (i=0; i<num_elem; i++)
+ {
+ if (insensitive)
+ {
+#ifdef WIN32
+ if (strnicmp(list[i], str, len) == 0)
+#else
+ if (strncasecmp(list[i], str, len) == 0)
+#endif
+ return 1;
+ }
+ else
+ {
+ if (strncmp(list[i], str, len) == 0)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int is_delim(char c, const char *delims, size_t num_delims)
+{
+ size_t i;
+
+ for (i=0; i<num_delims; i++)
+ {
+ if (c == delims[i])
+ return 1;
+ }
+ return 0;
+}
+
+
+void ares_strsplit_free(char **elms, size_t num_elm)
+{
+ size_t i;
+
+ if (elms == NULL)
+ return;
+
+ for (i=0; i<num_elm; i++)
+ ares_free(elms[i]);
+ ares_free(elms);
+}
+
+
+char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm)
+{
+ char *parsestr;
+ char **temp;
+ char **out;
+ size_t cnt;
+ size_t nelms;
+ size_t in_len;
+ size_t num_delims;
+ size_t i;
+
+ if (in == NULL || delms == NULL || num_elm == NULL)
+ return NULL;
+
+ *num_elm = 0;
+
+ in_len = strlen(in);
+ num_delims = strlen(delms);
+
+ /* Figure out how many elements. */
+ nelms = 1;
+ for (i=0; i<in_len; i++)
+ {
+ if (is_delim(in[i], delms, num_delims))
+ {
+ nelms++;
+ }
+ }
+
+ /* Copy of input so we can cut it up. */
+ parsestr = ares_strdup(in);
+ if (parsestr == NULL)
+ return NULL;
+
+ /* Temporary array to store locations of start of each element
+ * within parsestr. */
+ temp = ares_malloc(nelms * sizeof(*temp));
+ if (temp == NULL)
+ {
+ ares_free(parsestr);
+ return NULL;
+ }
+ temp[0] = parsestr;
+ cnt = 1;
+ for (i=0; i<in_len && cnt<nelms; i++)
+ {
+ if (!is_delim(parsestr[i], delms, num_delims))
+ continue;
+
+ /* Replace sep with NULL. */
+ parsestr[i] = '\0';
+ /* Add the pointer to the array of elements */
+ temp[cnt] = parsestr+i+1;
+ cnt++;
+ }
+
+ /* Copy each element to our output array. */
+ out = ares_malloc(nelms * sizeof(*out));
+ if (out == NULL)
+ {
+ ares_free(parsestr);
+ ares_free(temp);
+ return NULL;
+ }
+
+ nelms = 0;
+ for (i=0; i<cnt; i++)
+ {
+ if (temp[i][0] == '\0')
+ continue;
+
+ if (make_set && list_contains(out, nelms, temp[i], 1))
+ continue;
+
+ out[nelms] = ares_strdup(temp[i]);
+ if (out[nelms] == NULL)
+ {
+ ares_strsplit_free(out, nelms);
+ ares_free(parsestr);
+ ares_free(temp);
+ return NULL;
+ }
+ nelms++;
+ }
+
+
+ /* If there are no elements don't return an empty allocated
+ * array. */
+ if (nelms == 0)
+ {
+ ares_strsplit_free(out, nelms);
+ out = NULL;
+ }
+
+ /* Get the true number of elements (recalculated because of make_set) */
+ *num_elm = nelms;
+
+ ares_free(parsestr);
+ ares_free(temp);
+ return out;
+}
diff --git a/ares_strsplit.h b/ares_strsplit.h
new file mode 100644
index 0000000..e00fd14
--- /dev/null
+++ b/ares_strsplit.h
@@ -0,0 +1,43 @@
+#ifndef HEADER_CARES_STRSPLIT_H
+#define HEADER_CARES_STRSPLIT_H
+
+/* Copyright (C) 2018 by John Schember <john@nachtimwald.com>
+ *
+ * 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"
+
+/* Split a string on delem skipping empty elements.
+ *
+ * param in String to split.
+ * param delims String of characters to treat as a delimitor.
+ * Each character in the string is a delimitor so
+ * there can be multiple delimitors to split on.
+ * E.g. ", " will split on all comma's and spaces.
+ * param make_set Have the list be a Set where there are no
+ * duplicate entries. 1 for true, 0 or false.
+ * param num_elm Return parameter of the number of elements
+ * in the result array.
+ *
+ * returns an allocated array of allocated string elements.
+ *
+ */
+char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm);
+
+/* Frees the result returned from ares_strsplit(). */
+void ares_strsplit_free(char **elms, size_t num_elm);
+
+
+#endif /* HEADER_CARES_STRSPLIT_H */
+
diff --git a/ares_timeout.c b/ares_timeout.c
index 2da4f5f..293e4af 100644
--- a/ares_timeout.c
+++ b/ares_timeout.c
@@ -16,15 +16,20 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
#endif
-#include <time.h>
-
#include "ares.h"
#include "ares_private.h"
+/* return time offset between now and (future) check, in milliseconds */
+static long timeoffset(struct timeval *now, struct timeval *check)
+{
+ return (check->tv_sec - now->tv_sec)*1000 +
+ (check->tv_usec - now->tv_usec)/1000;
+}
+
/* WARNING: Beware that this is linear in the number of outstanding
* requests! You are probably far better off just calling ares_process()
* once per second, rather than calling ares_timeout() to figure out
@@ -55,26 +60,29 @@ struct timeval *ares_timeout(ares_channel channel, struct timeval *maxtv,
query = list_node->data;
if (query->timeout.tv_sec == 0)
continue;
- offset = ares__timeoffset(&now, &query->timeout);
+ offset = timeoffset(&now, &query->timeout);
if (offset < 0)
offset = 0;
if (min_offset == -1 || offset < min_offset)
min_offset = offset;
}
- if(min_offset != -1) {
- nextstop.tv_sec = min_offset/1000;
- nextstop.tv_usec = (min_offset%1000)*1000;
- }
-
/* If we found a minimum timeout and it's sooner than the one specified in
* maxtv (if any), return it. Otherwise go with maxtv.
*/
- if (min_offset != -1 && (!maxtv || ares__timedout(maxtv, &nextstop)))
+ if (min_offset != -1)
{
- *tvbuf = nextstop;
- return tvbuf;
+ int ioffset = (min_offset > (long)INT_MAX) ? INT_MAX : (int)min_offset;
+
+ nextstop.tv_sec = ioffset/1000;
+ nextstop.tv_usec = (ioffset%1000)*1000;
+
+ if (!maxtv || ares__timedout(maxtv, &nextstop))
+ {
+ *tvbuf = nextstop;
+ return tvbuf;
+ }
}
- else
- return maxtv;
+
+ return maxtv;
}
diff --git a/ares_version.h b/ares_version.h
index 50eb638..ed623d1 100644
--- a/ares_version.h
+++ b/ares_version.h
@@ -3,15 +3,15 @@
#define ARES__VERSION_H
/* This is the global package copyright */
-#define ARES_COPYRIGHT "2004 - 2010 Daniel Stenberg, <daniel@haxx.se>."
+#define ARES_COPYRIGHT "2004 - 2016 Daniel Stenberg, <daniel@haxx.se>."
#define ARES_VERSION_MAJOR 1
-#define ARES_VERSION_MINOR 7
-#define ARES_VERSION_PATCH 5
+#define ARES_VERSION_MINOR 12
+#define ARES_VERSION_PATCH 1
#define ARES_VERSION ((ARES_VERSION_MAJOR<<16)|\
(ARES_VERSION_MINOR<<8)|\
(ARES_VERSION_PATCH))
-#define ARES_VERSION_STR "1.7.5"
+#define ARES_VERSION_STR "1.12.1-DEV"
#if (ARES_VERSION >= 0x010700)
# define CARES_HAVE_ARES_LIBRARY_INIT 1
diff --git a/ares_writev.c b/ares_writev.c
index 9e8e2d6..e812c09 100644
--- a/ares_writev.c
+++ b/ares_writev.c
@@ -25,12 +25,12 @@
#include "ares_private.h"
#ifndef HAVE_WRITEV
-ssize_t ares_writev(ares_socket_t s, const struct iovec *iov, int iovcnt)
+ares_ssize_t ares_writev(ares_socket_t s, const struct iovec *iov, int iovcnt)
{
char *buffer, *bp;
int i;
size_t bytes = 0;
- ssize_t result;
+ ares_ssize_t result;
/* Validate iovcnt */
if (iovcnt <= 0)
@@ -54,7 +54,7 @@ ssize_t ares_writev(ares_socket_t s, const struct iovec *iov, int iovcnt)
return (0);
/* Allocate a temporary buffer to hold the data */
- buffer = malloc(bytes);
+ buffer = ares_malloc(bytes);
if (!buffer)
{
SET_ERRNO(ENOMEM);
@@ -71,7 +71,7 @@ ssize_t ares_writev(ares_socket_t s, const struct iovec *iov, int iovcnt)
/* Send buffer contents */
result = swrite(s, buffer, bytes);
- free(buffer);
+ ares_free(buffer);
return (result);
}
diff --git a/ares_writev.h b/ares_writev.h
index 1a23a0f..65cea87 100644
--- a/ares_writev.h
+++ b/ares_writev.h
@@ -29,7 +29,7 @@ struct iovec
size_t iov_len; /* Length of data. */
};
-extern ssize_t ares_writev(ares_socket_t s, const struct iovec *iov, int iovcnt);
+extern ares_ssize_t ares_writev(ares_socket_t s, const struct iovec *iov, int iovcnt);
#endif
diff --git a/bitncmp.c b/bitncmp.c
index 5c89506..1468d49 100644
--- a/bitncmp.c
+++ b/bitncmp.c
@@ -26,34 +26,34 @@
* bitncmp(l, r, n)
* compare bit masks l and r, for n bits.
* return:
- * -1, 1, or 0 in the libc tradition.
+ * <0, >0, or 0 in the libc tradition.
* note:
* network byte order assumed. this means 192.5.5.240/28 has
* 0x11110000 in its fourth octet.
* author:
* Paul Vixie (ISC), June 1996
*/
-int
-ares_bitncmp(const void *l, const void *r, int n) {
- unsigned int lb, rb;
- int x, b;
+int ares__bitncmp(const void *l, const void *r, int n)
+{
+ unsigned int lb, rb;
+ int x, b;
- b = n / 8;
- x = memcmp(l, r, b);
- if (x || (n % 8) == 0)
- return (x);
+ b = n / 8;
+ x = memcmp(l, r, b);
+ if (x || (n % 8) == 0)
+ return (x);
- lb = ((const unsigned char *)l)[b];
- rb = ((const unsigned char *)r)[b];
- for (b = n % 8; b > 0; b--) {
- if ((lb & 0x80) != (rb & 0x80)) {
- if (lb & 0x80)
- return (1);
- return (-1);
- }
- lb <<= 1;
- rb <<= 1;
- }
- return (0);
+ lb = ((const unsigned char *)l)[b];
+ rb = ((const unsigned char *)r)[b];
+ for (b = n % 8; b > 0; b--) {
+ if ((lb & 0x80) != (rb & 0x80)) {
+ if (lb & 0x80)
+ return (1);
+ return (-1);
+ }
+ lb <<= 1;
+ rb <<= 1;
+ }
+ return (0);
}
#endif
diff --git a/bitncmp.h b/bitncmp.h
index b0a5c81..7b8d66c 100644
--- a/bitncmp.h
+++ b/bitncmp.h
@@ -2,7 +2,7 @@
#define __ARES_BITNCMP_H
-/* Copyright (C) 2005 by Dominick Meglio
+/* Copyright (C) 2005, 2013 by Dominick Meglio
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -18,9 +18,9 @@
*/
#ifndef HAVE_BITNCMP
-int ares_bitncmp(const void *l, const void *r, int n);
+int ares__bitncmp(const void *l, const void *r, int n);
#else
-#define ares_bitncmp(x,y,z) bitncmp(x,y,z)
+#define ares__bitncmp(x,y,z) bitncmp(x,y,z)
#endif
#endif /* __ARES_BITNCMP_H */
diff --git a/config-dos.h b/config-dos.h
index d15a177..114db51 100644
--- a/config-dos.h
+++ b/config-dos.h
@@ -32,9 +32,6 @@
#define NEED_MALLOC_H 1
#define RETSIGTYPE void
-#define SIZEOF_INT 4
-#define SIZEOF_SHORT 2
-#define SIZEOF_SIZE_T 4
#define TIME_WITH_SYS_TIME 1
/* Qualifiers for send(), recv(), recvfrom() and getnameinfo(). */
@@ -63,11 +60,6 @@
#define BSD
-#if defined(__HIGHC__) || \
- (defined(__GNUC__) && (__GNUC__ < 4))
-#define ssize_t int
-#endif
-
/* Target HAVE_x section */
#if defined(DJGPP)
@@ -86,13 +78,14 @@
#elif defined(__HIGHC__)
#define HAVE_SYS_TIME_H 1
+ #define strerror(e) strerror_s_((e))
#endif
#ifdef WATT32
#define HAVE_AF_INET6 1
#define HAVE_ARPA_INET_H 1
#define HAVE_ARPA_NAMESER_H 1
- #define HAVE_CLOSESOCKET_CAMEL 1
+ #define HAVE_CLOSE_S 1
#define HAVE_GETHOSTNAME 1
#define HAVE_NETDB_H 1
#define HAVE_NETINET_IN_H 1
@@ -106,7 +99,6 @@
#define HAVE_SYS_UIO_H 1
#define NS_INADDRSZ 4
#define HAVE_STRUCT_SOCKADDR_IN6 1
- #define CloseSocket(s) close_s((s))
#endif
#undef word
diff --git a/config-win32.h b/config-win32.h
index 48ce512..8d70474 100644
--- a/config-win32.h
+++ b/config-win32.h
@@ -211,37 +211,15 @@
/* Define to the return type of signal handlers (int or void). */
#define RETSIGTYPE void
-/* Define if ssize_t is not an available 'typedefed' type. */
-#ifndef _SSIZE_T_DEFINED
-# if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \
- defined(__POCC__) || \
- defined(__MINGW32__)
-# elif defined(_WIN64)
-# define _SSIZE_T_DEFINED
-# define ssize_t __int64
-# else
-# define _SSIZE_T_DEFINED
-# define ssize_t int
-# endif
+#ifdef __cplusplus
+/* Compiling headers in C++ mode means bool is available */
+#define HAVE_BOOL_T
#endif
/* ---------------------------------------------------------------- */
/* TYPE SIZES */
/* ---------------------------------------------------------------- */
-/* Define to the size of `int', as computed by sizeof. */
-#define SIZEOF_INT 4
-
-/* Define to the size of `short', as computed by sizeof. */
-#define SIZEOF_SHORT 2
-
-/* Define to the size of `size_t', as computed by sizeof. */
-#if defined(_WIN64)
-# define SIZEOF_SIZE_T 8
-#else
-# define SIZEOF_SIZE_T 4
-#endif
-
/* ---------------------------------------------------------------- */
/* STRUCT RELATED */
/* ---------------------------------------------------------------- */
@@ -267,31 +245,19 @@
# define _CRT_NONSTDC_NO_DEPRECATE 1
#endif
-/* Officially, Microsoft's Windows SDK versions 6.X do not support Windows
- 2000 as a supported build target. VS2008 default installations provide
- an embedded Windows SDK v6.0A along with the claim that Windows 2000 is
- a valid build target for VS2008. Popular belief is that binaries built
- with VS2008 using Windows SDK versions 6.X and Windows 2000 as a build
- target are functional. */
-#if defined(_MSC_VER) && (_MSC_VER >= 1500)
-# define VS2008_MIN_TARGET 0x0500
-#endif
-
-/* When no build target is specified VS2008 default build target is Windows
- Vista, which leaves out even Winsows XP. If no build target has been given
- for VS2008 we will target the minimum Officially supported build target,
- which happens to be Windows XP. */
+/* Set the Target to Vista. However, any symbols required above Win2000
+ * should be loaded via LoadLibrary() */
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
-# define VS2008_DEF_TARGET 0x0501
+# define VS2008_MIN_TARGET 0x0600
#endif
/* VS2008 default target settings and minimum build target check. */
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
# ifndef _WIN32_WINNT
-# define _WIN32_WINNT VS2008_DEF_TARGET
+# define _WIN32_WINNT VS2008_MIN_TARGET
# endif
# ifndef WINVER
-# define WINVER VS2008_DEF_TARGET
+# define WINVER VS2008_MIN_TARGET
# endif
# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET)
# error VS2008 does not support Windows build targets prior to Windows 2000
@@ -299,13 +265,13 @@
#endif
/* When no build target is specified Pelles C 5.00 and later default build
- target is Windows Vista. We override default target to be Windows 2000. */
+ target is Windows Vista. */
#if defined(__POCC__) && (__POCC__ >= 500)
# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0500
+# define _WIN32_WINNT 0x0600
# endif
# ifndef WINVER
-# define WINVER 0x0500
+# define WINVER 0x0600
# endif
#endif
@@ -365,5 +331,21 @@
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
#endif
+/* ---------------------------------------------------------------- */
+/* Win CE */
+/* ---------------------------------------------------------------- */
+
+/* FIXME: A proper config-win32ce.h should be created to hold these */
+
+/*
+ * System error codes for Windows CE
+ */
+
+#if defined(_WIN32_WCE) && !defined(HAVE_ERRNO_H)
+# define ENOENT ERROR_FILE_NOT_FOUND
+# define ESRCH ERROR_PATH_NOT_FOUND
+# define ENOMEM ERROR_NOT_ENOUGH_MEMORY
+# define ENOSPC ERROR_INVALID_PARAMETER
+#endif
#endif /* HEADER_CARES_CONFIG_WIN32_H */
diff --git a/inet_net_pton.c b/inet_net_pton.c
index 45bb5d4..af1a534 100644
--- a/inet_net_pton.c
+++ b/inet_net_pton.c
@@ -18,9 +18,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -36,15 +33,10 @@
# include <arpa/nameser_compat.h>
#endif
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
#include "ares.h"
#include "ares_ipv6.h"
#include "ares_nowarn.h"
-#include "inet_net_pton.h"
+#include "ares_inet_net_pton.h"
const struct ares_in6_addr ares_in6addr_any = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
@@ -159,7 +151,7 @@ inet_net_pton_ipv4(const char *src, unsigned char *dst, size_t size)
/* If nothing was written to the destination, we found no address. */
if (dst == odst)
- goto enoent;
+ goto enoent; /* LCOV_EXCL_LINE: all valid paths above increment dst */
/* If no CIDR spec was given, infer width from net class. */
if (bits == -1) {
if (*odst >= 240) /* Class E */
@@ -365,8 +357,8 @@ inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size)
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
- const ssize_t n = tp - colonp;
- ssize_t i;
+ const ares_ssize_t n = tp - colonp;
+ ares_ssize_t i;
if (tp == endp)
goto enoent;
@@ -448,4 +440,11 @@ int ares_inet_pton(int af, const char *src, void *dst)
return 0;
return (result > -1 ? 1 : -1);
}
+#else /* HAVE_INET_PTON */
+int ares_inet_pton(int af, const char *src, void *dst)
+{
+ /* just relay this to the underlying function */
+ return inet_pton(af, src, dst);
+}
+
#endif
diff --git a/inet_ntop.c b/inet_ntop.c
index 57e1146..9420f6c 100644
--- a/inet_ntop.c
+++ b/inet_ntop.c
@@ -17,9 +17,6 @@
#include "ares_setup.h"
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
@@ -35,15 +32,8 @@
# include <arpa/nameser_compat.h>
#endif
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
#include "ares.h"
#include "ares_ipv6.h"
-#include "inet_ntop.h"
-
#ifndef HAVE_INET_NTOP
@@ -69,13 +59,13 @@ static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size);
* Paul Vixie, 1996.
*/
const char *
-ares_inet_ntop(int af, const void *src, char *dst, size_t size)
+ares_inet_ntop(int af, const void *src, char *dst, ares_socklen_t size)
{
switch (af) {
case AF_INET:
- return (inet_ntop4(src, dst, size));
+ return (inet_ntop4(src, dst, (size_t)size));
case AF_INET6:
- return (inet_ntop6(src, dst, size));
+ return (inet_ntop6(src, dst, (size_t)size));
default:
SET_ERRNO(EAFNOSUPPORT);
return (NULL);
@@ -205,4 +195,14 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size)
strcpy(dst, tmp);
return (dst);
}
-#endif
+
+#else /* HAVE_INET_NTOP */
+
+const char *
+ares_inet_ntop(int af, const void *src, char *dst, ares_socklen_t size)
+{
+ /* just relay this to the underlying function */
+ return inet_ntop(af, src, dst, size);
+}
+
+#endif /* HAVE_INET_NTOP */
diff --git a/nameser.h b/nameser.h
index 45f1e3e..a0302fd 100644
--- a/nameser.h
+++ b/nameser.h
@@ -186,11 +186,19 @@ typedef enum __ns_rcode {
#define T_SRV ns_t_srv
#define T_ATMA ns_t_atma
#define T_NAPTR ns_t_naptr
+#define T_KX ns_t_kx
+#define T_CERT ns_t_cert
+#define T_A6 ns_t_a6
+#define T_DNAME ns_t_dname
+#define T_SINK ns_t_sink
+#define T_OPT ns_t_opt
+#define T_APL ns_t_apl
#define T_DS ns_t_ds
#define T_SSHFP ns_t_sshfp
#define T_RRSIG ns_t_rrsig
#define T_NSEC ns_t_nsec
#define T_DNSKEY ns_t_dnskey
+#define T_TKEY ns_t_tkey
#define T_TSIG ns_t_tsig
#define T_IXFR ns_t_ixfr
#define T_AXFR ns_t_axfr
diff --git a/setup_once.h b/setup_once.h
index a333f54..a8cfe6b 100644
--- a/setup_once.h
+++ b/setup_once.h
@@ -2,7 +2,7 @@
#define __SETUP_ONCE_H
-/* Copyright (C) 2004 - 2011 by Daniel Stenberg et al
+/* Copyright (C) 2004 - 2013 by Daniel Stenberg et al
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
@@ -72,10 +72,38 @@
#include <fcntl.h>
#endif
-#ifdef HAVE_STDBOOL_H
+#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T)
#include <stdbool.h>
#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef __hpux
+# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
+# ifdef _APP32_64BIT_OFF_T
+# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T
+# undef _APP32_64BIT_OFF_T
+# else
+# undef OLD_APP32_64BIT_OFF_T
+# endif
+# endif
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef __hpux
+# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
+# ifdef OLD_APP32_64BIT_OFF_T
+# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T
+# undef OLD_APP32_64BIT_OFF_T
+# endif
+# endif
+#endif
+
/*
* Definition of timeval struct for platforms that don't have it.
@@ -103,7 +131,7 @@ struct timeval {
#if defined(__minix)
/* Minix doesn't support recv on TCP sockets */
-#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
+#define sread(x,y,z) (ares_ssize_t)read((RECV_TYPE_ARG1)(x), \
(RECV_TYPE_ARG2)(y), \
(RECV_TYPE_ARG3)(z))
@@ -139,7 +167,7 @@ struct timeval {
Error Missing_definition_of_return_and_arguments_types_of_recv
/* */
#else
-#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
+#define sread(x,y,z) (ares_ssize_t)recv((RECV_TYPE_ARG1)(x), \
(RECV_TYPE_ARG2)(y), \
(RECV_TYPE_ARG3)(z), \
(RECV_TYPE_ARG4)(0))
@@ -155,7 +183,7 @@ struct timeval {
#if defined(__minix)
/* Minix doesn't support send on TCP sockets */
-#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
+#define swrite(x,y,z) (ares_ssize_t)write((SEND_TYPE_ARG1)(x), \
(SEND_TYPE_ARG2)(y), \
(SEND_TYPE_ARG3)(z))
@@ -170,7 +198,7 @@ struct timeval {
Error Missing_definition_of_return_and_arguments_types_of_send
/* */
#else
-#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
+#define swrite(x,y,z) (ares_ssize_t)send((SEND_TYPE_ARG1)(x), \
(SEND_TYPE_ARG2)(y), \
(SEND_TYPE_ARG3)(z), \
(SEND_TYPE_ARG4)(SEND_4TH_ARG))
@@ -200,7 +228,7 @@ struct timeval {
Error Missing_definition_of_return_and_arguments_types_of_recvfrom
/* */
#else
-#define sreadfrom(s,b,bl,f,fl) (ssize_t)recvfrom((RECVFROM_TYPE_ARG1) (s), \
+#define sreadfrom(s,b,bl,f,fl) (ares_ssize_t)recvfrom((RECVFROM_TYPE_ARG1) (s), \
(RECVFROM_TYPE_ARG2 *)(b), \
(RECVFROM_TYPE_ARG3) (bl), \
(RECVFROM_TYPE_ARG4) (0), \
@@ -232,6 +260,8 @@ struct timeval {
# define sclose(x) closesocket((x))
#elif defined(HAVE_CLOSESOCKET_CAMEL)
# define sclose(x) CloseSocket((x))
+#elif defined(HAVE_CLOSE_S)
+# define sclose(x) close_s((x))
#else
# define sclose(x) close((x))
#endif
@@ -260,6 +290,18 @@ struct timeval {
/*
+ * 'bool' stuff compatible with HP-UX headers.
+ */
+
+#if defined(__hpux) && !defined(HAVE_BOOL_T)
+ typedef int bool;
+# define false 0
+# define true 1
+# define HAVE_BOOL_T
+#endif
+
+
+/*
* 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
* On non-C99 platforms there's no bool, so define an enum for that.
* On C99 platforms 'false' and 'true' also exist. Enum uses a
@@ -300,6 +342,27 @@ struct timeval {
/*
+ * Macro WHILE_FALSE may be used to build single-iteration do-while loops,
+ * avoiding compiler warnings. Mostly intended for other macro definitions.
+ */
+
+#define WHILE_FALSE while(0)
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# undef WHILE_FALSE
+# if (_MSC_VER < 1500)
+# define WHILE_FALSE while(1, 0)
+# else
+# define WHILE_FALSE \
+__pragma(warning(push)) \
+__pragma(warning(disable:4127)) \
+while(0) \
+__pragma(warning(pop))
+# endif
+#endif
+
+
+/*
* Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type.
*/
@@ -336,7 +399,7 @@ typedef int sig_atomic_t;
#ifdef DEBUGBUILD
#define DEBUGF(x) x
#else
-#define DEBUGF(x) do { } while (0)
+#define DEBUGF(x) do { } WHILE_FALSE
#endif
@@ -347,7 +410,7 @@ typedef int sig_atomic_t;
#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H)
#define DEBUGASSERT(x) assert(x)
#else
-#define DEBUGASSERT(x) do { } while (0)
+#define DEBUGASSERT(x) do { } WHILE_FALSE
#endif
@@ -460,18 +523,6 @@ typedef int sig_atomic_t;
/*
- * System error codes for Windows CE
- */
-
-#if defined(WIN32) && !defined(HAVE_ERRNO_H)
-#define ENOENT ERROR_FILE_NOT_FOUND
-#define ESRCH ERROR_PATH_NOT_FOUND
-#define ENOMEM ERROR_NOT_ENOUGH_MEMORY
-#define ENOSPC ERROR_INVALID_PARAMETER
-#endif
-
-
-/*
* Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid()
*/
@@ -501,4 +552,3 @@ typedef int sig_atomic_t;
#endif /* __SETUP_ONCE_H */
-