[c-ares/el5/master] Backport IPv6 NS patch and several small packaging fixes
Jakub Hrozek
jhrozek at fedoraproject.org
Sun Aug 8 19:33:34 UTC 2010
commit eaac8fbb970f6de54d836e9be4f96fed7e1611b2
Author: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun Aug 8 21:32:21 2010 +0200
Backport IPv6 NS patch and several small packaging fixes
- Backport the fix for usage of IPv6 nameserves from 1.7 branch
- Use default defattr
- Comment patches
- Convert the CHANGES file to UTF8
c-ares.spec | 18 +-
use-ipv6-nameservers-1.6.0.patch | 1407 ++++++++++++++++++++++++++++++++++++++
2 files changed, 1422 insertions(+), 3 deletions(-)
---
diff --git a/c-ares.spec b/c-ares.spec
index fa71382..0cb23b0 100644
--- a/c-ares.spec
+++ b/c-ares.spec
@@ -1,15 +1,19 @@
Summary: A library that performs asynchronous DNS operations
Name: c-ares
Version: 1.6.0
-Release: 2%{?dist}
+Release: 3%{?dist}
License: MIT
Group: System Environment/Libraries
URL: http://daniel.haxx.se/projects/c-ares/
Source0: http://daniel.haxx.se/projects/c-ares/c-ares-%{version}.tar.gz
Source1: LICENSE
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+# Backported fix for #597287
Patch0: domain-search-order-1.6.0.patch
+# Pass correct CFLAGS to the make machinery (no relevat BZ entry)
Patch1: c-ares-1.6.0-optflags.patch
+# Backported fix for #560116
+Patch2: use-ipv6-nameservers-1.6.0.patch
%description
c-ares is a C library that performs DNS requests and name resolves
@@ -30,7 +34,9 @@ compile applications or shared objects that use c-ares.
%setup -q
%patch0 -p1 -b .domain
%patch1 -p1 -b .optflags
+%patch2 -p1 -b .ipv6
cp %{SOURCE1} .
+f=CHANGES ; iconv -f iso-8859-1 -t utf-8 $f -o $f.utf8 ; mv $f.utf8 $f
%build
%configure --enable-shared --disable-static \
@@ -50,12 +56,12 @@ rm -rf $RPM_BUILD_ROOT
%postun -p /sbin/ldconfig
%files
-%defattr(-, root, root)
+%defattr(-, root, root, -)
%doc README README.cares CHANGES NEWS LICENSE
%{_libdir}/*.so.*
%files devel
-%defattr(-, root, root, 0755)
+%defattr(-, root, root, -)
%{_includedir}/ares.h
%{_includedir}/ares_dns.h
%{_includedir}/ares_version.h
@@ -64,6 +70,12 @@ rm -rf $RPM_BUILD_ROOT
%{_mandir}/man3/ares_*
%changelog
+* Thu Aug 5 2010 Jakub Hrozek <jhrozek at redhat.com> - 1.6.0-3
+- Backport the fix for usage of IPv6 nameserves from 1.7 branch
+- Use default defattr
+- Comment patches
+- Convert the CHANGES file to UTF8
+
* Thu Jun 2 2010 Jakub Hrozek <jhrozek at redhat.com> - 1.6.0-2
- Backport the fix the order of search domains from 1.7 branch
- Add patch do honor our CFLAGS (patch by Ville Skyttä)
diff --git a/use-ipv6-nameservers-1.6.0.patch b/use-ipv6-nameservers-1.6.0.patch
new file mode 100644
index 0000000..0f1ebfd
--- /dev/null
+++ b/use-ipv6-nameservers-1.6.0.patch
@@ -0,0 +1,1407 @@
+diff -up ./adig.c.ipv6 ./adig.c
+--- ./adig.c.ipv6 2008-10-18 15:32:02.000000000 +0200
++++ ./adig.c 2010-08-06 10:50:39.000000000 +0200
+@@ -170,6 +170,9 @@ static const unsigned char *display_rr(c
+ static const char *type_name(int type);
+ static const char *class_name(int dnsclass);
+ static void usage(void);
++static void destroy_addr_list(struct ares_addr_node *head);
++static void append_addr_list(struct ares_addr_node **head,
++ struct ares_addr_node *node);
+
+ int main(int argc, char **argv)
+ {
+@@ -180,6 +183,7 @@ int main(int argc, char **argv)
+ struct hostent *hostent;
+ fd_set read_fds, write_fds;
+ struct timeval *tvp, tv;
++ struct ares_addr_node *srvr, *servers = NULL;
+
+ #ifdef USE_WINSOCK
+ WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
+@@ -213,27 +217,56 @@ int main(int argc, char **argv)
+ break;
+
+ case 's':
+- /* Add a server, and specify servers in the option mask. */
+- if (ares_inet_pton(AF_INET, optarg, &inaddr) <= 0)
++ /* User specified name servers override default ones. */
++ srvr = malloc(sizeof(struct ares_addr_node));
++ if (!srvr)
++ {
++ fprintf(stderr, "Out of memory!\n");
++ destroy_addr_list(servers);
++ return 1;
++ }
++ append_addr_list(&servers, srvr);
++ if (ares_inet_pton(AF_INET, optarg, &srvr->addr.addr4) > 0)
++ srvr->family = AF_INET;
++ else if (ares_inet_pton(AF_INET6, optarg, &srvr->addr.addr6) > 0)
++ srvr->family = AF_INET6;
++ else
+ {
+ hostent = gethostbyname(optarg);
+- if (!hostent || hostent->h_addrtype != AF_INET)
++ if (!hostent)
+ {
+ fprintf(stderr, "adig: server %s not found.\n", optarg);
++ destroy_addr_list(servers);
+ return 1;
+ }
+- memcpy(&inaddr, hostent->h_addr, sizeof(struct in_addr));
+- }
+- options.servers = realloc(options.servers, (options.nservers + 1)
+- * sizeof(struct in_addr));
+- if (!options.servers)
+- {
+- fprintf(stderr, "Out of memory!\n");
+- return 1;
++ switch (hostent->h_addrtype)
++ {
++ case AF_INET:
++ srvr->family = AF_INET;
++ memcpy(&srvr->addr.addr4, hostent->h_addr,
++ sizeof(srvr->addr.addr4));
++ break;
++ case AF_INET6:
++ srvr->family = AF_INET6;
++ memcpy(&srvr->addr.addr6, hostent->h_addr,
++ sizeof(srvr->addr.addr6));
++ break;
++ default:
++ fprintf(stderr,
++ "adig: server %s unsupported address family.\n", optarg);
++ destroy_addr_list(servers);
++ return 1;
++ }
+ }
+- memcpy(&options.servers[options.nservers], &inaddr,
+- sizeof(struct in_addr));
+- options.nservers++;
++ /* Notice that calling ares_init_options() without servers in the
++ * options struct and with ARES_OPT_SERVERS set simultaneously in
++ * the options mask, results in an initialization with no servers.
++ * When alternative name servers have been specified these are set
++ * later calling ares_set_servers() overriding any existing server
++ * configuration. To prevent initial configuration with default
++ * servers that will be discarded later ARES_OPT_SERVERS is set.
++ * If this flag is not set here the result shall be the same but
++ * ares_init_options() will do needless work. */
+ optmask |= ARES_OPT_SERVERS;
+ break;
+
+@@ -292,6 +325,18 @@ int main(int argc, char **argv)
+ return 1;
+ }
+
++ if(servers)
++ {
++ status = ares_set_servers(channel, servers);
++ destroy_addr_list(servers);
++ if (status != ARES_SUCCESS)
++ {
++ fprintf(stderr, "ares_init_options: %s\n",
++ ares_strerror(status));
++ return 1;
++ }
++ }
++
+ /* Initiate the queries, one per command-line argument. If there is
+ * only one query to do, supply NULL as the callback argument;
+ * otherwise, supply the query name as an argument so we can
+@@ -719,3 +764,29 @@ static void usage(void)
+ "[-t type] [-p port] name ...\n");
+ exit(1);
+ }
++
++static void destroy_addr_list(struct ares_addr_node *head)
++{
++ while(head)
++ {
++ struct ares_addr_node *detached = head;
++ head = head->next;
++ free(detached);
++ }
++}
++
++static void append_addr_list(struct ares_addr_node **head,
++ struct ares_addr_node *node)
++{
++ struct ares_addr_node *last;
++ node->next = NULL;
++ if(*head)
++ {
++ last = *head;
++ while(last->next)
++ last = last->next;
++ last->next = node;
++ }
++ else
++ *head = node;
++}
+diff -up ./ahost.c.ipv6 ./ahost.c
+--- ./ahost.c.ipv6 2008-09-18 14:42:18.000000000 +0200
++++ ./ahost.c 2010-08-06 10:50:39.000000000 +0200
+@@ -68,7 +68,7 @@ int main(int argc, char **argv)
+ fd_set read_fds, write_fds;
+ struct timeval *tvp, tv;
+ struct in_addr addr4;
+- struct in6_addr addr6;
++ struct ares_in6_addr addr6;
+
+ #ifdef USE_WINSOCK
+ WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
+diff -up ./ares_destroy.c.ipv6 ./ares_destroy.c
+--- ./ares_destroy.c.ipv6 2008-02-03 13:18:05.000000000 +0100
++++ ./ares_destroy.c 2010-08-06 10:50:39.000000000 +0200
+@@ -25,7 +25,8 @@ void ares_destroy_options(struct ares_op
+ {
+ int i;
+
+- free(options->servers);
++ if(options->servers)
++ free(options->servers);
+ for (i = 0; i < options->ndomains; i++)
+ free(options->domains[i]);
+ free(options->domains);
+@@ -67,15 +68,7 @@ void ares_destroy(ares_channel channel)
+ }
+ #endif
+
+- if (channel->servers) {
+- for (i = 0; i < channel->nservers; i++)
+- {
+- struct server_state *server = &channel->servers[i];
+- ares__close_sockets(channel, server);
+- assert(ares__is_list_empty(&(server->queries_to_server)));
+- }
+- free(channel->servers);
+- }
++ ares__destroy_servers_state(channel);
+
+ if (channel->domains) {
+ for (i = 0; i < channel->ndomains; i++)
+@@ -91,3 +84,22 @@ void ares_destroy(ares_channel channel)
+
+ free(channel);
+ }
++
++void ares__destroy_servers_state(ares_channel channel)
++{
++ struct server_state *server;
++ int i;
++
++ if (channel->servers)
++ {
++ for (i = 0; i < channel->nservers; i++)
++ {
++ server = &channel->servers[i];
++ ares__close_sockets(channel, server);
++ assert(ares__is_list_empty(&server->queries_to_server));
++ }
++ free(channel->servers);
++ channel->servers = NULL;
++ }
++ channel->nservers = -1;
++}
+diff -up ./ares_gethostbyaddr.c.ipv6 ./ares_gethostbyaddr.c
+--- ./ares_gethostbyaddr.c.ipv6 2008-12-09 09:00:33.000000000 +0100
++++ ./ares_gethostbyaddr.c 2010-08-06 10:50:39.000000000 +0200
+@@ -79,8 +79,8 @@ void ares_gethostbyaddr(ares_channel cha
+ return;
+ }
+
+- if ((family == AF_INET && addrlen != sizeof(struct in_addr)) ||
+- (family == AF_INET6 && addrlen != sizeof(struct in6_addr)))
++ if ((family == AF_INET && addrlen != sizeof(aquery->addr.addrV4)) ||
++ (family == AF_INET6 && addrlen != sizeof(aquery->addr.addrV6)))
+ {
+ callback(arg, ARES_ENOTIMP, 0, NULL);
+ return;
+@@ -94,9 +94,9 @@ void ares_gethostbyaddr(ares_channel cha
+ }
+ aquery->channel = channel;
+ if (family == AF_INET)
+- memcpy(&aquery->addr.addrV4, addr, sizeof(struct in_addr));
++ memcpy(&aquery->addr.addrV4, addr, sizeof(aquery->addr.addrV4));
+ else
+- memcpy(&aquery->addr.addrV6, addr, sizeof(struct in6_addr));
++ memcpy(&aquery->addr.addrV6, addr, sizeof(aquery->addr.addrV6));
+ aquery->addr.family = family;
+ aquery->callback = callback;
+ aquery->arg = arg;
+@@ -145,16 +145,23 @@ static void addr_callback(void *arg, int
+ {
+ struct addr_query *aquery = (struct addr_query *) arg;
+ struct hostent *host;
++ int addrlen;
+
+ aquery->timeouts += timeouts;
+ if (status == ARES_SUCCESS)
+ {
+ if (aquery->addr.family == AF_INET)
+- status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV4,
+- sizeof(struct in_addr), AF_INET, &host);
++ {
++ addrlen = sizeof(aquery->addr.addrV4);
++ status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV4,
++ sizeof(struct in_addr), AF_INET, &host);
++ }
+ else
+- status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV6,
+- sizeof(struct in6_addr), AF_INET6, &host);
++ {
++ addrlen = sizeof(aquery->addr.addrV6);
++ status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV6,
++ sizeof(struct in6_addr), AF_INET6, &host);
++ }
+ end_aquery(aquery, status, host);
+ }
+ else if (status == ARES_EDESTRUCTION)
+@@ -234,12 +241,12 @@ static int file_lookup(struct ares_addr
+ }
+ if (addr->family == AF_INET)
+ {
+- if (memcmp((*host)->h_addr, &addr->addrV4, sizeof(struct in_addr)) == 0)
++ if (memcmp((*host)->h_addr, &addr->addrV4, sizeof(addr->addrV4)) == 0)
+ break;
+ }
+ else if (addr->family == AF_INET6)
+ {
+- if (memcmp((*host)->h_addr, &addr->addrV6, sizeof(struct in6_addr)) == 0)
++ if (memcmp((*host)->h_addr, &addr->addrV6, sizeof(addr->addrV6)) == 0)
+ break;
+ }
+ ares_free_hostent(*host);
+@@ -265,7 +272,7 @@ static void ptr_rr_name(char *name, stru
+ }
+ else
+ {
+- unsigned char *bytes = (unsigned char *)&addr->addrV6.s6_addr;
++ unsigned char *bytes = (unsigned char *)&addr->addrV6;
+ /* There are too many arguments to do this in one line using
+ * minimally C89-compliant compilers */
+ sprintf(name,
+diff -up ./ares_gethostbyname.c.ipv6 ./ares_gethostbyname.c
+--- ./ares_gethostbyname.c.ipv6 2008-11-25 19:51:55.000000000 +0100
++++ ./ares_gethostbyname.c 2010-08-06 10:50:39.000000000 +0200
+@@ -80,7 +80,7 @@ static void sort6_addresses(struct hoste
+ int nsort);
+ static int get_address_index(struct in_addr *addr, struct apattern *sortlist,
+ int nsort);
+-static int get6_address_index(struct in6_addr *addr, struct apattern *sortlist,
++static int get6_address_index(struct ares_in6_addr *addr, struct apattern *sortlist,
+ int nsort);
+
+ void ares_gethostbyname(ares_channel channel, const char *name, int family,
+@@ -230,7 +230,7 @@ static int fake_hostent(const char *name
+ char *addrs[2];
+ int result = 0;
+ struct in_addr in;
+- struct in6_addr in6;
++ struct ares_in6_addr in6;
+
+ if (family == AF_INET)
+ {
+@@ -267,7 +267,7 @@ static int fake_hostent(const char *name
+ }
+ else if (family == AF_INET6)
+ {
+- hostent.h_length = sizeof(struct in6_addr);
++ hostent.h_length = sizeof(struct ares_in6_addr);
+ addrs[0] = (char *)&in6;
+ }
+ /* Duplicate the name, to avoid a constness violation. */
+@@ -449,7 +449,7 @@ static int get_address_index(struct in_a
+ static void sort6_addresses(struct hostent *host, struct apattern *sortlist,
+ int nsort)
+ {
+- struct in6_addr a1, a2;
++ struct ares_in6_addr a1, a2;
+ int i1, i2, ind1, ind2;
+
+ /* This is a simple insertion sort, not optimized at all. i1 walks
+@@ -459,24 +459,24 @@ static void sort6_addresses(struct hoste
+ */
+ for (i1 = 0; host->h_addr_list[i1]; i1++)
+ {
+- memcpy(&a1, host->h_addr_list[i1], sizeof(struct in6_addr));
++ memcpy(&a1, host->h_addr_list[i1], sizeof(struct ares_in6_addr));
+ ind1 = get6_address_index(&a1, sortlist, nsort);
+ for (i2 = i1 - 1; i2 >= 0; i2--)
+ {
+- memcpy(&a2, host->h_addr_list[i2], sizeof(struct in6_addr));
++ memcpy(&a2, host->h_addr_list[i2], sizeof(struct ares_in6_addr));
+ ind2 = get6_address_index(&a2, sortlist, nsort);
+ if (ind2 <= ind1)
+ break;
+- memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct in6_addr));
++ memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct ares_in6_addr));
+ }
+- memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct in6_addr));
++ memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct ares_in6_addr));
+ }
+ }
+
+ /* Find the first entry in sortlist which matches addr. Return nsort
+ * if none of them match.
+ */
+-static int get6_address_index(struct in6_addr *addr, struct apattern *sortlist,
++static int get6_address_index(struct ares_in6_addr *addr, struct apattern *sortlist,
+ int nsort)
+ {
+ int i;
+@@ -485,7 +485,9 @@ static int get6_address_index(struct in6
+ {
+ if (sortlist[i].family != AF_INET6)
+ continue;
+- if (!ares_bitncmp(&addr->s6_addr, &sortlist[i].addrV6.s6_addr, sortlist[i].mask.bits))
++ if (!ares_bitncmp(addr,
++ &sortlist[i].addrV6,
++ sortlist[i].mask.bits))
+ break;
+ }
+ return i;
+diff -up ./ares_getnameinfo.c.ipv6 ./ares_getnameinfo.c
+--- ./ares_getnameinfo.c.ipv6 2008-12-01 15:20:41.000000000 +0100
++++ ./ares_getnameinfo.c 2010-08-06 10:50:39.000000000 +0200
+@@ -78,9 +78,11 @@ struct nameinfo_query {
+ };
+
+ #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+-#define IPBUFSIZ 40+IF_NAMESIZE
++#define IPBUFSIZ \
++ (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + IF_NAMESIZE)
+ #else
+-#define IPBUFSIZ 40
++#define IPBUFSIZ \
++ (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"))
+ #endif
+
+ static void nameinfo_callback(void *arg, int status, int timeouts, struct hostent *host);
+@@ -188,14 +190,16 @@ void ares_getnameinfo(ares_channel chann
+ {
+ niquery->family = AF_INET;
+ memcpy(&niquery->addr.addr4, addr, sizeof(addr));
+- ares_gethostbyaddr(channel, &addr->sin_addr, sizeof(struct in_addr), AF_INET,
++ ares_gethostbyaddr(channel, &addr->sin_addr,
++ sizeof(struct in_addr), AF_INET,
+ nameinfo_callback, niquery);
+ }
+ else
+ {
+ niquery->family = AF_INET6;
+ memcpy(&niquery->addr.addr6, addr6, sizeof(addr6));
+- ares_gethostbyaddr(channel, &addr6->sin6_addr, sizeof(struct in6_addr), AF_INET6,
++ ares_gethostbyaddr(channel, &addr6->sin6_addr,
++ sizeof(struct ares_in6_addr), AF_INET6,
+ nameinfo_callback, niquery);
+ }
+ }
+diff -up ./ares.h.ipv6 ./ares.h
+--- ./ares.h.ipv6 2008-12-04 13:53:03.000000000 +0100
++++ ./ares.h 2010-08-06 10:50:39.000000000 +0200
+@@ -90,6 +90,9 @@ extern "C" {
+ #define ARES_ENONAME 19
+ #define ARES_EBADHINTS 20
+
++/* Uninitialized library error code */
++#define ARES_ENOTINITIALIZED 21 /* backported from 1.7.0 */
++
+ /* Flag values */
+ #define ARES_FLAG_USEVC (1 << 0)
+ #define ARES_FLAG_PRIMARY (1 << 1)
+@@ -312,8 +315,30 @@ int ares_parse_ns_reply(const unsigned c
+ struct hostent **host);
+ void ares_free_string(void *str);
+ void ares_free_hostent(struct hostent *host);
++void ares_free_data(void *dataptr);
+ const char *ares_strerror(int code);
+
++struct ares_in6_addr {
++ union {
++ unsigned char _S6_u8[16];
++ } _S6_un;
++};
++
++struct ares_addr_node {
++ struct ares_addr_node *next;
++ int family;
++ union {
++ struct in_addr addr4;
++ struct ares_in6_addr addr6;
++ } addr;
++};
++
++int ares_set_servers(ares_channel channel,
++ struct ares_addr_node *servers);
++
++int ares_get_servers(ares_channel channel,
++ struct ares_addr_node **servers);
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff -up ./ares_init.3.ipv6 ./ares_init.3
+--- ./ares_init.3.ipv6 2010-08-06 10:50:39.000000000 +0200
++++ ./ares_init.3 2010-08-06 10:50:39.000000000 +0200
+@@ -93,8 +93,11 @@ service port.
+ .br
+ .B int \fInservers\fP;
+ .br
+-The list of servers to contact, instead of the servers specified in
+-resolv.conf or the local named.
++The list of IPv4 servers to contact, instead of the servers specified in
++resolv.conf or the local named. In order to allow specification of either
++IPv4 or IPv6 name servers, function
++.BR ares_set_servers(3)
++must be used instead.
+ .TP 18
+ .B ARES_OPT_DOMAINS
+ .B char **\fIdomains\fP;
+@@ -208,6 +211,7 @@ manual page.
+ .SH SEE ALSO
+ .BR ares_destroy(3),
+ .BR ares_dup(3)
++.BR ares_set_servers(3)
+ .SH AUTHOR
+ Greg Hudson, MIT Information Systems
+ .br
+diff -up ./ares_init.c.ipv6 ./ares_init.c
+--- ./ares_init.c.ipv6 2010-08-06 10:50:39.000000000 +0200
++++ ./ares_init.c 2010-08-06 10:52:59.000000000 +0200
+@@ -62,6 +62,7 @@
+
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <stddef.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <time.h>
+@@ -105,6 +106,72 @@ static char *try_config(char *s, const c
+ x->ndots > -1 && x->timeout > -1 && \
+ x->tries > -1)
+
++void ares_free_data(void *dataptr)
++{
++ struct ares_data *ptr;
++
++ if (!dataptr)
++ return;
++
++ ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data));
++
++ if (ptr->mark != ARES_DATATYPE_MARK)
++ return;
++
++ switch (ptr->type)
++ {
++ case ARES_DATATYPE_ADDR_NODE:
++
++ if (ptr->data.addr_node.next)
++ ares_free_data(ptr->data.addr_node.next);
++ break;
++
++ default:
++ return;
++ }
++
++ free(ptr);
++}
++
++void *ares_malloc_data(ares_datatype type)
++{
++ struct ares_data *ptr;
++
++ ptr = malloc(sizeof(struct ares_data));
++ if (!ptr)
++ return NULL;
++
++ switch (type)
++ {
++ case ARES_DATATYPE_ADDR_NODE:
++ ptr->data.addr_node.next = NULL;
++ ptr->data.addr_node.family = 0;
++ memset(&ptr->data.addr_node.addrV6, 0,
++ sizeof(ptr->data.addr_node.addrV6));
++
++ default:
++ free(ptr);
++ return NULL;
++ }
++
++ ptr->mark = ARES_DATATYPE_MARK;
++ ptr->type = type;
++
++ return &ptr->data;
++}
++
++ares_datatype ares_get_datatype(void * dataptr)
++{
++ struct ares_data *ptr;
++
++ ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data));
++
++ if (ptr->mark == ARES_DATATYPE_MARK)
++ return ptr->type;
++
++ return ARES_DATATYPE_UNKNOWN;
++}
++
+ int ares_init(ares_channel *channelptr)
+ {
+ return ares_init_options(channelptr, NULL, 0);
+@@ -116,7 +183,6 @@ int ares_init_options(ares_channel *chan
+ ares_channel channel;
+ int i;
+ int status = ARES_SUCCESS;
+- struct server_state *server;
+ struct timeval now;
+
+ #ifdef CURLDEBUG
+@@ -239,21 +305,7 @@ int ares_init_options(ares_channel *chan
+ if ((channel->flags & ARES_FLAG_PRIMARY) && channel->nservers > 1)
+ channel->nservers = 1;
+
+- /* Initialize server states. */
+- for (i = 0; i < channel->nservers; i++)
+- {
+- server = &channel->servers[i];
+- server->udp_socket = ARES_SOCKET_BAD;
+- server->tcp_socket = ARES_SOCKET_BAD;
+- server->tcp_connection_generation = ++channel->tcp_connection_generation;
+- server->tcp_lenbuf_pos = 0;
+- server->tcp_buffer = NULL;
+- server->qhead = NULL;
+- server->qtail = NULL;
+- ares__init_list_head(&(server->queries_to_server));
+- server->channel = channel;
+- server->is_broken = 0;
+- }
++ ares__init_servers_state(channel);
+
+ *channelptr = channel;
+ return ARES_SUCCESS;
+@@ -264,7 +316,9 @@ int ares_init_options(ares_channel *chan
+ int ares_dup(ares_channel *dest, ares_channel src)
+ {
+ struct ares_options opts;
+- int rc;
++ struct ares_addr_node *servers;
++ int ipv6_nservers = 0;
++ int i, rc;
+ int optmask;
+
+ *dest = NULL; /* in case of failure return NULL explicitly */
+@@ -288,16 +342,33 @@ int ares_dup(ares_channel *dest, ares_ch
+ (*dest)->sock_create_cb = src->sock_create_cb;
+ (*dest)->sock_create_cb_data = src->sock_create_cb_data;
+
++ /* Full name server cloning required when not all are IPv4 */
++ for (i = 0; i < src->nservers; i++)
++ {
++ if (src->servers[i].addr.family != AF_INET) {
++ ipv6_nservers++;
++ break;
++ }
++ }
++ if (ipv6_nservers) {
++ rc = ares_get_servers(src, &servers);
++ if (rc != ARES_SUCCESS)
++ return rc;
++ rc = ares_set_servers(*dest, servers);
++ ares_free_data(servers);
++ if (rc != ARES_SUCCESS)
++ return rc;
++ }
+
+ return ARES_SUCCESS; /* everything went fine */
+-
+ }
+
+ /* Save options from initialized channel */
+ int ares_save_options(ares_channel channel, struct ares_options *options,
+ int *optmask)
+ {
+- int i;
++ int i, j;
++ int ipv4_nservers = 0;
+
+ /* Zero everything out */
+ memset(options, 0, sizeof(struct ares_options));
+@@ -327,16 +398,27 @@ int ares_save_options(ares_channel chann
+ options->sock_state_cb = channel->sock_state_cb;
+ options->sock_state_cb_data = channel->sock_state_cb_data;
+
+- /* Copy servers */
++ /* Copy IPv4 servers */
+ if (channel->nservers) {
+- options->servers =
+- malloc(channel->nservers * sizeof(struct server_state));
+- if (!options->servers && channel->nservers != 0)
+- return ARES_ENOMEM;
+ for (i = 0; i < channel->nservers; i++)
+- options->servers[i] = channel->servers[i].addr;
++ {
++ if (channel->servers[i].addr.family == AF_INET)
++ ipv4_nservers++;
++ }
++ if (ipv4_nservers) {
++ options->servers = malloc(ipv4_nservers * sizeof(struct server_state));
++ if (!options->servers)
++ return ARES_ENOMEM;
++ for (i = j = 0; i < channel->nservers; i++)
++ {
++ if (channel->servers[i].addr.family == AF_INET)
++ memcpy(&options->servers[j++],
++ &channel->servers[i].addr.addrV4,
++ sizeof(channel->servers[i].addr.addrV4));
++ }
++ }
+ }
+- options->nservers = channel->nservers;
++ options->nservers = ipv4_nservers;
+
+ /* copy domains */
+ if (channel->ndomains) {
+@@ -412,7 +494,7 @@ static int init_by_options(ares_channel
+ && channel->socket_receive_buffer_size == -1)
+ channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
+
+- /* Copy the servers, if given. */
++ /* Copy the IPv4 servers, if given. */
+ if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
+ {
+ /* Avoid zero size allocations at any cost */
+@@ -423,7 +505,12 @@ static int init_by_options(ares_channel
+ if (!channel->servers)
+ return ARES_ENOMEM;
+ for (i = 0; i < options->nservers; i++)
+- channel->servers[i].addr = options->servers[i];
++ {
++ channel->servers[i].addr.family = AF_INET;
++ memcpy(&channel->servers[i].addr.addrV4,
++ &options->servers[i],
++ sizeof(channel->servers[i].addr.addrV4));
++ }
+ }
+ channel->nservers = options->nservers;
+ }
+@@ -993,7 +1080,8 @@ static int init_by_defaults(ares_channel
+ rc = ARES_ENOMEM;
+ goto error;
+ }
+- channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
++ channel->servers[0].addr.family = AF_INET;
++ channel->servers[0].addr.addrV4.s_addr = htonl(INADDR_LOOPBACK);
+ channel->nservers = 1;
+ }
+
+@@ -1133,61 +1221,62 @@ static int config_lookup(ares_channel ch
+ static int config_nameserver(struct server_state **servers, int *nservers,
+ char *str)
+ {
+- struct in_addr addr;
++ struct ares_addr host;
+ struct server_state *newserv;
++ char *p, *txtaddr;
+ /* On Windows, there may be more than one nameserver specified in the same
+- * registry key, so we parse it as a space or comma seperated list.
++ * registry key, so we parse input as a space or comma seperated list.
+ */
+-#ifdef WIN32
+- char *p = str;
+- char *begin = str;
+- int more = 1;
+- while (more)
+- {
+- more = 0;
+- while (*p && !ISSPACE(*p) && *p != ',')
+- p++;
+-
+- if (*p)
++ for (p = str; p;)
+ {
+- *p = '\0';
+- more = 1;
+- }
++ /* Skip whitespace and commas. */
++ while (*p && (ISSPACE(*p) || (*p == ',')))
++ p++;
++ if (!*p)
++ /* No more input, done. */
++ break;
+
+- /* Skip multiple spaces or trailing spaces */
+- if (!*begin)
+- {
+- begin = ++p;
+- continue;
++ /* Pointer to start of IPv4 or IPv6 address part. */
++ txtaddr = p;
++
++ /* Advance past this address. */
++ while (*p && !ISSPACE(*p) && (*p != ','))
++ p++;
++ if (*p)
++ /* Null terminate this address. */
++ *p++ = '\0';
++ else
++ /* Reached end of input, done when this address is processed. */
++ p = NULL;
++
++ /* Convert textual address to binary format. */
++ if (ares_inet_pton(AF_INET, txtaddr, &host.addrV4) == 1)
++ host.family = AF_INET;
++ else if (ares_inet_pton(AF_INET6, txtaddr, &host.addrV6) == 1)
++ host.family = AF_INET6;
++ else
++ continue;
++
++ /* Resize servers state array. */
++ newserv = realloc(*servers, (*nservers + 1) *
++ sizeof(struct server_state));
++ if (!newserv)
++ return ARES_ENOMEM;
++
++ /* Store address data. */
++ newserv[*nservers].addr.family = host.family;
++ if (host.family == AF_INET)
++ memcpy(&newserv[*nservers].addr.addrV4, &host.addrV4,
++ sizeof(host.addrV4));
++ else
++ memcpy(&newserv[*nservers].addr.addrV6, &host.addrV6,
++ sizeof(host.addrV6));
++
++ /* Update arguments. */
++ *servers = newserv;
++ *nservers += 1;
+ }
+
+- /* This is the part that actually sets the nameserver */
+- addr.s_addr = inet_addr(begin);
+- if (addr.s_addr == INADDR_NONE)
+- continue;
+- newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
+- if (!newserv)
+- return ARES_ENOMEM;
+- newserv[*nservers].addr = addr;
+- *servers = newserv;
+- (*nservers)++;
+-
+- if (!more)
+- break;
+- begin = ++p;
+- }
+-#else
+- /* Add a nameserver entry, if this is a valid address. */
+- addr.s_addr = inet_addr(str);
+- if (addr.s_addr == INADDR_NONE)
+- return ARES_SUCCESS;
+- newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
+- if (!newserv)
+- return ARES_ENOMEM;
+- newserv[*nservers].addr = addr;
+- *servers = newserv;
+- (*nservers)++;
+-#endif
+ return ARES_SUCCESS;
+ }
+
+@@ -1562,3 +1651,126 @@ void ares_set_socket_callback(ares_chann
+ channel->sock_create_cb = cb;
+ channel->sock_create_cb_data = data;
+ }
++
++void ares__init_servers_state(ares_channel channel)
++{
++ struct server_state *server;
++ int i;
++
++ for (i = 0; i < channel->nservers; i++)
++ {
++ server = &channel->servers[i];
++ server->udp_socket = ARES_SOCKET_BAD;
++ server->tcp_socket = ARES_SOCKET_BAD;
++ server->tcp_connection_generation = ++channel->tcp_connection_generation;
++ server->tcp_lenbuf_pos = 0;
++ server->tcp_buffer_pos = 0;
++ server->tcp_buffer = NULL;
++ server->tcp_length = 0;
++ server->qhead = NULL;
++ server->qtail = NULL;
++ ares__init_list_head(&server->queries_to_server);
++ server->channel = channel;
++ server->is_broken = 0;
++ }
++}
++
++int ares_get_servers(ares_channel channel,
++ struct ares_addr_node **servers)
++{
++ struct ares_addr_node *srvr_head = NULL;
++ struct ares_addr_node *srvr_last = NULL;
++ struct ares_addr_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_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;
++ 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)
++{
++ struct ares_addr_node *srvr;
++ int num_srvrs = 0;
++ int i;
++
++ 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 = 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;
++ 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;
++}
+diff -up ./ares_ipv6.h.ipv6 ./ares_ipv6.h
+--- ./ares_ipv6.h.ipv6 2007-12-10 22:19:28.000000000 +0100
++++ ./ares_ipv6.h 2010-08-06 10:50:39.000000000 +0200
+@@ -18,29 +18,22 @@
+ #ifndef ARES_IPV6_H
+ #define ARES_IPV6_H
+
++#if 0
+ #ifndef HAVE_PF_INET6
+ #define PF_INET6 AF_INET6
+ #endif
+
+-#if !defined(HAVE_STRUCT_IN6_ADDR) && !defined(s6_addr)
+-struct in6_addr {
+- union {
+- unsigned char _S6_u8[16];
+- } _S6_un;
+-};
+-#define s6_addr _S6_un._S6_u8
+-#endif
+-
+ #ifndef HAVE_STRUCT_SOCKADDR_IN6
+ struct sockaddr_in6
+ {
+- unsigned short sin6_family;
+- unsigned short sin6_port;
+- unsigned long sin6_flowinfo;
+- struct in6_addr sin6_addr;
+- unsigned int sin6_scope_id;
++ unsigned short sin6_family;
++ unsigned short sin6_port;
++ unsigned long sin6_flowinfo;
++ struct ares_in6_addr sin6_addr;
++ unsigned int sin6_scope_id;
+ };
+ #endif
++#endif
+
+ #ifndef HAVE_STRUCT_ADDRINFO
+ struct addrinfo
+diff -up ./ares_parse_aaaa_reply.c.ipv6 ./ares_parse_aaaa_reply.c
+--- ./ares_parse_aaaa_reply.c.ipv6 2008-09-18 14:42:18.000000000 +0200
++++ ./ares_parse_aaaa_reply.c 2010-08-06 10:50:39.000000000 +0200
+@@ -61,7 +61,7 @@ int ares_parse_aaaa_reply(const unsigned
+ long len;
+ const unsigned char *aptr;
+ char *hostname, *rr_name, *rr_data, **aliases;
+- struct in6_addr *addrs;
++ struct ares_in6_addr *addrs;
+ struct hostent *hostent;
+ const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0;
+
+@@ -97,7 +97,7 @@ int ares_parse_aaaa_reply(const unsigned
+ /* Allocate addresses and aliases; ancount gives an upper bound for both. */
+ if (host)
+ {
+- addrs = malloc(ancount * sizeof(struct in6_addr));
++ addrs = malloc(ancount * sizeof(struct ares_in6_addr));
+ if (!addrs)
+ {
+ free(hostname);
+@@ -139,27 +139,27 @@ int ares_parse_aaaa_reply(const unsigned
+ aptr += RRFIXEDSZ;
+
+ if (rr_class == C_IN && rr_type == T_AAAA
+- && rr_len == sizeof(struct in6_addr)
++ && rr_len == sizeof(struct ares_in6_addr)
+ && strcasecmp(rr_name, hostname) == 0)
+ {
+ if (addrs)
+ {
+- if (aptr + sizeof(struct in6_addr) > abuf + alen)
++ if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
+- memcpy(&addrs[naddrs], aptr, sizeof(struct in6_addr));
++ memcpy(&addrs[naddrs], aptr, sizeof(struct ares_in6_addr));
+ }
+ if (naddrs < max_addr_ttls)
+ {
+ struct addr6ttl * const at = &addrttls[naddrs];
+- if (aptr + sizeof(struct in6_addr) > abuf + alen)
++ if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
+- memcpy(&at->ip6addr, aptr, sizeof(struct in6_addr));
++ memcpy(&at->ip6addr, aptr, sizeof(struct ares_in6_addr));
+ at->ttl = rr_ttl;
+ }
+ naddrs++;
+@@ -228,7 +228,7 @@ int ares_parse_aaaa_reply(const unsigned
+ hostent->h_name = hostname;
+ hostent->h_aliases = aliases;
+ hostent->h_addrtype = AF_INET6;
+- hostent->h_length = sizeof(struct in6_addr);
++ hostent->h_length = sizeof(struct ares_in6_addr);
+ for (i = 0; i < naddrs; i++)
+ hostent->h_addr_list[i] = (char *) &addrs[i];
+ hostent->h_addr_list[naddrs] = NULL;
+diff -up ./ares_private.h.ipv6 ./ares_private.h
+--- ./ares_private.h.ipv6 2008-12-04 13:53:03.000000000 +0100
++++ ./ares_private.h 2010-08-06 10:50:39.000000000 +0200
+@@ -95,10 +95,12 @@
+ #include "ares_ipv6.h"
+ #include "ares_llist.h"
+
++#if 0
+ #ifndef HAVE_STRDUP
+ # include "ares_strdup.h"
+ # define strdup(ptr) ares_strdup(ptr)
+ #endif
++#endif
+
+ #ifndef HAVE_STRCASECMP
+ # include "ares_strcasecmp.h"
+@@ -118,8 +120,8 @@
+ struct ares_addr {
+ int family;
+ union {
+- struct in_addr addr4;
+- struct in6_addr addr6;
++ struct in_addr addr4;
++ struct ares_in6_addr addr6;
+ } addr;
+ };
+ #define addrV4 addr.addr4
+@@ -142,7 +144,7 @@ struct send_request {
+ };
+
+ struct server_state {
+- struct in_addr addr;
++ struct ares_addr addr;
+ ares_socket_t udp_socket;
+ ares_socket_t tcp_socket;
+
+@@ -226,14 +228,14 @@ struct query_server_info {
+ struct apattern {
+ union
+ {
+- struct in_addr addr4;
+- struct in6_addr addr6;
++ struct in_addr addr4;
++ struct ares_in6_addr addr6;
+ } addr;
+ union
+ {
+- struct in_addr addr4;
+- struct in6_addr addr6;
+- unsigned short bits;
++ struct in_addr addr4;
++ struct ares_in6_addr addr6;
++ unsigned short bits;
+ } mask;
+ int family;
+ unsigned short type;
+@@ -319,10 +321,31 @@ int ares__read_line(FILE *fp, char **buf
+ void ares__free_query(struct query *query);
+ unsigned short ares__generate_new_id(rc4_key* key);
+ struct timeval ares__tvnow(void);
++void ares__init_servers_state(ares_channel channel);
++void ares__destroy_servers_state(ares_channel channel);
+ #if 0 /* Not used */
+ long ares__tvdiff(struct timeval t1, struct timeval t2);
+ #endif
+
++typedef enum {
++ ARES_DATATYPE_UNKNOWN = 1,
++ ARES_DATATYPE_ADDR_NODE,
++ ARES_DATATYPE_LAST /* not used - introduced in 1.7.0 */
++} ares_datatype;
++
++struct ares_data {
++ ares_datatype type; /* Actual data type identifier. */
++ unsigned int mark; /* Private ares_data signature. */
++ union {
++ struct ares_addr_node addr_node;
++ } data;
++};
++
++void *ares_malloc_data(ares_datatype type);
++
++ares_datatype ares_get_datatype(void * dataptr);
++#define ARES_DATATYPE_MARK 0xbead
++
+ #define ARES_SWAP_BYTE(a,b) \
+ { unsigned char swapByte = *(a); *(a) = *(b); *(b) = swapByte; }
+
+diff -up ./ares_process.c.ipv6 ./ares_process.c
+--- ./ares_process.c.ipv6 2008-12-04 13:53:03.000000000 +0100
++++ ./ares_process.c 2010-08-06 10:50:39.000000000 +0200
+@@ -97,6 +97,7 @@ static int open_tcp_socket(ares_channel
+ static int open_udp_socket(ares_channel channel, struct server_state *server);
+ static int same_questions(const unsigned char *qbuf, int qlen,
+ const unsigned char *abuf, int alen);
++static int same_address(struct sockaddr *sa, struct ares_addr *aa);
+ static void end_query(ares_channel channel, struct query *query, int status,
+ unsigned char *abuf, int alen);
+
+@@ -428,8 +429,11 @@ static void read_udp_packets(ares_channe
+ ssize_t count;
+ unsigned char buf[PACKETSZ + 1];
+ #ifdef HAVE_RECVFROM
+- struct sockaddr_in from;
+ socklen_t fromlen;
++ union {
++ struct sockaddr_in sa4;
++ struct sockaddr_in6 sa6;
++ } from;
+ #endif
+
+ if(!read_fds && (read_fd == ARES_SOCKET_BAD))
+@@ -465,7 +469,10 @@ static void read_udp_packets(ares_channe
+ * packets as we can. */
+ do {
+ #ifdef HAVE_RECVFROM
+- fromlen = sizeof(from);
++ 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, (struct sockaddr *)&from, &fromlen);
+ #else
+@@ -476,10 +483,10 @@ static void read_udp_packets(ares_channe
+ else if (count <= 0)
+ handle_error(channel, i, now);
+ #ifdef HAVE_RECVFROM
+- else if (from.sin_addr.s_addr != server->addr.s_addr)
+- /* Address response came from did not match the address
+- * we sent the request to. Someone may be attempting
+- * to perform a cache poisoning attack */
++ else if (!same_address((struct sockaddr *)&from, &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. */
+ break;
+ #endif
+ else
+@@ -883,10 +890,39 @@ static int open_tcp_socket(ares_channel
+ {
+ ares_socket_t s;
+ int opt;
+- struct sockaddr_in sockin;
++ socklen_t salen;
++ union {
++ struct sockaddr_in sa4;
++ struct sockaddr_in6 sa6;
++ } saddr;
++ struct sockaddr *sa;
++
++ switch (server->addr.family)
++ {
++ case AF_INET:
++ sa = (void *)&saddr.sa4;
++ salen = sizeof(saddr.sa4);
++ memset(sa, 0, salen);
++ saddr.sa4.sin_family = AF_INET;
++ saddr.sa4.sin_port = (unsigned short)(channel->tcp_port & 0xffff);
++ memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
++ sizeof(server->addr.addrV4));
++ break;
++ case AF_INET6:
++ sa = (void *)&saddr.sa6;
++ salen = sizeof(saddr.sa6);
++ memset(sa, 0, salen);
++ saddr.sa6.sin6_family = AF_INET6;
++ saddr.sa6.sin6_port = (unsigned short)(channel->tcp_port & 0xffff);
++ memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
++ sizeof(server->addr.addrV6));
++ break;
++ default:
++ return -1;
++ }
+
+ /* Acquire a socket. */
+- s = socket(AF_INET, SOCK_STREAM, 0);
++ s = socket(server->addr.family, SOCK_STREAM, 0);
+ if (s == ARES_SOCKET_BAD)
+ return -1;
+
+@@ -914,11 +950,7 @@ static int open_tcp_socket(ares_channel
+ #endif
+
+ /* Connect to the server. */
+- memset(&sockin, 0, sizeof(sockin));
+- sockin.sin_family = AF_INET;
+- sockin.sin_addr = server->addr;
+- sockin.sin_port = (unsigned short)(channel->tcp_port & 0xffff);
+- if (connect(s, (struct sockaddr *) &sockin, sizeof(sockin)) == -1)
++ if (connect(s, sa, salen) == -1)
+ {
+ int err = SOCKERRNO;
+
+@@ -950,10 +982,39 @@ static int open_tcp_socket(ares_channel
+ static int open_udp_socket(ares_channel channel, struct server_state *server)
+ {
+ ares_socket_t s;
+- struct sockaddr_in sockin;
++ socklen_t salen;
++ union {
++ struct sockaddr_in sa4;
++ struct sockaddr_in6 sa6;
++ } saddr;
++ struct sockaddr *sa;
++
++ switch (server->addr.family)
++ {
++ case AF_INET:
++ sa = (void *)&saddr.sa4;
++ salen = sizeof(saddr.sa4);
++ memset(sa, 0, salen);
++ saddr.sa4.sin_family = AF_INET;
++ saddr.sa4.sin_port = (unsigned short)(channel->udp_port & 0xffff);
++ memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
++ sizeof(server->addr.addrV4));
++ break;
++ case AF_INET6:
++ sa = (void *)&saddr.sa6;
++ salen = sizeof(saddr.sa6);
++ memset(sa, 0, salen);
++ saddr.sa6.sin6_family = AF_INET6;
++ saddr.sa6.sin6_port = (unsigned short)(channel->udp_port & 0xffff);
++ memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
++ sizeof(server->addr.addrV6));
++ break;
++ default:
++ return -1;
++ }
+
+ /* Acquire a socket. */
+- s = socket(AF_INET, SOCK_DGRAM, 0);
++ s = socket(server->addr.family, SOCK_DGRAM, 0);
+ if (s == ARES_SOCKET_BAD)
+ return -1;
+
+@@ -965,11 +1026,7 @@ static int open_udp_socket(ares_channel
+ }
+
+ /* Connect to the server. */
+- memset(&sockin, 0, sizeof(sockin));
+- sockin.sin_family = AF_INET;
+- sockin.sin_addr = server->addr;
+- sockin.sin_port = (unsigned short)(channel->udp_port & 0xffff);
+- if (connect(s, (struct sockaddr *) &sockin, sizeof(sockin)) == -1)
++ if (connect(s, sa, salen) == -1)
+ {
+ int err = SOCKERRNO;
+
+@@ -1076,6 +1133,34 @@ static int same_questions(const unsigned
+ return 1;
+ }
+
++static int same_address(struct sockaddr *sa, struct ares_addr *aa)
++{
++ void *addr1;
++ void *addr2;
++
++ if (sa->sa_family == aa->family)
++ {
++ switch (aa->family)
++ {
++ case AF_INET:
++ addr1 = &aa->addrV4;
++ addr2 = &((struct sockaddr_in *)sa)->sin_addr;
++ if (memcmp(addr1, addr2, sizeof(aa->addrV4)) == 0)
++ return 1; /* match */
++ break;
++ case AF_INET6:
++ addr1 = &aa->addrV6;
++ addr2 = &((struct sockaddr_in6 *)sa)->sin6_addr;
++ if (memcmp(addr1, addr2, sizeof(aa->addrV6)) == 0)
++ return 1; /* match */
++ break;
++ default:
++ break;
++ }
++ }
++ return 0; /* different */
++}
++
+ static void end_query (ares_channel channel, struct query *query, int status,
+ unsigned char *abuf, int alen)
+ {
+diff -up ./ares_save_options.3.ipv6 ./ares_save_options.3
+--- ./ares_save_options.3.ipv6 2008-12-03 10:59:50.000000000 +0100
++++ ./ares_save_options.3 2010-08-06 10:50:39.000000000 +0200
+@@ -14,7 +14,7 @@
+ .\" this software for any purpose. It is provided "as is"
+ .\" without express or implied warranty.
+ .\"
+-.TH ARES_SAVE_OPTIONS 3 "1 June 2007"
++.TH ARES_SAVE_OPTIONS 3 "5 March 2010"
+ .SH NAME
+ ares_save_options \- Save configuration values obtained from initialized ares_channel
+ .SH SYNOPSIS
+@@ -38,13 +38,20 @@ are no longer needed, ares_destroy_optio
+ to free any associated memory.
+ .SH NOTE
+ Since c-ares 1.6.0 the ares_options struct has been "locked" meaning that it
+-won't be extended to cover new funtions. This function will remain
++won't be extended to cover new functions. This function will remain
+ functioning, but it can only return config data that can be represented in
+ this config struct, which may no longer be the complete set of config
+ options. \fBares_dup(3)\fP will not have that restriction.
++
++The ares_options struct can not handle potential IPv6 name servers the
++ares_channel might be configured to use. Function \fBares_save_options(3)\fP
++will only return IPv4 servers if any. In order to retrieve all name servers
++an ares_channel might be using, function \fBares_get_servers(3)\fP must be
++used instead.
+ .SH SEE ALSO
+ .BR ares_destroy_options (3),
+ .BR ares_init_options (3),
++.BR ares_get_servers (3),
+ .BR ares_dup (3)
+ .SH AVAILABILITY
+ ares_save_options(3) was added in c-ares 1.4.0
+diff -up ./inet_net_pton.c.ipv6 ./inet_net_pton.c
+--- ./inet_net_pton.c.ipv6 2008-09-25 09:31:14.000000000 +0200
++++ ./inet_net_pton.c 2010-08-06 10:50:39.000000000 +0200
+@@ -43,6 +43,7 @@
+ #include <string.h>
+ #include <stdlib.h>
+
++#include "ares.h"
+ #include "ares_ipv6.h"
+ #include "inet_net_pton.h"
+
+@@ -431,7 +432,7 @@ int ares_inet_pton(int af, const char *s
+ if (af == AF_INET)
+ size = sizeof(struct in_addr);
+ else if (af == AF_INET6)
+- size = sizeof(struct in6_addr);
++ size = sizeof(struct ares_in6_addr);
+ else
+ {
+ SET_ERRNO(EAFNOSUPPORT);
+diff -up ./inet_ntop.c.ipv6 ./inet_ntop.c
+--- ./inet_ntop.c.ipv6 2008-09-25 09:31:14.000000000 +0200
++++ ./inet_ntop.c 2010-08-06 10:50:39.000000000 +0200
+@@ -42,6 +42,7 @@
+ #include <string.h>
+ #include <stdlib.h>
+
++#include "ares.h"
+ #include "ares_ipv6.h"
+ #include "inet_ntop.h"
+
+diff -up ./Makefile.inc.ipv6 ./Makefile.inc
+--- ./Makefile.inc.ipv6 2008-12-04 13:53:19.000000000 +0100
++++ ./Makefile.inc 2010-08-06 10:50:39.000000000 +0200
+@@ -6,11 +6,12 @@ ares_timeout.c ares_destroy.c ares_mkque
+ ares_expand_name.c ares_parse_a_reply.c windows_port.c ares_strdup.c \
+ ares_expand_string.c ares_parse_ptr_reply.c ares_parse_aaaa_reply.c \
+ ares_getnameinfo.c inet_net_pton.c bitncmp.c inet_ntop.c ares_writev.c \
+-ares_parse_ns_reply.c ares_llist.c ares__timeval.c ares_strcasecmp.c
++ares_parse_ns_reply.c ares_llist.c ares__timeval.c ares_strcasecmp.c \
++ares_data.c
+
+ HHEADERS = ares.h ares_private.h setup.h ares_dns.h ares_version.h \
+ nameser.h inet_net_pton.h inet_ntop.h ares_ipv6.h bitncmp.h setup_once.h \
+- ares_llist.h ares_strdup.h ares_strcasecmp.h ares_writev.h
++ ares_llist.h ares_strdup.h ares_strcasecmp.h ares_writev.h ares_data.h
+
+ MANPAGES= ares_destroy.3 ares_expand_name.3 ares_expand_string.3 ares_fds.3 \
+ ares_free_hostent.3 ares_free_string.3 ares_gethostbyaddr.3 \
More information about the scm-commits
mailing list