diff --git a/0001-Allow-the-use-of-IPv6-nameservers.patch b/0001-Allow-the-use-of-IPv6-nameservers.patch new file mode 100644 index 0000000..174b780 --- /dev/null +++ b/0001-Allow-the-use-of-IPv6-nameservers.patch @@ -0,0 +1,1659 @@ +From a9794547f61ccca1cdf71949f3f7183387300a7a Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Sun, 7 Mar 2010 18:37:47 +0100 +Subject: [PATCH] IPv6 nameserver patch + +--- + Makefile.inc | 6 + + adig.c | 103 +++++++++++++--- + ahost.c | 4 +- + ares.h | 19 +++- + ares__get_hostent.c | 12 +- + ares_data.c | 13 ++ + ares_data.h | 6 +- + ares_destroy.c | 35 ++++-- + ares_free_data.3 | 14 ++- + ares_gethostbyaddr.c | 20 ++-- + ares_gethostbyname.c | 24 ++-- + ares_getnameinfo.c | 14 ++- + ares_init.3 | 18 ++- + ares_init.c | 307 +++++++++++++++++++++++++++++++++++------------ + ares_ipv6.h | 21 +--- + ares_parse_aaaa_reply.c | 18 ++-- + ares_private.h | 22 ++-- + ares_process.c | 125 ++++++++++++++++--- + ares_save_options.3 | 13 ++- + inet_net_pton.c | 5 +- + inet_ntop.c | 3 +- + vc/cares/vc6cares.dsp | 4 + + 22 files changed, 590 insertions(+), 216 deletions(-) + +diff --git a/Makefile.inc b/Makefile.inc +index 3227858..365de6c 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -70,6 +70,7 @@ MANPAGES = ares_cancel.3 \ + ares_free_data.3 \ + ares_free_hostent.3 \ + ares_free_string.3 \ ++ ares_get_servers.3 \ + ares_gethostbyaddr.3 \ + ares_gethostbyname.3 \ + ares_gethostbyname_file.3 \ +@@ -91,6 +92,7 @@ MANPAGES = ares_cancel.3 \ + ares_save_options.3 \ + ares_search.3 \ + ares_send.3 \ ++ ares_set_servers.3 \ + ares_set_socket_callback.3 \ + ares_strerror.3 \ + ares_timeout.3 \ +@@ -106,6 +108,7 @@ HTMLPAGES = ares_cancel.html \ + ares_free_data.html \ + ares_free_hostent.html \ + ares_free_string.html \ ++ ares_get_servers.html \ + ares_gethostbyaddr.html \ + ares_gethostbyname.html \ + ares_gethostbyname_file.html \ +@@ -127,6 +130,7 @@ HTMLPAGES = ares_cancel.html \ + ares_save_options.html \ + ares_search.html \ + ares_send.html \ ++ ares_set_servers.html \ + ares_set_socket_callback.html \ + ares_strerror.html \ + ares_timeout.html \ +@@ -142,6 +146,7 @@ PDFPAGES = ares_cancel.pdf \ + ares_free_data.pdf \ + ares_free_hostent.pdf \ + ares_free_string.pdf \ ++ ares_get_servers.pdf \ + ares_gethostbyaddr.pdf \ + ares_gethostbyname.pdf \ + ares_gethostbyname_file.pdf \ +@@ -163,6 +168,7 @@ PDFPAGES = ares_cancel.pdf \ + ares_save_options.pdf \ + ares_search.pdf \ + ares_send.pdf \ ++ ares_set_servers.pdf \ + ares_set_socket_callback.pdf \ + ares_strerror.pdf \ + ares_timeout.pdf \ +diff --git a/adig.c b/adig.c +index 8897448..d827e0e 100644 +--- a/adig.c ++++ b/adig.c +@@ -1,6 +1,6 @@ + /* Copyright 1998 by the Massachusetts Institute of Technology. + * +- * $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ ++ * $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without +@@ -164,8 +164,6 @@ static const char *rcodes[] = { + "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE" + }; + +-static struct in_addr inaddr; +- + static void callback(void *arg, int status, int timeouts, + unsigned char *abuf, int alen); + static const unsigned char *display_question(const unsigned char *aptr, +@@ -176,6 +174,9 @@ static const unsigned char *display_rr(const unsigned char *aptr, + 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) + { +@@ -186,6 +187,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); +@@ -227,27 +229,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; + +@@ -308,6 +339,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 +@@ -749,3 +792,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 --git a/ahost.c b/ahost.c +index ebfa97f..5256186 100644 +--- a/ahost.c ++++ b/ahost.c +@@ -1,6 +1,6 @@ + /* Copyright 1998 by the Massachusetts Institute of Technology. + * +- * $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ ++ * $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without +@@ -69,7 +69,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 --git a/ares.h b/ares.h +index b1c2c22..fc333e5 100644 +--- a/ares.h ++++ b/ares.h +@@ -1,7 +1,7 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright 1998, 2009 by the Massachusetts Institute of Technology. +- * Copyright (C) 2007-2009 by Daniel Stenberg ++ * Copyright (C) 2007-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without +@@ -487,6 +487,21 @@ CARES_EXTERN void ares_free_data(void *dataptr); + + CARES_EXTERN const char *ares_strerror(int code); + ++struct ares_addr_node { ++ struct ares_addr_node *next; ++ int family; ++ union { ++ struct in_addr addr4; ++ struct ares_in6_addr addr6; ++ } addr; ++}; ++ ++CARES_EXTERN int ares_set_servers(ares_channel channel, ++ struct ares_addr_node *servers); ++ ++CARES_EXTERN int ares_get_servers(ares_channel channel, ++ struct ares_addr_node **servers); ++ + #ifdef __cplusplus + } + #endif +diff --git a/ares__get_hostent.c b/ares__get_hostent.c +index 335f763..5d4956b 100644 +--- a/ares__get_hostent.c ++++ b/ares__get_hostent.c +@@ -1,6 +1,6 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + +-/* Copyright 1998, 2009 by the Massachusetts Institute of Technology. ++/* Copyright 1998, 2010 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without +@@ -146,7 +146,7 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host) + { + /* Actual network address family and length. */ + addr.family = AF_INET; +- addrlen = sizeof(struct in_addr); ++ addrlen = sizeof(addr.addrV4); + } + } + if ((family == AF_INET6) || ((family == AF_UNSPEC) && (!addrlen))) +@@ -155,7 +155,7 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host) + { + /* Actual network address family and length. */ + addr.family = AF_INET6; +- addrlen = sizeof(struct in6_addr); ++ addrlen = sizeof(addr.addrV6); + } + } + if (!addrlen) +@@ -189,9 +189,9 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host) + if (!hostent->h_addr_list[0]) + break; + if (addr.family == AF_INET) +- memcpy(hostent->h_addr_list[0], &addr.addrV4, sizeof(struct in_addr)); ++ memcpy(hostent->h_addr_list[0], &addr.addrV4, sizeof(addr.addrV4)); + else +- memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(struct in6_addr)); ++ memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(addr.addrV6)); + + /* Copy aliases. */ + hostent->h_aliases = malloc((naliases + 1) * sizeof(char *)); +diff --git a/ares_data.c b/ares_data.c +index 1ad66a6..06d61c5 100644 +--- a/ares_data.c ++++ b/ares_data.c +@@ -34,6 +34,7 @@ + ** of c-ares functions returning pointers that must be free'ed using this + ** function is: + ** ++** ares_get_servers() + ** ares_parse_srv_reply() + ** ares_parse_txt_reply() + */ +@@ -68,6 +69,12 @@ void ares_free_data(void *dataptr) + free(ptr->data.txt_reply.txt); + break; + ++ case ARES_DATATYPE_ADDR_NODE: ++ ++ if (ptr->data.addr_node.next) ++ ares_free_data(ptr->data.addr_node.next); ++ break; ++ + default: + return; + } +@@ -111,6 +118,12 @@ void *ares_malloc_data(ares_datatype type) + ptr->data.txt_reply.length = 0; + break; + ++ 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; +diff --git a/ares_data.h b/ares_data.h +index 18794e3..4ed626b 100644 +--- a/ares_data.h ++++ b/ares_data.h +@@ -1,6 +1,6 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + +-/* Copyright (C) 2009 by Daniel Stenberg ++/* Copyright (C) 2009-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without +@@ -19,6 +19,7 @@ typedef enum { + ARES_DATATYPE_UNKNOWN = 1, /* unknown data type - introduced in 1.7.0 */ + ARES_DATATYPE_SRV_REPLY, /* struct ares_srv_reply - introduced in 1.7.0 */ + ARES_DATATYPE_TXT_REPLY, /* struct ares_txt_reply - introduced in 1.7.0 */ ++ ARES_DATATYPE_ADDR_NODE, /* struct ares_addr_node - introduced in 1.7.1 */ + #if 0 + ARES_DATATYPE_ADDR6TTL, /* struct ares_addrttl */ + ARES_DATATYPE_ADDRTTL, /* struct ares_addr6ttl */ +@@ -54,6 +55,7 @@ struct ares_data { + union { + struct ares_txt_reply txt_reply; + struct ares_srv_reply srv_reply; ++ struct ares_addr_node addr_node; + } data; + }; + +diff --git a/ares_destroy.c b/ares_destroy.c +index 0044a71..1fa0196 100644 +--- a/ares_destroy.c ++++ b/ares_destroy.c +@@ -1,6 +1,7 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright 1998 by the Massachusetts Institute of Technology. ++ * Copyright (C) 2004-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without +@@ -25,7 +26,8 @@ void ares_destroy_options(struct ares_options *options) + { + 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 +69,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 +85,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 --git a/ares_free_data.3 b/ares_free_data.3 +index f0655c6..633f0b1 100644 +--- a/ares_free_data.3 ++++ b/ares_free_data.3 +@@ -1,7 +1,7 @@ +-.\" $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ ++.\" $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ + .\" + .\" Copyright 1998 by the Massachusetts Institute of Technology. +-.\" Copyright (C) 2004-2009 by Daniel Stenberg ++.\" Copyright (C) 2004-2010 by Daniel Stenberg + .\" + .\" Permission to use, copy, modify, and distribute this + .\" software and its documentation for any purpose and without +@@ -15,7 +15,7 @@ + .\" this software for any purpose. It is provided "as is" + .\" without express or implied warranty. + .\" +-.TH ARES_FREE_DATA 3 "23 Nov 2009" ++.TH ARES_FREE_DATA 3 "5 March 2010" + .SH NAME + ares_free_data \- Free data allocated by several c-ares functions + .SH SYNOPSIS +@@ -34,6 +34,11 @@ function frees one or more data structures allocated and returned + by several c-ares functions. Specifically the data returned by the + following list of functions must be deallocated using this function. + .TP 5 ++.B ares_get_servers(3) ++When used to free the data returned by ares_get_servers(3) this ++will free the whole linked list of ares_addr_node structures returned ++by ares_get_servers(3). ++.TP + .B ares_parse_srv_reply(3) + When used to free the data returned by ares_parse_srv_reply(3) this + will free the whole linked list of ares_srv_reply structures returned +@@ -50,6 +55,7 @@ The ares_free_data() function does not return a value. + .SH AVAILABILITY + This function was first introduced in c-ares version 1.7.0. + .SH SEE ALSO ++.BR ares_get_servers(3), + .BR ares_parse_srv_reply(3), + .BR ares_parse_txt_reply(3) + .SH AUTHOR +@@ -57,4 +63,4 @@ Yang Tse + .PP + Copyright 1998 by the Massachusetts Institute of Technology. + .br +-Copyright (C) 2004-2009 by Daniel Stenberg. ++Copyright (C) 2004-2010 by Daniel Stenberg. +diff --git a/ares_gethostbyaddr.c b/ares_gethostbyaddr.c +index 732a031..25dc8cb 100644 +--- a/ares_gethostbyaddr.c ++++ b/ares_gethostbyaddr.c +@@ -1,4 +1,4 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright 1998 by the Massachusetts Institute of Technology. + * +@@ -79,8 +79,8 @@ void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen, + 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 channel, const void *addr, int addrlen, + } + 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; +@@ -152,13 +152,13 @@ static void addr_callback(void *arg, int status, int timeouts, + { + if (aquery->addr.family == AF_INET) + { +- addrlen = sizeof(struct in_addr); ++ addrlen = sizeof(aquery->addr.addrV4); + status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV4, + (int)addrlen, AF_INET, &host); + } + else + { +- addrlen = sizeof(struct in6_addr); ++ addrlen = sizeof(aquery->addr.addrV6); + status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV6, + (int)addrlen, AF_INET6, &host); + } +@@ -241,12 +241,12 @@ static int file_lookup(struct ares_addr *addr, struct hostent **host) + } + 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); +@@ -272,7 +272,7 @@ static void ptr_rr_name(char *name, const struct ares_addr *addr) + } + 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 --git a/ares_gethostbyname.c b/ares_gethostbyname.c +index fc66c6f..7d0f8c6 100644 +--- a/ares_gethostbyname.c ++++ b/ares_gethostbyname.c +@@ -1,4 +1,4 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright 1998 by the Massachusetts Institute of Technology. + * +@@ -81,7 +81,7 @@ static void sort6_addresses(struct hostent *host, + const struct apattern *sortlist, int nsort); + static int get_address_index(const struct in_addr *addr, + const struct apattern *sortlist, int nsort); +-static int get6_address_index(const struct in6_addr *addr, ++static int get6_address_index(const struct ares_in6_addr *addr, + const struct apattern *sortlist, int nsort); + + void ares_gethostbyname(ares_channel channel, const char *name, int family, +@@ -243,7 +243,7 @@ static int fake_hostent(const char *name, int family, ares_host_callback callbac + char *addrs[2]; + int result = 0; + struct in_addr in; +- struct in6_addr in6; ++ struct ares_in6_addr in6; + + if (family == AF_INET || family == AF_INET6) + { +@@ -284,7 +284,7 @@ static int fake_hostent(const char *name, int family, ares_host_callback callbac + } + else if (family == AF_INET6) + { +- hostent.h_length = (int)sizeof(struct in6_addr); ++ hostent.h_length = (int)sizeof(struct ares_in6_addr); + addrs[0] = (char *)&in6; + } + /* Duplicate the name, to avoid a constness violation. */ +@@ -467,7 +467,7 @@ static int get_address_index(const struct in_addr *addr, + static void sort6_addresses(struct hostent *host, const 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 +@@ -477,24 +477,24 @@ static void sort6_addresses(struct hostent *host, const struct apattern *sortlis + */ + 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(const struct in6_addr *addr, ++static int get6_address_index(const struct ares_in6_addr *addr, + const struct apattern *sortlist, + int nsort) + { +@@ -504,7 +504,9 @@ static int get6_address_index(const struct in6_addr *addr, + { + 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 --git a/ares_getnameinfo.c b/ares_getnameinfo.c +index c1c0b16..94891ce 100644 +--- a/ares_getnameinfo.c ++++ b/ares_getnameinfo.c +@@ -1,4 +1,4 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright 2005 by Dominick Meglio + * +@@ -74,9 +74,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); +@@ -184,14 +186,16 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, + { + 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 --git a/ares_init.3 b/ares_init.3 +index 14be75f..d974090 100644 +--- a/ares_init.3 ++++ b/ares_init.3 +@@ -1,7 +1,7 @@ +-.\" $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ ++.\" $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ + .\" + .\" Copyright 1998 by the Massachusetts Institute of Technology. +-.\" Copyright (C) 2004-2009 by Daniel Stenberg ++.\" Copyright (C) 2004-2010 by Daniel Stenberg + .\" + .\" Permission to use, copy, modify, and distribute this + .\" software and its documentation for any purpose and without +@@ -15,7 +15,7 @@ + .\" this software for any purpose. It is provided "as is" + .\" without express or implied warranty. + .\" +-.TH ARES_INIT 3 "26 May 2009" ++.TH ARES_INIT 3 "5 March 2010" + .SH NAME + ares_init, ares_init_options \- Initialize a resolver channel + .SH SYNOPSIS +@@ -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; +@@ -190,10 +193,11 @@ c-ares library initialization not yet performed. + .SH SEE ALSO + .BR ares_destroy(3), + .BR ares_dup(3), +-.BR ares_library_init(3) ++.BR ares_library_init(3), ++.BR ares_set_servers(3) + .SH AUTHOR + Greg Hudson, MIT Information Systems + .br + Copyright 1998 by the Massachusetts Institute of Technology. + .br +-Copyright (C) 2004-2009 by Daniel Stenberg. ++Copyright (C) 2004-2010 by Daniel Stenberg. +diff --git a/ares_init.c b/ares_init.c +index cb541af..cdcf38a 100644 +--- a/ares_init.c ++++ b/ares_init.c +@@ -1,7 +1,7 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright 1998 by the Massachusetts Institute of Technology. +- * Copyright (C) 2007-2009 by Daniel Stenberg ++ * Copyright (C) 2007-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without +@@ -68,6 +68,7 @@ + #include "ares.h" + #include "inet_net_pton.h" + #include "ares_library_init.h" ++#include "ares_data.h" + #include "ares_private.h" + + #ifdef WATT32 +@@ -118,7 +119,6 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, + ares_channel channel; + int i; + int status = ARES_SUCCESS; +- struct server_state *server; + struct timeval now; + + #ifdef CURLDEBUG +@@ -247,21 +247,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, + 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; +@@ -272,7 +258,9 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, + 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 */ +@@ -296,16 +284,33 @@ int ares_dup(ares_channel *dest, ares_channel src) + (*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)); +@@ -335,16 +340,27 @@ int ares_save_options(ares_channel channel, struct ares_options *options, + 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) { +@@ -420,7 +436,7 @@ static int init_by_options(ares_channel 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 */ +@@ -431,7 +447,12 @@ static int init_by_options(ares_channel 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; + } +@@ -1001,7 +1022,8 @@ static int init_by_defaults(ares_channel 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; + } + +@@ -1149,61 +1171,62 @@ static int config_lookup(ares_channel channel, const char *str, + 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; + +- /* 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)++; ++ /* 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; ++ } + +- 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; + } + +@@ -1580,3 +1603,129 @@ void ares_set_socket_callback(ares_channel channel, + 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 (ares_library_initialized() != ARES_SUCCESS) ++ return ARES_ENOTINITIALIZED; ++ ++ 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 --git a/ares_ipv6.h b/ares_ipv6.h +index 18914d1..eb19f31 100644 +--- a/ares_ipv6.h ++++ b/ares_ipv6.h +@@ -1,4 +1,4 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright (C) 2005 by Dominick Meglio + * +@@ -22,23 +22,14 @@ + #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 + +diff --git a/ares_parse_aaaa_reply.c b/ares_parse_aaaa_reply.c +index c2329cc..364f430 100644 +--- a/ares_parse_aaaa_reply.c ++++ b/ares_parse_aaaa_reply.c +@@ -1,4 +1,4 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright 2005 Dominick Meglio +@@ -65,7 +65,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, + 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; + +@@ -101,7 +101,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, + /* Allocate addresses and aliases; ancount gives an upper bound for both. */ + if (host) + { +- addrs = malloc(ancount * sizeof(struct in6_addr)); ++ addrs = malloc(ancount * sizeof(struct ares_in6_addr)); + if (!addrs) + { + free(hostname); +@@ -143,27 +143,27 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, + 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 ares_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++; +@@ -233,7 +233,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, + 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 --git a/ares_private.h b/ares_private.h +index 4726d7a..1de693a 100644 +--- a/ares_private.h ++++ b/ares_private.h +@@ -1,10 +1,10 @@ + #ifndef __ARES_PRIVATE_H + #define __ARES_PRIVATE_H + +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright 1998 by the Massachusetts Institute of Technology. +- * Copyright (C) 2004-2009 by Daniel Stenberg ++ * Copyright (C) 2004-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without +@@ -113,8 +113,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 +@@ -137,7 +137,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; + +@@ -221,14 +221,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,6 +319,8 @@ struct timeval ares__tvnow(void); + int ares__expand_name_for_response(const unsigned char *encoded, + const unsigned char *abuf, int alen, + char **s, long *enclen); ++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 +diff --git a/ares_process.c b/ares_process.c +index 6182ccc..ef4060a 100644 +--- a/ares_process.c ++++ b/ares_process.c +@@ -97,6 +97,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server); + 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_channel channel, fd_set *read_fds, + ssize_t count; + unsigned char buf[PACKETSZ + 1]; + #ifdef HAVE_RECVFROM +- struct sockaddr_in from; + ares_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_channel channel, fd_set *read_fds, + * 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_channel channel, fd_set *read_fds, + 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 +@@ -886,10 +893,39 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server) + { + ares_socket_t s; + int opt; +- struct sockaddr_in sockin; ++ ares_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; + +@@ -917,11 +953,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server) + #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; + +@@ -953,10 +985,39 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server) + static int open_udp_socket(ares_channel channel, struct server_state *server) + { + ares_socket_t s; +- struct sockaddr_in sockin; ++ ares_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; + +@@ -968,11 +1029,7 @@ static int open_udp_socket(ares_channel channel, struct server_state *server) + } + + /* 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; + +@@ -1079,6 +1136,34 @@ static int same_questions(const unsigned char *qbuf, int qlen, + 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 --git a/ares_save_options.3 b/ares_save_options.3 +index 268327c..8ed8925 100644 +--- a/ares_save_options.3 ++++ b/ares_save_options.3 +@@ -1,4 +1,4 @@ +-.\" $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ ++.\" $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ + .\" + .\" Copyright 1998 by the Massachusetts Institute of Technology. + .\" +@@ -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 +@@ -52,13 +52,20 @@ The channel data identified by + were invalid. + .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 --git a/inet_net_pton.c b/inet_net_pton.c +index de09ace..f4a0812 100644 +--- a/inet_net_pton.c ++++ b/inet_net_pton.c +@@ -1,4 +1,4 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +@@ -43,6 +43,7 @@ + #include + #include + ++#include "ares.h" + #include "ares_ipv6.h" + #include "inet_net_pton.h" + +@@ -432,7 +433,7 @@ int ares_inet_pton(int af, const char *src, void *dst) + 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 --git a/inet_ntop.c b/inet_ntop.c +index 5b0d097..31b9ab1 100644 +--- a/inet_ntop.c ++++ b/inet_ntop.c +@@ -1,4 +1,4 @@ +-/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ ++/* $Id: 0001-Allow-the-use-of-IPv6-nameservers.patch,v 1.1 2010/04/06 07:36:25 jhrozek Exp $ */ + + /* Copyright (c) 1996 by Internet Software Consortium. + * +@@ -42,6 +42,7 @@ + #include + #include + ++#include "ares.h" + #include "ares_ipv6.h" + #include "inet_ntop.h" + +diff --git a/vc/cares/vc6cares.dsp b/vc/cares/vc6cares.dsp +index b7c50c6..583a55c 100644 +--- a/vc/cares/vc6cares.dsp ++++ b/vc/cares/vc6cares.dsp +@@ -226,6 +226,10 @@ SOURCE=..\..\ares_mkquery.c + # End Source File + # Begin Source File + ++SOURCE=..\..\ares_options.c ++# End Source File ++# Begin Source File ++ + SOURCE=..\..\ares_parse_a_reply.c + # End Source File + # Begin Source File +-- +1.6.6.1 + diff --git a/c-ares.spec b/c-ares.spec index a2c3d3c..b080ea7 100644 --- a/c-ares.spec +++ b/c-ares.spec @@ -1,13 +1,14 @@ Summary: A library that performs asynchronous DNS operations Name: c-ares Version: 1.7.0 -Release: 1%{?dist} +Release: 3%{?dist} License: MIT Group: System Environment/Libraries URL: http://c-ares.haxx.se/ Source0: http://c-ares.haxx.se/c-ares-%{version}.tar.gz Source1: LICENSE Patch0: %{name}-1.7.0-optflags.patch +Patch1: 0001-Allow-the-use-of-IPv6-nameservers.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %description @@ -28,6 +29,7 @@ compile applications or shared objects that use c-ares. %prep %setup -q %patch0 -p1 -b .optflags +%patch1 -p1 -b .ipv6 cp %{SOURCE1} . f=CHANGES ; iconv -f iso-8859-1 -t utf-8 $f -o $f.utf8 ; mv $f.utf8 $f @@ -64,6 +66,13 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man3/ares_* %changelog +* Sun Mar 7 2010 Jakub Hrozek - 1.7.0-3 +- Change IPv6 nameserver patch according to upstream changes + (upstream revisions 1199,1201,1202) + +* Wed Mar 3 2010 Jakub Hrozek - 1.7.0-2 +- Add a patch to allow usage of IPv6 nameservers + * Tue Dec 1 2009 Tom "spot" Callaway - 1.7.0-1 - update to 1.7.0