Fix missing RRSIGs for "glue" lookups with CD=1

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 b954a1df43)
This commit is contained in:
Mark Andrews 2025-09-10 16:18:41 +10:00
parent 1162ec2189
commit 018ecbb0c8
4 changed files with 45 additions and 28 deletions

View file

@ -996,7 +996,6 @@ static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
NULL,
NULL,
NULL,
NULL
};
static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = {

View 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.

View 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;
}
/*

View 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;