]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Check whether a rejected rrset is different
authorEvan Hunt <each@isc.org>
Fri, 24 Jan 2025 01:16:30 +0000 (17:16 -0800)
committerEvan Hunt <each@isc.org>
Thu, 20 Feb 2025 01:25:20 +0000 (17:25 -0800)
Add a new dns_rdataset_equals() function to check whether two
rdatasets are equal in DNSSEC terms.

When an rdataset being cached is rejected because its trust
level is lower than the existing rdataset, we now check to see
whether the rejected data was identical to the existing data.
This allows us to cache a potentially useful RRSIG when handling
CD=1 queries, while still rejecting RRSIGs that would definitely
have resulted in a validation failure.

lib/dns/include/dns/rdataset.h
lib/dns/rdataset.c
lib/dns/rdataslab.c
lib/dns/resolver.c

index 289cfa6dd658ac0be668af981cf4247992af1b17..e54fbc6b6b7d8035fc6897bc5b872acfb2275f32 100644 (file)
@@ -100,6 +100,8 @@ struct dns_rdatasetmethods {
        isc_result_t (*addglue)(dns_rdataset_t  *rdataset,
                                dns_dbversion_t *version, dns_message_t *msg);
        dns_slabheader_t *(*getheader)(const dns_rdataset_t *rdataset);
+       bool (*equals)(const dns_rdataset_t *rdataset1,
+                      const dns_rdataset_t *rdataset2);
 };
 
 #define DNS_RDATASET_MAGIC     ISC_MAGIC('D', 'N', 'S', 'R')
@@ -676,3 +678,14 @@ dns_rdataset_getheader(const dns_rdataset_t *rdataset);
  * Requires:
  * \li 'rdataset' is a valid rdataset.
  */
+
+bool
+dns_rdataset_equals(const dns_rdataset_t *rdataset1,
+                   const dns_rdataset_t *rdataset2);
+/*%<
+ * Returns true if the rdata in the rdataset is equal.
+ *
+ * Requires:
+ * \li 'rdataset1' is a valid rdataset.
+ * \li 'rdataset2' is a valid rdataset.
+ */
index ceef803ee5dc4f2213dccbf507d866b7b320beac..d0962fe95e6b8876a2e9d2f3792ee8c0931c5751 100644 (file)
@@ -659,3 +659,18 @@ dns_rdataset_getheader(const dns_rdataset_t *rdataset) {
 
        return NULL;
 }
+
+bool
+dns_rdataset_equals(const dns_rdataset_t *rdataset1,
+                   const dns_rdataset_t *rdataset2) {
+       REQUIRE(DNS_RDATASET_VALID(rdataset1));
+       REQUIRE(DNS_RDATASET_VALID(rdataset2));
+
+       if (rdataset1->methods->equals != NULL &&
+           rdataset1->methods->equals == rdataset2->methods->equals)
+       {
+               return (rdataset1->methods->equals)(rdataset1, rdataset2);
+       }
+
+       return false;
+}
index 65b803d162f0a737f6e4252267fe8e50c8e33ef3..e4fce867bae02fd89665b9a7df00be093a02592c 100644 (file)
@@ -115,6 +115,9 @@ static void
 rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
 static dns_slabheader_t *
 rdataset_getheader(const dns_rdataset_t *rdataset);
+static bool
+rdataset_equals(const dns_rdataset_t *rdataset1,
+               const dns_rdataset_t *rdataset2);
 
 /*% Note: the "const void *" are just to make qsort happy.  */
 static int
@@ -943,6 +946,7 @@ dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = {
        .setownercase = rdataset_setownercase,
        .getownercase = rdataset_getownercase,
        .getheader = rdataset_getheader,
+       .equals = rdataset_equals,
 };
 
 /* Fixed RRSet helper macros */
@@ -1234,3 +1238,19 @@ rdataset_getheader(const dns_rdataset_t *rdataset) {
        dns_slabheader_t *header = (dns_slabheader_t *)rdataset->slab.raw;
        return header - 1;
 }
+
+static bool
+rdataset_equals(const dns_rdataset_t *rdataset1,
+               const dns_rdataset_t *rdataset2) {
+       if (rdataset1->rdclass != rdataset2->rdclass ||
+           rdataset1->type != rdataset2->type)
+       {
+               return false;
+       }
+
+       dns_slabheader_t *header1 = (dns_slabheader_t *)rdataset1->slab.raw - 1;
+       dns_slabheader_t *header2 = (dns_slabheader_t *)rdataset2->slab.raw - 1;
+
+       return dns_rdataslab_equalx(header1, header2, rdataset1->rdclass,
+                                   rdataset2->type);
+}
index ec23f3b185262821492580f548c09c2d04c655e6..e99e21c76338bac54ce339c4213b8320cf870c63 100644 (file)
@@ -6096,33 +6096,43 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
                                if (result == DNS_R_UNCHANGED) {
                                        result = ISC_R_SUCCESS;
                                        if (!need_validation &&
-                                           ardataset != NULL &&
-                                           NEGATIVE(ardataset))
+                                           ardataset != NULL)
                                        {
                                                /*
                                                 * The answer in the
                                                 * cache is better than
-                                                * the answer we found,
-                                                * and is a negative
-                                                * cache entry, so we
+                                                * the answer we found.
+                                                * If it's a negative
+                                                * cache entry, we
                                                 * must set eresult
                                                 * appropriately.
                                                 */
                                                if (NXDOMAIN(ardataset)) {
                                                        eresult =
                                                                DNS_R_NCACHENXDOMAIN;
-                                               } else {
+                                               } else if (NEGATIVE(ardataset))
+                                               {
                                                        eresult =
                                                                DNS_R_NCACHENXRRSET;
                                                }
+
                                                /*
-                                                * We have a negative
-                                                * response from the
-                                                * cache so don't
-                                                * attempt to add the
-                                                * RRSIG rrset.
+                                                * 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. If
+                                                * not, move on.
                                                 */
-                                               continue;
+                                               if (sigrdataset != NULL &&
+                                                   !dns_rdataset_equals(
+                                                           rdataset,
+                                                           addedrdataset))
+                                               {
+                                                       continue;
+                                               }
                                        }
                                }
                                if (result != ISC_R_SUCCESS) {