]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix DiG UDP query retry and fail-over bug
authorAram Sargsyan <aram@isc.org>
Wed, 15 Jun 2022 12:57:14 +0000 (12:57 +0000)
committerAram Sargsyan <aram@isc.org>
Fri, 22 Jul 2022 09:00:08 +0000 (09:00 +0000)
When the `udp_ready()` callback function gets called with a failure
result code, DiG erroneously cancels the lookup.

Copy the logic behind `tcp_connected()` callback function into
`udp_ready()` so that DiG will now retry the failed query (if retries
are enabled) and then, if it fails again, it will fail-over to the next
server in the list, which synchronizes the behavior between TCP and UDP
modes.

Also, `udp_ready()` was calling `lookup_detach()` without calling
`lookup_attach()` first, but the issue was masked behind the fact
that `clear_current_lookup()` wasn't being called when needed, and
`lookup_detach()` was compensating for that. This also has been fixed.

(cherry picked from commit 3f3108552577c326b4dab6c3b631c51cf0040144)

bin/dig/dighost.c

index ca3a4062323b18f6f2ee2776b5d4450a8a2d9c4c..a9a4b0f388d1ad9865ed0f912e1082266e3315e9 100644 (file)
@@ -3112,6 +3112,9 @@ send_udp(dig_query_t *query) {
 static void
 udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
        dig_query_t *query = (dig_query_t *)arg;
+       dig_query_t *next = NULL;
+       char sockstr[ISC_SOCKADDR_FORMATSIZE];
+       dig_lookup_t *l = NULL;
        dig_query_t *readquery = NULL;
        int local_timeout = timeout * 1000;
 
@@ -3132,30 +3135,63 @@ udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
        debug("udp_ready(%p, %s, %p)", handle, isc_result_totext(eresult),
              query);
 
-       if (eresult == ISC_R_CANCELED || query->canceled) {
-               dig_lookup_t *l = query->lookup;
+       LOCK_LOOKUP;
+       lookup_attach(query->lookup, &l);
 
+       if (eresult == ISC_R_CANCELED || query->canceled) {
                debug("in cancel handler");
                if (!query->canceled) {
                        cancel_lookup(l);
                }
                query_detach(&query);
                lookup_detach(&l);
+               clear_current_lookup();
+               UNLOCK_LOOKUP;
                return;
        } else if (eresult != ISC_R_SUCCESS) {
-               dig_lookup_t *l = query->lookup;
-
                debug("udp setup failed: %s", isc_result_totext(eresult));
+               isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
+               dighost_warning("UDP setup with %s(%s) for %s failed: %s.",
+                               sockstr, query->servname, l->textname,
+                               isc_result_totext(eresult));
 
                if (exitcode < 9) {
                        exitcode = 9;
                }
+
+               if (l->retries > 1) {
+                       l->retries--;
+                       debug("making new UDP request, %d tries left",
+                             l->retries);
+                       requeue_lookup(l, true);
+                       next = NULL;
+               } else if ((l->current_query != NULL) &&
+                          (ISC_LINK_LINKED(l->current_query, link)))
+               {
+                       next = ISC_LIST_NEXT(l->current_query, link);
+               } else {
+                       next = NULL;
+               }
+
                query_detach(&query);
-               cancel_lookup(l);
+               if (next == NULL) {
+                       cancel_lookup(l);
+               }
                lookup_detach(&l);
+
+               if (next != NULL) {
+                       start_udp(next);
+               } else {
+                       clear_current_lookup();
+               }
+
+               check_if_done();
+               UNLOCK_LOOKUP;
                return;
        }
 
+       exitcode = 0;
+
        query_attach(query, &readquery);
 
        debug("recving with lookup=%p, query=%p, handle=%p", query->lookup,
@@ -3177,6 +3213,8 @@ udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
        send_udp(readquery);
 
        query_detach(&query);
+       lookup_detach(&l);
+       UNLOCK_LOOKUP;
 }
 
 /*%