forked from pool/c-ares
4c1bcc5dd1
Needed to fix envoy-proxy - Add upstream patches with the ares_getaddrinfo function: * 0001-Add-initial-implementation-for-ares_getaddrinfo-112.patch * 0002-Remaining-queries-counter-fix-additional-unit-tests-.patch * 0003-Bugfix-for-ares_getaddrinfo-and-additional-unit-test.patch * 0004-Add-ares__sortaddrinfo-to-support-getaddrinfo-sorted.patch * 0005-getaddrinfo-avoid-infinite-loop-in-case-of-NXDOMAIN-.patch * 0006-getaddrinfo-callback-must-be-called-on-bad-domain-24.patch * 0007-getaddrinfo-enhancements-257.patch * 0008-Add-missing-limits.h-include-from-ares_getaddrinfo.c.patch * 0009-Increase-portability-of-ares-test-mock-ai.cc-235.patch - Add a patch which disables test failing on OBS (but passing in local environment): * 0010-Disable-failing-test.patch OBS-URL: https://build.opensuse.org/request/show/742197 OBS-URL: https://build.opensuse.org/package/show/devel:libraries:c_c++/c-ares?expand=0&rev=9
1473 lines
50 KiB
Diff
1473 lines
50 KiB
Diff
From b565626751ea6bb69fbe1642c89c8b634b064911 Mon Sep 17 00:00:00 2001
|
|
From: Andrew Selivanov <andrew.selivanov@gmail.com>
|
|
Date: Wed, 23 Jan 2019 17:09:33 +0300
|
|
Subject: [PATCH 04/10] Add ares__sortaddrinfo() to support getaddrinfo()
|
|
sorted results (#239)
|
|
|
|
This is a port of RFC 6724 compliant sorting function from Android Bionic project:
|
|
https://android.googlesource.com/platform/bionic/+/e919b116d35aa7deb24ddece69c491e24c3b0d6f/libc/netbsd/net/getaddrinfo.c
|
|
|
|
The latest version is essentially the same, except two additional parameters to test connection with (mark/uid):
|
|
https://android.googlesource.com/platform/bionic/+/master/libc/dns/net/getaddrinfo.c
|
|
|
|
Please note that even that version has some restrictions. It doesn't support some rules from RFC 6724:
|
|
|
|
Rule 3 (Avoid deprecated addresses)
|
|
Rule 4 (Prefer home addresses)
|
|
Rule 7 (Prefer native transport)
|
|
|
|
Submitted By: Andrew Selivanov (@ki11roy)
|
|
---
|
|
Makefile.inc | 1 +
|
|
ares.h | 1 +
|
|
ares__sortaddrinfo.c | 495 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
ares_getaddrinfo.3 | 18 +-
|
|
ares_getaddrinfo.c | 14 +-
|
|
ares_ipv6.h | 7 +
|
|
ares_private.h | 1 +
|
|
test/ares-test-ai.h | 11 --
|
|
test/ares-test-live-ai.cc | 47 +++--
|
|
test/ares-test-mock-ai.cc | 286 +++++++++++++--------------
|
|
test/ares-test.cc | 58 +++++-
|
|
test/ares-test.h | 28 ++-
|
|
12 files changed, 759 insertions(+), 208 deletions(-)
|
|
create mode 100644 ares__sortaddrinfo.c
|
|
|
|
diff --git a/Makefile.inc b/Makefile.inc
|
|
index 381cc75..de165cf 100644
|
|
--- a/Makefile.inc
|
|
+++ b/Makefile.inc
|
|
@@ -1,6 +1,7 @@
|
|
|
|
CSOURCES = ares__close_sockets.c \
|
|
ares__get_hostent.c \
|
|
+ ares__sortaddrinfo.c \
|
|
ares__read_line.c \
|
|
ares__timeval.c \
|
|
ares_android.c \
|
|
diff --git a/ares.h b/ares.h
|
|
index 99e3e0b..af82141 100644
|
|
--- a/ares.h
|
|
+++ b/ares.h
|
|
@@ -309,6 +309,7 @@ typedef int (*ares_sock_config_callback)(ares_socket_t socket_fd,
|
|
|
|
typedef void (*ares_addr_callback)(void *arg,
|
|
int status,
|
|
+ int timeouts,
|
|
struct ares_addrinfo *res);
|
|
|
|
CARES_EXTERN int ares_library_init(int flags);
|
|
diff --git a/ares__sortaddrinfo.c b/ares__sortaddrinfo.c
|
|
new file mode 100644
|
|
index 0000000..4d3c8d6
|
|
--- /dev/null
|
|
+++ b/ares__sortaddrinfo.c
|
|
@@ -0,0 +1,495 @@
|
|
+/*
|
|
+ * Original file name getaddrinfo.c
|
|
+ * Lifted from the 'Android Bionic' project with the BSD license.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
+ * Copyright (C) 2018 The Android Open Source Project
|
|
+ * Copyright (C) 2019 by Andrew Selivanov
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the project nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ */
|
|
+
|
|
+#include "ares_setup.h"
|
|
+
|
|
+#ifdef HAVE_NETINET_IN_H
|
|
+# include <netinet/in.h>
|
|
+#endif
|
|
+#ifdef HAVE_NETDB_H
|
|
+# include <netdb.h>
|
|
+#endif
|
|
+#ifdef HAVE_STRINGS_H
|
|
+# include <strings.h>
|
|
+#endif
|
|
+
|
|
+#include <assert.h>
|
|
+#include <limits.h>
|
|
+
|
|
+#include "ares.h"
|
|
+#include "ares_private.h"
|
|
+
|
|
+struct addrinfo_sort_elem
|
|
+{
|
|
+ struct ares_addrinfo *ai;
|
|
+ int has_src_addr;
|
|
+ ares_sockaddr src_addr;
|
|
+ int original_order;
|
|
+};
|
|
+
|
|
+#define IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
|
|
+
|
|
+#define IPV6_ADDR_SCOPE_NODELOCAL 0x01
|
|
+#define IPV6_ADDR_SCOPE_INTFACELOCAL 0x01
|
|
+#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02
|
|
+#define IPV6_ADDR_SCOPE_SITELOCAL 0x05
|
|
+#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08
|
|
+#define IPV6_ADDR_SCOPE_GLOBAL 0x0e
|
|
+
|
|
+#define IN_LOOPBACK(a) ((((long int)(a)) & 0xff000000) == 0x7f000000)
|
|
+
|
|
+/* RFC 4193. */
|
|
+#define IN6_IS_ADDR_ULA(a) (((a)->s6_addr[0] & 0xfe) == 0xfc)
|
|
+
|
|
+/* These macros are modelled after the ones in <netinet/in6.h>. */
|
|
+/* RFC 4380, section 2.6 */
|
|
+#define IN6_IS_ADDR_TEREDO(a) \
|
|
+ ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000)))
|
|
+/* RFC 3056, section 2. */
|
|
+#define IN6_IS_ADDR_6TO4(a) \
|
|
+ (((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
|
|
+/* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */
|
|
+#define IN6_IS_ADDR_6BONE(a) \
|
|
+ (((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe))
|
|
+
|
|
+static int get_scope(const struct sockaddr *addr)
|
|
+{
|
|
+ if (addr->sa_family == AF_INET6)
|
|
+ {
|
|
+ const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
|
|
+ if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr))
|
|
+ {
|
|
+ return IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr);
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) ||
|
|
+ IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr))
|
|
+ {
|
|
+ /*
|
|
+ * RFC 4291 section 2.5.3 says loopback is to be treated as having
|
|
+ * link-local scope.
|
|
+ */
|
|
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr))
|
|
+ {
|
|
+ return IPV6_ADDR_SCOPE_SITELOCAL;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ return IPV6_ADDR_SCOPE_GLOBAL;
|
|
+ }
|
|
+ }
|
|
+ else if (addr->sa_family == AF_INET)
|
|
+ {
|
|
+ const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
|
|
+ unsigned long int na = ntohl(addr4->sin_addr.s_addr);
|
|
+ if (IN_LOOPBACK(na) || /* 127.0.0.0/8 */
|
|
+ (na & 0xffff0000) == 0xa9fe0000) /* 169.254.0.0/16 */
|
|
+ {
|
|
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*
|
|
+ * RFC 6724 section 3.2. Other IPv4 addresses, including private
|
|
+ * addresses and shared addresses (100.64.0.0/10), are assigned global
|
|
+ * scope.
|
|
+ */
|
|
+ return IPV6_ADDR_SCOPE_GLOBAL;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*
|
|
+ * This should never happen.
|
|
+ * Return a scope with low priority as a last resort.
|
|
+ */
|
|
+ return IPV6_ADDR_SCOPE_NODELOCAL;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int get_label(const struct sockaddr *addr)
|
|
+{
|
|
+ if (addr->sa_family == AF_INET)
|
|
+ {
|
|
+ return 4;
|
|
+ }
|
|
+ else if (addr->sa_family == AF_INET6)
|
|
+ {
|
|
+ const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
|
|
+ if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 4;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 2;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 5;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 13;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 3;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 11;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 12;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* All other IPv6 addresses, including global unicast addresses. */
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*
|
|
+ * This should never happen.
|
|
+ * Return a semi-random label as a last resort.
|
|
+ */
|
|
+ return 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Get the precedence for a given IPv4/IPv6 address.
|
|
+ * RFC 6724, section 2.1.
|
|
+ */
|
|
+static int get_precedence(const struct sockaddr *addr)
|
|
+{
|
|
+ if (addr->sa_family == AF_INET)
|
|
+ {
|
|
+ return 35;
|
|
+ }
|
|
+ else if (addr->sa_family == AF_INET6)
|
|
+ {
|
|
+ const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
|
|
+ if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 50;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 35;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 30;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 5;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 3;
|
|
+ }
|
|
+ else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) ||
|
|
+ IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) ||
|
|
+ IN6_IS_ADDR_6BONE(&addr6->sin6_addr))
|
|
+ {
|
|
+ return 1;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* All other IPv6 addresses, including global unicast addresses. */
|
|
+ return 40;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ return 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Find number of matching initial bits between the two addresses a1 and a2.
|
|
+ */
|
|
+static int common_prefix_len(const struct in6_addr *a1,
|
|
+ const struct in6_addr *a2)
|
|
+{
|
|
+ const char *p1 = (const char *)a1;
|
|
+ const char *p2 = (const char *)a2;
|
|
+ unsigned i;
|
|
+ for (i = 0; i < sizeof(*a1); ++i)
|
|
+ {
|
|
+ int x, j;
|
|
+ if (p1[i] == p2[i])
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+ x = p1[i] ^ p2[i];
|
|
+ for (j = 0; j < CHAR_BIT; ++j)
|
|
+ {
|
|
+ if (x & (1 << (CHAR_BIT - 1)))
|
|
+ {
|
|
+ return i * CHAR_BIT + j;
|
|
+ }
|
|
+ x <<= 1;
|
|
+ }
|
|
+ }
|
|
+ return sizeof(*a1) * CHAR_BIT;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Compare two source/destination address pairs.
|
|
+ * RFC 6724, section 6.
|
|
+ */
|
|
+static int rfc6724_compare(const void *ptr1, const void *ptr2)
|
|
+{
|
|
+ const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1;
|
|
+ const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2;
|
|
+ int scope_src1, scope_dst1, scope_match1;
|
|
+ int scope_src2, scope_dst2, scope_match2;
|
|
+ int label_src1, label_dst1, label_match1;
|
|
+ int label_src2, label_dst2, label_match2;
|
|
+ int precedence1, precedence2;
|
|
+ int prefixlen1, prefixlen2;
|
|
+
|
|
+ /* Rule 1: Avoid unusable destinations. */
|
|
+ if (a1->has_src_addr != a2->has_src_addr)
|
|
+ {
|
|
+ return a2->has_src_addr - a1->has_src_addr;
|
|
+ }
|
|
+
|
|
+ /* Rule 2: Prefer matching scope. */
|
|
+ scope_src1 = get_scope(&a1->src_addr.sa);
|
|
+ scope_dst1 = get_scope(a1->ai->ai_addr);
|
|
+ scope_match1 = (scope_src1 == scope_dst1);
|
|
+
|
|
+ scope_src2 = get_scope(&a2->src_addr.sa);
|
|
+ scope_dst2 = get_scope(a2->ai->ai_addr);
|
|
+ scope_match2 = (scope_src2 == scope_dst2);
|
|
+
|
|
+ if (scope_match1 != scope_match2)
|
|
+ {
|
|
+ return scope_match2 - scope_match1;
|
|
+ }
|
|
+
|
|
+ /* Rule 3: Avoid deprecated addresses. */
|
|
+
|
|
+ /* Rule 4: Prefer home addresses. */
|
|
+
|
|
+ /* Rule 5: Prefer matching label. */
|
|
+ label_src1 = get_label(&a1->src_addr.sa);
|
|
+ label_dst1 = get_label(a1->ai->ai_addr);
|
|
+ label_match1 = (label_src1 == label_dst1);
|
|
+
|
|
+ label_src2 = get_label(&a2->src_addr.sa);
|
|
+ label_dst2 = get_label(a2->ai->ai_addr);
|
|
+ label_match2 = (label_src2 == label_dst2);
|
|
+
|
|
+ if (label_match1 != label_match2)
|
|
+ {
|
|
+ return label_match2 - label_match1;
|
|
+ }
|
|
+
|
|
+ /* Rule 6: Prefer higher precedence. */
|
|
+ precedence1 = get_precedence(a1->ai->ai_addr);
|
|
+ precedence2 = get_precedence(a2->ai->ai_addr);
|
|
+ if (precedence1 != precedence2)
|
|
+ {
|
|
+ return precedence2 - precedence1;
|
|
+ }
|
|
+
|
|
+ /* Rule 7: Prefer native transport. */
|
|
+
|
|
+ /* Rule 8: Prefer smaller scope. */
|
|
+ if (scope_dst1 != scope_dst2)
|
|
+ {
|
|
+ return scope_dst1 - scope_dst2;
|
|
+ }
|
|
+
|
|
+ /* Rule 9: Use longest matching prefix. */
|
|
+ if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 &&
|
|
+ a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6)
|
|
+ {
|
|
+ const struct sockaddr_in6 *a1_src = &a1->src_addr.sa6;
|
|
+ const struct sockaddr_in6 *a1_dst =
|
|
+ (const struct sockaddr_in6 *)a1->ai->ai_addr;
|
|
+ const struct sockaddr_in6 *a2_src = &a2->src_addr.sa6;
|
|
+ const struct sockaddr_in6 *a2_dst =
|
|
+ (const struct sockaddr_in6 *)a2->ai->ai_addr;
|
|
+ prefixlen1 = common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr);
|
|
+ prefixlen2 = common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr);
|
|
+ if (prefixlen1 != prefixlen2)
|
|
+ {
|
|
+ return prefixlen2 - prefixlen1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Rule 10: Leave the order unchanged.
|
|
+ * We need this since qsort() is not necessarily stable.
|
|
+ */
|
|
+ return a1->original_order - a2->original_order;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Find the source address that will be used if trying to connect to the given
|
|
+ * address.
|
|
+ *
|
|
+ * Returns 1 if a source address was found, 0 if the address is unreachable,
|
|
+ * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are
|
|
+ * undefined.
|
|
+ */
|
|
+static int find_src_addr(ares_channel channel,
|
|
+ const struct sockaddr *addr,
|
|
+ struct sockaddr *src_addr)
|
|
+{
|
|
+ int sock;
|
|
+ int ret;
|
|
+ socklen_t len;
|
|
+
|
|
+ switch (addr->sa_family)
|
|
+ {
|
|
+ case AF_INET:
|
|
+ len = sizeof(struct sockaddr_in);
|
|
+ break;
|
|
+ case AF_INET6:
|
|
+ len = sizeof(struct sockaddr_in6);
|
|
+ break;
|
|
+ default:
|
|
+ /* No known usable source address for non-INET families. */
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ sock = channel->sock_funcs->asocket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP, channel->sock_func_cb_data);
|
|
+ if (sock == -1)
|
|
+ {
|
|
+ if (errno == EAFNOSUPPORT)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ do
|
|
+ {
|
|
+ ret = channel->sock_funcs->aconnect(sock, addr, len, channel->sock_func_cb_data);
|
|
+ }
|
|
+ while (ret == -1 && errno == EINTR);
|
|
+
|
|
+ if (ret == -1)
|
|
+ {
|
|
+ channel->sock_funcs->aclose(sock, channel->sock_func_cb_data);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (getsockname(sock, src_addr, &len) == -1)
|
|
+ {
|
|
+ channel->sock_funcs->aclose(sock, channel->sock_func_cb_data);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ channel->sock_funcs->aclose(sock, channel->sock_func_cb_data);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Sort the linked list starting at sentinel->ai_next in RFC6724 order.
|
|
+ * Will leave the list unchanged if an error occurs.
|
|
+ */
|
|
+int ares__sortaddrinfo(ares_channel channel, struct ares_addrinfo *list_sentinel)
|
|
+{
|
|
+ struct ares_addrinfo *cur;
|
|
+ int nelem = 0, i;
|
|
+ int has_src_addr;
|
|
+ struct addrinfo_sort_elem *elems;
|
|
+
|
|
+ cur = list_sentinel->ai_next;
|
|
+ while (cur)
|
|
+ {
|
|
+ ++nelem;
|
|
+ cur = cur->ai_next;
|
|
+ }
|
|
+ elems = (struct addrinfo_sort_elem *)ares_malloc(
|
|
+ nelem * sizeof(struct addrinfo_sort_elem));
|
|
+ if (!elems)
|
|
+ {
|
|
+ return ARES_ENOMEM;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Convert the linked list to an array that also contains the candidate
|
|
+ * source address for each destination address.
|
|
+ */
|
|
+ for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next)
|
|
+ {
|
|
+ assert(cur != NULL);
|
|
+ elems[i].ai = cur;
|
|
+ elems[i].original_order = i;
|
|
+ has_src_addr = find_src_addr(channel, cur->ai_addr, &elems[i].src_addr.sa);
|
|
+ if (has_src_addr == -1)
|
|
+ {
|
|
+ ares_free(elems);
|
|
+ return ARES_ENOTFOUND;
|
|
+ }
|
|
+ elems[i].has_src_addr = has_src_addr;
|
|
+ }
|
|
+
|
|
+ /* Sort the addresses, and rearrange the linked list so it matches the sorted
|
|
+ * order. */
|
|
+ qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem),
|
|
+ rfc6724_compare);
|
|
+
|
|
+ list_sentinel->ai_next = elems[0].ai;
|
|
+ for (i = 0; i < nelem - 1; ++i)
|
|
+ {
|
|
+ elems[i].ai->ai_next = elems[i + 1].ai;
|
|
+ }
|
|
+ elems[nelem - 1].ai->ai_next = NULL;
|
|
+
|
|
+ ares_free(elems);
|
|
+ return ARES_SUCCESS;
|
|
+}
|
|
diff --git a/ares_getaddrinfo.3 b/ares_getaddrinfo.3
|
|
index 42a43fc..0089227 100644
|
|
--- a/ares_getaddrinfo.3
|
|
+++ b/ares_getaddrinfo.3
|
|
@@ -21,7 +21,7 @@ ares_getaddrinfo \- Initiate a host query by name
|
|
.B #include <ares.h>
|
|
.PP
|
|
.B typedef void (*ares_addr_callback)(void *\fIarg\fP, int \fIstatus\fP,
|
|
-.B struct ares_addrinfo *\fIresult\fP)
|
|
+.B int \fItimeouts\fP, struct ares_addrinfo *\fIresult\fP)
|
|
.PP
|
|
.B void ares_getaddrinfo(ares_channel \fIchannel\fP, const char *\fIname\fP,
|
|
.B const char* \fIservice\fP, const struct ares_addrinfo *\fIhints\fP,
|
|
@@ -98,17 +98,25 @@ On successful completion of the query, the callback argument
|
|
points to a
|
|
.B struct addrinfo
|
|
which is a linked list, where each item contains family and address of
|
|
-the requested name. The list is not sorted. The reserved memory has to be
|
|
-deleted by
|
|
+the requested name. The reserved memory has to be deleted by
|
|
.B ares_freeaddrinfo.
|
|
+
|
|
+The result is sorted according to RFC6724 except:
|
|
+ - Rule 3 (Avoid deprecated addresses)
|
|
+ - Rule 4 (Prefer home addresses)
|
|
+ - Rule 7 (Prefer native transport)
|
|
+
|
|
+Please note that the function will attempt a connection
|
|
+on each of the resolved addresses as per RFC6724.
|
|
.SH SEE ALSO
|
|
.BR ares_freeaddrinfo (3)
|
|
.SH AUTHOR
|
|
Christian Ammer
|
|
+.br
|
|
+Andrew Selivanov <andrew.selivanov@gmail.com>
|
|
.SH CAVEATS
|
|
This function is under development. It only supports a minimum feature set
|
|
of the function
|
|
.B getaddrinfo
|
|
-defined in RFC-3493. It also does not support the destination address selection
|
|
-algorithm defined in RFC-6724.
|
|
+defined in RFC-3493
|
|
.br
|
|
diff --git a/ares_getaddrinfo.c b/ares_getaddrinfo.c
|
|
index b89a29c..ebaeda8 100644
|
|
--- a/ares_getaddrinfo.c
|
|
+++ b/ares_getaddrinfo.c
|
|
@@ -91,20 +91,21 @@ void ares_getaddrinfo(ares_channel channel,
|
|
const char* node, const char* service,
|
|
const struct ares_addrinfo* hints,
|
|
ares_addr_callback callback, void* arg) {
|
|
+ struct ares_addrinfo sentinel;
|
|
struct host_query *hquery;
|
|
char *single = NULL;
|
|
int ai_family;
|
|
|
|
ai_family = hints ? hints->ai_family : AF_UNSPEC;
|
|
if (!is_implemented(ai_family)) {
|
|
- callback(arg, ARES_ENOTIMP, NULL);
|
|
+ callback(arg, ARES_ENOTIMP, 0, NULL);
|
|
return;
|
|
}
|
|
|
|
/* Allocate and fill in the host query structure. */
|
|
hquery = ares_malloc(sizeof(struct host_query));
|
|
if (!hquery) {
|
|
- callback(arg, ARES_ENOMEM, NULL);
|
|
+ callback(arg, ARES_ENOMEM, 0, NULL);
|
|
return;
|
|
}
|
|
hquery->ai = NULL;
|
|
@@ -115,7 +116,7 @@ void ares_getaddrinfo(ares_channel channel,
|
|
hquery->sent_family = -1; /* nothing is sent yet */
|
|
if (!hquery->name) {
|
|
ares_free(hquery);
|
|
- callback(arg, ARES_ENOMEM, NULL);
|
|
+ callback(arg, ARES_ENOMEM, 0, NULL);
|
|
return;
|
|
}
|
|
hquery->callback = callback;
|
|
@@ -126,6 +127,9 @@ void ares_getaddrinfo(ares_channel channel,
|
|
|
|
/* Host file lookup */
|
|
if (file_lookup(hquery->name, ai_family, &hquery->ai) == ARES_SUCCESS) {
|
|
+ sentinel.ai_next = hquery->ai;
|
|
+ ares__sortaddrinfo(channel, &sentinel);
|
|
+ hquery->ai = sentinel.ai_next;
|
|
end_hquery(hquery, ARES_SUCCESS);
|
|
}
|
|
else {
|
|
@@ -251,6 +255,7 @@ static int add_to_addrinfo(struct ares_addrinfo** ai,
|
|
front->ai_family = AF_INET;
|
|
front->ai_addr = ares_malloc(sizeof(struct sockaddr_in));
|
|
if (!front->ai_addr) goto nomem;
|
|
+ memset(front->ai_addr, 0, sizeof(struct sockaddr_in));
|
|
memcpy(&((struct sockaddr_in*)(front->ai_addr))->sin_addr, *p,
|
|
host->h_length);
|
|
}
|
|
@@ -259,6 +264,7 @@ static int add_to_addrinfo(struct ares_addrinfo** ai,
|
|
front->ai_family = AF_INET6;
|
|
front->ai_addr = ares_malloc(sizeof(struct sockaddr_in6));
|
|
if (!front->ai_addr) goto nomem;
|
|
+ memset(front->ai_addr, 0, sizeof(struct sockaddr_in6));
|
|
memcpy(&((struct sockaddr_in6*)(front->ai_addr))->sin6_addr, *p,
|
|
host->h_length);
|
|
}
|
|
@@ -310,7 +316,7 @@ static void next_dns_lookup(struct host_query *hquery) {
|
|
}
|
|
|
|
static void end_hquery(struct host_query *hquery, int status) {
|
|
- hquery->callback(hquery->arg, status, hquery->ai);
|
|
+ hquery->callback(hquery->arg, status, hquery->timeouts, hquery->ai);
|
|
ares_free(hquery->name);
|
|
ares_free(hquery);
|
|
}
|
|
diff --git a/ares_ipv6.h b/ares_ipv6.h
|
|
index b0017f1..fdbc21f 100644
|
|
--- a/ares_ipv6.h
|
|
+++ b/ares_ipv6.h
|
|
@@ -32,6 +32,13 @@ struct sockaddr_in6
|
|
};
|
|
#endif
|
|
|
|
+typedef union
|
|
+{
|
|
+ struct sockaddr sa;
|
|
+ struct sockaddr_in sa4;
|
|
+ struct sockaddr_in6 sa6;
|
|
+} ares_sockaddr;
|
|
+
|
|
#ifndef HAVE_STRUCT_ADDRINFO
|
|
struct addrinfo
|
|
{
|
|
diff --git a/ares_private.h b/ares_private.h
|
|
index 8e16256..dcbdf0e 100644
|
|
--- a/ares_private.h
|
|
+++ b/ares_private.h
|
|
@@ -358,6 +358,7 @@ void ares__destroy_servers_state(ares_channel channel);
|
|
int ares__parse_qtype_reply(const unsigned char* abuf, int alen, int* qtype);
|
|
int ares__single_domain(ares_channel channel, const char *name, char **s);
|
|
int ares__cat_domain(const char *name, const char *domain, char **s);
|
|
+int ares__sortaddrinfo(ares_channel channel, struct ares_addrinfo *ai);
|
|
|
|
#if 0 /* Not used */
|
|
long ares__tvdiff(struct timeval t1, struct timeval t2);
|
|
diff --git a/test/ares-test-ai.h b/test/ares-test-ai.h
|
|
index d558489..7cf27e3 100644
|
|
--- a/test/ares-test-ai.h
|
|
+++ b/test/ares-test-ai.h
|
|
@@ -51,17 +51,6 @@ class DefaultChannelTestAI : public LibraryTest {
|
|
ares_channel channel_;
|
|
};
|
|
|
|
-// Structure that describes the result of an ares_addr_callback invocation.
|
|
-struct AIResult {
|
|
- AIResult() : done(), status(), airesult() {}
|
|
- // Whether the callback has been invoked.
|
|
- bool done;
|
|
- // Explicitly provided result information.
|
|
- int status;
|
|
- // Contents of the ares_addrinfo structure, if provided.
|
|
- struct ares_addrinfo* airesult;
|
|
-};
|
|
-
|
|
}
|
|
}
|
|
|
|
diff --git a/test/ares-test-live-ai.cc b/test/ares-test-live-ai.cc
|
|
index 96260fb..ab93587 100644
|
|
--- a/test/ares-test-live-ai.cc
|
|
+++ b/test/ares-test-live-ai.cc
|
|
@@ -15,20 +15,20 @@ namespace test {
|
|
|
|
MATCHER_P(IncludesAtLeastNumAddresses, n, "") {
|
|
int cnt = 0;
|
|
- for (const ares_addrinfo* ai = arg; ai != NULL; ai = ai->ai_next)
|
|
+ for (const ares_addrinfo* ai = arg.get(); ai != NULL; ai = ai->ai_next)
|
|
cnt++;
|
|
return cnt >= n;
|
|
}
|
|
|
|
MATCHER_P(OnlyIncludesAddrType, addrtype, "") {
|
|
- for (const ares_addrinfo* ai = arg; ai != NULL; ai = ai->ai_next)
|
|
+ for (const ares_addrinfo* ai = arg.get(); ai != NULL; ai = ai->ai_next)
|
|
if (ai->ai_family != addrtype)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
MATCHER_P(IncludesAddrType, addrtype, "") {
|
|
- for (const ares_addrinfo* ai = arg; ai != NULL; ai = ai->ai_next)
|
|
+ for (const ares_addrinfo* ai = arg.get(); ai != NULL; ai = ai->ai_next)
|
|
if (ai->ai_family == addrtype)
|
|
return true;
|
|
return false;
|
|
@@ -44,41 +44,38 @@ void DefaultChannelTestAI::Process() {
|
|
VIRT_NONVIRT_TEST_F(DefaultChannelTestAI, LiveGetHostByNameV4) {
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- AIResult result;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ AddrInfoResult result;
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_SUCCESS, result.status);
|
|
- EXPECT_THAT(result.airesult, IncludesAtLeastNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, OnlyIncludesAddrType(AF_INET));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_SUCCESS, result.status_);
|
|
+ EXPECT_THAT(result.ai_, IncludesAtLeastNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, OnlyIncludesAddrType(AF_INET));
|
|
}
|
|
|
|
VIRT_NONVIRT_TEST_F(DefaultChannelTestAI, LiveGetHostByNameV6) {
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET6;
|
|
- AIResult result;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ AddrInfoResult result;
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_SUCCESS, result.status);
|
|
- EXPECT_THAT(result.airesult, IncludesAtLeastNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, OnlyIncludesAddrType(AF_INET6));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_SUCCESS, result.status_);
|
|
+ EXPECT_THAT(result.ai_, IncludesAtLeastNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, OnlyIncludesAddrType(AF_INET6));
|
|
}
|
|
|
|
VIRT_NONVIRT_TEST_F(DefaultChannelTestAI, LiveGetHostByNameV4AndV6) {
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_UNSPEC;
|
|
- AIResult result;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ AddrInfoResult result;
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_SUCCESS, result.status);
|
|
- EXPECT_THAT(result.airesult, IncludesAtLeastNumAddresses(2));
|
|
- EXPECT_THAT(result.airesult, IncludesAddrType(AF_INET6));
|
|
- EXPECT_THAT(result.airesult, IncludesAddrType(AF_INET));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_SUCCESS, result.status_);
|
|
+ EXPECT_THAT(result.ai_, IncludesAtLeastNumAddresses(2));
|
|
+ EXPECT_THAT(result.ai_, IncludesAddrType(AF_INET6));
|
|
+ EXPECT_THAT(result.ai_, IncludesAddrType(AF_INET));
|
|
}
|
|
|
|
} // namespace test
|
|
diff --git a/test/ares-test-mock-ai.cc b/test/ares-test-mock-ai.cc
|
|
index a67f811..c293102 100644
|
|
--- a/test/ares-test-mock-ai.cc
|
|
+++ b/test/ares-test-mock-ai.cc
|
|
@@ -16,17 +16,21 @@ namespace ares {
|
|
namespace test {
|
|
|
|
MATCHER_P(IncludesNumAddresses, n, "") {
|
|
+ if(!arg)
|
|
+ return false;
|
|
int cnt = 0;
|
|
- for (const ares_addrinfo* ai = arg; ai != NULL; ai = ai->ai_next)
|
|
+ for (const ares_addrinfo* ai = arg.get(); ai != NULL; ai = ai->ai_next)
|
|
cnt++;
|
|
return n == cnt;
|
|
}
|
|
|
|
MATCHER_P(IncludesV4Address, address, "") {
|
|
+ if(!arg)
|
|
+ return false;
|
|
in_addr addressnum = {};
|
|
if (!inet_pton(AF_INET, address, &addressnum))
|
|
return false; // wrong number format?
|
|
- for (const ares_addrinfo* ai = arg; ai != NULL; ai = ai->ai_next) {
|
|
+ for (const ares_addrinfo* ai = arg.get(); ai != NULL; ai = ai->ai_next) {
|
|
if (ai->ai_family != AF_INET)
|
|
continue;
|
|
if (reinterpret_cast<sockaddr_in*>(ai->ai_addr)->sin_addr.s_addr ==
|
|
@@ -37,11 +41,13 @@ MATCHER_P(IncludesV4Address, address, "") {
|
|
}
|
|
|
|
MATCHER_P(IncludesV6Address, address, "") {
|
|
+ if(!arg)
|
|
+ return false;
|
|
in6_addr addressnum = {};
|
|
if (!inet_pton(AF_INET6, address, &addressnum)) {
|
|
return false; // wrong number format?
|
|
}
|
|
- for (const ares_addrinfo* ai = arg; ai != NULL; ai = ai->ai_next) {
|
|
+ for (const ares_addrinfo* ai = arg.get(); ai != NULL; ai = ai->ai_next) {
|
|
if (ai->ai_family != AF_INET6)
|
|
continue;
|
|
if (!memcmp(
|
|
@@ -69,31 +75,28 @@ TEST_P(MockUDPChannelTestAI, ParallelLookups) {
|
|
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- AIResult result1;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result1);
|
|
- AIResult result2;
|
|
- ares_getaddrinfo(channel_, "www.example.com.", NULL, &hints, AICallback, &result2);
|
|
- AIResult result3;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result3);
|
|
+ AddrInfoResult result1;
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result1);
|
|
+ AddrInfoResult result2;
|
|
+ ares_getaddrinfo(channel_, "www.example.com.", NULL, &hints, AddrInfoCallback, &result2);
|
|
+ AddrInfoResult result3;
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result3);
|
|
Process();
|
|
|
|
- EXPECT_TRUE(result1.done);
|
|
- EXPECT_EQ(result1.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result1.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result1.airesult, IncludesV4Address("2.3.4.5"));
|
|
- ares_freeaddrinfo(result1.airesult);
|
|
-
|
|
- EXPECT_TRUE(result2.done);
|
|
- EXPECT_EQ(result2.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result2.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result2.airesult, IncludesV4Address("1.2.3.4"));
|
|
- ares_freeaddrinfo(result2.airesult);
|
|
-
|
|
- EXPECT_TRUE(result3.done);
|
|
- EXPECT_EQ(result3.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result3.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result3.airesult, IncludesV4Address("2.3.4.5"));
|
|
- ares_freeaddrinfo(result3.airesult);
|
|
+ EXPECT_TRUE(result1.done_);
|
|
+ EXPECT_EQ(result1.status_, ARES_SUCCESS);
|
|
+ EXPECT_THAT(result1.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result1.ai_, IncludesV4Address("2.3.4.5"));
|
|
+
|
|
+ EXPECT_TRUE(result2.done_);
|
|
+ EXPECT_EQ(result2.status_, ARES_SUCCESS);
|
|
+ EXPECT_THAT(result2.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result2.ai_, IncludesV4Address("1.2.3.4"));
|
|
+
|
|
+ EXPECT_TRUE(result3.done_);
|
|
+ EXPECT_EQ(result3.status_, ARES_SUCCESS);
|
|
+ EXPECT_THAT(result3.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result3.ai_, IncludesV4Address("2.3.4.5"));
|
|
}
|
|
|
|
// UDP to TCP specific test
|
|
@@ -109,16 +112,15 @@ TEST_P(MockUDPChannelTestAI, TruncationRetry) {
|
|
.WillOnce(SetReply(&server_, &rsptruncated))
|
|
.WillOnce(SetReply(&server_, &rspok));
|
|
|
|
- AIResult result;
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(result.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("1.2.3.4"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(result.status_, ARES_SUCCESS);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("1.2.3.4"));
|
|
}
|
|
|
|
// TCP only to prevent retries
|
|
@@ -127,14 +129,13 @@ TEST_P(MockTCPChannelTestAI, MalformedResponse) {
|
|
EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillOnce(SetReplyData(&server_, one));
|
|
|
|
- AIResult result;
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_ETIMEOUT, result.status);
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_ETIMEOUT, result.status_);
|
|
}
|
|
|
|
TEST_P(MockTCPChannelTestAI, FormErrResponse) {
|
|
@@ -144,15 +145,14 @@ TEST_P(MockTCPChannelTestAI, FormErrResponse) {
|
|
rsp.set_rcode(ns_r_formerr);
|
|
EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillOnce(SetReply(&server_, &rsp));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_EFORMERR, result.status);
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_EFORMERR, result.status_);
|
|
}
|
|
|
|
TEST_P(MockTCPChannelTestAI, ServFailResponse) {
|
|
@@ -162,16 +162,15 @@ TEST_P(MockTCPChannelTestAI, ServFailResponse) {
|
|
rsp.set_rcode(ns_r_servfail);
|
|
EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillOnce(SetReply(&server_, &rsp));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
+ EXPECT_TRUE(result.done_);
|
|
// ARES_FLAG_NOCHECKRESP not set, so SERVFAIL consumed
|
|
- EXPECT_EQ(ARES_ECONNREFUSED, result.status);
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_EQ(ARES_ECONNREFUSED, result.status_);
|
|
}
|
|
|
|
TEST_P(MockTCPChannelTestAI, NotImplResponse) {
|
|
@@ -181,16 +180,15 @@ TEST_P(MockTCPChannelTestAI, NotImplResponse) {
|
|
rsp.set_rcode(ns_r_notimpl);
|
|
EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillOnce(SetReply(&server_, &rsp));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
+ EXPECT_TRUE(result.done_);
|
|
// ARES_FLAG_NOCHECKRESP not set, so NOTIMPL consumed
|
|
- EXPECT_EQ(ARES_ECONNREFUSED, result.status);
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_EQ(ARES_ECONNREFUSED, result.status_);
|
|
}
|
|
|
|
TEST_P(MockTCPChannelTestAI, RefusedResponse) {
|
|
@@ -200,16 +198,15 @@ TEST_P(MockTCPChannelTestAI, RefusedResponse) {
|
|
rsp.set_rcode(ns_r_refused);
|
|
EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillOnce(SetReply(&server_, &rsp));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
+ EXPECT_TRUE(result.done_);
|
|
// ARES_FLAG_NOCHECKRESP not set, so REFUSED consumed
|
|
- EXPECT_EQ(ARES_ECONNREFUSED, result.status);
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_EQ(ARES_ECONNREFUSED, result.status_);
|
|
}
|
|
|
|
// TODO: make it work
|
|
@@ -221,14 +218,13 @@ TEST_P(MockTCPChannelTestAI, RefusedResponse) {
|
|
// EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
// .WillOnce(SetReply(&server_, &rsp));
|
|
//
|
|
-// AIResult result;
|
|
+// AddrInfoResult result;
|
|
// struct ares_addrinfo hints = {};
|
|
// hints.ai_family = AF_INET;
|
|
-// ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+// ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
// Process();
|
|
-// EXPECT_TRUE(result.done);
|
|
-// EXPECT_EQ(ARES_ENODATA, result.status);
|
|
-// ares_freeaddrinfo(result.airesult);
|
|
+// EXPECT_TRUE(result.done_);
|
|
+// EXPECT_EQ(ARES_ENODATA, result.status_);
|
|
//}
|
|
|
|
class MockExtraOptsTestAI
|
|
@@ -263,17 +259,16 @@ TEST_P(MockExtraOptsTestAI, SimpleQuery) {
|
|
.add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5}));
|
|
ON_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &rsp));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_SUCCESS, result.status);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("2.3.4.5"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_SUCCESS, result.status_);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("2.3.4.5"));
|
|
}
|
|
|
|
class MockFlagsChannelOptsTestAI
|
|
@@ -304,15 +299,14 @@ TEST_P(MockNoCheckRespChannelTestAI, ServFailResponse) {
|
|
rsp.set_rcode(ns_r_servfail);
|
|
ON_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &rsp));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_ESERVFAIL, result.status);
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_ESERVFAIL, result.status_);
|
|
}
|
|
|
|
TEST_P(MockNoCheckRespChannelTestAI, NotImplResponse) {
|
|
@@ -322,15 +316,14 @@ TEST_P(MockNoCheckRespChannelTestAI, NotImplResponse) {
|
|
rsp.set_rcode(ns_r_notimpl);
|
|
ON_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &rsp));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_ENOTIMP, result.status);
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_ENOTIMP, result.status_);
|
|
}
|
|
|
|
TEST_P(MockNoCheckRespChannelTestAI, RefusedResponse) {
|
|
@@ -340,15 +333,14 @@ TEST_P(MockNoCheckRespChannelTestAI, RefusedResponse) {
|
|
rsp.set_rcode(ns_r_refused);
|
|
ON_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &rsp));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_EREFUSED, result.status);
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(ARES_EREFUSED, result.status_);
|
|
}
|
|
|
|
TEST_P(MockChannelTestAI, FamilyV6) {
|
|
@@ -360,17 +352,15 @@ TEST_P(MockChannelTestAI, FamilyV6) {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03}));
|
|
ON_CALL(server_, OnRequest("example.com", ns_t_aaaa))
|
|
.WillByDefault(SetReply(&server_, &rsp6));
|
|
- AIResult result;
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET6;
|
|
ares_getaddrinfo(channel_, "example.com.", NULL, &hints,
|
|
- AICallback, &result);
|
|
+ AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(result.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, IncludesV6Address("2121:0000:0000:0000:0000:0000:0000:0303"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, IncludesV6Address("2121:0000:0000:0000:0000:0000:0000:0303"));
|
|
}
|
|
|
|
TEST_P(MockChannelTestAI, FamilyV4) {
|
|
@@ -380,17 +370,15 @@ TEST_P(MockChannelTestAI, FamilyV4) {
|
|
.add_answer(new DNSARR("example.com", 100, {2, 3, 4, 5}));
|
|
ON_CALL(server_, OnRequest("example.com", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &rsp4));
|
|
- AIResult result = {};
|
|
+ AddrInfoResult result = {};
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
ares_getaddrinfo(channel_, "example.com.", NULL, &hints,
|
|
- AICallback, &result);
|
|
+ AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(result.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("2.3.4.5"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("2.3.4.5"));
|
|
}
|
|
|
|
TEST_P(MockChannelTestAI, FamilyV4_MultipleAddresses) {
|
|
@@ -401,18 +389,16 @@ TEST_P(MockChannelTestAI, FamilyV4_MultipleAddresses) {
|
|
.add_answer(new DNSARR("example.com", 100, {7, 8, 9, 0}));
|
|
ON_CALL(server_, OnRequest("example.com", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &rsp4));
|
|
- AIResult result = {};
|
|
+ AddrInfoResult result = {};
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
ares_getaddrinfo(channel_, "example.com.", NULL, &hints,
|
|
- AICallback, &result);
|
|
+ AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(result.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(2));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("2.3.4.5"));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("7.8.9.0"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(2));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("2.3.4.5"));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("7.8.9.0"));
|
|
}
|
|
|
|
TEST_P(MockChannelTestAI, FamilyUnspecified) {
|
|
@@ -430,18 +416,16 @@ TEST_P(MockChannelTestAI, FamilyUnspecified) {
|
|
.add_answer(new DNSARR("example.com", 100, {2, 3, 4, 5}));
|
|
ON_CALL(server_, OnRequest("example.com", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &rsp4));
|
|
- AIResult result;
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_UNSPEC;
|
|
ares_getaddrinfo(channel_, "example.com.", NULL, &hints,
|
|
- AICallback, &result);
|
|
+ AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(result.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(2));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("2.3.4.5"));
|
|
- EXPECT_THAT(result.airesult, IncludesV6Address("2121:0000:0000:0000:0000:0000:0000:0303"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(2));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("2.3.4.5"));
|
|
+ EXPECT_THAT(result.ai_, IncludesV6Address("2121:0000:0000:0000:0000:0000:0000:0303"));
|
|
}
|
|
|
|
class MockEDNSChannelTestAI : public MockFlagsChannelOptsTestAI {
|
|
@@ -460,16 +444,15 @@ TEST_P(MockEDNSChannelTestAI, RetryWithoutEDNS) {
|
|
EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
|
.WillOnce(SetReply(&server_, &rspfail))
|
|
.WillOnce(SetReply(&server_, &rspok));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.google.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(ARES_SUCCESS, result.status);
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("1.2.3.4"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("1.2.3.4"));
|
|
}
|
|
|
|
TEST_P(MockChannelTestAI, SearchDomains) {
|
|
@@ -490,16 +473,14 @@ TEST_P(MockChannelTestAI, SearchDomains) {
|
|
ON_CALL(server_, OnRequest("www.third.gov", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &yesthird));
|
|
|
|
- AIResult result;
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(result.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("2.3.4.5"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("2.3.4.5"));
|
|
}
|
|
|
|
TEST_P(MockChannelTestAI, SearchDomainsServFailOnAAAA) {
|
|
@@ -513,7 +494,7 @@ TEST_P(MockChannelTestAI, SearchDomainsServFailOnAAAA) {
|
|
.add_question(new DNSQuestion("www.first.com", ns_t_a));
|
|
ON_CALL(server_, OnRequest("www.first.com", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &nofirst4));
|
|
-
|
|
+
|
|
DNSPacket nosecond;
|
|
nosecond.set_response().set_aa().set_rcode(ns_r_nxdomain)
|
|
.add_question(new DNSQuestion("www.second.org", ns_t_aaaa));
|
|
@@ -525,7 +506,7 @@ TEST_P(MockChannelTestAI, SearchDomainsServFailOnAAAA) {
|
|
.add_answer(new DNSARR("www.second.org", 0x0200, {2, 3, 4, 5}));
|
|
ON_CALL(server_, OnRequest("www.second.org", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &yessecond4));
|
|
-
|
|
+
|
|
DNSPacket failthird;
|
|
failthird.set_response().set_aa().set_rcode(ns_r_servfail)
|
|
.add_question(new DNSQuestion("www.third.gov", ns_t_aaaa));
|
|
@@ -536,17 +517,15 @@ TEST_P(MockChannelTestAI, SearchDomainsServFailOnAAAA) {
|
|
.add_question(new DNSQuestion("www.third.gov", ns_t_a));
|
|
ON_CALL(server_, OnRequest("www.third.gov", ns_t_a))
|
|
.WillByDefault(SetReply(&server_, &failthird4));
|
|
-
|
|
- AIResult result;
|
|
+
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_UNSPEC;
|
|
- ares_getaddrinfo(channel_, "www", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(result.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("2.3.4.5"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("2.3.4.5"));
|
|
}
|
|
|
|
class MockMultiServerChannelTestAI
|
|
@@ -556,16 +535,15 @@ class MockMultiServerChannelTestAI
|
|
MockMultiServerChannelTestAI(bool rotate)
|
|
: MockChannelOptsTest(3, GetParam().first, GetParam().second, nullptr, rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE) {}
|
|
void CheckExample() {
|
|
- AIResult result;
|
|
+ AddrInfoResult result;
|
|
struct ares_addrinfo hints = {};
|
|
hints.ai_family = AF_INET;
|
|
- ares_getaddrinfo(channel_, "www.example.com.", NULL, &hints, AICallback, &result);
|
|
+ ares_getaddrinfo(channel_, "www.example.com.", NULL, &hints, AddrInfoCallback, &result);
|
|
Process();
|
|
- EXPECT_TRUE(result.done);
|
|
- EXPECT_EQ(result.status, ARES_SUCCESS);
|
|
- EXPECT_THAT(result.airesult, IncludesNumAddresses(1));
|
|
- EXPECT_THAT(result.airesult, IncludesV4Address("2.3.4.5"));
|
|
- ares_freeaddrinfo(result.airesult);
|
|
+ EXPECT_TRUE(result.done_);
|
|
+ EXPECT_EQ(result.status_, ARES_SUCCESS);
|
|
+ EXPECT_THAT(result.ai_, IncludesNumAddresses(1));
|
|
+ EXPECT_THAT(result.ai_, IncludesV4Address("2.3.4.5"));
|
|
}
|
|
};
|
|
|
|
diff --git a/test/ares-test.cc b/test/ares-test.cc
|
|
index 7776548..1128e99 100644
|
|
--- a/test/ares-test.cc
|
|
+++ b/test/ares-test.cc
|
|
@@ -565,14 +565,58 @@ void HostCallback(void *data, int status, int timeouts,
|
|
if (verbose) std::cerr << "HostCallback(" << *result << ")" << std::endl;
|
|
}
|
|
|
|
-void AICallback(void *data, int status,
|
|
- struct ares_addrinfo *res) {
|
|
+std::ostream& operator<<(std::ostream& os, const AddrInfoResult& result) {
|
|
+ os << '{';
|
|
+ if (result.done_) {
|
|
+ os << StatusToString(result.status_) << " " << result.ai_;
|
|
+ } else {
|
|
+ os << "(incomplete)";
|
|
+ }
|
|
+ os << '}';
|
|
+ return os;
|
|
+}
|
|
+
|
|
+std::ostream& operator<<(std::ostream& os, const AddrInfo& ai) {
|
|
+ os << '{';
|
|
+ struct ares_addrinfo *next = ai.get();
|
|
+ while(next) {
|
|
+ if(next->ai_canonname) {
|
|
+ os << "'" << next->ai_canonname << "' ";
|
|
+ }
|
|
+ unsigned short port = 0;
|
|
+ os << "addr=[";
|
|
+ if(next->ai_family == AF_INET) {
|
|
+ sockaddr_in* sin = (sockaddr_in*)next->ai_addr;
|
|
+ port = ntohs(sin->sin_port);
|
|
+ os << AddressToString(&sin->sin_addr, 4);
|
|
+ }
|
|
+ else if (next->ai_family == AF_INET6) {
|
|
+ sockaddr_in6* sin = (sockaddr_in6*)next->ai_addr;
|
|
+ port = ntohs(sin->sin6_port);
|
|
+ os << "[" << AddressToString(&sin->sin6_addr, 16) << "]";
|
|
+ }
|
|
+ else
|
|
+ os << "unknown family";
|
|
+ if(port) {
|
|
+ os << ":" << port;
|
|
+ }
|
|
+ os << "]";
|
|
+ if((next = next->ai_next))
|
|
+ os << ", ";
|
|
+ }
|
|
+ os << '}';
|
|
+ return os;
|
|
+}
|
|
+
|
|
+void AddrInfoCallback(void *data, int status, int timeouts,
|
|
+ struct ares_addrinfo *ai) {
|
|
EXPECT_NE(nullptr, data);
|
|
- AIResult* result = reinterpret_cast<AIResult*>(data);
|
|
- result->done = true;
|
|
- result->status = status;
|
|
- result->airesult = res;
|
|
- //if (verbose) std::cerr << "HostCallback(" << *result << ")" << std::endl;
|
|
+ AddrInfoResult* result = reinterpret_cast<AddrInfoResult*>(data);
|
|
+ result->done_ = true;
|
|
+ result->status_ = status;
|
|
+ result->timeouts_= timeouts;
|
|
+ result->ai_ = AddrInfo(ai);
|
|
+ if (verbose) std::cerr << "AddrInfoCallback(" << *result << ")" << std::endl;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const SearchResult& result) {
|
|
diff --git a/test/ares-test.h b/test/ares-test.h
|
|
index 03e15ec..ae675aa 100644
|
|
--- a/test/ares-test.h
|
|
+++ b/test/ares-test.h
|
|
@@ -279,6 +279,30 @@ struct NameInfoResult {
|
|
};
|
|
std::ostream& operator<<(std::ostream& os, const NameInfoResult& result);
|
|
|
|
+struct AddrInfoDeleter {
|
|
+ void operator() (ares_addrinfo *ptr) {
|
|
+ if (ptr) ares_freeaddrinfo(ptr);
|
|
+ }
|
|
+};
|
|
+
|
|
+// C++ wrapper for struct ares_addrinfo.
|
|
+using AddrInfo = std::unique_ptr<ares_addrinfo, AddrInfoDeleter>;
|
|
+
|
|
+std::ostream& operator<<(std::ostream& os, const AddrInfo& result);
|
|
+
|
|
+// Structure that describes the result of an ares_addrinfo_callback invocation.
|
|
+struct AddrInfoResult {
|
|
+ AddrInfoResult() : done_(false), status_(-1), timeouts_(0) {}
|
|
+ // Whether the callback has been invoked.
|
|
+ bool done_;
|
|
+ // Explicitly provided result information.
|
|
+ int status_;
|
|
+ int timeouts_;
|
|
+ // Contents of the ares_addrinfo structure, if provided.
|
|
+ AddrInfo ai_;
|
|
+};
|
|
+std::ostream& operator<<(std::ostream& os, const AddrInfoResult& result);
|
|
+
|
|
// Standard implementation of ares callbacks that fill out the corresponding
|
|
// structures.
|
|
void HostCallback(void *data, int status, int timeouts,
|
|
@@ -287,8 +311,8 @@ void SearchCallback(void *data, int status, int timeouts,
|
|
unsigned char *abuf, int alen);
|
|
void NameInfoCallback(void *data, int status, int timeouts,
|
|
char *node, char *service);
|
|
-void AICallback(void *data, int status,
|
|
- struct ares_addrinfo *res);
|
|
+void AddrInfoCallback(void *data, int status, int timeouts,
|
|
+ struct ares_addrinfo *res);
|
|
|
|
// Retrieve the name servers used by a channel.
|
|
std::vector<std::string> GetNameServers(ares_channel channel);
|
|
--
|
|
2.16.4
|
|
|