From b52d1d2017128056413353f7641e3e2fe49b7115 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Thu, 21 Aug 2025 13:21:27 +0100 Subject: [PATCH] Tweak get_new_frec() behaviour in "force" mode. 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 | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/forward.c b/src/forward.c index 310b84e..1885907 100644 --- a/src/forward.c +++ b/src/forward.c @@ -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))))