diff --git a/bin/tests/system/dnssec/ns1/sign.sh b/bin/tests/system/dnssec/ns1/sign.sh index 0bcf5673cd35bad16d1e762e6bbf8f77648f5ba2..313d098ab923173345960fa0a9a03e922ec6fbea 100644 --- a/bin/tests/system/dnssec/ns1/sign.sh +++ b/bin/tests/system/dnssec/ns1/sign.sh @@ -42,6 +42,7 @@ cp trusted.conf ../ns3/trusted.conf cp trusted.conf ../ns4/trusted.conf cp trusted.conf ../ns6/trusted.conf cp trusted.conf ../ns7/trusted.conf +cp trusted.conf ../ns9/trusted.conf # ...or with a managed key. keyfile_to_managed_keys $keyname > managed.conf diff --git a/bin/tests/system/dnssec/ns2/sign.sh b/bin/tests/system/dnssec/ns2/sign.sh index 584c36ecdf50188ce3dbbd591e8ef250e696a747..b93651aee88eb2f30ffbaad5e17b65d366b33b22 100644 --- a/bin/tests/system/dnssec/ns2/sign.sh +++ b/bin/tests/system/dnssec/ns2/sign.sh @@ -18,7 +18,7 @@ SYSTEMTESTTOP=../.. echo_i "ns2/sign.sh" # Get the DS records for the "trusted." and "managed." zones. -for subdomain in secure unsupported disabled enabled +for subdomain in secure unsupported do cp ../ns3/dsset-$subdomain.managed$TP . cp ../ns3/dsset-$subdomain.trusted$TP . diff --git a/bin/tests/system/dnssec/ns9/named.conf.in b/bin/tests/system/dnssec/ns9/named.conf.in new file mode 100644 index 0000000000000000000000000000000000000000..d655112a70efc7c3ed775632117ccf4f0a04da26 --- /dev/null +++ b/bin/tests/system/dnssec/ns9/named.conf.in @@ -0,0 +1,38 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +// NS9 + +options { + query-source address 10.53.0.9; + notify-source 10.53.0.9; + transfer-source 10.53.0.9; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.9; }; + listen-on-v6 { none; }; + recursion yes; + dnssec-enable yes; + dnssec-validation yes; + forward only; + forwarders { 10.53.0.4; }; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +include "trusted.conf"; diff --git a/bin/tests/system/dnssec/setup.sh b/bin/tests/system/dnssec/setup.sh index c6767054bcad659dca3e2b46eff2e811947b5bbd..a6838de97c1a52f5c6469be39883460c3120afe3 100644 --- a/bin/tests/system/dnssec/setup.sh +++ b/bin/tests/system/dnssec/setup.sh @@ -26,6 +26,7 @@ copy_setports ns5/named1.conf.in ns5/named.conf copy_setports ns6/named.conf.in ns6/named.conf copy_setports ns7/named.conf.in ns7/named.conf copy_setports ns8/named.conf.in ns8/named.conf +copy_setports ns9/named.conf.in ns9/named.conf cd ns1 $SHELL sign.sh diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 71bf407e160923a643db3c8951d71904626926d0..51dc1178db96af7e65f0815388327e7099719825 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -2280,7 +2280,29 @@ $RNDCCMD 10.53.0.4 nta -remove secure.example > rndc.out.ns4.test$n.3 2>/dev/nul if [ $ret != 0 ]; then echo_i "failed - NTA lifetime clamping failed"; fi status=`expr $status + $ret` -ret=0 + +n=`expr $n + 1` +echo_i "checking that NTAs work with 'forward only;' to a validating resolver ($n)" +ret=0 +# Sanity check behavior without an NTA in place. +$DIG $DIGOPTS @10.53.0.9 badds.example. SOA > dig.out.ns9.test$n.1 || ret=1 +grep "SERVFAIL" dig.out.ns9.test$n.1 > /dev/null || ret=1 +grep "ANSWER: 0" dig.out.ns9.test$n.1 > /dev/null || ret=1 +grep "flags:[^;]* ad[ ;].*QUERY" dig.out.ns9.test$n.1 > /dev/null && ret=1 +# Add an NTA, expecting that to cause resolution to succeed. +$RNDCCMD 10.53.0.9 nta badds.example > rndc.out.ns9.test$n.1 2>&1 || ret=1 +$DIG $DIGOPTS @10.53.0.9 badds.example. SOA > dig.out.ns9.test$n.2 || ret=1 +grep "NOERROR" dig.out.ns9.test$n.2 > /dev/null || ret=1 +grep "ANSWER: 2" dig.out.ns9.test$n.2 > /dev/null || ret=1 +grep "flags:[^;]* ad[ ;].*QUERY" dig.out.ns9.test$n.2 > /dev/null && ret=1 +# Remove the NTA, expecting that to cause resolution to fail again. +$RNDCCMD 10.53.0.9 nta -remove badds.example > rndc.out.ns9.test$n.2 2>&1 || ret=1 +$DIG $DIGOPTS @10.53.0.9 badds.example. SOA > dig.out.ns9.test$n.3 || ret=1 +grep "SERVFAIL" dig.out.ns9.test$n.3 > /dev/null || ret=1 +grep "ANSWER: 0" dig.out.ns9.test$n.3 > /dev/null || ret=1 +grep "flags:[^;]* ad[ ;].*QUERY" dig.out.ns9.test$n.3 > /dev/null && ret=1 +if [ "$ret" -ne 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` echo_i "completed NTA tests" diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 8e21298c03944ef40634858a7f373a88b414d491..335e46129fa5da7ef84c006239cda0f7242a2a0a 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -1189,14 +1189,16 @@ dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp); isc_result_t dns_view_issecuredomain(dns_view_t *view, dns_name_t *name, - isc_stdtime_t now, bool checknta, + isc_stdtime_t now, bool checknta, bool *ntap, bool *secure_domain); /*%< * Is 'name' at or beneath a trusted key, and not covered by a valid * negative trust anchor? Put answer in '*secure_domain'. * * If 'checknta' is false, ignore the NTA table in determining - * whether this is a secure domain. + * whether this is a secure domain. If 'checknta' is not false, and if + * 'ntap' is non-NULL, then '*ntap' will be updated with true if the + * name is covered by an NTA. * * Requires: * \li 'view' is valid. diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index cb678e085e94a69ad2ffa5d23a80424a2f56d613..3a945366f3d31f613efa0f076f32a2256620732d 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -2086,8 +2086,7 @@ compute_cc(resquery_t *query, unsigned char *cookie, size_t len) { static isc_result_t issecuredomain(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, - isc_stdtime_t now, bool checknta, - bool *issecure) + isc_stdtime_t now, bool checknta, bool *ntap, bool *issecure) { dns_name_t suffix; unsigned int labels; @@ -2105,7 +2104,8 @@ issecuredomain(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, name = &suffix; } - return (dns_view_issecuredomain(view, name, now, checknta, issecure)); + return (dns_view_issecuredomain(view, name, now, checknta, + ntap, issecure)); } static bool @@ -2114,17 +2114,20 @@ wouldvalidate(fetchctx_t *fctx) { isc_result_t result; isc_stdtime_t now; - if (!fctx->res->view->enablevalidation) + if (!fctx->res->view->enablevalidation) { return (false); + } - if (fctx->res->view->dlv != NULL) + if (fctx->res->view->dlv != NULL) { return (true); + } isc_stdtime_get(&now); result = dns_view_issecuredomain(fctx->res->view, &fctx->name, - now, true, &secure_domain); - if (result != ISC_R_SUCCESS) + now, true, NULL, &secure_domain); + if (result != ISC_R_SUCCESS) { return (false); + } return (secure_domain); } @@ -2229,24 +2232,30 @@ resquery_send(resquery_t *query) { * question is under a secure entry point and this is a * recursive/forward query -- unless the client said not to. */ - if ((query->options & DNS_FETCHOPT_NOCDFLAG) != 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) { fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD; - else if (res->view->enablevalidation && - ((fctx->qmessage->flags & DNS_MESSAGEFLAG_RD) != 0)) + } 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, &secure_domain); - if (result != ISC_R_SUCCESS) + checknta, &ntacovered, &secure_domain); + if (result != ISC_R_SUCCESS) { secure_domain = false; - if (res->view->dlv != NULL) + } + if (res->view->dlv != NULL) { secure_domain = true; - if (secure_domain) + } + + if (secure_domain || + (ISFORWARDER(query->addrinfo) && ntacovered)) + { fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD; + } } /* @@ -5419,7 +5428,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, if (res->view->enablevalidation) { result = issecuredomain(res->view, name, fctx->type, - now, checknta, &secure_domain); + now, checknta, NULL, &secure_domain); if (result != ISC_R_SUCCESS) { return (result); } @@ -6006,7 +6015,7 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, if (fctx->res->view->enablevalidation) { result = issecuredomain(res->view, name, fctx->type, - now, checknta, &secure_domain); + now, checknta, NULL, &secure_domain); if (result != ISC_R_SUCCESS) return (result); diff --git a/lib/dns/tests/keytable_test.c b/lib/dns/tests/keytable_test.c index 17da3f399885ecf8d60a444985dd69aa052d188f..6329daf1aab5cdb2265afb6eb7a4c2f0290dc901 100644 --- a/lib/dns/tests/keytable_test.c +++ b/lib/dns/tests/keytable_test.c @@ -554,15 +554,17 @@ nta_test(void **state) { /* Should be secure */ result = dns_view_issecuredomain(myview, str2name("test.secure.example"), - now, true, &issecure); + now, true, &covered, &issecure); assert_int_equal(result, ISC_R_SUCCESS); + assert_false(covered); assert_true(issecure); /* Should not be secure */ result = dns_view_issecuredomain(myview, str2name("test.insecure.example"), - now, true, &issecure); + now, true, &covered, &issecure); assert_int_equal(result, ISC_R_SUCCESS); + assert_true(covered); assert_false(issecure); /* NTA covered */ @@ -578,14 +580,16 @@ nta_test(void **state) { /* As of now + 2, the NTA should be clear */ result = dns_view_issecuredomain(myview, str2name("test.insecure.example"), - now + 2, true, &issecure); + now + 2, true, &covered, &issecure); assert_int_equal(result, ISC_R_SUCCESS); + assert_false(covered); assert_true(issecure); /* Now check deletion */ result = dns_view_issecuredomain(myview, str2name("test.new.example"), - now, true, &issecure); + now, true, &covered, &issecure); assert_int_equal(result, ISC_R_SUCCESS); + assert_false(covered); assert_true(issecure); result = dns_ntatable_add(ntatable, str2name("new.example"), @@ -593,16 +597,18 @@ nta_test(void **state) { assert_int_equal(result, ISC_R_SUCCESS); result = dns_view_issecuredomain(myview, str2name("test.new.example"), - now, true, &issecure); + now, true, &covered, &issecure); assert_int_equal(result, ISC_R_SUCCESS); + assert_true(covered); assert_false(issecure); result = dns_ntatable_delete(ntatable, str2name("new.example")); assert_int_equal(result, ISC_R_SUCCESS); result = dns_view_issecuredomain(myview, str2name("test.new.example"), - now, true, &issecure); + now, true, &covered, &issecure); assert_int_equal(result, ISC_R_SUCCESS); + assert_false(covered); assert_true(issecure); /* Clean up */ diff --git a/lib/dns/view.c b/lib/dns/view.c index 3a61e816fe4540a735bced4161b07b5f53283c49..12b608e03c598fb2e8e0c7d6d0213894a24fffec 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -1941,7 +1941,7 @@ dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now, isc_result_t dns_view_issecuredomain(dns_view_t *view, dns_name_t *name, - isc_stdtime_t now, bool checknta, + isc_stdtime_t now, bool checknta, bool *ntap, bool *secure_domain) { isc_result_t result; @@ -1951,19 +1951,29 @@ dns_view_issecuredomain(dns_view_t *view, dns_name_t *name, REQUIRE(DNS_VIEW_VALID(view)); - if (view->secroots_priv == NULL) + if (view->secroots_priv == NULL) { return (ISC_R_NOTFOUND); + } anchor = dns_fixedname_initname(&fn); result = dns_keytable_issecuredomain(view->secroots_priv, name, anchor, &secure); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { return (result); + } + if (ntap != NULL) { + *ntap = false; + } if (checknta && secure && view->ntatable_priv != NULL && dns_ntatable_covered(view->ntatable_priv, now, name, anchor)) + { + if (ntap != NULL) { + *ntap = true; + } secure = false; + } *secure_domain = secure; return (ISC_R_SUCCESS);