2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 13:38:26 +00:00

[9.18] fix: usr: Remove NSEC/DS/NSEC3 RRSIG check from dns_message_parse

Previously, when parsing responses, named incorrectly rejected responses without matching RRSIG records for NSEC/DS/NSEC3 records in the authority section. This rejection, if appropriate, should have been left for the validator to determine and has been fixed.

Closes #5185

Backport of MR !10125

Merge branch 'backport-5185-remove-rrsig-check-from-dns_message_parse-9.18' into 'bind-9.18'

See merge request isc-projects/bind9!10143
This commit is contained in:
Mark Andrews 2025-02-21 03:53:32 +00:00
commit b601cb32ee
4 changed files with 24 additions and 71 deletions

View File

@ -38,6 +38,7 @@ def logquery(type, qname):
# NS gets a unsigned response. # NS gets a unsigned response.
# DNSKEY get a unsigned NODATA response. # DNSKEY get a unsigned NODATA response.
# A gets a signed response. # A gets a signed response.
# TXT gets a signed NODATA response without RRSIG.
# All other types get a unsigned NODATA response. # All other types get a unsigned NODATA response.
############################################################################ ############################################################################
def create_response(msg): def create_response(msg):
@ -72,6 +73,11 @@ def create_response(msg):
r.answer.append(dns.rrset.from_text(qname, 1, IN, NS, ".")) r.answer.append(dns.rrset.from_text(qname, 1, IN, NS, "."))
elif rrtype == SOA: elif rrtype == SOA:
r.answer.append(dns.rrset.from_text(qname, 1, IN, SOA, ". . 0 0 0 0 0")) r.answer.append(dns.rrset.from_text(qname, 1, IN, SOA, ". . 0 0 0 0 0"))
elif rrtype == TXT:
r.authority.append(dns.rrset.from_text(qname, 1, IN, SOA, ". . 0 0 0 0 0"))
r.authority.append(
dns.rrset.from_text(qname, 1, IN, NSEC, qname + " A NS SOA RRSIG NSEC")
)
else: else:
r.authority.append(dns.rrset.from_text(qname, 1, IN, SOA, ". . 0 0 0 0 0")) r.authority.append(dns.rrset.from_text(qname, 1, IN, SOA, ". . 0 0 0 0 0"))
r.flags |= dns.flags.AA r.flags |= dns.flags.AA

View File

@ -43,3 +43,5 @@ ds-rrsigs-stripped. NS ns2.ds-rrsigs-stripped.
ns2.ds-rrsigs-stripped. A 10.53.0.2 ns2.ds-rrsigs-stripped. A 10.53.0.2
inconsistent. NS ns2.inconsistent. inconsistent. NS ns2.inconsistent.
ns2.inconsistent. A 10.53.0.2 ns2.inconsistent. A 10.53.0.2
nsec-rrsigs-stripped. NS ns10.nsec-rrsigs-stripped.
ns10.nsec-rrsigs-stripped. A 10.53.0.10

View File

@ -4553,5 +4553,21 @@ n=$((n + 1))
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret)) status=$((status + ret))
echo_i "checking that a insecure negative response where there is a NSEC without a RRSIG succeeds ($n)"
ret=0
# check server preconditions
dig_with_opts +notcp @10.53.0.10 nsec-rrsigs-stripped. TXT +dnssec >dig.out.ns10.test$n
grep "status: NOERROR" dig.out.ns10.test$n >/dev/null || ret=1
grep "QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 1" dig.out.ns10.test$n >/dev/null || ret=1
grep "IN.RRSIG.NSEC" dig.out.ns10.test$n >/dev/null && ret=1
# check resolver succeeds
dig_with_opts @10.53.0.4 nsec-rrsigs-stripped. TXT +dnssec >dig.out.ns4.test$n
grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
grep "QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 1" dig.out.ns4.test$n >/dev/null || ret=1
grep "IN.RRSIG.NSEC" 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" echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1 [ $status -eq 0 ] || exit 1

View File

@ -1197,62 +1197,6 @@ update(dns_section_t section, dns_rdataclass_t rdclass) {
return false; return false;
} }
/*
* Check to confirm that all DNSSEC records (DS, NSEC, NSEC3) have
* covering RRSIGs.
*/
static bool
auth_signed(dns_namelist_t *section) {
dns_name_t *name;
for (name = ISC_LIST_HEAD(*section); name != NULL;
name = ISC_LIST_NEXT(name, link))
{
int auth_dnssec = 0, auth_rrsig = 0;
dns_rdataset_t *rds;
for (rds = ISC_LIST_HEAD(name->list); rds != NULL;
rds = ISC_LIST_NEXT(rds, link))
{
switch (rds->type) {
case dns_rdatatype_ds:
auth_dnssec |= 0x1;
break;
case dns_rdatatype_nsec:
auth_dnssec |= 0x2;
break;
case dns_rdatatype_nsec3:
auth_dnssec |= 0x4;
break;
case dns_rdatatype_rrsig:
break;
default:
continue;
}
switch (rds->covers) {
case dns_rdatatype_ds:
auth_rrsig |= 0x1;
break;
case dns_rdatatype_nsec:
auth_rrsig |= 0x2;
break;
case dns_rdatatype_nsec3:
auth_rrsig |= 0x4;
break;
default:
break;
}
}
if (auth_dnssec != auth_rrsig) {
return false;
}
}
return true;
}
static isc_result_t static isc_result_t
getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
dns_section_t sectionid, unsigned int options) { dns_section_t sectionid, unsigned int options) {
@ -1723,21 +1667,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
INSIST(!free_name); INSIST(!free_name);
} }
/*
* If any of DS, NSEC or NSEC3 appeared in the
* authority section of a query response without
* a covering RRSIG, FORMERR
*/
if (sectionid == DNS_SECTION_AUTHORITY &&
msg->opcode == dns_opcode_query &&
((msg->flags & DNS_MESSAGEFLAG_QR) != 0) &&
((msg->flags & DNS_MESSAGEFLAG_TC) == 0) && !preserve_order &&
!auth_signed(section))
{
/* XXX test coverage */
DO_ERROR(DNS_R_FORMERR);
}
if (seen_problem) { if (seen_problem) {
result = DNS_R_RECOVERABLE; result = DNS_R_RECOVERABLE;
} }