badds NS ns.badds
ns.badds A 10.53.0.3
+; A subdomain with a corrupt DS, but locally trusted by the forwarder
+localkey NS ns.localkey
+ns.localkey A 10.53.0.3
+
; A dynamic secure subdomain
dynamic NS dynamic
dynamic A 10.53.0.3
# Get the DS records for the "example." zone.
for subdomain in digest-alg-unsupported ds-unsupported secure badds \
- bogus dynamic keyless nsec3 optout \
+ bogus localkey dynamic keyless nsec3 optout \
nsec3-unknown optout-unknown multiple rsasha256 rsasha512 \
kskonly update-nsec3 auto-nsec auto-nsec3 secure.below-cname \
ttlpatch split-dnssec split-smart expired expiring upper lower \
allow-update { any; };
};
+zone "localkey.example" {
+ type primary;
+ file "localkey.example.db.signed";
+ allow-update { any; };
+};
+
zone "dynamic.example" {
type primary;
file "dynamic.example.db.signed";
"$SIGNER" -P -o "$zone" "$zonefile" >/dev/null
sed -e 's/bogus/badds/g' <dsset-bogus.example. >dsset-badds.example.
+#
+# Same as badds, but locally trusted by the forwarder
+#
+zone=localkey.example.
+infile=bogus.example.db.in
+zonefile=localkey.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
+
+cat "$infile" "$keyname.key" >"$zonefile"
+
+"$SIGNER" -P -o "$zone" "$zonefile" >/dev/null
+sed -e 's/bogus/localkey/g' <dsset-bogus.example. >dsset-localkey.example.
+keyfile_to_static_keys $keyname >../ns9/trusted-localkey.conf
+
#
# A zone with future signatures.
#
--- /dev/null
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// NS4
+
+options {
+ query-source address 10.53.0.4;
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation yes;
+ minimal-responses no;
+
+};
+
+# Note: This is deliberately wrong! The bind.keys file contains
+# the real DNS root key, so it won't work with the local toy
+# root zones used in the tests. This is to test a forwarder
+# talking to a resolver with a misconfigured trust anchor.
+include "../../../../../bind.keys";
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../_common/root.hint";
+};
+
+zone "corp" {
+ type static-stub;
+ server-addresses { 10.53.0.2; };
+};
};
include "trusted.conf";
+include "trusted-localkey.conf";
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
status=$((status + ret))
+echo_i "checking validating forwarder behavior with mismatching NS ($n)"
+ret=0
+rndccmd 10.53.0.4 flush 2>&1 | sed 's/^/ns4 /' | cat_i
+$DIG +tcp +cd -p "$PORT" -t ns inconsistent @10.53.0.9 >dig.out.ns9.test$n.1 || ret=1
+grep "ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1" dig.out.ns9.test$n.1 >/dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns9.test$n.1 >/dev/null && ret=1
+$DIG +tcp +cd +dnssec -p "$PORT" -t ns inconsistent @10.53.0.9 >dig.out.ns9.test$n.2 || ret=1
+grep "ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1" dig.out.ns9.test$n.2 >/dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns9.test$n.2 >/dev/null && ret=1
+$DIG +tcp +dnssec -p "$PORT" -t ns inconsistent @10.53.0.9 >dig.out.ns9.test$n.3 || ret=1
+grep "ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1" dig.out.ns9.test$n.3 >/dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns9.test$n.3 >/dev/null || ret=1
+n=$((n + 1))
+if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
+echo_i "checking forwarder CD behavior (DS mismatch and local trust anchor) ($n)"
+ret=0
+rndccmd 10.53.0.4 flush 2>&1 | sed 's/^/ns4 /' | cat_i
+# confirm invalid DS produces SERVFAIL in resolver
+$DIG +tcp +dnssec -p "$PORT" @10.53.0.4 localkey.example soa >dig.out.ns4.test$n || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n >/dev/null || ret=1
+# check that lookup using forwarder succeeds and that SERVFAIL was received
+nextpart ns9/named.run >/dev/null
+$DIG +tcp +dnssec -p "$PORT" @10.53.0.9 localkey.example soa >dig.out.ns9.test$n || ret=1
+grep "status: NOERROR" dig.out.ns9.test$n >/dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns9.test$n >/dev/null || ret=1
+nextpart ns9/named.run | grep 'status: SERVFAIL' >/dev/null || ret=1
+n=$((n + 1))
+if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
+copy_setports ns4/named5.conf.in ns4/named.conf
+rndccmd 10.53.0.4 reconfig 2>&1 | sed 's/^/ns4 /' | cat_i
+sleep 3
+
+echo_i "checking forwarder CD behavior (forward server with bad trust anchor) ($n)"
+ret=0
+# confirm invalid trust anchor produces SERVFAIL in resolver
+$DIG +tcp +dnssec -p "$PORT" @10.53.0.4 a.secure.example >dig.out.ns4.test$n || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n >/dev/null || ret=1
+# check that lookup using forwarder succeeds and that SERVFAIL was received
+nextpart ns9/named.run >/dev/null
+$DIG +tcp +dnssec -p "$PORT" @10.53.0.9 a.secure.example soa >dig.out.ns9.test$n || ret=1
+grep "status: NOERROR" dig.out.ns9.test$n >/dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns9.test$n >/dev/null || ret=1
+nextpart ns9/named.run | grep 'status: SERVFAIL' >/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
"ns3/future.example.db",
"ns3/keyless.example.db",
"ns3/kskonly.example.db",
+ "ns3/localkey.example.db",
"ns3/lower.example.db",
"ns3/managed-future.example.db",
"ns3/multiple.example.db",
"ns4/named_dump.db",
"ns4/named_dump.db.*",
"ns5/revoked.conf",
- "ns5/trusted.conf",
"ns6/optout-tld.db",
"ns7/split-rrsig.db",
"ns7/split-rrsig.db.unsplit",
+ "ns9/trusted-localkey.conf",
"signer/example.db",
"signer/example.db.after",
"signer/example.db.before",
* possible. */
DNS_FETCHOPT_QMINFETCH = 1 << 16, /*%< Qmin fetch */
DNS_FETCHOPT_WANTZONEVERSION = 1 << 17, /*%< Request ZONEVERSION */
+ DNS_FETCHOPT_TRYCD = 1 << 18, /*%< Send the first query
+ * to a forwader with
+ * CD=0, but retry with CD=1
+ * if it returns SERVFAIL.
+ */
/*% EDNS version bits: */
DNS_FETCHOPT_EDNSVERSIONSET = 1 << 23,
dns_peer_t *peer = NULL;
dns_compress_t cctx;
bool useedns;
- bool secure_domain;
bool tcp = ((query->options & DNS_FETCHOPT_TCP) != 0);
dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
unsigned int ednsopt = 0;
*/
if ((query->options & DNS_FETCHOPT_NOCDFLAG) != 0) {
/* Do nothing */
- } else if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) {
+ } else if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0 ||
+ (query->options & DNS_FETCHOPT_TRYCD) != 0)
+ {
fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
} else if (res->view->enablevalidation &&
((fctx->qmessage->flags & DNS_MESSAGEFLAG_RD) != 0))
{
- bool checknta = ((query->options & DNS_FETCHOPT_NONTA) == 0);
- bool ntacovered = false;
- result = issecuredomain(res->view, fctx->name, fctx->type,
- isc_time_seconds(&query->start),
- checknta, &ntacovered, &secure_domain);
- if (result != ISC_R_SUCCESS) {
- secure_domain = false;
- }
- if (secure_domain ||
- (ISFORWARDER(query->addrinfo) && ntacovered))
- {
- fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
- }
+ query->options |= DNS_FETCHOPT_TRYCD;
}
/*
fetchctx_t *fctx = rctx->fctx;
resquery_t *query = rctx->query;
+ QTRACE("response_continue");
+
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("signature check failed", result);
if (result == DNS_R_UNEXPECTEDTSIG ||
char code[64];
dns_rcode_t rcode = rctx->query->rmessage->rcode;
+ QTRACE("rctx_badserver");
+
if (rcode == dns_rcode_noerror || rcode == dns_rcode_yxdomain ||
rcode == dns_rcode_nxdomain)
{
}
query->addrinfo->flags |= FCTX_ADDRINFO_BADCOOKIE;
rctx->resend = true;
+ } else if (ISFORWARDER(query->addrinfo) &&
+ query->rmessage->rcode == dns_rcode_servfail &&
+ (query->options & DNS_FETCHOPT_TRYCD) != 0)
+ {
+ /*
+ * We got a SERVFAIL from a forwarder with
+ * CD=0; try again with CD=1.
+ */
+ rctx->retryopts |= DNS_FETCHOPT_TRYCD;
+ rctx->resend = true;
} else {
rctx->broken_server = DNS_R_UNEXPECTEDRCODE;
rctx->next_server = true;