]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Consider non-stale data when in serve-stale mode
authorMatthijs Mekking <matthijs@isc.org>
Thu, 17 Nov 2022 13:52:26 +0000 (13:52 +0000)
committerMatthijs Mekking <matthijs@isc.org>
Mon, 9 Jan 2023 13:26:02 +0000 (14:26 +0100)
With 'stale-answer-enable yes;' and 'stale-answer-client-timeout off;',
consider the following situation:

A CNAME record and its target record are in the cache, then the CNAME
record expires, but the target record is still valid.

When a new query for the CNAME record arrives, and the query fails,
the stale record is used, and then the query "restarts" to follow
the CNAME target. The problem is that the query's multiple stale
options (like DNS_DBFIND_STALEOK) are not reset, so 'query_lookup()'
treats the restarted query as a lookup following a failed lookup,
and returns a SERVFAIL answer when there is no stale data found in the
cache, even if there is valid non-stale data there available.

With this change, query_lookup() now considers non-stale data in the
cache in the first place, and returns it if it is available.

(cherry picked from commit 91a1a8efc5bca44ff3aa6861c31759449ea65ecd)

lib/dns/include/dns/rdataset.h
lib/ns/query.c

index 6ae21dcc4b539e25b76ef3c1283a9d8b47534929..d240d2e019739061b234091c375e13887a47bb96 100644 (file)
@@ -156,6 +156,11 @@ struct dns_rdataset {
  *
  * \def DNS_RDATASETATTR_LOADORDER
  *     Output the RRset in load order.
+ *
+ * \def DNS_RDATASETATTR_STALE_ADDED
+ *     Set on rdatasets that were added during a stale-answer-client-timeout
+ *     lookup. In other words, the RRset was added during a lookup of stale
+ *     data and does not necessarily mean that the rdataset itself is stale.
  */
 
 #define DNS_RDATASETATTR_NONE        0x00000000 /*%< No ordering. */
index d1fac6f383e435bcee3873bed9e356ececafb31d..35c6af86ce16b1059312af92fb13c39da5f07e91 100644 (file)
@@ -5866,6 +5866,7 @@ query_lookup(query_ctx_t *qctx) {
        dns_ttl_t stale_refresh = 0;
        bool dbfind_stale = false;
        bool stale_timeout = false;
+       bool answer_found = false;
        bool stale_found = false;
        bool stale_refresh_window = false;
        uint16_t ede = 0;
@@ -5973,6 +5974,14 @@ query_lookup(query_ctx_t *qctx) {
         */
        stale_timeout = ((dboptions & DNS_DBFIND_STALETIMEOUT) != 0);
 
+       if (dns_rdataset_isassociated(qctx->rdataset) &&
+           dns_rdataset_count(qctx->rdataset) > 0 && !STALE(qctx->rdataset))
+       {
+               /* Found non-stale usable rdataset. */
+               answer_found = true;
+               goto gotanswer;
+       }
+
        if (dbfind_stale || stale_refresh_window || stale_timeout) {
                dns_name_format(qctx->client->query.qname, namebuf,
                                sizeof(namebuf));
@@ -6099,7 +6108,8 @@ query_lookup(query_ctx_t *qctx) {
                }
        }
 
-       if (stale_timeout && stale_found) {
+gotanswer:
+       if (stale_timeout && (answer_found || stale_found)) {
                /*
                 * Mark RRsets that we are adding to the client message on a
                 * lookup during 'stale-answer-client-timeout', so we can