c-ares/use-ipv6-nameservers-1.6.0....

1408 lines
45 KiB
Diff

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 \