]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix missing RRSIGs for "glue" lookups with CD=1
authorMark Andrews <marka@isc.org>
Wed, 10 Sep 2025 06:18:41 +0000 (16:18 +1000)
committerMark Andrews <marka@isc.org>
Wed, 10 Sep 2025 22:27:50 +0000 (08:27 +1000)
The code to test whether to store the RRSIGs on DNS_R_UNCHANGED
with CD=1 was failing because the comparison methods of the two
rdatatset instances were not compatible.  Move the testing into
dns_db_addrdataset(), and request it by setting the DNS_ADD_EQUALOK
option.  If the option is set and the old and new rrsets compare
as equal, dns_db_addrdataset() returns ISC_R_SUCCESS instead of
DNS_R_UNCHANGED.

(cherry picked from commit b954a1df43e6e6e5ff60f1da1240ece644b7e190)

lib/dns/dnsrps.c
lib/dns/include/dns/db.h
lib/dns/rbtdb.c
lib/dns/resolver.c

index e1bf958e57d50e56bbd9d50941346188b46f5420..3cbc98583cad73bfc9e0a8ba47066bf935a4202e 100644 (file)
@@ -996,7 +996,6 @@ static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
        NULL,
        NULL,
        NULL,
-       NULL
 };
 
 static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = {
index 5eb2cea58fd2dfe4f49d8efa9d5c615cea01607e..882b568b68cd35ffbf7a6842b7e4c380c277dcda 100644 (file)
@@ -287,6 +287,7 @@ struct dns_dbonupdatelistener {
 #define DNS_DBADD_EXACT           0x04
 #define DNS_DBADD_EXACTTTL 0x08
 #define DNS_DBADD_PREFETCH 0x10
+#define DNS_DBADD_EQUALOK  0x20
 /*@}*/
 
 /*%
@@ -1228,6 +1229,10 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
  *     the old and new rdata sets.  If #DNS_DBADD_EXACTTTL is set then both
  *     the old and new rdata sets must have the same ttl.
  *
+ * \li If the #DNS_DBADD_EQUALOK option is set, and the database is not
+ *     changed, compare the old and new rdatasets; if they are equal,
+ *     return #ISC_R_SUCCESS instead of #DNS_R_UNCHANGED.
+ *
  * \li The 'now' field is ignored if 'db' is a zone database.  If 'db' is
  *     a cache database, then the added rdataset will expire no later than
  *     now + rdataset->ttl.
@@ -1257,8 +1262,12 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
  * Returns:
  *
  * \li #ISC_R_SUCCESS
- * \li #DNS_R_UNCHANGED                        The operation did not change
- * anything. \li       #ISC_R_NOMEMORY \li     #DNS_R_NOTEXACT
+ * \li #DNS_R_UNCHANGED        The operation did not change anything.
+ * \li #ISC_R_NOMEMORY
+ * \li #DNS_R_NOTEXACT         The TTL didn't match and #DNS_DBADD_EXACTTTL
+ *                             was set, or there was a partial overlap
+ *                             between the old and new rdatasets and
+ *                             DNS_DBADD_EXACT was set.
  *
  * \li Other results are possible, depending upon the database
  *     implementation used.
index 54363c0319efddca1e86d7b62c45d2da8ca1c7e9..8fedf2cff9f11de38736aa738027f7637409ad49 100644 (file)
@@ -6510,13 +6510,22 @@ find_header:
                if (rbtversion == NULL && trust < header->trust &&
                    (ACTIVE(header, now) || header_nx))
                {
-                       free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
-                       if (addedrdataset != NULL) {
-                               bind_rdataset(rbtdb, rbtnode, header, now,
-                                             isc_rwlocktype_write,
-                                             addedrdataset);
+                       result = DNS_R_UNCHANGED;
+                       bind_rdataset(rbtdb, rbtnode, header, now,
+                                     isc_rwlocktype_write, addedrdataset);
+                       if (ACTIVE(header, now) &&
+                           (options & DNS_DBADD_EQUALOK) != 0 &&
+                           dns_rdataslab_equalx(
+                                   (unsigned char *)header,
+                                   (unsigned char *)newheader,
+                                   (unsigned int)(sizeof(*newheader)),
+                                   rbtdb->common.rdclass,
+                                   (dns_rdatatype_t)header->type))
+                       {
+                               result = ISC_R_SUCCESS;
                        }
-                       return DNS_R_UNCHANGED;
+                       free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                       return result;
                }
 
                /*
index ff845ec1d84a879e6608e513ceb819070cea33fd..2c354f565ed32c55b94e7311951978cf983113c3 100644 (file)
@@ -6331,7 +6331,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
        bool have_answer = false;
        isc_result_t result, eresult = ISC_R_SUCCESS;
        dns_fetchevent_t *event = NULL;
-       unsigned int options;
+       unsigned int options = 0, equalok = 0;
        isc_task_t *task;
        bool fail;
        unsigned int valoptions = 0;
@@ -6548,6 +6548,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
                        }
                        if (!need_validation || !ANSWER(rdataset)) {
                                options = 0;
+                               equalok = 0;
                                if (ANSWER(rdataset) &&
                                    rdataset->type != dns_rdatatype_rrsig)
                                {
@@ -6573,10 +6574,23 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
                                {
                                        options |= DNS_DBADD_FORCE;
                                }
+                               /*
+                                * If we're validating and passing the added
+                                * rdataset back to the caller, then we ask
+                                * dns_db_addrdataset() to compare the old and
+                                * new rdatasets whenever the result would
+                                * normally have been DNS_R_UNCHANGED, and to
+                                * return ISC_R_SUCCESS if they compare equal.
+                                * This allows us to continue and cache RRSIGs
+                                * in that case.
+                                */
+                               if (!need_validation && ardataset != NULL) {
+                                       equalok = DNS_DBADD_EQUALOK;
+                               }
                                addedrdataset = ardataset;
                                result = dns_db_addrdataset(
                                        fctx->cache, node, NULL, now, rdataset,
-                                       options, addedrdataset);
+                                       options | equalok, addedrdataset);
                                if (result == DNS_R_UNCHANGED) {
                                        result = ISC_R_SUCCESS;
                                        if (!need_validation &&
@@ -6600,25 +6614,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
                                                                DNS_R_NCACHENXRRSET;
                                                }
                                                continue;
-                                       } else if (!need_validation &&
-                                                  ardataset != NULL &&
-                                                  sigrdataset != NULL &&
-                                                  !dns_rdataset_equals(
-                                                          rdataset, ardataset))
-                                       {
-                                               /*
-                                                * The cache wasn't updated
-                                                * because something was
-                                                * already there. If the
-                                                * data was the same as what
-                                                * we were trying to add,
-                                                * then sigrdataset might
-                                                * still be useful, and we
-                                                * should carry on caching
-                                                * it. Otherwise, move on.
-                                                */
+                                       }
+                                       if (equalok) {
                                                continue;
                                        }
+                                       result = ISC_R_SUCCESS;
                                }
                                if (result != ISC_R_SUCCESS) {
                                        break;