mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 10:10:00 -04:00
Fix "dig +nssearch" indefinitely hanging issue
When finishing the NSSEARCH task and there is no more followup
lookups to start, dig does not destroy the last lookup, which
causes it to hang indefinitely.
Rename the unused `first_pass` member of `dig_query_t` to `started`
and make it `true` in the first callback after `start_udp()` or
`start_tcp()` of the query to indicate that the query has been
started.
Create a new `check_if_queries_done()` function to check whether
all of the queries inside a lookup have been started and finished,
or canceled.
Use the mentioned function in the TRACE code block in `recv_done()`
to check whether the current query is the last one in the lookup and
cancel the lookup in that case to free the resources.
(cherry picked from commit 7d360bd05e)
This commit is contained in:
parent
49320f73df
commit
16bdced2ca
2 changed files with 37 additions and 4 deletions
|
|
@ -1520,6 +1520,30 @@ check_if_done(void) {
|
|||
}
|
||||
}
|
||||
|
||||
/*%
|
||||
* Check if we're done with all the queries in the lookup, except for
|
||||
* the `except_q` query (can be NULL if no exception is required).
|
||||
* Expects `l` to be a valid and locked lookup.
|
||||
*/
|
||||
static bool
|
||||
check_if_queries_done(dig_lookup_t *l, dig_query_t *except_q) {
|
||||
dig_query_t *q = ISC_LIST_HEAD(l->q);
|
||||
|
||||
debug("check_if_queries_done(%p)", l);
|
||||
|
||||
while (q != NULL) {
|
||||
if (!q->started || isc_refcount_current(&q->references) > 1) {
|
||||
if (!q->canceled && q != except_q) {
|
||||
debug("there is a pending query %p", q);
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
q = ISC_LIST_NEXT(q, link);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
static void
|
||||
_destroy_lookup(dig_lookup_t *lookup) {
|
||||
dig_server_t *s;
|
||||
|
|
@ -2075,7 +2099,6 @@ _new_query(dig_lookup_t *lookup, char *servname, char *userarg,
|
|||
*query = (dig_query_t){ .sendbuf = lookup->renderbuf,
|
||||
.servname = servname,
|
||||
.userarg = userarg,
|
||||
.first_pass = true,
|
||||
.warn_id = true,
|
||||
.recvspace = isc_mem_get(mctx, COMMSIZE),
|
||||
.tmpsendspace = isc_mem_get(mctx, COMMSIZE) };
|
||||
|
|
@ -2895,6 +2918,8 @@ udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
|
|||
dig_query_t *readquery = NULL;
|
||||
int local_timeout = timeout * 1000;
|
||||
|
||||
query->started = true;
|
||||
|
||||
if (eresult == ISC_R_CANCELED || query->canceled) {
|
||||
dig_lookup_t *l = query->lookup;
|
||||
|
||||
|
|
@ -3234,14 +3259,17 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
|
|||
char sockstr[ISC_SOCKADDR_FORMATSIZE];
|
||||
dig_lookup_t *l = NULL;
|
||||
|
||||
REQUIRE(DIG_VALID_QUERY(query));
|
||||
REQUIRE(query->handle == NULL);
|
||||
|
||||
debug("tcp_connected()");
|
||||
|
||||
query->started = true;
|
||||
|
||||
if (atomic_load(&cancel_now)) {
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE(DIG_VALID_QUERY(query));
|
||||
REQUIRE(query->handle == NULL);
|
||||
INSIST(!free_now);
|
||||
|
||||
debug("tcp_connected(%p, %s, %p)", handle, isc_result_totext(eresult),
|
||||
|
|
@ -4120,7 +4148,12 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|||
l->trace_root = false;
|
||||
usesearch = false;
|
||||
} else {
|
||||
/*
|
||||
* This is a query in the followup lookup
|
||||
*/
|
||||
dighost_printmessage(query, &b, msg, true);
|
||||
|
||||
docancel = check_if_queries_done(l, query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ struct dig_lookup {
|
|||
struct dig_query {
|
||||
unsigned int magic;
|
||||
dig_lookup_t *lookup;
|
||||
bool first_pass;
|
||||
bool started;
|
||||
bool first_soa_rcvd;
|
||||
bool second_rr_rcvd;
|
||||
bool first_repeat_rcvd;
|
||||
|
|
|
|||
Loading…
Reference in a new issue