]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Don't use stale nodes when looking up a zonecut
authorMatthijs Mekking <matthijs@isc.org>
Wed, 11 Aug 2021 08:31:56 +0000 (10:31 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Fri, 13 Aug 2021 09:37:52 +0000 (11:37 +0200)
When looking up a zonecut in cache, we use 'dns_rbt_findnode' to find
the closest matching node. This function however does not take into
account stale nodes. When we do find a stale node and use it, this
has implications for subsequent lookups. For example, this may break
QNAME minimization because we are using a deeper zonecut than we should
have.

Check the header for staleness and if so, and stale entries are not
accepted, look for the deepest zonecut from this node up.

lib/dns/rbtdb.c

index bfca24a5b9e167ba303c5eed72f6195113a4343d..32355c1398f5fdce5890ad5d46325c9bfdaf5815 100644 (file)
@@ -5363,6 +5363,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
        } else if (!dcnull) {
                dns_name_copy(dcname, foundname);
        }
+
        /*
         * We now go looking for an NS rdataset at the node.
         */
@@ -5378,7 +5379,22 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
                header_next = header->next;
                if (check_stale_header(node, header, &locktype, lock, &search,
                                       &header_prev)) {
-                       /* Do nothing. */
+                       /*
+                        * The function dns_rbt_findnode found us the a matching
+                        * node for 'name' and stored the result in 'dcname'.
+                        * This is the deepest known zonecut in our database.
+                        * However, this node may be stale and if serve-stale
+                        * is not enabled (in other words 'stale-answer-enable'
+                        * is set to no), this node may not be used as a
+                        * zonecut we know about. If so, find the deepest
+                        * zonecut from this node up and return that instead.
+                        */
+                       NODE_UNLOCK(lock, locktype);
+                       result = find_deepest_zonecut(&search, node, nodep,
+                                                     foundname, rdataset,
+                                                     sigrdataset);
+                       dns_name_copy(foundname, dcname);
+                       goto tree_exit;
                } else if (EXISTS(header) && !ANCIENT(header)) {
                        /*
                         * If we found a type we were looking for, remember