summaryrefslogtreecommitdiff
path: root/ares
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2009-01-31 20:17:41 +0000
committerDaniel Stenberg <daniel@haxx.se>2009-01-31 20:17:41 +0000
commita2256e899b7c122169b9c50e8cb92ac6fc51e95b (patch)
tree0235ee52cb2d1054027f4a7c083b0665035b442e /ares
parent8b6805572a5322bd4addbf45382f0041cc09c885 (diff)
downloadcurl-a2256e899b7c122169b9c50e8cb92ac6fc51e95b.tar.gz
- 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.
Diffstat (limited to 'ares')
-rw-r--r--ares/CHANGES5
-rw-r--r--ares/RELEASE-NOTES6
-rw-r--r--ares/ares__get_hostent.c24
-rw-r--r--ares/ares_gethostbyname.c95
4 files changed, 77 insertions, 53 deletions
diff --git a/ares/CHANGES b/ares/CHANGES
index 232147211..ec202261d 100644
--- a/ares/CHANGES
+++ b/ares/CHANGES
@@ -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
diff --git a/ares/RELEASE-NOTES b/ares/RELEASE-NOTES
index 8b5aa49fb..761121be5 100644
--- a/ares/RELEASE-NOTES
+++ b/ares/RELEASE-NOTES
@@ -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:
diff --git a/ares/ares__get_hostent.c b/ares/ares__get_hostent.c
index 40dad5d56..c14919a97 100644
--- a/ares/ares__get_hostent.c
+++ b/ares/ares__get_hostent.c
@@ -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. */
diff --git a/ares/ares_gethostbyname.c b/ares/ares_gethostbyname.c
index 55bfb300e..e6b9f7f40 100644
--- a/ares/ares_gethostbyname.c
+++ b/ares/ares_gethostbyname.c
@@ -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);
}