From 982ca161c26c2e6cd90b19888331bb015dcbae1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Tue, 26 Aug 2025 17:52:45 +0200 Subject: [PATCH 1/2] Preserve ZEROTTL attribute when replacing NS RRset Previously, BIND 9 would drop the ZEROTTL attribute when updating previously cached NS entry with ZEROTTL attribute set. Co-authored-by: Jinmei Tatuya --- lib/dns/qpcache.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 6ced85532d..ecb2b11eac 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -2790,6 +2790,11 @@ find_header: header->trust <= newheader->trust) { if (newheader->expire > header->expire) { + if (ZEROTTL(header)) { + DNS_SLABHEADER_SETATTR( + newheader, + DNS_SLABHEADERATTR_ZEROTTL); + } newheader->expire = header->expire; } } From 9f7ba584cf46ffbb17c0793d19a334533914aba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Tue, 26 Aug 2025 18:18:12 +0200 Subject: [PATCH 2/2] Don't preserve cache entries if new TTL is smaller than existing Under certain circumstances, cache entries with equivalent rdataset might not get replaced. Previously such entry would get preserved regardless of the new TTL and expire time on the existing header would get updated when the expire time was less than the expire time on the existing header. Change the logic to preserve the existing header only if the new expire time is larger than the existing one and replace the existing cache entry when the new expire time is less than the existing one. Co-authored-by: Jinmei Tatuya --- lib/dns/qpcache.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index ecb2b11eac..56682966d2 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -2734,29 +2734,22 @@ find_header: } /* - * Don't replace existing NS, A and AAAA RRsets in the - * cache if they already exist. This prevents named - * being locked to old servers. Don't lower trust of - * existing record if the update is forced. Nothing - * special to be done w.r.t stale data; it gets replaced - * normally further down. + * Don't replace existing NS in the cache if they already exist + * and replacing the existing one would increase the TTL. This + * prevents named being locked to old servers. Don't lower trust + * of existing record if the update is forced. Nothing special + * to be done w.r.t stale data; it gets replaced normally + * further down. */ if (ACTIVE(header, now) && top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) && EXISTS(header) && EXISTS(newheader) && header->trust >= newheader->trust && + header->expire < newheader->expire && dns_rdataslab_equalx(header, newheader, qpdb->common.rdclass, DNS_TYPEPAIR_TYPE(top->typepair))) { - /* - * Honour the new ttl if it is less than the - * older one. - */ - if (header->expire > newheader->expire) { - setttl(header, newheader->expire); - } - qpcache_hit(qpdb, header); if (header->noqname == NULL && @@ -2806,16 +2799,9 @@ find_header: top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) && EXISTS(header) && EXISTS(newheader) && header->trust >= newheader->trust && + header->expire < newheader->expire && dns_rdataslab_equal(header, newheader)) { - /* - * Honour the new ttl if it is less than the - * older one. - */ - if (header->expire > newheader->expire) { - setttl(header, newheader->expire); - } - qpcache_hit(qpdb, header); if (header->noqname == NULL &&