1408 lines
45 KiB
Diff
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 \
|