]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Check whether a rejected rrset is different
authorEvan Hunt <each@isc.org>
Thu, 20 Feb 2025 01:51:53 +0000 (17:51 -0800)
committerEvan Hunt <each@isc.org>
Thu, 20 Feb 2025 02:55:01 +0000 (18:55 -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.

(cherry picked from commit 6aba56ae89cde535fcc6fbee0366c843cdf47845)

lib/dns/dnsrps.c
lib/dns/include/dns/rdataset.h
lib/dns/keytable.c
lib/dns/ncache.c
lib/dns/rbtdb.c
lib/dns/rdatalist.c
lib/dns/rdataset.c
lib/dns/resolver.c
lib/dns/sdb.c
lib/dns/sdlz.c

index 7fa1523c67d908446fef59242dfa2d5bfb3e2564..e1bf958e57d50e56bbd9d50941346188b46f5420 100644 (file)
@@ -995,6 +995,7 @@ static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
 };
 
index caa49c5845a115144c725aa408d8cdbaae7e080e..fec02474cf84961579cff224235aa753c33eb521 100644 (file)
@@ -86,6 +86,8 @@ typedef struct dns_rdatasetmethods {
        void (*getownercase)(const dns_rdataset_t *rdataset, dns_name_t *name);
        isc_result_t (*addglue)(dns_rdataset_t  *rdataset,
                                dns_dbversion_t *version, dns_message_t *msg);
+       bool (*equals)(const dns_rdataset_t *rdataset1,
+                      const dns_rdataset_t *rdataset2);
 } dns_rdatasetmethods_t;
 
 #define DNS_RDATASET_MAGIC     ISC_MAGIC('D', 'N', 'S', 'R')
@@ -629,4 +631,14 @@ dns_trust_totext(dns_trust_t trust);
  * Display trust in textual form.
  */
 
+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.
+ */
 ISC_LANG_ENDDECLS
index e52d45d0e5c4833eebba8c47fd5d5b3d3e013758..215afa340b42be205f5cf31739fbfe9b540b1446 100644 (file)
@@ -90,7 +90,8 @@ static dns_rdatasetmethods_t methods = {
        NULL, /* clearprefetch */
        NULL,
        NULL,
-       NULL /* addglue */
+       NULL, /* addglue */
+       NULL, /* equals */
 };
 
 static void
index da980d28fafbca60a82608b16d794690db25cf84..4018aa97382cb0029fb5958ca7ae24d89a9f36db 100644 (file)
@@ -524,7 +524,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL,              /* clearprefetch */
        NULL,              /* setownercase */
        NULL,              /* getownercase */
-       NULL               /* addglue */
+       NULL,              /* addglue */
+       NULL,              /* equals */
 };
 
 isc_result_t
index 6b35b25715289367c1fb1a29e9de5ba8b4e1c037..4bd5c728b883ea55826f6401d1addfe0a756c209 100644 (file)
@@ -608,6 +608,9 @@ rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
 static isc_result_t
 rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
                 dns_message_t *msg);
+static bool
+rdataset_equals(const dns_rdataset_t *rdataset1,
+               const dns_rdataset_t *rdataset2);
 static void
 free_gluetable(rbtdb_version_t *version);
 static isc_result_t
@@ -628,7 +631,8 @@ static dns_rdatasetmethods_t rdataset_methods = { rdataset_disassociate,
                                                  rdataset_clearprefetch,
                                                  rdataset_setownercase,
                                                  rdataset_getownercase,
-                                                 rdataset_addglue };
+                                                 rdataset_addglue,
+                                                 rdataset_equals };
 
 static dns_rdatasetmethods_t slab_methods = {
        rdataset_disassociate,
@@ -646,7 +650,8 @@ static dns_rdatasetmethods_t slab_methods = {
        NULL, /* clearprefetch */
        NULL, /* setownercase */
        NULL, /* getownercase */
-       NULL  /* addglue */
+       NULL, /* addglue */
+       NULL, /* equals */
 };
 
 static void
@@ -10398,6 +10403,23 @@ no_glue:
        /* UNREACHABLE */
 }
 
+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;
+       }
+
+       uint8_t *header1 = (uint8_t *)rdataset1->private3 -
+                          sizeof(rdatasetheader_t);
+       uint8_t *header2 = (uint8_t *)rdataset2->private3 -
+                          sizeof(rdatasetheader_t);
+       return dns_rdataslab_equalx(header1, header2, sizeof(rdatasetheader_t),
+                                   rdataset1->rdclass, rdataset2->type);
+}
+
 /*%
  * Routines for LRU-based cache management.
  */
index 971e4e656ce2cc6c79470cb0e812f2ee2e1e578a..5cccea514983068d9d39690ae20861836fddaef5 100644 (file)
@@ -42,7 +42,8 @@ static dns_rdatasetmethods_t methods = {
        NULL, /* clearprefetch */
        isc__rdatalist_setownercase,
        isc__rdatalist_getownercase,
-       NULL /* addglue */
+       NULL, /* addglue */
+       NULL, /* equals */
 };
 
 void
index 532e49ac00b855565f4fb82d817aa87316623f6d..a0ba221fdaaffa852078a3865b31bbe954065064 100644 (file)
@@ -196,7 +196,8 @@ static dns_rdatasetmethods_t question_methods = {
        NULL, /* clearprefetch */
        NULL, /* setownercase */
        NULL, /* getownercase */
-       NULL  /* addglue */
+       NULL, /* addglue */
+       NULL, /* equals */
 };
 
 void
@@ -752,3 +753,18 @@ dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
 
        return (rdataset->methods->addglue)(rdataset, version, msg);
 }
+
+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 b4e2983b04019188b89aa7e9c3609218bf03376b..00b10c2bd53e3be64fb2a1a369ab530d9504c76c 100644 (file)
@@ -6590,33 +6590,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) {
index aa0d5478a33ba564bd1121f7e5dc83ae1ff561d1..40fe6f7ab2b1f8c4242a61e6da0ccf3709030be3 100644 (file)
@@ -1439,7 +1439,8 @@ static dns_rdatasetmethods_t sdb_rdataset_methods = {
        NULL, /* clearprefetch */
        NULL, /* setownercase */
        NULL, /* getownercase */
-       NULL  /* addglue */
+       NULL, /* addglue */
+       NULL, /* equals */
 };
 
 static void
index b71fa8cb6ed49662deea35693bc53b125fb6ed08..ebd7fdd50b66f35b6d7bf445d8f7b63a8732d5ae 100644 (file)
@@ -1451,7 +1451,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL, /* clearprefetch */
        NULL, /* setownercase */
        NULL, /* getownercase */
-       NULL  /* addglue */
+       NULL, /* addglue */
+       NULL, /* equals */
 };
 
 static void