From 1c3a52b510f2a873f52b660799ea497f4535a3eb Mon Sep 17 00:00:00 2001 From: Brad House Date: Wed, 27 Sep 2023 16:30:45 -0400 Subject: [PATCH] Don't requeue any queries for getaddrinfo() during destruction. (#553) During ares_destroy(), any outstanding queries are terminated, however ares_getaddrinfo() had an ordering issue with status codes which in some circumstances could lead to a new query being enqueued rather than honoring the termination. Fixes #532 Fix By: @Chilledheart and Brad House (@bradh352) --- src/lib/ares_getaddrinfo.c | 78 +++++++++++++++----------------------- 1 file changed, 31 insertions(+), 47 deletions(-) diff --git a/src/lib/ares_getaddrinfo.c b/src/lib/ares_getaddrinfo.c index 6ce6979d..e212a4df 100644 --- a/src/lib/ares_getaddrinfo.c +++ b/src/lib/ares_getaddrinfo.c @@ -598,56 +598,40 @@ static void host_callback(void *arg, int status, int timeouts, hquery->timeouts += timeouts; hquery->remaining--; - if (status == ARES_SUCCESS) - { - addinfostatus = ares__parse_into_addrinfo(abuf, alen, 1, hquery->port, hquery->ai); - if (addinfostatus == ARES_SUCCESS && alen >= HFIXEDSZ) - { - qid = DNS_HEADER_QID(abuf); /* Converts to host byte order */ - terminate_retries(hquery, qid); - } + if (status == ARES_SUCCESS) { + addinfostatus = ares__parse_into_addrinfo(abuf, alen, 1, hquery->port, + hquery->ai); + if (addinfostatus == ARES_SUCCESS && alen >= HFIXEDSZ) { + qid = DNS_HEADER_QID(abuf); /* Converts to host byte order */ + terminate_retries(hquery, qid); } + } - if (!hquery->remaining) - { - if (addinfostatus != ARES_SUCCESS && addinfostatus != ARES_ENODATA) - { - /* error in parsing result e.g. no memory */ - if (addinfostatus == ARES_EBADRESP && hquery->ai->nodes) - { - /* We got a bad response from server, but at least one query - * ended with ARES_SUCCESS */ - end_hquery(hquery, ARES_SUCCESS); - } - else - { - end_hquery(hquery, addinfostatus); - } - } - else if (hquery->ai->nodes) - { - /* at least one query ended with ARES_SUCCESS */ - end_hquery(hquery, ARES_SUCCESS); - } - else if (status == ARES_ENOTFOUND || status == ARES_ENODATA || - addinfostatus == ARES_ENODATA) - { - if (status == ARES_ENODATA || addinfostatus == ARES_ENODATA) - hquery->nodata_cnt++; - next_lookup(hquery, hquery->nodata_cnt?ARES_ENODATA:status); - } - else if (status == ARES_EDESTRUCTION) - { - /* NOTE: Could also be ARES_EDESTRUCTION. We need to only call this - * once all queries (there can be multiple for getaddrinfo) are - * terminated. */ - end_hquery(hquery, status); - } - else - { - end_hquery(hquery, status); - } + if (!hquery->remaining) { + if (addinfostatus != ARES_SUCCESS && addinfostatus != ARES_ENODATA) { + /* error in parsing result e.g. no memory */ + if (addinfostatus == ARES_EBADRESP && hquery->ai->nodes) { + /* We got a bad response from server, but at least one query + * ended with ARES_SUCCESS */ + end_hquery(hquery, ARES_SUCCESS); + } else { + end_hquery(hquery, addinfostatus); + } + } else if (hquery->ai->nodes) { + /* at least one query ended with ARES_SUCCESS */ + end_hquery(hquery, ARES_SUCCESS); + } else if (status == ARES_EDESTRUCTION || status == ARES_ECANCELLED) { + /* must make sure we don't do next_lookup() on destroy or cancel */ + end_hquery(hquery, status); + } else if (status == ARES_ENOTFOUND || status == ARES_ENODATA || + addinfostatus == ARES_ENODATA) { + if (status == ARES_ENODATA || addinfostatus == ARES_ENODATA) + hquery->nodata_cnt++; + next_lookup(hquery, hquery->nodata_cnt?ARES_ENODATA:status); + } else { + end_hquery(hquery, status); } + } /* at this point we keep on waiting for the next query to finish */ }