diff options
Diffstat (limited to 'ares/ares_gethostbyname.c')
-rw-r--r-- | ares/ares_gethostbyname.c | 95 |
1 files changed, 54 insertions, 41 deletions
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); } |