From a2256e899b7c122169b9c50e8cb92ac6fc51e95b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 31 Jan 2009 20:17:41 +0000 Subject: - 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. --- ares/CHANGES | 5 +++ ares/RELEASE-NOTES | 6 ++- ares/ares__get_hostent.c | 24 +++++++----- ares/ares_gethostbyname.c | 95 +++++++++++++++++++++++++++-------------------- 4 files changed, 77 insertions(+), 53 deletions(-) (limited to 'ares') 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); } -- cgit v1.2.3