2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-03 16:15:27 +00:00

Merge branch '901-empty-any' into 'master'

handle empty ANY query responses

Closes #901

See merge request isc-projects/bind9!1580
This commit is contained in:
Evan Hunt
2019-02-28 19:05:44 -05:00
6 changed files with 74 additions and 40 deletions

View File

@@ -1,3 +1,7 @@
5169. [bug] The presence of certain types in an otherwise
empty node could cause a crash while processing a
type ANY query. [GL #901]
5168. [bug] Do not crash on shutdown when RPZ fails to load. Also, 5168. [bug] Do not crash on shutdown when RPZ fails to load. Also,
keep previous version of the database if RPZ fails to keep previous version of the database if RPZ fails to
load. [GL #813] load. [GL #813]

View File

@@ -21,4 +21,5 @@ ns A 10.53.0.3
a A 10.0.0.1 a A 10.0.0.1
b A 10.0.0.2 b A 10.0.0.2
d A 10.0.0.4 d A 10.0.0.4
x DNSKEY 258 3 5 Cg==
z A 10.0.0.26 z A 10.0.0.26

View File

@@ -28,6 +28,7 @@ g A 10.0.0.7
z A 10.0.0.26 z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27 a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a x CNAME a
zz DNSKEY 258 3 5 Cg==
private NS ns.private private NS ns.private
ns.private A 10.53.0.2 ns.private A 10.53.0.2

View File

@@ -3635,6 +3635,19 @@ n=$((n+1))
test "$ret" -eq 0 || echo_i "failed" test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret)) status=$((status+ret))
echo_i "checking DNSSEC records are occluded from ANY in an insecure zone ($n)"
ret=0
dig_with_opts any x.insecure.example. @10.53.0.3 > dig.out.ns3.1.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.1.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.ns3.1.test$n > /dev/null || ret=1
dig_with_opts any zz.secure.example. @10.53.0.3 > dig.out.ns3.2.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.2.test$n > /dev/null || ret=1
# DNSKEY+RRSIG, NSEC+RRSIG
grep "ANSWER: 4," dig.out.ns3.2.test$n > /dev/null || ret=1
n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
# Note: after this check, ns4 will not be validating any more; do not add any # Note: after this check, ns4 will not be validating any more; do not add any
# further validation tests employing ns4 below this check. # further validation tests employing ns4 below this check.
echo_i "check that validation defaults to off when dnssec-enable is off ($n)" echo_i "check that validation defaults to off when dnssec-enable is off ($n)"

View File

@@ -127,7 +127,9 @@
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
None. The presence of certain record types in an otherwise empty
node of a zone could trigger an assertion failure while processing
a query of type ANY. [GL #901]
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>

View File

@@ -6727,7 +6727,7 @@ query_addnoqnameproof(query_ctx_t *qctx) {
*/ */
static isc_result_t static isc_result_t
query_respond_any(query_ctx_t *qctx) { query_respond_any(query_ctx_t *qctx) {
bool found = false; bool found = false, hidden = false;
dns_rdatasetiter_t *rdsiter = NULL; dns_rdatasetiter_t *rdsiter = NULL;
isc_result_t result; isc_result_t result;
dns_rdatatype_t onetype = 0; /* type to use for minimal-any */ dns_rdatatype_t onetype = 0; /* type to use for minimal-any */
@@ -6782,11 +6782,11 @@ query_respond_any(query_ctx_t *qctx) {
dns_rdatatype_isdnssec(qctx->rdataset->type)) dns_rdatatype_isdnssec(qctx->rdataset->type))
{ {
/* /*
* The zone is transitioning from insecure * The zone may be transitioning from insecure
* to secure. Hide the dnssec records from * to secure. Hide DNSSEC records from ANY queries.
* ANY queries.
*/ */
dns_rdataset_disassociate(qctx->rdataset); dns_rdataset_disassociate(qctx->rdataset);
hidden = true;
} else if (qctx->view->minimal_any && } else if (qctx->view->minimal_any &&
!TCP(qctx->client) && !WANTDNSSEC(qctx->client) && !TCP(qctx->client) && !WANTDNSSEC(qctx->client) &&
qctx->qtype == dns_rdatatype_any && qctx->qtype == dns_rdatatype_any &&
@@ -6808,7 +6808,8 @@ query_respond_any(query_ctx_t *qctx) {
qctx->rdataset->type == qctx->qtype) && qctx->rdataset->type == qctx->qtype) &&
qctx->rdataset->type != 0) qctx->rdataset->type != 0)
{ {
if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) if (NOQNAME(qctx->rdataset) &&
WANTDNSSEC(qctx->client))
{ {
qctx->noqname = qctx->rdataset; qctx->noqname = qctx->rdataset;
} else { } else {
@@ -6864,8 +6865,9 @@ query_respond_any(query_ctx_t *qctx) {
} }
qctx->rdataset = ns_client_newrdataset(qctx->client); qctx->rdataset = ns_client_newrdataset(qctx->client);
if (qctx->rdataset == NULL) if (qctx->rdataset == NULL) {
break; break;
}
} else { } else {
/* /*
* We're not interested in this rdataset. * We're not interested in this rdataset.
@@ -6886,48 +6888,59 @@ query_respond_any(query_ctx_t *qctx) {
} }
if (found) { if (found) {
/*
* Call hook if any answers were found.
* Do this before releasing qctx->fname, in case
* the hook function needs it.
*/
CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx); CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx);
if (qctx->fname != NULL) {
dns_message_puttempname(qctx->client->message,
&qctx->fname);
}
query_addauth(qctx);
return (ns_query_done(qctx));
} }
/*
* If we're here, no matching rdatasets were found. If we were
* searching for RRSIG/SIG, that may be okay, but otherwise
* something's gone wrong.
*/
INSIST(qctx->qtype == dns_rdatatype_rrsig ||
qctx->qtype == dns_rdatatype_sig);
if (qctx->fname != NULL) { if (qctx->fname != NULL) {
dns_message_puttempname(qctx->client->message, dns_message_puttempname(qctx->client->message, &qctx->fname);
&qctx->fname);
} }
if (!qctx->is_zone) { if (found) {
qctx->authoritative = false; /*
qctx->client->attributes &= ~NS_CLIENTATTR_RA; * At least one matching rdataset was found
*/
query_addauth(qctx); query_addauth(qctx);
return (ns_query_done(qctx)); } else if (qctx->qtype == dns_rdatatype_rrsig ||
qctx->qtype == dns_rdatatype_sig)
{
/*
* No matching rdatasets were found, but we got
* here on a search for RRSIG/SIG, so that's okay.
*/
if (!qctx->is_zone) {
qctx->authoritative = false;
qctx->client->attributes &= ~NS_CLIENTATTR_RA;
query_addauth(qctx);
return (ns_query_done(qctx));
}
if (qctx->qtype == dns_rdatatype_rrsig &&
dns_db_issecure(qctx->db))
{
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(qctx->client->query.qname,
namebuf, sizeof(namebuf));
ns_client_log(qctx->client, DNS_LOGCATEGORY_DNSSEC,
NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
"missing signature for %s", namebuf);
}
qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
return (query_sign_nodata(qctx));
} else if (!hidden) {
/*
* No matching rdatasets were found and nothing was
* deliberately hidden: something must have gone wrong.
*/
QUERY_ERROR(qctx, DNS_R_SERVFAIL);
} }
if (qctx->qtype == dns_rdatatype_rrsig && dns_db_issecure(qctx->db)) { return (ns_query_done(qctx));
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(qctx->client->query.qname,
namebuf, sizeof(namebuf));
ns_client_log(qctx->client, DNS_LOGCATEGORY_DNSSEC,
NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
"missing signature for %s", namebuf);
}
qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
return (query_sign_nodata(qctx));
cleanup: cleanup:
return (result); return (result);