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)
NULL,
NULL,
NULL,
- NULL
};
static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = {
#define DNS_DBADD_EXACT 0x04
#define DNS_DBADD_EXACTTTL 0x08
#define DNS_DBADD_PREFETCH 0x10
+#define DNS_DBADD_EQUALOK 0x20
/*@}*/
/*%
* 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.
* 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.
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;
}
/*
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;
}
if (!need_validation || !ANSWER(rdataset)) {
options = 0;
+ equalok = 0;
if (ANSWER(rdataset) &&
rdataset->type != dns_rdatatype_rrsig)
{
{
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 &&
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;