diff --git a/bin/tests/system/additional/ns1/naptr.db b/bin/tests/system/additional/ns1/naptr.db index d604a3ac23..d14bec455d 100644 --- a/bin/tests/system/additional/ns1/naptr.db +++ b/bin/tests/system/additional/ns1/naptr.db @@ -10,7 +10,7 @@ $TTL 86400 @ IN SOA ns1 hostmaster ( 2 8H 2H 4W 1D ); NS ns1 -ns1 A 127.0.0.0 +ns1 A 10.53.0.1 nap IN NAPTR 50 50 "S" "SIPS+D2T" "" server server SRV 0 0 5061 server diff --git a/bin/tests/system/additional/ns1/naptr2.db b/bin/tests/system/additional/ns1/naptr2.db index 090e9b6241..fbdd179756 100644 --- a/bin/tests/system/additional/ns1/naptr2.db +++ b/bin/tests/system/additional/ns1/naptr2.db @@ -10,7 +10,7 @@ $TTL 86400 @ IN SOA ns1 hostmaster ( 2 8H 2H 4W 1D ); NS ns1 -ns1 A 127.0.0.0 +ns1 A 10.53.0.1 nap IN NAPTR 50 50 "S" "SIPS+D2T" "" server.hang3a.zone. www AAAA 192::99 diff --git a/bin/tests/system/additional/ns1/nid.db b/bin/tests/system/additional/ns1/nid.db index 70e4dc839c..5d5bee8e09 100644 --- a/bin/tests/system/additional/ns1/nid.db +++ b/bin/tests/system/additional/ns1/nid.db @@ -10,7 +10,7 @@ $TTL 86400 @ IN SOA ns1 hostmaster ( 2 8H 2H 4W 1D ); NS ns1 -ns1 A 127.0.0.0 +ns1 A 10.53.0.1 ns1 NID 2 0:0:0:0 ns1 L64 2 0:0:0:0 diff --git a/bin/tests/system/additional/ns1/rt.db b/bin/tests/system/additional/ns1/rt.db index 57ee400ec3..6958f38fd6 100644 --- a/bin/tests/system/additional/ns1/rt.db +++ b/bin/tests/system/additional/ns1/rt.db @@ -10,7 +10,8 @@ $TTL 86400 @ IN SOA ns1 hostmaster ( 2 8H 2H 4W 1D ); NS ns1 -ns1 A 127.0.0.0 + NS ns1.rt2.example. +ns1 A 10.53.0.1 rt RT 2 www www AAAA 192::99 diff --git a/bin/tests/system/additional/ns1/rt2.db b/bin/tests/system/additional/ns1/rt2.db index 73cb9f30d6..667eb118a8 100644 --- a/bin/tests/system/additional/ns1/rt2.db +++ b/bin/tests/system/additional/ns1/rt2.db @@ -10,7 +10,7 @@ $TTL 86400 @ IN SOA ns1 hostmaster ( 2 8H 2H 4W 1D ); NS ns1 -ns1 A 127.0.0.0 +ns1 A 10.53.0.1 rt RT 2 www.hang3b.zone. server SRV 0 0 5061 server diff --git a/bin/tests/system/additional/ns3/ex.db b/bin/tests/system/additional/ns3/ex.db new file mode 100644 index 0000000000..409c2dfd48 --- /dev/null +++ b/bin/tests/system/additional/ns3/ex.db @@ -0,0 +1,14 @@ +; 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. + +$TTL 86400 +@ IN SOA ns1 hostmaster ( 2 8H 2H 4W 1D ); + NS ns1 + NS ns1.ex2. +ns1 A 10.53.0.1 diff --git a/bin/tests/system/additional/ns3/ex2.db b/bin/tests/system/additional/ns3/ex2.db new file mode 100644 index 0000000000..30d4ca7c7a --- /dev/null +++ b/bin/tests/system/additional/ns3/ex2.db @@ -0,0 +1,13 @@ +; 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. + +$TTL 86400 +@ IN SOA ns1 hostmaster ( 2 8H 2H 4W 1D ); + NS ns1 +ns1 A 10.53.0.1 diff --git a/bin/tests/system/additional/ns3/named.conf.in b/bin/tests/system/additional/ns3/named.conf.in index bd730ae418..7dcd0bd0be 100644 --- a/bin/tests/system/additional/ns3/named.conf.in +++ b/bin/tests/system/additional/ns3/named.conf.in @@ -21,9 +21,20 @@ options { listen-on-v6 { none; }; recursion yes; dnssec-validation yes; + minimal-responses no; }; zone "." { type hint; file "root.hint"; }; + +zone "ex" { + type master; + file "ex.db"; +}; + +zone "ex2" { + type master; + file "ex2.db"; +}; diff --git a/bin/tests/system/additional/tests.sh b/bin/tests/system/additional/tests.sh index 6819ec6224..e3e9a3da25 100644 --- a/bin/tests/system/additional/tests.sh +++ b/bin/tests/system/additional/tests.sh @@ -228,7 +228,7 @@ n=`expr $n + 1` echo_i "testing with 'minimal-any no;' ($n)" ret=0 $DIG $DIGOPTS -t ANY www.rt.example @10.53.0.1 > dig.out.$n || ret=1 -grep "ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 2" dig.out.$n > /dev/null || ret=1 +grep "ANSWER: 3, AUTHORITY: 2, ADDITIONAL: 2" dig.out.$n > /dev/null || ret=1 if [ $ret -eq 1 ] ; then echo_i " failed"; status=1 fi @@ -322,5 +322,23 @@ if [ $ret -eq 1 ] ; then echo_i " failed"; status=1 fi +n=`expr $n + 1` +echo_i "testing out-of-zone additional data from auth zones (authoritative) ($n)" +ret=0 +$DIG $DIGOPTS -t NS rt.example @10.53.0.1 > dig.out.$n || ret=1 +grep "ADDITIONAL: 2" dig.out.$n > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo_i " failed"; status=1 +fi + +n=`expr $n + 1` +echo_i "testing out-of-zone additional data from auth zones (recursive) ($n)" +ret=0 +$DIG $DIGOPTS -t NS ex @10.53.0.3 > dig.out.$n || ret=1 +grep "ADDITIONAL: 3" dig.out.$n > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo_i " failed"; status=1 +fi + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/lib/ns/query.c b/lib/ns/query.c index 57d8b17ecd..3b6b3dc3d1 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -1442,6 +1442,175 @@ query_isduplicate(ns_client_t *client, dns_name_t *name, return (false); } +/* + * Look up data for given 'name' and 'type' in given 'version' of 'db' for + * 'client'. Called from query_additionalauth(). + * + * If the lookup is successful: + * + * - store the node containing the result at 'nodep', + * + * - store the owner name of the returned node in 'fname', + * + * - if 'type' is not ANY, dns_db_findext() will put the exact rdataset being + * looked for in 'rdataset' and its signatures (if any) in 'sigrdataset', + * + * - if 'type' is ANY, dns_db_findext() will leave 'rdataset' and + * 'sigrdataset' disassociated and the returned node will be iterated in + * query_additional_cb(). + * + * If the lookup is not successful: + * + * - 'nodep' will not be written to, + * - 'fname' may still be modified as it is passed to dns_db_findext(), + * - 'rdataset' and 'sigrdataset' will remain disassociated. + */ +static isc_result_t +query_additionalauthfind(dns_db_t *db, dns_dbversion_t *version, + const dns_name_t *name, dns_rdatatype_t type, + ns_client_t *client, dns_dbnode_t **nodep, + dns_name_t *fname, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset) +{ + dns_clientinfomethods_t cm; + dns_dbnode_t *node = NULL; + dns_clientinfo_t ci; + isc_result_t result; + + dns_clientinfomethods_init(&cm, ns_client_sourceip); + dns_clientinfo_init(&ci, client, NULL); + + /* + * Since we are looking for authoritative data, we do not set + * the GLUEOK flag. Glue will be looked for later, but not + * necessarily in the same database. + */ + result = dns_db_findext(db, name, version, type, + client->query.dboptions, client->now, &node, + fname, &cm, &ci, rdataset, sigrdataset); + if (result != ISC_R_SUCCESS) { + if (dns_rdataset_isassociated(rdataset)) { + dns_rdataset_disassociate(rdataset); + } + + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + { + dns_rdataset_disassociate(sigrdataset); + } + + if (node != NULL) { + dns_db_detachnode(db, &node); + } + + return (result); + } + + /* + * Do not return signatures if the zone is not fully signed. + */ + if (sigrdataset != NULL && !dns_db_issecure(db) && + dns_rdataset_isassociated(sigrdataset)) + { + dns_rdataset_disassociate(sigrdataset); + } + + *nodep = node; + + return (ISC_R_SUCCESS); +} + +/* + * For query context 'qctx', try finding authoritative additional data for + * given 'name' and 'type'. Called from query_additional_cb(). + * + * If successful: + * + * - store pointers to the database and node which contain the result in + * 'dbp' and 'nodep', respectively, + * + * - store the owner name of the returned node in 'fname', + * + * - potentially bind 'rdataset' and 'sigrdataset', as explained in the + * comment for query_additionalauthfind(). + * + * If unsuccessful: + * + * - 'dbp' and 'nodep' will not be written to, + * - 'fname' may still be modified as it is passed to dns_db_findext(), + * - 'rdataset' and 'sigrdataset' will remain disassociated. + */ +static isc_result_t +query_additionalauth(query_ctx_t *qctx, const dns_name_t *name, + dns_rdatatype_t type, dns_db_t **dbp, + dns_dbnode_t **nodep, dns_name_t *fname, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + ns_client_t *client = qctx->client; + ns_dbversion_t *dbversion = NULL; + dns_dbversion_t *version = NULL; + dns_dbnode_t *node = NULL; + dns_zone_t *zone = NULL; + dns_db_t *db = NULL; + isc_result_t result; + + /* + * First, look within the same zone database for authoritative + * additional data. + */ + if (!client->query.authdbset || client->query.authdb == NULL) { + return (ISC_R_NOTFOUND); + } + + dbversion = ns_client_findversion(client, client->query.authdb); + if (dbversion == NULL) { + return (ISC_R_NOTFOUND); + } + + dns_db_attach(client->query.authdb, &db); + version = dbversion->version; + + CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: same zone"); + + result = query_additionalauthfind(db, version, name, type, client, + &node, fname, rdataset, sigrdataset); + if (result != ISC_R_SUCCESS && + qctx->view->minimalresponses == dns_minimal_no && + RECURSIONOK(client)) + { + /* + * If we aren't doing response minimization and recursion is + * allowed, we can try and see if any other zone matches. + */ + version = NULL; + dns_db_detach(&db); + result = query_getzonedb(client, name, type, DNS_GETDB_NOLOG, + &zone, &db, &version); + if (result != ISC_R_SUCCESS) { + return (result); + } + dns_zone_detach(&zone); + + CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: other zone"); + + result = query_additionalauthfind(db, version, name, type, + client, &node, fname, + rdataset, sigrdataset); + } + + if (result != ISC_R_SUCCESS) { + dns_db_detach(&db); + } else { + *nodep = node; + node = NULL; + + *dbp = db; + db = NULL; + } + + return (result); +} + static isc_result_t query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { query_ctx_t *qctx = arg; @@ -1515,58 +1684,17 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { } /* - * Look within the same zone database for authoritative - * additional data. + * First, look for authoritative additional data. */ - if (!client->query.authdbset || client->query.authdb == NULL) { - goto try_cache; - } - - dbversion = ns_client_findversion(client, client->query.authdb); - if (dbversion == NULL) { - goto try_cache; - } - - dns_db_attach(client->query.authdb, &db); - version = dbversion->version; - - CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: db_find"); - - /* - * Since we are looking for authoritative data, we do not set - * the GLUEOK flag. Glue will be looked for later, but not - * necessarily in the same database. - */ - result = dns_db_findext(db, name, version, type, - client->query.dboptions, - client->now, &node, fname, &cm, &ci, - rdataset, sigrdataset); + result = query_additionalauth(qctx, name, type, &db, &node, fname, + rdataset, sigrdataset); if (result == ISC_R_SUCCESS) { - if (sigrdataset != NULL && !dns_db_issecure(db) && - dns_rdataset_isassociated(sigrdataset)) - { - dns_rdataset_disassociate(sigrdataset); - } goto found; } - if (dns_rdataset_isassociated(rdataset)) { - dns_rdataset_disassociate(rdataset); - } - if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { - dns_rdataset_disassociate(sigrdataset); - } - if (node != NULL) { - dns_db_detachnode(db, &node); - } - version = NULL; - dns_db_detach(&db); - /* * No authoritative data was found. The cache is our next best bet. */ - - try_cache: if (!qctx->view->recursion) { goto try_glue; }