Added IPv6 name servers support

pull/1/head
Yang Tse 15 years ago
parent 249fc61b8c
commit 8fe746fcf2
  1. 21
      CHANGES
  2. 9
      Makefile.inc
  3. 5
      RELEASE-NOTES
  4. 101
      adig.c
  5. 2
      ahost.c
  6. 17
      ares.h
  7. 10
      ares__get_hostent.c
  8. 15
      ares_data.c
  9. 4
      ares_data.h
  10. 33
      ares_destroy.c
  11. 12
      ares_free_data.3
  12. 78
      ares_get_servers.3
  13. 16
      ares_gethostbyaddr.c
  14. 18
      ares_gethostbyname.c
  15. 12
      ares_getnameinfo.c
  16. 16
      ares_init.3
  17. 201
      ares_init.c
  18. 15
      ares_ipv6.h
  19. 128
      ares_options.c
  20. 16
      ares_parse_aaaa_reply.c
  21. 20
      ares_private.h
  22. 125
      ares_process.c
  23. 11
      ares_save_options.3
  24. 84
      ares_set_servers.3
  25. 3
      inet_net_pton.c
  26. 1
      inet_ntop.c
  27. 4
      vc/cares/vc6cares.dsp

@ -1,5 +1,26 @@
Changelog for the c-ares project
* March 5, 2010 (Yang Tse)
- Added IPv6 name servers support. Implementation has been based on code,
comments and feedback provided November and December of 2008 by Daniel
Stenberg, Gregor Jasny, Phil Blundell and myself, December 2009 by Cedric
Bail, and February 2010 by Jakub Hrozek on the c-ares mailing list. On
March I reviewed all that, selected the best of each, and adjusted or
extended parts of it to make the best fit.
The external and visible result of all this is that two new functions are
added to the external API, ares_get_servers() and ares_set_servers(), which
becomes now the preferred way of getting and setting name servers for any
ares channel as these support both IPv4 and IPv6 name servers.
In order to not break ABI compatibility, ares_init_options() with option
mask ARES_OPT_SERVERS and ares_save_options() may still be used in code
which is intended to run on IPv4-only stacks. But remember that these
functions do not support IPv6 name servers. This implies that if the user
is capable of defining or providing an IPv6 name server, and the app is
using ares_init_options() or ares_save_options() at some point to handle
the name servers, the app will likely loose IPv6 name servers.
* January 28, 2010 (Daniel Stenberg)
- Tommie Gannert pointed out a silly bug in ares_process_fd() since it didn't
check for broken connections like ares_process() did. Based on that, I

@ -20,6 +20,7 @@ CSOURCES = ares__close_sockets.c \
ares_llist.c \
ares_mkquery.c \
ares_nowarn.c \
ares_options.c \
ares_parse_a_reply.c \
ares_parse_aaaa_reply.c \
ares_parse_ns_reply.c \
@ -48,8 +49,8 @@ HHEADERS = ares.h \
ares_ipv6.h \
ares_library_init.h \
ares_llist.h \
ares_private.h \
ares_nowarn.h \
ares_private.h \
ares_rules.h \
ares_strcasecmp.h \
ares_strdup.h \
@ -72,6 +73,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 \
@ -93,6 +95,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 \
@ -108,6 +111,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 \
@ -129,6 +133,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 \
@ -144,6 +149,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 \
@ -165,6 +171,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 \

@ -2,7 +2,7 @@ This is what's new and changed in the c-ares 1.7.1 release:
Changed:
o
o added IPv6 name servers support
Fixed:
@ -12,6 +12,7 @@ Fixed:
Thanks go to these friendly people for their efforts and contributions:
Ingmar Runge, Laszlo Tamas Szabo, Yang Tse, Tommie Gannert
Ingmar Runge, Laszlo Tamas Szabo, Yang Tse, Tommie Gannert, Gregor Jasny,
Phil Blundell, Cedric Bail, Jakub Hrozek
Have fun!

101
adig.c

@ -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;
}

@ -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);

@ -1,7 +1,7 @@
/* $Id$ */
/* 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

@ -1,6 +1,6 @@
/* $Id$ */
/* 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 *));

@ -1,6 +1,6 @@
/* $Id$ */
/* 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
@ -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()
*/
@ -78,6 +79,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;
}
@ -121,6 +128,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;

@ -1,6 +1,6 @@
/* $Id$ */
/* 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;
};

@ -1,6 +1,7 @@
/* $Id$ */
/* 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;
}

@ -1,7 +1,7 @@
.\" $Id$
.\"
.\" 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.

@ -0,0 +1,78 @@
.\" $Id$
.\"
.\" Copyright 1998 by the Massachusetts Institute of Technology.
.\" Copyright (C) 2008-2010 by Daniel Stenberg
.\"
.\" Permission to use, copy, modify, and distribute this
.\" software and its documentation for any purpose and without
.\" fee is hereby granted, provided that the above copyright
.\" notice appear in all copies and that both that copyright
.\" notice and this permission notice appear in supporting
.\" documentation, and that the name of M.I.T. not be used in
.\" advertising or publicity pertaining to distribution of the
.\" software without specific, written prior permission.
.\" M.I.T. makes no representations about the suitability of
.\" this software for any purpose. It is provided "as is"
.\" without express or implied warranty.
.\"
.TH ARES_GET_SERVERS 3 "5 March 2010"
.SH NAME
ares_get_servers \- Retrieve name servers from an initialized ares_channel
.SH SYNOPSIS
.nf
.B #include <ares.h>
.PP
.B int ares_get_servers(ares_channel \fIchannel\fP, struct ares_addr_node **\fIservers\fP)
.fi
.SH DESCRIPTION
The \fBares_get_servers(3)\fP function retrieves name servers configuration
from the
channel data identified by
.IR channel ,
as a linked list of ares_addr_node structs storing a pointer to the first
node at the address specified by
.IR servers .
Function caller may traverse the returned name server linked list, or may use
it directly as suitable input for the \fBares_set_servers(3)\fP function, but
shall not shrink or extend the list on its own.
Each node of the name server linked list is stored in memory dynamically
allocated and managed by c-ares. It is the caller's responsibility to free
the resulting linked list, using \fBares_free_data(3)\fP , once the caller
does not need it any longer.
This function is capable of handling IPv4 and IPv6 name server
addresses simultaneously, rendering \fBares_save_options(3)\fP with
optmask \fBARES_OPT_SERVERS\fP functionally obsolete except for
IPv4-only name server usage.
.SH RETURN VALUES
.B ares_get_servers(3)
may return any of the following values:
.TP 15
.B ARES_SUCCESS
The name servers configuration was successfuly retrieved
.TP 15
.B ARES_ENOMEM
The memory was exhausted
.TP 15
.B ARES_ENODATA
The channel data identified by
.IR channel
was invalid.
.SH SEE ALSO
.BR ares_set_servers (3),
.BR ares_init_options (3),
.BR ares_save_options(3)
.SH AVAILABILITY
ares_get_servers(3) was added in c-ares 1.7.1
.SH AUTHOR
Implementation of this function and associated library internals are based
on code, comments and feedback provided November and December of 2008 by
Daniel Stenberg, Gregor Jasny, Phil Blundell and Yang Tse, December 2009
by Cedric Bail, February 2010 by Jakub Hrozek. On March 2010 Yang Tse
shuffled all the bits and this function popped out.
.br
Copyright 1998 by the Massachusetts Institute of Technology.
Copyright (C) 2008-2010 by Daniel Stenberg

@ -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);

@ -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)
{

@ -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);
}
}

@ -1,7 +1,7 @@
.\" $Id$
.\"
.\" 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.

@ -1,7 +1,7 @@
/* $Id$ */
/* 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
@ -118,7 +118,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 +246,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 +257,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 +283,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 +339,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 +435,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 +446,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 +1021,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 +1170,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 +1602,26 @@ 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;
}
}

@ -23,22 +23,17 @@
#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

@ -0,0 +1,128 @@
/* $Id$ */
/* Copyright 1998 by the Massachusetts Institute of Technology.
* Copyright (C) 2008-2010 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#include "ares_setup.h"
#include "ares.h"
#include "ares_data.h"
#include "ares_private.h"
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;
}

@ -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;

@ -4,7 +4,7 @@
/* $Id$ */
/* 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

@ -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);
@ -434,8 +435,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))
@ -471,7 +475,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
@ -482,10 +489,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
@ -893,10 +900,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;
@ -924,11 +960,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;
@ -960,10 +992,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;
@ -975,11 +1036,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;
@ -1086,6 +1143,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)
{

@ -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

@ -0,0 +1,84 @@
.\" $Id$
.\"
.\" Copyright 1998 by the Massachusetts Institute of Technology.
.\" Copyright (C) 2008-2010 by Daniel Stenberg
.\"
.\" Permission to use, copy, modify, and distribute this
.\" software and its documentation for any purpose and without
.\" fee is hereby granted, provided that the above copyright
.\" notice appear in all copies and that both that copyright
.\" notice and this permission notice appear in supporting
.\" documentation, and that the name of M.I.T. not be used in
.\" advertising or publicity pertaining to distribution of the
.\" software without specific, written prior permission.
.\" M.I.T. makes no representations about the suitability of
.\" this software for any purpose. It is provided "as is"
.\" without express or implied warranty.
.\"
.TH ARES_SET_SERVERS 3 "5 March 2010"
.SH NAME
ares_set_servers \- Initialize an ares_channel name servers configuration
.SH SYNOPSIS
.nf
.B #include <ares.h>
.PP
.B int ares_set_servers(ares_channel \fIchannel\fP, struct ares_addr_node *\fIservers\fP)
.fi
.SH DESCRIPTION
The \fBares_set_servers(3)\fP function initializes name servers configuration
for the channel data identified by
.IR channel ,
from a
.IR servers
pointer to a linked list of ares_addr_node structs holding name servers
address data.
The name server linked list pointer argument may be the result of a previous
call to \fBares_get_servers(3)\fP or a linked list of ares_addr_node structs
setup by other means.
This function replaces any potentially previously configured name servers
with the ones given in the linked list. So, in order to configure a channel
with more than one name server all the desired ones must be specified in a
single list.
\fBares_set_servers(3)\fP does not take ownership of the linked list argument.
The caller is responsible to free the linked list when no longer needed.
This function is capable of handling IPv4 and IPv6 name server
addresses simultaneously, rendering \fBares_init_options(3)\fP with
optmask \fBARES_OPT_SERVERS\fP functionally obsolete except for
IPv4-only name server usage.
.SH RETURN VALUES
.B ares_set_servers(3)
may return any of the following values:
.TP 15
.B ARES_SUCCESS
The name servers configuration was successfuly initialized.
.TP 15
.B ARES_ENOMEM
The process's available memory was exhausted.
.TP 15
.B ARES_ENODATA
The channel data identified by
.IR channel
was invalid.
.TP 15
.B ARES_ENOTINITIALIZED
c-ares library initialization not yet performed.
.SH SEE ALSO
.BR ares_get_servers (3),
.BR ares_init_options (3),
.BR ares_dup(3)
.SH AVAILABILITY
ares_set_servers(3) was added in c-ares 1.7.1
.SH AUTHOR
Implementation of this function and associated library internals are based
on code, comments and feedback provided November and December of 2008 by
Daniel Stenberg, Gregor Jasny, Phil Blundell and Yang Tse, December 2009
by Cedric Bail, February 2010 by Jakub Hrozek. On March 2010 Yang Tse
shuffled all the bits and this function popped out.
.br
Copyright 1998 by the Massachusetts Institute of Technology.
Copyright (C) 2008-2010 by Daniel Stenberg

@ -43,6 +43,7 @@
#include <string.h>
#include <stdlib.h>
#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);

@ -42,6 +42,7 @@
#include <string.h>
#include <stdlib.h>
#include "ares.h"
#include "ares_ipv6.h"
#include "inet_ntop.h"

@ -230,6 +230,10 @@ SOURCE=..\..\ares_nowarn.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

Loading…
Cancel
Save