]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix "dig +nssearch" indefinitely hanging issue
authorAram Sargsyan <aram@isc.org>
Sun, 20 Mar 2022 13:54:39 +0000 (13:54 +0000)
committerArаm Sаrgsyаn <aram@isc.org>
Fri, 1 Apr 2022 10:56:27 +0000 (10:56 +0000)
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.

bin/dig/dighost.c
bin/dig/dighost.h

index 661ca6e8abf3b9df87cf9aa416d03a799951484f..6d710adb49afeb3c188ca81f218049b0e27bba44 100644 (file)
@@ -1551,6 +1551,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;
@@ -2126,7 +2150,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) };
@@ -3074,6 +3097,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;
 
@@ -3413,14 +3438,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),
@@ -4310,7 +4338,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);
                        }
                }
        }
index 3e3e0a0d8bf70c960e26a4a57cc394fe1fb01ffa..d79cc6fc1a6567bf2d30c853701fce5007490d43 100644 (file)
@@ -194,7 +194,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;