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)
NULL,
NULL,
NULL,
+ NULL,
NULL
};
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')
* 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
NULL, /* clearprefetch */
NULL,
NULL,
- NULL /* addglue */
+ NULL, /* addglue */
+ NULL, /* equals */
};
static void
NULL, /* clearprefetch */
NULL, /* setownercase */
NULL, /* getownercase */
- NULL /* addglue */
+ NULL, /* addglue */
+ NULL, /* equals */
};
isc_result_t
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
rdataset_clearprefetch,
rdataset_setownercase,
rdataset_getownercase,
- rdataset_addglue };
+ rdataset_addglue,
+ rdataset_equals };
static dns_rdatasetmethods_t slab_methods = {
rdataset_disassociate,
NULL, /* clearprefetch */
NULL, /* setownercase */
NULL, /* getownercase */
- NULL /* addglue */
+ NULL, /* addglue */
+ NULL, /* equals */
};
static void
/* 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.
*/
NULL, /* clearprefetch */
isc__rdatalist_setownercase,
isc__rdatalist_getownercase,
- NULL /* addglue */
+ NULL, /* addglue */
+ NULL, /* equals */
};
void
NULL, /* clearprefetch */
NULL, /* setownercase */
NULL, /* getownercase */
- NULL /* addglue */
+ NULL, /* addglue */
+ NULL, /* equals */
};
void
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;
+}
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) {
NULL, /* clearprefetch */
NULL, /* setownercase */
NULL, /* getownercase */
- NULL /* addglue */
+ NULL, /* addglue */
+ NULL, /* equals */
};
static void
NULL, /* clearprefetch */
NULL, /* setownercase */
NULL, /* getownercase */
- NULL /* addglue */
+ NULL, /* addglue */
+ NULL, /* equals */
};
static void