]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix dig hanging issue in cases when the lookup's next query can't start
authorAram Sargsyan <aram@isc.org>
Fri, 1 Apr 2022 13:12:40 +0000 (13:12 +0000)
committerAram Sargsyan <aram@isc.org>
Mon, 4 Apr 2022 09:15:56 +0000 (09:15 +0000)
In recv_done(), when dig decides to start the lookup's next query in
the line using `start_udp()` or `start_tcp()`, and for some reason,
no queries get started, dig doesn't cancel the lookup.

This can occur, for example, when there are two queries in the lookup,
one with a regular IP address, and another with a IPv4 mapped IPv6
address. When the regular IP address fails to serve the query, its
`recv_done()` callback starts the next query in the line (in this
case the one with a mapped IP address), but because `dig` doesn't
connect to such IP addresses, and there are no other queries in the
list, no new queries are being started, and the lookup keeps hanging.

After calling `start_udp()` or `start_tcp()` in `recv_done()`, check
if there are no pending/working queries then cancel the lookup instead
of only detaching from the current query.

bin/dig/dighost.c
bin/tests/system/digdelv/tests.sh

index 6f99f540647d2bbfb7a77944b0bddf631426d436..166358b34802eb008996d1ea25a2cf1b9e45aa4f 100644 (file)
@@ -3881,6 +3881,9 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
                                      l->retries);
                                start_udp(newq);
                        }
+                       if (check_if_queries_done(l, query)) {
+                               goto cancel_lookup;
+                       }
 
                        goto detach_query;
                } else if (l->retries > 1 && l->tcp_mode) {
@@ -3917,6 +3920,10 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
                                                start_udp(next);
                                        }
                                }
+                               if (check_if_queries_done(l, query)) {
+                                       goto cancel_lookup;
+                               }
+
                                goto detach_query;
                        }
 
@@ -3958,6 +3965,10 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
                                        start_udp(next);
                                }
                        }
+                       if (check_if_queries_done(l, query)) {
+                               goto cancel_lookup;
+                       }
+
                        goto detach_query;
                }
 
@@ -4234,6 +4245,10 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
                                                 ? "SERVFAIL reply"
                                                 : "recursion not available",
                                         query->servname);
+                       if (check_if_queries_done(l, query)) {
+                               goto cancel_lookup;
+                       }
+
                        goto detach_query;
                }
        }
index 2e735c66ea276050f68a462ad18853e08ad01fe1..05ee71052210f9ccd0b980a2625e075ec088e51d 100644 (file)
@@ -1071,6 +1071,16 @@ if [ -x "$DIG" ] ; then
   grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
   if [ $ret -ne 0 ]; then echo_i "failed"; fi
   status=$((status+ret))
+
+  # See [GL #3248] for more information
+  n=$((n+1))
+  echo_i "check that dig correctly refuses to use a server with a IPv4 mapped IPv6 address after failing with a regular IP address ($n)"
+  ret=0
+  dig_with_opts @10.53.0.8 @::ffff:10.53.0.8 a.example > dig.out.test$n 2>&1 || ret=1
+  grep -F ";; Skipping mapped address" dig.out.test$n > /dev/null || ret=1
+  grep -F ";; No acceptable nameservers" dig.out.test$n > /dev/null || ret=1
+  if [ $ret -ne 0 ]; then echo_i "failed"; fi
+  status=$((status+ret))
 else
   echo_i "$DIG is needed, so skipping these dig tests"
 fi