diff options
author | Steinar H. Gunderson <sesse@google.com> | 2007-10-16 21:27:51 +0000 |
---|---|---|
committer | Steinar H. Gunderson <sesse@google.com> | 2007-10-16 21:27:51 +0000 |
commit | 92aaff009d0a2e5ade970fb3700ca2d516ff12ec (patch) | |
tree | 79e191f80483048540b7dcc8a56b1de1a359cf80 | |
parent | 65ba6e3337d5f328c614a9e6b8e15b8d74d9b5e9 (diff) |
Fix a bug where fallback from AF_INET6 to AF_INET would not work properly together with relative search; if you had a search path of .a.com and .b.com, and foo.a.com would return ARES_ENODATA and foo.b.com would return ARES_ENOTFOUND, the lookup would not properly retry with AF_INET as it forgot the first ARES_ENODATA.
-rw-r--r-- | ares/ares_search.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/ares/ares_search.c b/ares/ares_search.c index ca703a3cb..c65f70f0a 100644 --- a/ares/ares_search.c +++ b/ares/ares_search.c @@ -42,6 +42,7 @@ struct search_query { int next_domain; /* next search domain to try */ int trying_as_is; /* current query is for name as-is */ int timeouts; /* number of timeouts we saw for this request */ + int ever_got_nodata; /* did we ever get ARES_ENODATA along the way? */ }; static void search_callback(void *arg, int status, int timeouts, @@ -58,7 +59,7 @@ void ares_search(ares_channel channel, const char *name, int dnsclass, char *s; const char *p; int status, ndots; - + /* If name only yields one domain to search, then we don't have * to keep extra state, so just do an ares_query(). */ @@ -98,6 +99,7 @@ void ares_search(ares_channel channel, const char *name, int dnsclass, squery->callback = callback; squery->arg = arg; squery->timeouts = 0; + squery->ever_got_nodata = 0; /* Count the number of dots in name. */ ndots = 0; @@ -145,7 +147,7 @@ static void search_callback(void *arg, int status, int timeouts, struct search_query *squery = (struct search_query *) arg; ares_channel channel = squery->channel; char *s; - + squery->timeouts += timeouts; /* Stop searching unless we got a non-fatal error. */ @@ -157,6 +159,17 @@ static void search_callback(void *arg, int status, int timeouts, /* Save the status if we were trying as-is. */ if (squery->trying_as_is) squery->status_as_is = status; + + /* + * If we ever get ARES_ENODATA along the way, record that; if the search + * should run to the very end and we got at least one ARES_ENODATA, + * then callers like ares_gethostbyname() may want to try a T_A search + * even if the last domain we queried for T_AAAA resource records + * returned ARES_ENOTFOUND. + */ + if (status == ARES_ENODATA) + squery->ever_got_nodata = 1; + if (squery->next_domain < channel->ndomains) { /* Try the next domain. */ @@ -180,8 +193,13 @@ static void search_callback(void *arg, int status, int timeouts, ares_query(channel, squery->name, squery->dnsclass, squery->type, search_callback, squery); } - else - end_squery(squery, squery->status_as_is, NULL, 0); + else { + if (squery->status_as_is == ARES_ENOTFOUND && squery->ever_got_nodata) { + end_squery(squery, ARES_ENODATA, NULL, 0); + } + else + end_squery(squery, squery->status_as_is, NULL, 0); + } } } |