From 3cc8c7d63040a3eafde2b00e1f60465e7053208a Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 4 Nov 2014 23:49:56 -0800 Subject: [PATCH] [master] fix nxrrset in nxdomain redirection 4000. [bug] NXDOMAIN redirection incorrectly handled NXRRSET from the redirect zone. [RT #37722] --- CHANGES | 3 ++ bin/named/query.c | 75 +++++++++++++++++++++--------- bin/tests/system/redirect/tests.sh | 8 ++++ doc/arm/notes.xml | 7 +++ 4 files changed, 72 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index cb15c9b632..a903fa6b87 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4000. [bug] NXDOMAIN redirection incorrectly handled NXRRSET + from the redirect zone. [RT #37722] + 3999. [func] "mkeys" and "nzf" files are now named after their corresponding views, unless the view name contains characters that would be incompatible diff --git a/bin/named/query.c b/bin/named/query.c index 6f90c0fc41..87f0033256 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -6010,7 +6010,7 @@ dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset, * Only perform the update if the client is in the allow query acl and * returning the update would not cause a DNSSEC validation failure. */ -static isc_boolean_t +static isc_result_t redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp, dns_rdatatype_t qtype) @@ -6029,7 +6029,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, CTRACE(ISC_LOG_DEBUG(3), "redirect"); if (client->view->redirect == NULL) - return (ISC_FALSE); + return (ISC_R_NOTFOUND); dns_fixedname_init(&fixed); found = dns_fixedname_name(&fixed); @@ -6039,15 +6039,15 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, dns_clientinfo_init(&ci, client, NULL); if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp)) - return (ISC_FALSE); + return (ISC_R_NOTFOUND); if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) { if (rdataset->trust == dns_trust_secure) - return (ISC_FALSE); + return (ISC_R_NOTFOUND); if (rdataset->trust == dns_trust_ultimate && (rdataset->type == dns_rdatatype_nsec || rdataset->type == dns_rdatatype_nsec3)) - return (ISC_FALSE); + return (ISC_R_NOTFOUND); if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; @@ -6058,7 +6058,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, if (type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3 || type == dns_rdatatype_rrsig) - return (ISC_FALSE); + return (ISC_R_NOTFOUND); } } } @@ -6067,16 +6067,16 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, dns_zone_getqueryacl(client->view->redirect), ISC_TRUE); if (result != ISC_R_SUCCESS) - return (ISC_FALSE); + return (ISC_R_NOTFOUND); result = dns_zone_getdb(client->view->redirect, &db); if (result != ISC_R_SUCCESS) - return (ISC_FALSE); + return (ISC_R_NOTFOUND); dbversion = query_findversion(client, db); if (dbversion == NULL) { dns_db_detach(&db); - return (ISC_FALSE); + return (ISC_R_NOTFOUND); } /* @@ -6085,16 +6085,22 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, result = dns_db_findext(db, client->query.qname, dbversion->version, qtype, DNS_DBFIND_NOZONECUT, client->now, &node, found, &cm, &ci, &trdataset, NULL); - if (result != ISC_R_SUCCESS) { + if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + if (dns_rdataset_isassociated(&trdataset)) + dns_rdataset_disassociate(&trdataset); + goto nxrrset; + } else if (result != ISC_R_SUCCESS) { if (dns_rdataset_isassociated(&trdataset)) dns_rdataset_disassociate(&trdataset); if (node != NULL) dns_db_detachnode(db, &node); dns_db_detach(&db); - return (ISC_FALSE); + return (ISC_R_NOTFOUND); } - CTRACE(ISC_LOG_DEBUG(3), "redirect: found data: done"); + CTRACE(ISC_LOG_DEBUG(3), "redirect: found data: done"); dns_name_copy(found, name, NULL); if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); @@ -6102,6 +6108,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, dns_rdataset_clone(&trdataset, rdataset); dns_rdataset_disassociate(&trdataset); } + nxrrset: if (*nodep != NULL) dns_db_detachnode(*dbp, nodep); dns_db_detach(dbp); @@ -6114,7 +6121,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY | NS_QUERYATTR_NOADDITIONAL); - return (ISC_TRUE); + return (result); } /* @@ -6142,7 +6149,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) int order; isc_buffer_t *dbuf; isc_buffer_t b; - isc_result_t result, eresult; + isc_result_t result, eresult, tresult; dns_fixedname_t fixed; dns_fixedname_t wildcardname; dns_dbversion_t *version, *zversion; @@ -6157,6 +6164,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) int line = -1; isc_boolean_t dns64_exclude, dns64; isc_boolean_t nxrewrite = ISC_FALSE; + isc_boolean_t redirected = ISC_FALSE; dns_clientinfomethods_t cm; dns_clientinfo_t ci; char errmsg[256]; @@ -6388,7 +6396,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_db_t *tdb = NULL; dns_zone_t *tzone = NULL; dns_dbversion_t *tversion = NULL; - isc_result_t tresult; tresult = query_getzonedb(client, client->query.qname, qtype, DNS_GETDB_PARTIAL, &tzone, &tdb, @@ -7191,6 +7198,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * Look for a NSEC3 record if we don't have a NSEC record. */ nxrrset_rrsig: + if (redirected) + goto cleanup; if (!dns_rdataset_isassociated(rdataset) && WANTDNSSEC(client)) { if ((fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) { @@ -7315,10 +7324,21 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) case DNS_R_NXDOMAIN: INSIST(is_zone); - if (!empty_wild && - redirect(client, fname, rdataset, &node, &db, &version, - type)) - break; + if (!empty_wild) { + tresult = redirect(client, fname, rdataset, &node, + &db, &version, type); + if (tresult == ISC_R_SUCCESS) + break; + if (tresult == DNS_R_NXRRSET) { + redirected = ISC_TRUE; + goto iszone_nxrrset; + } + if (tresult == DNS_R_NCACHENXRRSET) { + redirected = ISC_TRUE; + is_zone = ISC_FALSE; + goto ncache_nxrrset; + } + } if (dns_rdataset_isassociated(rdataset)) { /* * If we've got a NSEC record, we need to save the @@ -7381,9 +7401,22 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) goto cleanup; case DNS_R_NCACHENXDOMAIN: - if (redirect(client, fname, rdataset, &node, &db, &version, - type)) + tresult = redirect(client, fname, rdataset, &node, + &db, &version, type); + if (tresult == ISC_R_SUCCESS) break; + if (tresult == DNS_R_NXRRSET) { + redirected = ISC_TRUE; + is_zone = ISC_TRUE; + goto iszone_nxrrset; + } + if (tresult == DNS_R_NCACHENXRRSET) { + redirected = ISC_TRUE; + result = tresult; + goto ncache_nxrrset; + } + /* FALLTHROUGH */ + case DNS_R_NCACHENXRRSET: ncache_nxrrset: INSIST(!is_zone); diff --git a/bin/tests/system/redirect/tests.sh b/bin/tests/system/redirect/tests.sh index a9de4130fd..1b802aad3d 100644 --- a/bin/tests/system/redirect/tests.sh +++ b/bin/tests/system/redirect/tests.sh @@ -332,6 +332,14 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:checking redirect works (with noerror) when qtype is not found ($n)" +ret=0 +$DIG $DIGOPTS nonexist. @10.53.0.2 -b 10.53.0.2 txt > dig.out.ns2.test$n || ret=1 +grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 +n=`expr $n + 1` +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:checking that redirect zones reload correctly" ret=0 sleep 1 # ensure file mtime will have changed diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index ed00f28a41..db721d7f9a 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -334,6 +334,13 @@ corrected at run time. [RT #37187] + + + When NXDOMAIN redirection is in use, queries for a name + that is present in the redirection zone but a type that + is not present will now return NOERROR instead of NXDOMAIN. + +