[9.18] fix: usr: Missing DNSSEC information when CD bit is set in query

The RRSIGs for glue records were not being cached correctly for CD=1 queries.  This has been fixed.

Closes #5502

Backport of MR !10938

Merge branch 'backport-5502-fix-missing-rrsig-with-cd-9.18' into 'bind-9.18'

See merge request isc-projects/bind9!10957
This commit is contained in:
Mark Andrews 2025-09-11 18:48:24 +10:00
commit 990586f049
12 changed files with 57 additions and 84 deletions

View file

@ -4620,5 +4620,16 @@ n=$((n + 1))
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "test that RRSIGS are returned for glue name with CD=1 ($n)"
ret=0
dig_with_opts @10.53.0.4 ns3.secure.example A +cd >dig.out.ns4.test$n
grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
grep "ANSWER: 2," dig.out.ns4.test$n >/dev/null || ret=1
grep "ns3\.secure\.example\..[0-9]*.IN.A.10\.53\.0.3" dig.out.ns4.test$n >/dev/null || ret=1
grep "ns3\.secure\.example\..[0-9]*.IN.RRSIG.A " dig.out.ns4.test$n >/dev/null || ret=1
n=$((n + 1))
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

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

@ -86,8 +86,6 @@ 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')
@ -631,14 +629,4 @@ 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

View file

@ -91,7 +91,6 @@ static dns_rdatasetmethods_t methods = {
NULL,
NULL,
NULL, /* addglue */
NULL, /* equals */
};
static void

View file

@ -525,7 +525,6 @@ static dns_rdatasetmethods_t rdataset_methods = {
NULL, /* setownercase */
NULL, /* getownercase */
NULL, /* addglue */
NULL, /* equals */
};
isc_result_t

View file

@ -610,9 +610,6 @@ 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
@ -633,8 +630,7 @@ static dns_rdatasetmethods_t rdataset_methods = { rdataset_disassociate,
rdataset_clearprefetch,
rdataset_setownercase,
rdataset_getownercase,
rdataset_addglue,
rdataset_equals };
rdataset_addglue };
static dns_rdatasetmethods_t slab_methods = {
rdataset_disassociate,
@ -653,7 +649,6 @@ static dns_rdatasetmethods_t slab_methods = {
NULL, /* setownercase */
NULL, /* getownercase */
NULL, /* addglue */
NULL, /* equals */
};
static void
@ -6510,13 +6505,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;
}
/*
@ -10398,23 +10402,6 @@ 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.
*/

View file

@ -43,7 +43,6 @@ static dns_rdatasetmethods_t methods = {
isc__rdatalist_setownercase,
isc__rdatalist_getownercase,
NULL, /* addglue */
NULL, /* equals */
};
void

View file

@ -197,7 +197,6 @@ static dns_rdatasetmethods_t question_methods = {
NULL, /* setownercase */
NULL, /* getownercase */
NULL, /* addglue */
NULL, /* equals */
};
void
@ -753,18 +752,3 @@ 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;
}

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;

View file

@ -1440,7 +1440,6 @@ static dns_rdatasetmethods_t sdb_rdataset_methods = {
NULL, /* setownercase */
NULL, /* getownercase */
NULL, /* addglue */
NULL, /* equals */
};
static void

View file

@ -1452,7 +1452,6 @@ static dns_rdatasetmethods_t rdataset_methods = {
NULL, /* setownercase */
NULL, /* getownercase */
NULL, /* addglue */
NULL, /* equals */
};
static void