diff --git a/CHANGES b/CHANGES
index 4d9fb19374..c4b4db394e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4108. [func] A additional nxdomain redirect (nxdomain-redirect)
+ is now supported. [RT #37989]
+
4107. [bug] Address potential deadlock when updating zone content.
[RT #39269]
diff --git a/bin/named/client.c b/bin/named/client.c
index 21afbbd3fc..0e79d7cc1d 100644
--- a/bin/named/client.c
+++ b/bin/named/client.c
@@ -3599,6 +3599,7 @@ ns_client_qnamereplace(ns_client_t *client, dns_name_t *name) {
&client->query.qname);
}
client->query.qname = name;
+ client->query.attributes &= ~NS_QUERYATTR_REDIRECT;
UNLOCK(&client->query.fetchlock);
}
diff --git a/bin/named/include/named/query.h b/bin/named/include/named/query.h
index e4179f1f93..3e6c03a775 100644
--- a/bin/named/include/named/query.h
+++ b/bin/named/include/named/query.h
@@ -67,6 +67,19 @@ struct ns_query {
unsigned int dns64_aaaaoklen;
unsigned int dns64_options;
unsigned int dns64_ttl;
+ struct {
+ dns_db_t * db;
+ dns_zone_t * zone;
+ dns_dbnode_t * node;
+ dns_rdatatype_t qtype;
+ dns_name_t * fname;
+ dns_fixedname_t fixed;
+ isc_result_t result;
+ dns_rdataset_t * rdataset;
+ dns_rdataset_t * sigrdataset;
+ isc_boolean_t authoritative;
+ } redirect;
+
};
#define NS_QUERYATTR_RECURSIONOK 0x0001
@@ -86,6 +99,7 @@ struct ns_query {
#define NS_QUERYATTR_DNS64 0x4000
#define NS_QUERYATTR_DNS64EXCLUDE 0x8000
#define NS_QUERYATTR_RRL_CHECKED 0x10000
+#define NS_QUERYATTR_REDIRECT 0x20000
isc_result_t
ns_query_init(ns_client_t *client);
diff --git a/bin/named/query.c b/bin/named/query.c
index 68cd9d2163..7aa95ce49b 100644
--- a/bin/named/query.c
+++ b/bin/named/query.c
@@ -122,6 +122,9 @@
#define DNS64EXCLUDE(c) (((c)->query.attributes & \
NS_QUERYATTR_DNS64EXCLUDE) != 0)
+#define REDIRECT(c) (((c)->query.attributes & \
+ NS_QUERYATTR_REDIRECT) != 0)
+
/*% No QNAME Proof? */
#define NOQNAME(r) (((r)->attributes & \
DNS_RDATASETATTR_NOQNAME) != 0)
@@ -381,6 +384,17 @@ query_reset(ns_client_t *client, isc_boolean_t everything) {
client->query.dns64_aaaaoklen = 0;
}
+ query_putrdataset(client, &client->query.redirect.rdataset);
+ query_putrdataset(client, &client->query.redirect.sigrdataset);
+ if (client->query.redirect.db != NULL) {
+ if (client->query.redirect.node != NULL)
+ dns_db_detachnode(client->query.redirect.db,
+ &client->query.redirect.node);
+ dns_db_detach(&client->query.redirect.db);
+ }
+ if (client->query.redirect.zone != NULL)
+ dns_zone_detach(&client->query.redirect.zone);
+
query_freefreeversions(client, everything);
for (dbuf = ISC_LIST_HEAD(client->query.namebufs);
@@ -655,6 +669,16 @@ ns_query_init(ns_client_t *client) {
client->query.dns64_sigaaaa = NULL;
client->query.dns64_aaaaok = NULL;
client->query.dns64_aaaaoklen = 0;
+ client->query.redirect.db = NULL;
+ client->query.redirect.node = NULL;
+ client->query.redirect.zone = NULL;
+ client->query.redirect.qtype = dns_rdatatype_none;
+ client->query.redirect.result = ISC_R_SUCCESS;
+ client->query.redirect.rdataset = NULL;
+ client->query.redirect.sigrdataset = NULL;
+ dns_fixedname_init(&client->query.redirect.fixed);
+ client->query.redirect.fname =
+ dns_fixedname_name(&client->query.redirect.fixed);
query_reset(client, ISC_FALSE);
result = query_newdbversion(client, 3);
if (result != ISC_R_SUCCESS) {
@@ -6140,6 +6164,168 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
return (result);
}
+static isc_result_t
+redirect2(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)
+{
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_fixedname_t fixed;
+ dns_fixedname_t fixedredirect;
+ dns_name_t *found, *redirectname;
+ dns_rdataset_t trdataset;
+ isc_result_t result;
+ dns_rdatatype_t type;
+ dns_clientinfomethods_t cm;
+ dns_clientinfo_t ci;
+ dns_dbversion_t *version = NULL;
+ dns_zone_t *zone = NULL;
+ unsigned int options;
+ isc_boolean_t is_zonep = ISC_FALSE;
+
+ CTRACE(ISC_LOG_DEBUG(3), "redirect2");
+
+ if (client->view->redirectzone == NULL)
+ return (ISC_R_NOTFOUND);
+
+ if (dns_name_issubdomain(name, client->view->redirectzone))
+ return (ISC_R_NOTFOUND);
+
+ dns_fixedname_init(&fixed);
+ found = dns_fixedname_name(&fixed);
+ dns_rdataset_init(&trdataset);
+
+ dns_clientinfomethods_init(&cm, ns_client_sourceip);
+ dns_clientinfo_init(&ci, client, NULL);
+
+ if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
+ return (ISC_R_NOTFOUND);
+
+ if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
+ if (rdataset->trust == dns_trust_secure)
+ return (ISC_R_NOTFOUND);
+ if (rdataset->trust == dns_trust_ultimate &&
+ (rdataset->type == dns_rdatatype_nsec ||
+ rdataset->type == dns_rdatatype_nsec3))
+ return (ISC_R_NOTFOUND);
+ if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
+ for (result = dns_rdataset_first(rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(rdataset)) {
+ dns_ncache_current(rdataset, found, &trdataset);
+ type = trdataset.type;
+ dns_rdataset_disassociate(&trdataset);
+ if (type == dns_rdatatype_nsec ||
+ type == dns_rdatatype_nsec3 ||
+ type == dns_rdatatype_rrsig)
+ return (ISC_R_NOTFOUND);
+ }
+ }
+ }
+
+ dns_fixedname_init(&fixedredirect);
+ redirectname = dns_fixedname_name(&fixedredirect);
+ if (dns_name_countlabels(name) > 1U) {
+ dns_name_t prefix;
+ unsigned int labels = dns_name_countlabels(name) - 1;
+
+ dns_name_init(&prefix, NULL);
+ dns_name_getlabelsequence(name, 0, labels, &prefix);
+ result = dns_name_concatenate(&prefix,
+ client->view->redirectzone,
+ redirectname, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOTFOUND);
+ } else
+ dns_name_copy(redirectname, client->view->redirectzone, NULL);
+
+ options = 0;
+ result = query_getdb(client, redirectname, qtype, options, &zone,
+ &db, &version, &is_zonep);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOTFOUND);
+
+ /*
+ * Lookup the requested data in the redirect zone.
+ */
+ result = dns_db_findext(db, redirectname, version,
+ qtype, 0, client->now,
+ &node, found, &cm, &ci, &trdataset, NULL);
+ 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_NOTFOUND || result == DNS_R_DELEGATION) {
+ /*
+ * Cleanup.
+ */
+ if (dns_rdataset_isassociated(&trdataset))
+ dns_rdataset_disassociate(&trdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ /*
+ * Don't loop forever if the lookup failed last time.
+ */
+ if (!REDIRECT(client)) {
+ result = query_recurse(client, qtype, redirectname,
+ NULL, NULL, ISC_TRUE);
+ if (result == ISC_R_SUCCESS) {
+ client->query.attributes |=
+ NS_QUERYATTR_RECURSING;
+ client->query.attributes |=
+ NS_QUERYATTR_REDIRECT;
+ return (DNS_R_CONTINUE);
+ }
+ }
+ return (ISC_R_NOTFOUND);
+ } 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_R_NOTFOUND);
+ }
+
+ CTRACE(ISC_LOG_DEBUG(3), "redirect2: found data: done");
+ /*
+ * Adjust the found name to not include the redirectzone suffix.
+ */
+ dns_name_split(found, dns_name_countlabels(client->view->redirectzone),
+ found, NULL);
+ /*
+ * Make the name absolute.
+ */
+ result = dns_name_concatenate(found, dns_rootname, found, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ dns_name_copy(found, name, NULL);
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ if (dns_rdataset_isassociated(&trdataset)) {
+ dns_rdataset_clone(&trdataset, rdataset);
+ dns_rdataset_disassociate(&trdataset);
+ }
+ nxrrset:
+ if (*nodep != NULL)
+ dns_db_detachnode(*dbp, nodep);
+ dns_db_detach(dbp);
+ dns_db_attachnode(db, node, nodep);
+ dns_db_attach(db, dbp);
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ *versionp = version;
+
+ client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
+ NS_QUERYATTR_NOADDITIONAL);
+
+ return (result);
+}
+
/*
* Do the bulk of query processing for the current query of 'client'.
* If 'event' is non-NULL, we are returning from recursion and 'qtype'
@@ -6253,6 +6439,33 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
rpz_st->r.r_type = event->qtype;
rpz_st->r.r_rdataset = event->rdataset;
query_putrdataset(client, &event->sigrdataset);
+ } else if (REDIRECT(client)) {
+
+ /*
+ * Restore saved state.
+ */
+ qtype = client->query.redirect.qtype;
+ rdataset = client->query.redirect.rdataset;
+ client->query.redirect.rdataset = NULL;
+ sigrdataset = client->query.redirect.sigrdataset;
+ client->query.redirect.sigrdataset = NULL;
+ db = client->query.redirect.db;
+ client->query.redirect.db = NULL;
+ node = client->query.redirect.node;
+ client->query.redirect.node = NULL;
+ zone = client->query.redirect.zone;
+ client->query.redirect.zone = NULL;
+ authoritative = client->query.redirect.authoritative;
+
+ /*
+ * Free resources used while recursing.
+ */
+ query_putrdataset(client, &event->rdataset);
+ query_putrdataset(client, &event->sigrdataset);
+ if (event->node != NULL)
+ dns_db_detachnode(event->db, &event->node);
+ if (event->db != NULL)
+ dns_db_detach(&event->db);
} else {
authoritative = ISC_FALSE;
@@ -6297,6 +6510,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
if (rpz_st != NULL &&
(rpz_st->state & DNS_RPZ_RECURSING) != 0) {
tname = rpz_st->fname;
+ } else if (REDIRECT(client)) {
+ tname = client->query.redirect.fname;
} else {
tname = dns_fixedname_name(&event->foundname);
}
@@ -6312,6 +6527,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
rpz_st->r.r_result = event->result;
result = rpz_st->q.result;
isc_event_free(ISC_EVENT_PTR(&event));
+ } else if (REDIRECT(client)) {
+ result = client->query.redirect.result;
} else {
result = event->result;
}
@@ -7350,6 +7567,40 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
is_zone = ISC_FALSE;
goto ncache_nxrrset;
}
+ tresult = redirect2(client, fname, rdataset, &node,
+ &db, &version, type);
+ if (tresult == DNS_R_CONTINUE) {
+ client->query.redirect.qtype = qtype;
+ client->query.redirect.rdataset = rdataset;
+ client->query.redirect.sigrdataset =
+ sigrdataset;
+ client->query.redirect.db = db;
+ client->query.redirect.node = node;
+ client->query.redirect.zone = zone;
+ client->query.redirect.result = DNS_R_NXDOMAIN;
+ dns_name_copy(fname,
+ client->query.redirect.fname,
+ NULL);
+ client->query.redirect.authoritative =
+ authoritative;
+ db = NULL;
+ node = NULL;
+ zone = NULL;
+ rdataset = NULL;
+ sigrdataset = NULL;
+ goto cleanup;
+ }
+ 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)) {
/*
@@ -7427,6 +7678,37 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
result = tresult;
goto ncache_nxrrset;
}
+ tresult = redirect2(client, fname, rdataset, &node,
+ &db, &version, type);
+ if (tresult == DNS_R_CONTINUE) {
+ client->query.redirect.db = db;
+ client->query.redirect.node = node;
+ client->query.redirect.zone = zone;
+ client->query.redirect.qtype = qtype;
+ client->query.redirect.rdataset = rdataset;
+ client->query.redirect.sigrdataset = sigrdataset;
+ client->query.redirect.result = DNS_R_NCACHENXDOMAIN;
+ dns_name_copy(fname, client->query.redirect.fname,
+ NULL);
+ client->query.redirect.authoritative = authoritative;
+ db = NULL;
+ node = NULL;
+ rdataset = NULL;
+ sigrdataset = NULL;
+ goto cleanup;
+ }
+ 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:
@@ -7533,12 +7815,14 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
* We don't call query_addrrset() because we don't need any
* of its extra features (and things would probably break!).
*/
- query_keepname(client, fname, dbuf);
- dns_message_addname(client->message, fname,
- DNS_SECTION_AUTHORITY);
- ISC_LIST_APPEND(fname->list, rdataset, link);
- fname = NULL;
- rdataset = NULL;
+ if (dns_rdataset_isassociated(rdataset)) {
+ query_keepname(client, fname, dbuf);
+ dns_message_addname(client->message, fname,
+ DNS_SECTION_AUTHORITY);
+ ISC_LIST_APPEND(fname->list, rdataset, link);
+ fname = NULL;
+ rdataset = NULL;
+ }
goto cleanup;
case DNS_R_CNAME:
diff --git a/bin/named/server.c b/bin/named/server.c
index bb7e087804..8067a602b4 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -3816,6 +3816,20 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
fail_ttl = 300;
dns_view_setfailttl(view, fail_ttl);
+ /*
+ * Name space to look up redirect information in.
+ */
+ obj = NULL;
+ result = ns_config_get(maps, "nxdomain-redirect", &obj);
+ if (result == ISC_R_SUCCESS) {
+ dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
+ CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
+ NULL));
+ view->redirectzone = name;
+ } else
+ view->redirectzone = NULL;
+
+
result = ISC_R_SUCCESS;
cleanup:
diff --git a/bin/tests/system/redirect/clean.sh b/bin/tests/system/redirect/clean.sh
index 431c1f29d2..83568a8f86 100644
--- a/bin/tests/system/redirect/clean.sh
+++ b/bin/tests/system/redirect/clean.sh
@@ -14,14 +14,20 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-rm -f ns1/K*
-rm -f ns1/signed.db*
-rm -f ns1/nsec3.db*
-rm -f ns1/dsset-signed.
-rm -f ns1/dsset-nsec3.
rm -f */named.memstats
rm -f */named.run
rm -f dig.out.*
-rm -f ns2/*.db
-rm -f rndc.out
rm -f ns*/named.lock
+rm -f ns1/K*
+rm -f ns1/dsset-nsec3.
+rm -f ns1/dsset-signed.
+rm -f ns1/nsec3.db*
+rm -f ns1/signed.db*
+rm -f ns2/*.db
+rm -f ns3/K*
+rm -f ns3/dsset-nsec3.
+rm -f ns3/dsset-signed.
+rm -f ns3/nsec3.db*
+rm -f ns3/signed.db*
+rm -f ns4/*.db
+rm -f rndc.out
diff --git a/bin/tests/system/redirect/ns3/example.db b/bin/tests/system/redirect/ns3/example.db
new file mode 100644
index 0000000000..2877e9d878
--- /dev/null
+++ b/bin/tests/system/redirect/ns3/example.db
@@ -0,0 +1,55 @@
+; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: example.db,v 1.3 2011/03/01 23:48:06 tbox Exp $
+
+$TTL 3600
+@ SOA ns3 marka.isc.org. 0 0 0 0 1200
+@ NS ns3
+ns3 A 10.53.0.3
+excluded-good-a AAAA 2001:eeee::1
+ A 1.2.3.4
+excluded-bad-a AAAA 2001:eeee::2
+ A 10.0.0.1
+excluded-only AAAA 2001:eeee::3
+partially-excluded-good-a AAAA 2001:eeee::1
+ AAAA 2001::1
+ A 1.2.3.4
+partially-excluded-bad-a AAAA 2001:eeee::2
+ AAAA 2001::2
+ A 10.0.0.1
+partially-excluded-only AAAA 2001:eeee::3
+ AAAA 2001::3
+a-only A 1.2.3.5
+a-and-aaaa AAAA 2001::1
+ A 1.2.3.6
+aaaa-only AAAA 2001::2
+a-not-mapped A 10.0.0.2
+mx-only MX 10 ns.example.
+cname-excluded-good-a CNAME excluded-good-a
+cname-excluded-bad-a CNAME excluded-bad-a
+cname-excluded-only CNAME excluded-only
+cname-partial-excluded-good-a CNAME partial-excluded-good-a
+cname-partial-excluded-bad-a CNAME partial-excluded-bad-a
+cname-partial-excluded-only CNAME partial-excluded-only
+cname-a-only CNAME a-only
+cname-a-and-aaaa CNAME a-and-aaaa
+cname-aaaa-only CNAME aaaa-only
+cname-a-not-mapped CNAME a-not-mapped
+cname-mx-only CNAME mx-only
+cname-non-existent CNAME non-existent
+ttl-less-than-600 500 A 5.6.7.8
+ttl-more-than-600 700 A 5.6.7.8
+ttl-less-than-minimum 1100 A 5.6.7.8
+ttl-more-than-minimum 1300 A 5.6.7.8
diff --git a/bin/tests/system/redirect/ns3/named.conf b/bin/tests/system/redirect/ns3/named.conf
new file mode 100644
index 0000000000..d8e14054cd
--- /dev/null
+++ b/bin/tests/system/redirect/ns3/named.conf
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+controls { /* empty */ };
+
+acl rfc1918 { 10/8; 192.168/16; 172.16/12; };
+
+options {
+ query-source address 10.53.0.3;
+ notify-source 10.53.0.3;
+ transfer-source 10.53.0.3;
+ port 5300;
+ pid-file "named.pid";
+ listen-on { 10.53.0.3; };
+ listen-on-v6 { none; };
+ allow-recursion { 10.53.0.3; };
+ notify yes;
+ dnssec-enable yes;
+ dnssec-validation yes;
+};
+
+zone "." {
+ type master;
+ file "root.db";
+};
+
+zone "example" {
+ type master;
+ file "example.db";
+};
+
+zone "signed" {
+ type master;
+ file "signed.db.signed";
+};
+
+zone "nsec3" {
+ type master;
+ file "nsec3.db.signed";
+};
+
+zone "redirect" {
+ type master;
+ file "redirect.db";
+};
+
+// include "trusted.conf";
diff --git a/bin/tests/system/redirect/ns3/redirect.db b/bin/tests/system/redirect/ns3/redirect.db
new file mode 100644
index 0000000000..3b4efd716b
--- /dev/null
+++ b/bin/tests/system/redirect/ns3/redirect.db
@@ -0,0 +1,21 @@
+; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: redirect.db,v 1.3 2011/03/01 23:48:06 tbox Exp $
+
+$TTL 300
+@ IN SOA a.root-servers.nil. hostmaster.example.net. 0 0 0 0 0
+@ IN NS a.root-servers.nil.
+* IN A 100.100.100.1
+* IN AAAA 2001:ffff:ffff::100.100.100.1
diff --git a/bin/tests/system/redirect/ns3/root.db b/bin/tests/system/redirect/ns3/root.db
new file mode 100644
index 0000000000..3273989a1d
--- /dev/null
+++ b/bin/tests/system/redirect/ns3/root.db
@@ -0,0 +1,25 @@
+; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: root.db,v 1.3 2011/03/01 23:48:06 tbox Exp $
+
+$TTL 3600
+@ SOA a.root-servers.nil. marka.isc.org. 0 0 0 0 0
+@ NS a.root-servers.nil.
+a.root-servers.nil. A 10.53.0.3
+example NS ns1.example.
+ns1.example. A 10.53.0.3
+signed NS ns1.example.
+ns1.signed. A 10.53.0.3
+redirect NS a.root-servers.nil
diff --git a/bin/tests/system/redirect/ns3/sign.sh b/bin/tests/system/redirect/ns3/sign.sh
new file mode 100644
index 0000000000..fe5d562e82
--- /dev/null
+++ b/bin/tests/system/redirect/ns3/sign.sh
@@ -0,0 +1,42 @@
+#!/bin/sh -e
+#
+# Copyright (C) 2011, 2012, 2014 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: sign.sh,v 1.3 2011/03/01 23:48:06 tbox Exp $
+
+SYSTEMTESTTOP=../..
+. $SYSTEMTESTTOP/conf.sh
+
+zone=signed
+infile=example.db
+zonefile=signed.db
+
+key1=`$KEYGEN -q -r $RANDFILE $zone`
+key2=`$KEYGEN -q -r $RANDFILE -fk $zone`
+
+cat $infile $key1.key $key2.key > $zonefile
+
+$SIGNER -P -g -r $RANDFILE -o $zone $zonefile > /dev/null
+
+zone=nsec3
+infile=example.db
+zonefile=nsec3.db
+
+key1=`$KEYGEN -q -r $RANDFILE -3 $zone`
+key2=`$KEYGEN -q -r $RANDFILE -3 -fk $zone`
+
+cat $infile $key1.key $key2.key > $zonefile
+
+$SIGNER -P -3 - -g -r $RANDFILE -o $zone $zonefile > /dev/null
diff --git a/bin/tests/system/redirect/ns4/example.db.in b/bin/tests/system/redirect/ns4/example.db.in
new file mode 100644
index 0000000000..cf08a09a6b
--- /dev/null
+++ b/bin/tests/system/redirect/ns4/example.db.in
@@ -0,0 +1,19 @@
+; Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 300 ; 5 minutes
+@ IN SOA ns.example.net hostmaster.example.net 0 0 0 0 0
+@ NS ns4
+ns2 A 10.53.0.4
+a A 10.53.0.2
diff --git a/bin/tests/system/redirect/ns4/named.conf b/bin/tests/system/redirect/ns4/named.conf
new file mode 100644
index 0000000000..2d077aa3dc
--- /dev/null
+++ b/bin/tests/system/redirect/ns4/named.conf
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: named.conf,v 1.3 2011/03/01 23:48:07 tbox Exp $ */
+
+// NS2
+
+controls { /* empty */ };
+
+acl rfc1918 { 10/8; 192.168/16; 172.16/12; };
+
+options {
+ query-source address 10.53.0.2; /* note this is not 10.53.0.3 */
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port 5300;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ recursion yes;
+ notify yes;
+ dnssec-enable yes;
+ dnssec-validation yes;
+ nxdomain-redirect "redirect";
+
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm hmac-sha256;
+};
+
+controls {
+ inet 10.53.0.4 port 9953 allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "root.hint";
+};
diff --git a/bin/tests/system/redirect/ns4/root.hint b/bin/tests/system/redirect/ns4/root.hint
new file mode 100644
index 0000000000..2dc780cfd9
--- /dev/null
+++ b/bin/tests/system/redirect/ns4/root.hint
@@ -0,0 +1,19 @@
+; Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: root.hint,v 1.5 2007/06/19 23:47:01 tbox Exp $
+
+$TTL 999999
+. IN NS a.root-servers.nil.
+a.root-servers.nil. IN A 10.53.0.3
diff --git a/bin/tests/system/redirect/setup.sh b/bin/tests/system/redirect/setup.sh
index 9fecc9ad81..388999838a 100644
--- a/bin/tests/system/redirect/setup.sh
+++ b/bin/tests/system/redirect/setup.sh
@@ -23,4 +23,7 @@ test -r $RANDFILE || $GENRANDOM 400 $RANDFILE
cp ns2/redirect.db.in ns2/redirect.db
cp ns2/example.db.in ns2/example.db
-cd ns1 && $SHELL sign.sh
+( cd ns1 && $SHELL sign.sh )
+
+cp ns4/example.db.in ns4/example.db
+( cd ns3 && $SHELL sign.sh )
diff --git a/bin/tests/system/redirect/tests.sh b/bin/tests/system/redirect/tests.sh
index dd8dadc850..f2894334c8 100644
--- a/bin/tests/system/redirect/tests.sh
+++ b/bin/tests/system/redirect/tests.sh
@@ -46,7 +46,7 @@ do
status=`expr $status + $ret`
done
-echo "I:checking A redirect works for nonexist ($n)"
+echo "I:checking A zone redirect works for nonexist ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.2 -b 10.53.0.2 a > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
@@ -55,7 +55,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect works for nonexist ($n)"
+echo "I:checking AAAA zone redirect works for nonexist ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.2 -b 10.53.0.2 aaaa > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
@@ -64,7 +64,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect works for nonexist ($n)"
+echo "I:checking ANY zone redirect works for nonexist ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.2 -b 10.53.0.2 any > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
@@ -74,7 +74,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect doesn't work for acl miss ($n)"
+echo "I:checking A zone redirect doesn't work for acl miss ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.2 -b 10.53.0.4 a > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -83,7 +83,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect doesn't work for acl miss ($n)"
+echo "I:checking AAAA zone redirect doesn't work for acl miss ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.2 -b 10.53.0.4 aaaa > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -92,7 +92,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect doesn't work for acl miss ($n)"
+echo "I:checking ANY zone redirect doesn't work for acl miss ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.2 -b 10.53.0.4 any > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -102,7 +102,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect works for signed nonexist, DO=0 ($n)"
+echo "I:checking A zone redirect works for signed nonexist, DO=0 ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. @10.53.0.2 -b 10.53.0.2 a > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
@@ -111,7 +111,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect works for signed nonexist, DO=0 ($n)"
+echo "I:checking AAAA zone redirect works for signed nonexist, DO=0 ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. @10.53.0.2 -b 10.53.0.2 aaaa > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
@@ -120,7 +120,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect works for signed nonexist, DO=0 ($n)"
+echo "I:checking ANY zone redirect works for signed nonexist, DO=0 ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. @10.53.0.2 -b 10.53.0.2 any > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
@@ -130,7 +130,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect fails for signed nonexist, DO=1 ($n)"
+echo "I:checking A zone redirect fails for signed nonexist, DO=1 ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.2 -b 10.53.0.2 a > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -139,7 +139,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect fails for signed nonexist, DO=1 ($n)"
+echo "I:checking AAAA zone redirect fails for signed nonexist, DO=1 ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.2 -b 10.53.0.2 aaaa > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -148,7 +148,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect fails for signed nonexist, DO=1 ($n)"
+echo "I:checking ANY zone redirect fails for signed nonexist, DO=1 ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.2 -b 10.53.0.2 any > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -158,7 +158,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect fails for nsec3 signed nonexist, DO=1 ($n)"
+echo "I:checking A zone redirect fails for nsec3 signed nonexist, DO=1 ($n)"
ret=0
$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.2 -b 10.53.0.2 a > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -168,7 +168,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect fails for nsec3 signed nonexist, DO=1 ($n)"
+echo "I:checking AAAA zone redirect fails for nsec3 signed nonexist, DO=1 ($n)"
ret=0
$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.2 -b 10.53.0.2 aaaa > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -178,7 +178,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect fails for nsec3 signed nonexist, DO=1 ($n)"
+echo "I:checking ANY zone redirect fails for nsec3 signed nonexist, DO=1 ($n)"
ret=0
$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.2 -b 10.53.0.2 any > dig.out.ns2.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1
@@ -189,7 +189,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect works for nonexist authoritative ($n)"
+echo "I:checking A zone redirect works for nonexist authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.1 -b 10.53.0.1 a > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
@@ -198,7 +198,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect works for nonexist authoritative ($n)"
+echo "I:checking AAAA zone redirect works for nonexist authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.1 -b 10.53.0.1 aaaa > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
@@ -207,7 +207,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect works for nonexist authoritative ($n)"
+echo "I:checking ANY zone redirect works for nonexist authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.1 -b 10.53.0.1 any > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
@@ -217,7 +217,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect doesn't work for acl miss authoritative ($n)"
+echo "I:checking A zone redirect doesn't work for acl miss authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.1 -b 10.53.0.4 a > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -226,7 +226,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect doesn't work for acl miss authoritative ($n)"
+echo "I:checking AAAA zone redirect doesn't work for acl miss authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.1 -b 10.53.0.4 aaaa > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -235,7 +235,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect doesn't work for acl miss authoritative ($n)"
+echo "I:checking ANY zone redirect doesn't work for acl miss authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist. @10.53.0.1 -b 10.53.0.4 any > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -245,7 +245,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect works for signed nonexist, DO=0 authoritative ($n)"
+echo "I:checking A zone redirect works for signed nonexist, DO=0 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. @10.53.0.1 -b 10.53.0.1 a > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
@@ -254,7 +254,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect works for signed nonexist, DO=0 authoritative ($n)"
+echo "I:checking AAAA zone redirect works for signed nonexist, DO=0 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. @10.53.0.1 -b 10.53.0.1 aaaa > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
@@ -263,7 +263,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect works for signed nonexist, DO=0 authoritative ($n)"
+echo "I:checking ANY zone redirect works for signed nonexist, DO=0 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. @10.53.0.1 -b 10.53.0.1 any > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
@@ -273,7 +273,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect fails for signed nonexist, DO=1 authoritative ($n)"
+echo "I:checking A zone redirect fails for signed nonexist, DO=1 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.1 -b 10.53.0.1 a > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -282,7 +282,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect fails for signed nonexist, DO=1 authoritative ($n)"
+echo "I:checking AAAA zone redirect fails for signed nonexist, DO=1 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.1 -b 10.53.0.1 aaaa > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -291,7 +291,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect fails for signed nonexist, DO=1 authoritative ($n)"
+echo "I:checking ANY zone redirect fails for signed nonexist, DO=1 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.1 -b 10.53.0.1 any > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -301,7 +301,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking A redirect fails for nsec3 signed nonexist, DO=1 authoritative ($n)"
+echo "I:checking A zone redirect fails for nsec3 signed nonexist, DO=1 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.1 -b 10.53.0.1 a > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -311,7 +311,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking AAAA redirect fails for nsec3 signed nonexist, DO=1 authoritative ($n)"
+echo "I:checking AAAA zone redirect fails for nsec3 signed nonexist, DO=1 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.1 -b 10.53.0.1 aaaa > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -321,7 +321,7 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking ANY redirect fails for nsec3 signed nonexist, DO=1 authoritative ($n)"
+echo "I:checking ANY zone redirect fails for nsec3 signed nonexist, DO=1 authoritative ($n)"
ret=0
$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.1 -b 10.53.0.1 any > dig.out.ns1.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1
@@ -332,7 +332,7 @@ 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)"
+echo "I:checking zone 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
@@ -363,5 +363,128 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
+echo "I:checking A nxdomain-redirect works for nonexist ($n)"
+ret=0
+$DIG $DIGOPTS nonexist. @10.53.0.4 -b 10.53.0.2 a > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "nonexist. .*100.100.100.1" dig.out.ns4.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 AAAA nxdomain-redirect works for nonexist ($n)"
+ret=0
+$DIG $DIGOPTS nonexist. @10.53.0.4 -b 10.53.0.2 aaaa > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "nonexist. .*2001:ffff:ffff::6464:6401" dig.out.ns4.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 ANY nxdomain-redirect works for nonexist ($n)"
+ret=0
+$DIG $DIGOPTS nonexist. @10.53.0.4 -b 10.53.0.2 any > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "100.100.100.1" dig.out.ns4.test$n > /dev/null || ret=1
+grep "2001:ffff:ffff::6464:6401" dig.out.ns4.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 A nxdomain-redirect works for signed nonexist, DO=0 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.signed. @10.53.0.4 -b 10.53.0.2 a > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "100.100.100.1" dig.out.ns4.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 AAAA nxdomain-redirect works for signed nonexist, DO=0 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.signed. @10.53.0.4 -b 10.53.0.2 aaaa > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "2001:ffff:ffff::6464:6401" dig.out.ns4.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 ANY nxdomain-redirect works for signed nonexist, DO=0 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.signed. @10.53.0.4 -b 10.53.0.2 any > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "100.100.100.1" dig.out.ns4.test$n > /dev/null || ret=1
+grep "2001:ffff:ffff::6464:6401" dig.out.ns4.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 A nxdomain-redirect fails for signed nonexist, DO=1 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.4 -b 10.53.0.2 a > dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "100.100.100.1" dig.out.ns4.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 AAAA nxdomain-redirect fails for signed nonexist, DO=1 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.4 -b 10.53.0.2 aaaa > dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "2001:ffff:ffff::6464:6401" dig.out.ns4.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 ANY nxdomain-redirect fails for signed nonexist, DO=1 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.signed. +dnssec @10.53.0.4 -b 10.53.0.2 any > dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "100.100.100.1" dig.out.ns4.test$n > /dev/null && ret=1
+grep "2001:ffff:ffff::6464:6401" dig.out.ns4.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 A nxdomain-redirect fails for nsec3 signed nonexist, DO=1 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.4 -b 10.53.0.2 a > dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "100.100.100.1" dig.out.ns4.test$n > /dev/null && ret=1
+grep "IN.NSEC3" dig.out.ns4.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 AAAA nxdomain-redirect fails for nsec3 signed nonexist, DO=1 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.4 -b 10.53.0.2 aaaa > dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "2001:ffff:ffff::6464:6401" dig.out.ns4.test$n > /dev/null && ret=1
+grep "IN.NSEC3" dig.out.ns4.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 ANY nxdomain-redirect fails for nsec3 signed nonexist, DO=1 ($n)"
+ret=0
+$DIG $DIGOPTS nonexist.nsec3. +dnssec @10.53.0.4 -b 10.53.0.2 any > dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "100.100.100.1" dig.out.ns4.test$n > /dev/null && ret=1
+grep "2001:ffff:ffff::6464:6401" dig.out.ns4.test$n > /dev/null && ret=1
+grep "IN.NSEC3" dig.out.ns4.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 nxdomain-redirect works (with noerror) when qtype is not found ($n)"
+ret=0
+$DIG $DIGOPTS nonexist. @10.53.0.4 -b 10.53.0.2 txt > dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
echo "I:exit status: $status"
exit $status
diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
index b85123e796..528e2df95d 100644
--- a/doc/arm/Bv9ARM-book.xml
+++ b/doc/arm/Bv9ARM-book.xml
@@ -10521,6 +10521,42 @@ example.com CNAME rpz-tcp-only.
RateSlipped and RespTruncated.
+
+
+
+ Named supports NXDOMAIN redirection via two methods:
+
+ Redirect zone
+ Redirect namespace
+
+
+
+ With both methods when named gets a NXDOMAIN response
+ it examines a seperate namespace to see if the NXDOMAIN
+ response should be replaced with a alternative response.
+
+
+ With a redirect zone (zone "." { type redirect; };), the
+ data used to replace the NXDOMAIN is held in a single
+ zone which is not part of the normal namespace. All the
+ redirect information is contained in the zone; there are
+ no delegations.
+
+
+ With a redirect namespace (option { nxdomain-redirect
+ <suffix> };) the data used to replace the
+ NXDOMAIN is part of the normal namespace and is looked up by
+ appending the specified suffix to the original query name.
+ This roughly doubles the cache required to process NXDOMAIN
+ responses as you have the original NXDOMAIN response and
+ the replacement data or a NXDOMAIN indicating that there
+ is no replacement.
+
+
+ If both a redirect zone and a redirect namespace are configured,
+ the redirect zone is tried first.
+
+
diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml
index 9b272c4968..cbde1d9c52 100644
--- a/doc/arm/notes.xml
+++ b/doc/arm/notes.xml
@@ -467,6 +467,14 @@
in the prior response. [RT #39047]
+
+
+ A alternative NXDOMAIN redirect method (nxdomain-redirect)
+ which allows the redirect information to be looked up from
+ a namespace on the Internet rather than requiring a zone
+ to be configured on the server is now available.
+
+
diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h
index 9136267466..e5d2396f06 100644
--- a/lib/dns/include/dns/view.h
+++ b/lib/dns/include/dns/view.h
@@ -199,6 +199,9 @@ struct dns_view {
dns_zone_t * managed_keys;
dns_zone_t * redirect;
+ dns_name_t * redirectzone; /* points to redirectfixed
+ when valid */
+ dns_fixedname_t redirectfixed;
/*
* File and configuration data for zones added at runtime
diff --git a/lib/dns/view.c b/lib/dns/view.c
index 84c00640f7..fb6368615a 100644
--- a/lib/dns/view.c
+++ b/lib/dns/view.c
@@ -230,6 +230,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
dns_fixedname_init(&view->dlv_fixed);
view->managed_keys = NULL;
view->redirect = NULL;
+ view->redirectzone = NULL;
+ dns_fixedname_init(&view->redirectfixed);
view->requestnsid = ISC_FALSE;
view->requestsit = ISC_TRUE;
view->new_zone_file = NULL;
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
index 2f91e543a9..48108a739b 100644
--- a/lib/isccfg/namedconf.c
+++ b/lib/isccfg/namedconf.c
@@ -1530,6 +1530,7 @@ view_clauses[] = {
{ "minimal-responses", &cfg_type_boolean, 0 },
{ "nta-recheck", &cfg_type_ttlval, 0 },
{ "nta-lifetime", &cfg_type_ttlval, 0 },
+ { "nxdomain-redirect", &cfg_type_astring, 0 },
{ "prefetch", &cfg_type_prefetch, 0 },
{ "preferred-glue", &cfg_type_astring, 0 },
{ "no-case-compress", &cfg_type_bracketed_aml, 0 },