- ares_gethostbyname() now accepts 'AF_UNSPEC' as a family for resolving

either AF_INET6 or AF_INET. It works by accepting any of the looksups in the
  hosts file, and it resolves the AAAA field with a fallback to A.
This commit is contained in:
Daniel Stenberg 2009-01-31 20:17:41 +00:00
parent 8b6805572a
commit a2256e899b
4 changed files with 77 additions and 53 deletions

View File

@ -1,5 +1,10 @@
Changelog for the c-ares project
* January 31 2009 (Daniel Stenberg)
- ares_gethostbyname() now accepts 'AF_UNSPEC' as a family for resolving
either AF_INET6 or AF_INET. It works by accepting any of the looksups in the
hosts file, and it resolves the AAAA field with a fallback to A.
* January 14 2009 (Daniel Stenberg)
- ares.h no longer uses the HAVE_STRUCT_IN6_ADDR define check, but instead it
now declares the private struct ares_in6_addr for all systems instead of

View File

@ -2,8 +2,10 @@ This is what's new and changed in the c-ares 1.6.1 release:
Changed:
o in6_addr is not used in ares.h anymore, but a private ares_in6_addr is instead
declared and used
o in6_addr is not used in ares.h anymore, but a private ares_in6_addr is
instead declared and used
p ares_gethostbyname() now supports 'AF_UNSPEC' as a family for resolving
either AF_INET6 or AF_INET
Fixed:

View File

@ -68,17 +68,21 @@ int ares__get_hostent(FILE *fp, int family, struct hostent **host)
*p = 0;
addr.s_addr = inet_addr(line);
if (addr.s_addr == INADDR_NONE)
{
if (ares_inet_pton(AF_INET6, line, &addr6) > 0)
{
if (family != AF_INET6)
continue;
addrlen = sizeof(struct in6_addr);
}
else
continue;
}
{
/* It wasn't an AF_INET dotted address, then AF_UNSPEC and AF_INET6
families are subject for this further check */
if ((family != AF_INET) &&
(ares_inet_pton(AF_INET6, line, &addr6) > 0)) {
addrlen = sizeof(struct in6_addr);
family = AF_INET6;
}
else
continue;
}
else if (family == AF_UNSPEC)
family = AF_INET; /* now confirmed! */
else if (family != AF_INET)
/* unknown, keep moving */
continue;
/* Get the canonical hostname. */

View File

@ -61,7 +61,8 @@ struct host_query {
char *name;
ares_host_callback callback;
void *arg;
int family;
int sent_family; /* this family is what was is being used */
int want_family; /* this family is what is asked for in the API */
const char *remaining_lookups;
int timeouts;
};
@ -71,29 +72,34 @@ static void host_callback(void *arg, int status, int timeouts,
unsigned char *abuf, int alen);
static void end_hquery(struct host_query *hquery, int status,
struct hostent *host);
static int fake_hostent(const char *name, int family, ares_host_callback callback,
void *arg);
static int fake_hostent(const char *name, int family,
ares_host_callback callback, void *arg);
static int file_lookup(const char *name, int family, struct hostent **host);
static void sort_addresses(struct hostent *host, const struct apattern *sortlist,
int nsort);
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, const struct apattern *sortlist,
int nsort);
static void sort_addresses(struct hostent *host,
const struct apattern *sortlist, int nsort);
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,
const struct apattern *sortlist, int nsort);
void ares_gethostbyname(ares_channel channel, const char *name, int family,
ares_host_callback callback, void *arg)
{
struct host_query *hquery;
/* Right now we only know how to look up Internet addresses. */
if (family != AF_INET && family != AF_INET6)
{
callback(arg, ARES_ENOTIMP, 0, NULL);
return;
}
/* Right now we only know how to look up Internet addresses - and unspec
means try both basically. */
switch (family) {
case AF_INET:
case AF_INET6:
case AF_UNSPEC:
break;
default:
callback(arg, ARES_ENOTIMP, 0, NULL);
return;
}
if (fake_hostent(name, family, callback, arg))
return;
@ -107,13 +113,13 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
}
hquery->channel = channel;
hquery->name = strdup(name);
hquery->family = family;
if (!hquery->name)
{
free(hquery);
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
hquery->want_family = family;
hquery->sent_family = -1; /* nothing is sent yet */
if (!hquery->name) {
free(hquery);
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
hquery->callback = callback;
hquery->arg = arg;
hquery->remaining_lookups = channel->lookups;
@ -136,17 +142,23 @@ static void next_lookup(struct host_query *hquery, int status_code)
case 'b':
/* DNS lookup */
hquery->remaining_lookups = p + 1;
if (hquery->family == AF_INET6)
if ((hquery->want_family == AF_INET6) ||
(hquery->want_family == AF_UNSPEC)) {
/* if inet6 or unspec, start out with AAAA */
hquery->sent_family = AF_INET6;
ares_search(hquery->channel, hquery->name, C_IN, T_AAAA,
host_callback, hquery);
else
}
else {
hquery->sent_family = AF_INET;
ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
hquery);
}
return;
case 'f':
/* Host file lookup */
status = file_lookup(hquery->name, hquery->family, &host);
status = file_lookup(hquery->name, hquery->want_family, &host);
/* this status check below previously checked for !ARES_ENOTFOUND,
but we should not assume that this single error code is the one
@ -173,33 +185,34 @@ static void host_callback(void *arg, int status, int timeouts,
hquery->timeouts += timeouts;
if (status == ARES_SUCCESS)
{
if (hquery->family == AF_INET)
if (hquery->sent_family == AF_INET)
{
status = ares_parse_a_reply(abuf, alen, &host, NULL, NULL);
if (host && channel->nsort)
sort_addresses(host, channel->sortlist, channel->nsort);
}
else if (hquery->family == AF_INET6)
else if (hquery->sent_family == AF_INET6)
{
status = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL);
if (status == ARES_ENODATA)
{
/* The query returned something (e.g. CNAME) but there were no
AAAA records. Try looking up A instead. */
hquery->family = AF_INET;
ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
hquery);
return;
}
if (status == ARES_ENODATA) {
/* The query returned something (e.g. CNAME) but there were no
AAAA records. Try looking up A instead. We should possibly
limit this attempt-next logic to AF_UNSPEC lookups only. */
hquery->sent_family = AF_INET;
ares_search(hquery->channel, hquery->name, C_IN, T_A,
host_callback, hquery);
return;
}
if (host && channel->nsort)
sort6_addresses(host, channel->sortlist, channel->nsort);
}
end_hquery(hquery, status, host);
}
else if (status == ARES_ENODATA && hquery->family == AF_INET6)
else if (status == ARES_ENODATA && hquery->sent_family == AF_INET6)
{
/* There was no AAAA. Now lookup an A */
hquery->family = AF_INET;
/* There was no AAAA. Now lookup an A. We should possibly limit this
attempt-next logic to AF_UNSPEC lookups only. */
hquery->sent_family = AF_INET;
ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
hquery);
}