mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-27 20:25:55 -04:00
[9.20] 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.20' into 'bind-9.20' See merge request isc-projects/bind9!10956
This commit is contained in:
commit
968a6be41f
8 changed files with 74 additions and 80 deletions
|
|
@ -4754,5 +4754,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
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ enum {
|
|||
#define DNS_DBADD_EXACT 0x04
|
||||
#define DNS_DBADD_EXACTTTL 0x08
|
||||
#define DNS_DBADD_PREFETCH 0x10
|
||||
#define DNS_DBADD_EQUALOK 0x20
|
||||
/*@}*/
|
||||
|
||||
/*%
|
||||
|
|
@ -1248,6 +1249,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.
|
||||
|
|
@ -1277,8 +1282,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.
|
||||
|
|
|
|||
|
|
@ -101,8 +101,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')
|
||||
|
|
@ -693,14 +691,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
|
||||
|
|
|
|||
|
|
@ -2993,13 +2993,23 @@ find_header:
|
|||
*/
|
||||
if (trust < header->trust && (ACTIVE(header, now) || header_nx))
|
||||
{
|
||||
dns_slabheader_destroy(&newheader);
|
||||
if (addedrdataset != NULL) {
|
||||
bindrdataset(qpdb, qpnode, header, now,
|
||||
nlocktype, tlocktype,
|
||||
addedrdataset DNS__DB_FLARG_PASS);
|
||||
isc_result_t result = DNS_R_UNCHANGED;
|
||||
bindrdataset(qpdb, qpnode, header, now, nlocktype,
|
||||
tlocktype,
|
||||
addedrdataset DNS__DB_FLARG_PASS);
|
||||
if (ACTIVE(header, now) &&
|
||||
(options & DNS_DBADD_EQUALOK) != 0 &&
|
||||
dns_rdataslab_equalx(
|
||||
(unsigned char *)header,
|
||||
(unsigned char *)newheader,
|
||||
(unsigned int)(sizeof(*newheader)),
|
||||
qpdb->common.rdclass,
|
||||
(dns_rdatatype_t)header->type))
|
||||
{
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
return DNS_R_UNCHANGED;
|
||||
dns_slabheader_destroy(&newheader);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2729,14 +2729,24 @@ find_header:
|
|||
if (rbtversion == NULL && trust < header->trust &&
|
||||
(ACTIVE(header, now) || header_nx))
|
||||
{
|
||||
dns_slabheader_destroy(&newheader);
|
||||
if (addedrdataset != NULL) {
|
||||
dns__rbtdb_bindrdataset(
|
||||
rbtdb, rbtnode, header, now,
|
||||
isc_rwlocktype_write,
|
||||
addedrdataset DNS__DB_FLARG_PASS);
|
||||
result = DNS_R_UNCHANGED;
|
||||
dns__rbtdb_bindrdataset(
|
||||
rbtdb, rbtnode, header, now,
|
||||
isc_rwlocktype_write,
|
||||
addedrdataset DNS__DB_FLARG_PASS);
|
||||
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;
|
||||
dns_slabheader_destroy(&newheader);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -676,18 +676,3 @@ dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
|
|||
rdataset->ttl = ttl;
|
||||
sigrdataset->ttl = ttl;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,9 +125,6 @@ static void
|
|||
rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name);
|
||||
static void
|
||||
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
|
||||
static bool
|
||||
rdataset_equals(const dns_rdataset_t *rdataset1,
|
||||
const dns_rdataset_t *rdataset2);
|
||||
|
||||
/*% Note: the "const void *" are just to make qsort happy. */
|
||||
static int
|
||||
|
|
@ -1158,7 +1155,6 @@ dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = {
|
|||
.clearprefetch = rdataset_clearprefetch,
|
||||
.setownercase = rdataset_setownercase,
|
||||
.getownercase = rdataset_getownercase,
|
||||
.equals = rdataset_equals,
|
||||
};
|
||||
|
||||
/* Fixed RRSet helper macros */
|
||||
|
|
@ -1477,18 +1473,3 @@ rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
|
|||
unlock:
|
||||
dns_db_unlocknode(header->db, header->node, isc_rwlocktype_read);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned char *header1 = rdataset1->slab.raw - sizeof(dns_slabheader_t);
|
||||
unsigned char *header2 = rdataset2->slab.raw - sizeof(dns_slabheader_t);
|
||||
return dns_rdataslab_equalx(header1, header2, sizeof(dns_slabheader_t),
|
||||
rdataset1->rdclass, rdataset2->type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5877,7 +5877,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_fetchresponse_t *resp = NULL;
|
||||
unsigned int options;
|
||||
unsigned int options = 0, equalok = 0;
|
||||
bool fail;
|
||||
unsigned int valoptions = 0;
|
||||
bool checknta = true;
|
||||
|
|
@ -6089,6 +6089,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)
|
||||
{
|
||||
|
|
@ -6114,10 +6115,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 &&
|
||||
|
|
@ -6141,25 +6155,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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue