Tweak get_new_frec() behaviour in "force" mode.
authorSimon Kelley <simon@thekelleys.org.uk>
Thu, 21 Aug 2025 12:21:27 +0000 (13:21 +0100)
committerSimon Kelley <simon@thekelleys.org.uk>
Thu, 21 Aug 2025 12:21:27 +0000 (13:21 +0100)
get_new_frec() is not supposed to ever free an frec when
the force arg is set. Make this so. In theory, this fixes
a bug, but it's practically impossible to provoke and I have
no evidence that it has ever happened IRL.

src/forward.c

index 310b84e..1885907 100644 (file)
@@ -3128,36 +3128,40 @@ static struct frec *get_new_frec(time_t now, struct server *master, int force)
          /* Don't free DNSSEC sub-queries here, as we may end up with
             dangling references to them. They'll go when their "real" query 
             is freed. */
-         if (!f->dependent && !force)
+         if (!f->dependent)
 #endif
-           {
-             if (difftime(now, f->time) >= 4*TIMEOUT)
-               {
-                 daemon->metrics[METRIC_DNS_UNANSWERED_QUERY]++;
-                 free_frec(f);
-                 target = f;
-               }
-             else if (!oldest || difftime(f->time, oldest->time) <= 0)
-               oldest = f;
-           }
+           if (!force)
+             {
+               if (difftime(now, f->time) >= 4*TIMEOUT)
+                 {
+                   daemon->metrics[METRIC_DNS_UNANSWERED_QUERY]++;
+                   free_frec(f);
+                   target = f;
+                 }
+               else if (!oldest || difftime(f->time, oldest->time) <= 0)
+                 oldest = f;
+             }
        }
       
       if (f->sentto && ((int)difftime(now, f->time)) < TIMEOUT && server_samegroup(f->sentto, master))
        count++;
     }
-
-  if (!force && count >= daemon->ftabsize)
-    {
-      query_full(now, master->domain);
-      return NULL;
-    }
   
-  if (!target && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
-    { 
-      /* can't find empty one, use oldest if there is one and it's older than timeout */
-      daemon->metrics[METRIC_DNS_UNANSWERED_QUERY]++;
-      free_frec(oldest);
-      target = oldest;
+  if (!force)
+    {
+      if (count >= daemon->ftabsize)
+       {
+         query_full(now, master->domain);
+         return NULL;
+       }
+      
+      if (!target && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
+       { 
+         /* can't find empty one, use oldest if there is one and it's older than timeout */
+         daemon->metrics[METRIC_DNS_UNANSWERED_QUERY]++;
+         free_frec(oldest);
+         target = oldest;
+       }      
     }
   
   if (!target && (target = (struct frec *)whine_malloc(sizeof(struct frec))))