[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