]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
move NTA test cases to a separate python test
authorEvan Hunt <each@isc.org>
Thu, 26 Jun 2025 20:05:40 +0000 (13:05 -0700)
committerEvan Hunt <each@isc.org>
Thu, 31 Jul 2025 19:55:40 +0000 (12:55 -0700)
the tests of "rndc nta" behavior have been moved out of the
dnssec shell test, into bin/tests/system/nta, and converted
to python. features of the dnssec test framework that were
needed for NTA testing have been moved to the nta test, and
dnssec has been correspondingly simplified.

22 files changed:
bin/tests/system/dnssec/ns2/named.conf.j2
bin/tests/system/dnssec/ns4/named1.conf.in
bin/tests/system/dnssec/ns4/named2.conf.in
bin/tests/system/dnssec/ns4/named3.conf.in
bin/tests/system/dnssec/ns4/named4.conf.in
bin/tests/system/dnssec/ns5/named.conf.j2
bin/tests/system/dnssec/tests.sh
bin/tests/system/nta/ns1/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nta/ns1/root.db.in [new file with mode: 0644]
bin/tests/system/nta/ns1/sign.sh [new file with mode: 0644]
bin/tests/system/nta/ns2/corp.db [moved from bin/tests/system/dnssec/ns2/corp.db with 100% similarity]
bin/tests/system/nta/ns2/example.db.in [new file with mode: 0644]
bin/tests/system/nta/ns2/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nta/ns2/sign.sh [new file with mode: 0644]
bin/tests/system/nta/ns3/bogus.example.db.in [new file with mode: 0644]
bin/tests/system/nta/ns3/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nta/ns3/secure.example.db.in [new file with mode: 0644]
bin/tests/system/nta/ns3/sign.sh [new file with mode: 0644]
bin/tests/system/nta/ns4/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nta/ns9/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nta/setup.sh [moved from bin/tests/system/dnssec/ntadiff.pl with 58% similarity, mode: 0644]
bin/tests/system/nta/tests_nta.py [new file with mode: 0644]

index 3b31574579a1970b648d020a2e83b8cdb48eb3c3..da6df5d5fbd8dc5223271f3c85e2f62b46b9edce 100644 (file)
@@ -190,11 +190,6 @@ zone "updatecheck-kskonly.secure" {
        allow-update { any; };
 };
 
-zone "corp" {
-       type primary;
-       file "corp.db";
-};
-
 zone "hours-vs-days" {
        type primary;
        file "hours-vs-days.db.signed";
index a2413cef79aa9f35f680f71ce3accae487ecf889..66975a352af0d99e3e28dddab91776f675d4db78 100644 (file)
@@ -24,10 +24,6 @@ options {
        recursion yes;
        minimal-responses no;
 
-       nta-lifetime 12s;
-       nta-recheck 9s;
-       validate-except { corp; };
-
        # Note: We only reference the bind.keys file here to confirm that it
        # is *not* being used.  It contains the real root key, and we're
        # using a local toy root zone for the tests, so it wouldn't work.
@@ -52,8 +48,3 @@ zone "." {
        type hint;
        file "../../_common/root.hint";
 };
-
-zone "corp" {
-       type static-stub;
-       server-addresses { 10.53.0.2; };
-};
index 04d98b89add043ec20dee77d8e360e406bdd003c..c8699834f337917ec677d539bb0392921b47eaeb 100644 (file)
@@ -24,10 +24,6 @@ options {
        recursion yes;
        minimal-responses no;
 
-       nta-lifetime 12s;
-       nta-recheck 9s;
-       validate-except { corp; };
-
        dnssec-validation auto;
        bindkeys-file "managed.conf";
 };
@@ -45,8 +41,3 @@ zone "." {
        type hint;
        file "../../_common/root.hint";
 };
-
-zone "corp" {
-       type static-stub;
-       server-addresses { 10.53.0.2; };
-};
index 28a9abe804024925697e4d2df469396185caa9b8..24012b38e7236c2552a0ca50135786a2aeefe796 100644 (file)
@@ -24,10 +24,6 @@ options {
        recursion yes;
        minimal-responses no;
 
-       nta-lifetime 12s;
-       nta-recheck 9s;
-       validate-except { corp; };
-
        dnssec-accept-expired yes;
        servfail-ttl 0;
 
@@ -48,8 +44,3 @@ zone "." {
        type hint;
        file "../../_common/root.hint";
 };
-
-zone "corp" {
-       type static-stub;
-       server-addresses { 10.53.0.2; };
-};
index 4655d5959ebc801df416dab039ba8ad495914cdd..f5b387d0bdcb718682d8170d42d729da9155b0a9 100644 (file)
@@ -23,9 +23,6 @@ options {
        listen-on-v6 { none; };
        minimal-responses no;
 
-       nta-lifetime 12s;
-       nta-recheck 9s;
-
        disable-algorithms "digest-alg-unsupported.example." { ECDSAP384SHA384; };
        disable-ds-digests "digest-alg-unsupported.example." { "SHA384"; "SHA-384"; };
        disable-ds-digests "ds-unsupported.example." { "SHA256"; "SHA-256"; "SHA384"; "SHA-384"; };
index c47306f3716ff67daeca608b277ce30d0033f1af..bdbd1f3b30f04216cfff71d9d77ea4710f5b18cd 100644 (file)
@@ -61,11 +61,6 @@ controls {
                file "../../_common/root.hint";
        };
 
-       zone "corp" {
-               type static-stub;
-               server-addresses { 10.53.0.2; };
-       };
-
        include "broken.conf";
 {% else %}
        zone "." {
index a5f879b589682fdfc0bdbb317b2fe18e7075d447..d61dbcc7369b4fab093662e50574c22840757dcc 100644 (file)
@@ -2156,7 +2156,7 @@ check_secroots_layout named.secroots.test$n || ret=1
 linecount=$(grep -c "./$DEFAULT_ALGORITHM/$keyid ; static" named.secroots.test$n || true)
 [ "$linecount" -eq 1 ] || ret=1
 linecount=$(wc <named.secroots.test$n -l)
-[ "$linecount" -eq 10 ] || ret=1
+[ "$linecount" -eq 9 ] || ret=1
 n=$((n + 1))
 test "$ret" -eq 0 || echo_i "failed"
 status=$((status + ret))
@@ -2240,492 +2240,6 @@ n=$((n + 1))
 test "$ret" -eq 0 || echo_i "failed"
 status=$((status + ret))
 
-echo_i "checking validate-except in an insecure local domain ($n)"
-ret=0
-dig_with_opts ns www.corp @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n >/dev/null && ret=1
-n=$((n + 1))
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-echo_i "checking positive and negative validation with negative trust anchors ($n)"
-ret=0
-
-#
-# check correct initial behavior
-#
-dig_with_opts a.bogus.example. a @10.53.0.4 >dig.out.ns4.test$n.1 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.1 >/dev/null || ret=1
-dig_with_opts badds.example. soa @10.53.0.4 >dig.out.ns4.test$n.2 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.2 >/dev/null || ret=1
-dig_with_opts a.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.3 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.3 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.3 >/dev/null || ret=1
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - checking initial state"; fi
-status=$((status + ret))
-ret=0
-
-#
-# add negative trust anchors
-#
-rndccmd 10.53.0.4 nta -f -l 20s bogus.example 2>&1 | sed 's/^/ns4 /' | cat_i
-rndccmd 10.53.0.4 nta badds.example 2>&1 | sed 's/^/ns4 /' | cat_i
-# reconfig should maintain NTAs
-rndccmd 10.53.0.4 reconfig 2>&1 | sed 's/^/ns4 /' | cat_i
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.1
-lines=$(wc -l <rndc.out.ns4.test$n.1)
-[ "$lines" -eq 3 ] || ret=1
-rndccmd 10.53.0.4 nta secure.example 2>&1 | sed 's/^/ns4 /' | cat_i
-rndccmd 10.53.0.4 nta fakenode.secure.example 2>&1 | sed 's/^/ns4 /' | cat_i
-# reload should maintain NTAs
-rndc_reload ns4 10.53.0.4
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.2
-lines=$(wc -l <rndc.out.ns4.test$n.2)
-[ "$lines" -eq 5 ] || ret=1
-# shellcheck disable=SC2016
-start=$($PERL -e 'print time()."\n";')
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - adding NTA's failed"; fi
-status=$((status + ret))
-ret=0
-
-#
-# check behavior with NTA's in place
-#
-dig_with_opts a.bogus.example. a @10.53.0.4 >dig.out.ns4.test$n.4 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.4 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.4 >/dev/null && ret=1
-dig_with_opts badds.example. soa @10.53.0.4 >dig.out.ns4.test$n.5 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.5 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.5 >/dev/null && ret=1
-dig_with_opts a.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.6 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.6 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.6 >/dev/null && ret=1
-dig_with_opts a.fakenode.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.7 || ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.7 >/dev/null && ret=1
-echo_i "dumping secroots"
-rndccmd 10.53.0.4 secroots | sed 's/^/ns4 /' | cat_i
-cp ns4/named.secroots named.secroots.test$n
-check_secroots_layout named.secroots.test$n || ret=1
-grep "bogus.example: expiry" named.secroots.test$n >/dev/null || ret=1
-grep "badds.example: expiry" named.secroots.test$n >/dev/null || ret=1
-grep "secure.example: expiry" named.secroots.test$n >/dev/null || ret=1
-grep "fakenode.secure.example: expiry" named.secroots.test$n >/dev/null || ret=1
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - with NTA's in place failed"; fi
-status=$((status + ret))
-ret=0
-
-echo_i "waiting for NTA rechecks/expirations"
-
-#
-# secure.example and badds.example used default nta-duration
-# (configured as 12s in ns4/named1.conf), but nta recheck interval
-# is configured to 9s, so at t=10 the NTAs for secure.example and
-# fakenode.secure.example should both be lifted, but badds.example
-# should still be going.
-#
-# shellcheck disable=SC2016
-$PERL -e 'my $delay =  '"$start"' + 10 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
-dig_with_opts b.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.8 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.8 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.8 >/dev/null || ret=1
-dig_with_opts b.fakenode.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.9 || ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.9 >/dev/null || ret=1
-grep "status: NXDOMAIN" dig.out.ns4.test$n.9 >/dev/null || ret=1
-dig_with_opts badds.example. soa @10.53.0.4 >dig.out.ns4.test$n.10 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.10 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.10 >/dev/null && ret=1
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - checking that default nta's were lifted due to recheck"; fi
-status=$((status + ret))
-ret=0
-
-#
-# bogus.example was set to expire in 20s, so at t=13
-# it should still be NTA'd, but badds.example used the default
-# lifetime of 12s, so it should revert to SERVFAIL now.
-#
-# shellcheck disable=SC2016
-$PERL -e 'my $delay = '"$start"' + 13 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
-# check nta table
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n._11
-lines=$(grep -c " expiry " rndc.out.ns4.test$n._11 || true)
-[ "$lines" -le 2 ] || ret=1
-grep "bogus.example/_default: expiry" rndc.out.ns4.test$n._11 >/dev/null || ret=1
-grep "badds.example/_default: expiry" rndc.out.ns4.test$n._11 >/dev/null && ret=1
-dig_with_opts b.bogus.example. a @10.53.0.4 >dig.out.ns4.test$n.11 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.11 >/dev/null && ret=1
-dig_with_opts a.badds.example. a @10.53.0.4 >dig.out.ns4.test$n.12 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.12 >/dev/null || ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.12 >/dev/null && ret=1
-dig_with_opts c.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.13 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.13 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.13 >/dev/null || ret=1
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - checking that default nta's were lifted due to lifetime"; fi
-status=$((status + ret))
-ret=0
-
-#
-# at t=21, all the NTAs should have expired.
-#
-# shellcheck disable=SC2016
-$PERL -e 'my $delay = '"$start"' + 21 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
-# check correct behavior after bogus.example expiry
-dig_with_opts d.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.14 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.14 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.14 >/dev/null || ret=1
-dig_with_opts c.bogus.example. a @10.53.0.4 >dig.out.ns4.test$n.15 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.15 >/dev/null || ret=1
-# check nta table has been cleaned up now
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.3
-lines=$(grep -c " expiry " rndc.out.ns4.test$n.3 || true)
-[ "$lines" -eq 0 ] || ret=1
-n=$((n + 1))
-if [ "$ret" -ne 0 ]; then echo_i "failed - checking that all nta's have been lifted"; fi
-status=$((status + ret))
-ret=0
-
-echo_i "testing NTA removals ($n)"
-rndccmd 10.53.0.4 nta badds.example 2>&1 | sed 's/^/ns4 /' | cat_i
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.1
-grep "badds.example/_default: expiry" rndc.out.ns4.test$n.1 >/dev/null || ret=1
-dig_with_opts a.badds.example. a @10.53.0.4 >dig.out.ns4.test$n.1 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.1 >/dev/null && ret=1
-grep "^a.badds.example." dig.out.ns4.test$n.1 >/dev/null || ret=1
-rndccmd 10.53.0.4 nta -remove badds.example >rndc.out.ns4.test$n.2
-grep "Negative trust anchor removed: badds.example/_default" rndc.out.ns4.test$n.2 >/dev/null || ret=1
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.3
-grep "badds.example/_default: expiry" rndc.out.ns4.test$n.3 >/dev/null && ret=1
-dig_with_opts a.badds.example. a @10.53.0.4 >dig.out.ns4.test$n.2 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.2 >/dev/null || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-ret=0
-
-echo_i "remove non-existent NTA three times"
-rndccmd 10.53.0.4 nta -r foo >rndc.out.ns4.test$n.4 2>&1
-rndccmd 10.53.0.4 nta -remove foo >rndc.out.ns4.test$n.5 2>&1
-rndccmd 10.53.0.4 nta -r foo >rndc.out.ns4.test$n.6 2>&1
-grep "not found" rndc.out.ns4.test$n.6 >/dev/null || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-ret=0
-
-n=$((n + 1))
-echo_i "testing NTA with bogus lifetimes ($n)"
-echo_i "check with no nta lifetime specified"
-rndccmd 10.53.0.4 nta -l "" foo >rndc.out.ns4.test$n.1 2>&1 || true
-grep "'nta' failed: bad ttl" rndc.out.ns4.test$n.1 >/dev/null || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-ret=0
-
-echo_i "check with bad nta lifetime"
-rndccmd 10.53.0.4 nta -l garbage foo >rndc.out.ns4.test$n.2 2>&1 || true
-grep "'nta' failed: bad ttl" rndc.out.ns4.test$n.2 >/dev/null || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-ret=0
-
-echo_i "check with too long nta lifetime"
-rndccmd 10.53.0.4 nta -l 7d1h foo >rndc.out.ns4.test$n.3 2>&1 || true
-grep "'nta' failed: out of range" rndc.out.ns4.test$n.3 >/dev/null || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-ret=0
-
-#
-# check NTA persistence across restarts
-#
-n=$((n + 1))
-echo_i "testing NTA persistence across restarts ($n)"
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.1
-lines=$(grep -c " expiry " rndc.out.ns4.test$n.1 || true)
-[ "$lines" -eq 0 ] || ret=1
-rndccmd 10.53.0.4 nta -f -l 30s bogus.example 2>&1 | sed 's/^/ns4 /' | cat_i
-rndccmd 10.53.0.4 nta -f -l 10s badds.example 2>&1 | sed 's/^/ns4 /' | cat_i
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.2
-lines=$(grep -c " expiry " rndc.out.ns4.test$n.2 || true)
-[ "$lines" -eq 2 ] || ret=1
-# shellcheck disable=SC2016
-start=$($PERL -e 'print time()."\n";')
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - NTA persistence: adding NTA's failed"; fi
-status=$((status + ret))
-ret=0
-
-echo_i "killing ns4 with SIGTERM"
-kill -TERM "$(cat ns4/named.pid)"
-rm -f ns4/named.pid
-
-#
-# ns4 has now shutdown. wait until t=14 when badds.example's NTA
-# (lifetime=10s) would have expired, and then restart ns4.
-#
-echo_i "waiting till 14s have passed since NTAs were added before restarting ns4"
-# shellcheck disable=SC2016
-$PERL -e 'my $delay = '"$start"' + 14 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
-
-if
-  start_server --noclean --restart --port "$PORT" ns4
-then
-  echo_i "restarted server ns4"
-else
-  echo_i "could not restart server ns4"
-  exit 1
-fi
-
-echo_i "sleeping for an additional 4 seconds for ns4 to fully startup"
-sleep 4
-
-#
-# ns4 should be back up now. The NTA for bogus.example should still be
-# valid, whereas badds.example should not have been added during named
-# startup (as it had already expired), the fact that it's ignored should
-# be logged.
-#
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.3
-lines=$(wc -l <rndc.out.ns4.test$n.3)
-[ "$lines" -eq 2 ] || ret=1
-grep "bogus.example/_default: expiry" rndc.out.ns4.test$n.3 >/dev/null || ret=1
-dig_with_opts b.bogus.example. a @10.53.0.4 >dig.out.ns4.test$n.4 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.4 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.4 >/dev/null && ret=1
-dig_with_opts a.badds.example. a @10.53.0.4 >dig.out.ns4.test$n.5 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.5 >/dev/null || ret=1
-grep "ignoring expired NTA at badds.example" ns4/named.run >/dev/null || ret=1
-
-# cleanup
-rndccmd 10.53.0.4 nta -remove bogus.example >rndc.out.ns4.test$n.6
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - NTA persistence: restoring NTA failed"; fi
-status=$((status + ret))
-ret=0
-
-#
-# check "regular" attribute in NTA file works as expected at named
-# startup.
-#
-n=$((n + 1))
-echo_i "testing loading regular attribute from NTA file ($n)"
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.1 2>/dev/null
-lines=$(wc -l <rndc.out.ns4.test$n.1)
-[ "$lines" -eq 1 ] || ret=1
-# initially, secure.example. validates with AD=1
-dig_with_opts a.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.2 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.2 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.2 >/dev/null || ret=1
-
-echo_i "killing ns4 with SIGTERM"
-kill -TERM "$(cat ns4/named.pid)"
-rm -f ns4/named.pid
-
-echo_i "sleeping for an additional 4 seconds for ns4 to fully shutdown"
-sleep 4
-
-#
-# ns4 has now shutdown. add NTA for secure.example. directly into the
-# _default.nta file with the regular attribute and some future timestamp.
-#
-future="$(($(date +%Y) + 20))0101010000"
-echo "secure.example. regular $future" >ns4/_default.nta
-# shellcheck disable=SC2016
-start=$($PERL -e 'print time()."\n";')
-
-if
-  start_server --noclean --restart --port "$PORT" ns4
-then
-  echo_i "restarted server ns4"
-else
-  echo_i "could not restart server ns4"
-  exit 1
-fi
-
-# nta-recheck is configured as 9s, so at t=12 the NTAs for
-# secure.example. should be lifted as it is not a forced NTA.
-echo_i "waiting till 12s have passed after ns4 was restarted"
-# shellcheck disable=SC2016
-$PERL -e 'my $delay = '"$start"' + 12 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
-
-# secure.example. should now return an AD=1 answer (still validates) as
-# the NTA has been lifted.
-dig_with_opts a.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.3 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.3 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.3 >/dev/null || ret=1
-
-# cleanup
-rndccmd 10.53.0.4 nta -remove secure.example >rndc.out.ns4.test$n.4 2>/dev/null
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - NTA persistence: loading regular NTAs failed"; fi
-status=$((status + ret))
-ret=0
-
-#
-# check "forced" attribute in NTA file works as expected at named
-# startup.
-#
-n=$((n + 1))
-echo_i "testing loading forced attribute from NTA file ($n)"
-rndccmd 10.53.0.4 nta -d >rndc.out.ns4.test$n.1 2>/dev/null
-lines=$(wc -l <rndc.out.ns4.test$n.1)
-[ "$lines" -eq 1 ] || ret=1
-# initially, secure.example. validates with AD=1
-dig_with_opts a.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.2 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.2 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.2 >/dev/null || ret=1
-
-echo_i "killing ns4 with SIGTERM"
-kill -TERM "$(cat ns4/named.pid)"
-rm -f named.pid
-
-echo_i "sleeping for an additional 4 seconds for ns4 to fully shutdown"
-sleep 4
-
-#
-# ns4 has now shutdown. add NTA for secure.example. directly into the
-# _default.nta file with the forced attribute and some future timestamp.
-#
-echo "secure.example. forced $future" >ns4/_default.nta
-start=$($PERL -e 'print time()."\n";')
-
-if
-  start_server --noclean --restart --port "$PORT" ns4
-then
-  echo_i "restarted server ns4"
-else
-  echo_i "could not restart server ns4"
-  exit 1
-fi
-
-# nta-recheck is configured as 9s, but even at t=12 the NTAs for
-# secure.example. should not be lifted as it is a forced NTA.
-echo_i "waiting till 12s have passed after ns4 was restarted"
-# shellcheck disable=SC2016
-$PERL -e 'my $delay = '"$start"' + 12 - time(); select(undef, undef, undef, $delay) if ($delay > 0);'
-
-# secure.example. should now return an AD=0 answer (non-authenticated)
-# as the NTA is still there.
-dig_with_opts a.secure.example. a @10.53.0.4 >dig.out.ns4.test$n.3 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.3 >/dev/null && ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.3 >/dev/null && ret=1
-
-# cleanup
-rndccmd 10.53.0.4 nta -remove secure.example >rndc.out.ns4.test$n.4 2>/dev/null
-
-if [ "$ret" -ne 0 ]; then echo_i "failed - NTA persistence: loading forced NTAs failed"; fi
-status=$((status + ret))
-ret=0
-
-#
-# check that NTA lifetime read from file is clamped to 1 week.
-#
-n=$((n + 1))
-echo_i "testing loading out of bounds lifetime from NTA file ($n)"
-
-echo_i "killing ns4 with SIGTERM"
-kill -TERM "$(cat ns4/named.pid)"
-rm -f ns4/named.pid
-
-echo_i "sleeping for an additional 4 seconds for ns4 to fully shutdown"
-sleep 4
-
-#
-# ns4 has now shutdown. add NTA for secure.example. directly into the
-# _default.nta file with a lifetime well into the future.
-#
-echo "secure.example. forced $future" >ns4/_default.nta
-added=$($PERL -e 'print time()."\n";')
-
-if
-  start_server --noclean --restart --port "$PORT" ns4
-then
-  echo_i "restarted server ns4"
-else
-  echo_i "could not restart server ns4"
-  exit 1
-fi
-
-echo_i "sleeping for an additional 4 seconds for ns4 to fully startup"
-sleep 4
-
-# dump the NTA to a file (omit validate-except entries)
-echo_i "testing 'rndc nta -d' with NTA"
-rndccmd 10.53.0.4 nta -d | grep -v ": permanent" >rndc.out.ns4.test$n.1 2>/dev/null
-# "corp" is configured as a validate-except domain and thus should be
-# removed by the grep -v above. only "secure.example" should appear in
-# the dump.
-lines=$(wc -l <rndc.out.ns4.test$n.1)
-[ "$lines" -eq 1 ] || ret=1
-grep 'secure.example' rndc.out.ns4.test$n.1 >/dev/null || ret=1
-ts=$(awk '{print $3" "$4}' <rndc.out.ns4.test$n.1)
-# rndc nta outputs localtime, so append the timezone
-ts_with_zone="$ts $(date +%z)"
-echo "ts=$ts" >rndc.out.ns4.test$n.2
-echo "ts_with_zone=$ts_with_zone" >>rndc.out.ns4.test$n.2
-echo "added=$added" >>rndc.out.ns4.test$n.2
-if $PERL -e 'use Time::Piece; use Time::Seconds;' 2>/dev/null; then
-  # ntadiff.pl computes $ts_with_zone - ($added + 1week)
-  d=$($PERL ./ntadiff.pl "$ts_with_zone" "$added")
-  echo "d=$d" >>rndc.out.ns4.test$n.2
-  # diff from $added(now) + 1week to the clamped NTA lifetime should be
-  # less than a few seconds (handle daylight saving changes by adding 3600).
-  [ "$d" -lt 3610 ] || ret=1
-else
-  echo_i "skipped ntadiff test; install PERL module Time::Piece"
-fi
-
-echo_i "testing 'rndc nta' lifetime clamping"
-rndccmd 10.53.0.4 nta -d | grep ": permanent" >rndc.out.ns4.test$n.1 2>/dev/null
-# "corp" is configured as a validate-except domain and thus should be
-# the only entry in the dump.
-lines=$(wc -l <rndc.out.ns4.test$n.1)
-[ "$lines" -eq 1 ] || ret=1
-grep 'corp/_default' rndc.out.ns4.test$n.1 >/dev/null || ret=1
-
-# cleanup
-rndccmd 10.53.0.4 nta -remove secure.example >rndc.out.ns4.test$n.3 2>/dev/null
-
-n=$((n + 1))
-if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-echo_i "testing 'rndc nta -d' displays validate-except entries"
-rndccmd 10.53.0.4 nta -d | grep ": permanent" >rndc.out.ns4.test$n.1 2>/dev/null
-lines=$(wc -l <rndc.out.ns4.test$n.1)
-[ "$lines" -eq 1 ] || ret=1
-grep 'corp/_default' rndc.out.ns4.test$n.1 >/dev/null || ret=1
-n=$((n + 1))
-if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-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_with_opts @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_with_opts @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_with_opts @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=$((status + ret))
-
-echo_i "completed NTA tests"
-
 # Run a minimal update test if possible.  This is really just
 # a regression test for RT #2399; more tests should be added.
 
diff --git a/bin/tests/system/nta/ns1/named.conf.j2 b/bin/tests/system/nta/ns1/named.conf.j2
new file mode 100644 (file)
index 0000000..bd1ccc4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+// NS1
+
+options {
+       query-source address 10.53.0.1;
+       notify-source 10.53.0.1;
+       transfer-source 10.53.0.1;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.1; };
+       listen-on-v6 { none; };
+       recursion no;
+       notify yes;
+       dnssec-validation yes;
+       /* test that we can turn off trust-anchor-telemetry */
+       trust-anchor-telemetry no;
+};
+
+zone "." {
+       type primary;
+       file "root.db.signed";
+};
+
+include "trusted.conf";
diff --git a/bin/tests/system/nta/ns1/root.db.in b/bin/tests/system/nta/ns1/root.db.in
new file mode 100644 (file)
index 0000000..34f7773
--- /dev/null
@@ -0,0 +1,24 @@
+; 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.
+
+$TTL 300
+.                      IN SOA  gson.nominum.com. a.root.servers.nil. (
+                               2000042100      ; serial
+                               600             ; refresh
+                               600             ; retry
+                               1200            ; expire
+                               600             ; minimum
+                               )
+.                      NS      a.root-servers.nil.
+a.root-servers.nil.    A       10.53.0.1
+
+example.               NS      ns2.example.
+ns2.example.           A       10.53.0.2
diff --git a/bin/tests/system/nta/ns1/sign.sh b/bin/tests/system/nta/ns1/sign.sh
new file mode 100644 (file)
index 0000000..243503d
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh -e
+
+# 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.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+zone=.
+infile=root.db.in
+zonefile=root.db
+
+(cd ../ns2 && $SHELL sign.sh)
+
+cp "../ns2/dsset-example." .
+
+ksk=$("$KEYGEN" -q -fk -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+zsk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+
+cat "$infile" "$ksk.key" "$zsk.key" >"$zonefile"
+
+"$SIGNER" -g -o "$zone" "$zonefile" >/dev/null 2>&1
+
+# Configure the resolving server with a static key.
+keyfile_to_static_ds "$ksk" >trusted.conf
+cp trusted.conf ../ns4/trusted.conf
+cp trusted.conf ../ns9/trusted.conf
diff --git a/bin/tests/system/nta/ns2/example.db.in b/bin/tests/system/nta/ns2/example.db.in
new file mode 100644 (file)
index 0000000..f72258f
--- /dev/null
@@ -0,0 +1,35 @@
+; 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.
+
+$TTL 300       ; 5 minutes
+@                      IN SOA  mname1. . (
+                               2000042407 ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns2
+                       NS      ns3
+ns2                    A       10.53.0.2
+ns3                    A       10.53.0.3
+
+; A secure subdomain
+secure                 NS      ns3.secure
+ns3.secure             A       10.53.0.3
+
+; A secure subdomain we're going to inject bogus data into
+bogus                  NS      ns.bogus
+ns.bogus               A       10.53.0.3
+
+; A subdomain with a corrupt DS
+badds                  NS      ns.badds
+ns.badds               A       10.53.0.3
diff --git a/bin/tests/system/nta/ns2/named.conf.j2 b/bin/tests/system/nta/ns2/named.conf.j2
new file mode 100644 (file)
index 0000000..9bfbcde
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+// NS2
+
+options {
+       query-source address 10.53.0.2;
+       notify-source 10.53.0.2;
+       transfer-source 10.53.0.2;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.2; };
+       listen-on-v6 { none; };
+       allow-transfer { any; };
+       recursion no;
+       notify yes;
+        notify-delay 1;
+       dnssec-validation no;
+       minimal-responses no;
+};
+
+key rndc_key {
+        secret "1234abcd8765";
+        algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+        inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "example" {
+       type primary;
+       file "example.db.signed";
+       allow-update { any; };
+};
+
+zone "corp" {
+       type primary;
+       file "corp.db";
+};
diff --git a/bin/tests/system/nta/ns2/sign.sh b/bin/tests/system/nta/ns2/sign.sh
new file mode 100644 (file)
index 0000000..5eb698e
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh -e
+
+# 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.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+# Sign child zones (served by ns3).
+(cd ../ns3 && $SHELL sign.sh)
+
+# The "example." zone.
+zone=example.
+infile=example.db.in
+zonefile=example.db
+
+# Get the DS records for the "example." zone.
+for subdomain in bogus badds secure; do
+  cp "../ns3/dsset-$subdomain.example." .
+done
+
+# Sign the "example." zone.
+keyname1=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -f KSK "$zone")
+keyname2=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" "$zone")
+
+cat "$infile" "$keyname1.key" "$keyname2.key" >"$zonefile"
+
+"$SIGNER" -g -o "$zone" -k "$keyname1" "$zonefile" "$keyname2" >/dev/null 2>&1
diff --git a/bin/tests/system/nta/ns3/bogus.example.db.in b/bin/tests/system/nta/ns3/bogus.example.db.in
new file mode 100644 (file)
index 0000000..0feb441
--- /dev/null
@@ -0,0 +1,27 @@
+; 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.
+
+$TTL 300       ; 5 minutes
+@                      IN SOA  mname1. . (
+                               2000042407 ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns
+ns                     A       10.53.0.3
+
+a                      A       10.0.0.1
+b                      A       10.0.0.2
+c                      A       10.0.0.3
+d                      A       10.0.0.4
+z                      A       10.0.0.26
diff --git a/bin/tests/system/nta/ns3/named.conf.j2 b/bin/tests/system/nta/ns3/named.conf.j2
new file mode 100644 (file)
index 0000000..3c3f256
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+// NS3
+
+options {
+       query-source address 10.53.0.3;
+       notify-source 10.53.0.3;
+       transfer-source 10.53.0.3;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.3; };
+       listen-on-v6 { none; };
+       allow-transfer { any; };
+       recursion no;
+       notify yes;
+       dnssec-validation no;
+       minimal-responses no;
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+       inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "example" {
+       type secondary;
+       primaries { 10.53.0.2; };
+       file "example.bk";
+};
+
+zone "secure.example" {
+       type primary;
+       file "secure.example.db.signed";
+       allow-update { any; };
+};
+
+zone "bogus.example" {
+       type primary;
+       file "bogus.example.db.signed";
+       allow-update { any; };
+};
+
+zone "badds.example" {
+       type primary;
+       file "badds.example.db.signed";
+       allow-update { any; };
+};
diff --git a/bin/tests/system/nta/ns3/secure.example.db.in b/bin/tests/system/nta/ns3/secure.example.db.in
new file mode 100644 (file)
index 0000000..182329b
--- /dev/null
@@ -0,0 +1,30 @@
+; 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.
+
+$TTL 300       ; 5 minutes
+@                      IN SOA  mname1. . (
+                               2000042407 ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns3
+ns3                    A       10.53.0.3
+
+a                      A       10.0.0.1
+b                      A       10.0.0.2
+c                      A       10.0.0.3
+d                      A       10.0.0.4
+e                      A       10.0.0.5
+f                      A       10.0.0.6
+g                      A       10.0.0.7
+z                      A       10.0.0.26
diff --git a/bin/tests/system/nta/ns3/sign.sh b/bin/tests/system/nta/ns3/sign.sh
new file mode 100644 (file)
index 0000000..5e5405a
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/sh -e
+
+# 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.
+
+# shellcheck source=conf.sh
+. ../../conf.sh
+
+set -e
+
+# a validly signed zone
+zone=secure.example.
+infile=secure.example.db.in
+zonefile=secure.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+
+cat "$infile" "$keyname.key" >"$zonefile"
+
+"$SIGNER" -z -D -o "$zone" "$zonefile" >/dev/null
+cat "$zonefile" "$zonefile".signed >"$zonefile".tmp
+mv "$zonefile".tmp "$zonefile".signed
+
+# a zone that we'll add bogus data to
+zone=bogus.example.
+infile=bogus.example.db.in
+zonefile=bogus.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+
+cat "$infile" "$keyname.key" >"$zonefile"
+
+"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null
+
+{
+  echo "a.bogus.example.       A       10.0.0.22"
+  echo "b.bogus.example.       A       10.0.0.23"
+  echo "c.bogus.example.       A       10.0.0.23"
+} >>bogus.example.db.signed
+
+#
+# A zone with a bad DS in the parent
+# (sourced from bogus.example.db.in)
+#
+zone=badds.example.
+infile=bogus.example.db.in
+zonefile=badds.example.db
+
+keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
+
+cat "$infile" "$keyname.key" >"$zonefile"
+
+"$SIGNER" -P -o "$zone" "$zonefile" >/dev/null
+sed -e 's/bogus/badds/g' <dsset-bogus.example. >dsset-badds.example.
diff --git a/bin/tests/system/nta/ns4/named.conf.j2 b/bin/tests/system/nta/ns4/named.conf.j2
new file mode 100644 (file)
index 0000000..87f70e2
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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;
+       minimal-responses no;
+
+       nta-lifetime 12s;
+       nta-recheck 9s;
+       validate-except { corp; };
+
+       dnssec-validation yes;
+};
+
+include "trusted.conf";
+
+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; };
+};
diff --git a/bin/tests/system/nta/ns9/named.conf.j2 b/bin/tests/system/nta/ns9/named.conf.j2
new file mode 100644 (file)
index 0000000..cdbe7ec
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+// 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-validation yes;
+       forward only;
+       forwarders { 10.53.0.4; };
+       servfail-ttl 0;
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+       inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+include "trusted.conf";
old mode 100755 (executable)
new mode 100644 (file)
similarity index 58%
rename from bin/tests/system/dnssec/ntadiff.pl
rename to bin/tests/system/nta/setup.sh
index ca80eac..4a4db2d
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/bin/sh -e
 
 # Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 #
 # See the COPYRIGHT file distributed with this work for additional
 # information regarding copyright ownership.
 
-use strict;
-use Time::Piece;
-use Time::Seconds;
+# shellcheck source=conf.sh
+. ../conf.sh
 
-exit 1 if (scalar(@ARGV) != 2);
+set -e
 
-my $actual = Time::Piece->strptime($ARGV[0], '%d-%b-%Y %H:%M:%S.000 %z');
-my $expected = Time::Piece->strptime($ARGV[1], '%s') + ONE_WEEK;
-my $diff = abs($actual - $expected);
-
-print($diff . "\n");
+(
+  cd ns1
+  $SHELL sign.sh
+)
diff --git a/bin/tests/system/nta/tests_nta.py b/bin/tests/system/nta/tests_nta.py
new file mode 100644 (file)
index 0000000..088a3c5
--- /dev/null
@@ -0,0 +1,430 @@
+# 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.
+
+import os
+import re
+import time
+
+import pytest
+
+import isctest
+
+
+# helper functions
+def hasmatch(regex, blob):
+    return re.search(regex, blob, flags=re.MULTILINE)
+
+
+def active(blob):
+    return len([x for x in blob.splitlines() if " expiry" in x])
+
+
+# global start-time variable
+# pylint: disable=global-statement
+# pylint: disable=global-variable-not-assigned
+start = 0
+
+
+def test_initial():
+    m = isctest.query.create("a.bogus.example.", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.servfail(res)
+
+    m = isctest.query.create("badds.example.", "SOA")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.servfail(res)
+
+    m = isctest.query.create("a.secure.example.", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+
+
+def test_nta_validate_except(servers):
+    ns4 = servers["ns4"]
+    response = ns4.rndc("secroots -", log=False)
+    assert hasmatch("^corp: permanent", response)
+
+    # check insecure local domain works with validate-except
+    m = isctest.query.create("www.corp", "NS")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+
+def test_nta_bogus_lifetimes(servers):
+    ns4 = servers["ns4"]
+
+    # no nta lifetime specified:
+    response = ns4.rndc("nta -l '' foo", ignore_errors=True, log=False)
+    assert "'nta' failed: bad ttl" in response
+
+    # bad nta lifetime:
+    response = ns4.rndc("nta -l garbage foo", ignore_errors=True, log=False)
+    assert "'nta' failed: bad ttl" in response
+
+    # excessive nta lifetime:
+    response = ns4.rndc("nta -l 7d1h foo", ignore_errors=True, log=False)
+    assert "'nta' failed: out of range" in response
+
+
+def test_nta_install(servers):
+    global start
+
+    ns4 = servers["ns4"]
+    ns4.rndc("nta -f -l 20s bogus.example", log=False)
+    ns4.rndc("nta badds.example", log=False)
+
+    # NTAs should persist after reconfig
+    with ns4.watch_log_from_here() as watcher:
+        ns4.reconfigure(log=False)
+        watcher.wait_for_line("any newly configured zones are now loaded")
+
+    response = ns4.rndc("nta -d", log=False)
+    assert len(response.splitlines()) == 3
+
+    ns4.rndc("nta secure.example", log=False)
+    ns4.rndc("nta fakenode.secure.example", log=False)
+    with ns4.watch_log_from_here() as watcher:
+        ns4.rndc("reload", log=False)
+        watcher.wait_for_line("all zones loaded")
+
+    response = ns4.rndc("nta -d", log=False)
+    assert len(response.splitlines()) == 5
+
+    start = time.time()
+
+
+def test_nta_behavior(servers):
+    global start
+    assert start, "test_nta_behavior must be run as part of the full NTA test"
+
+    m = isctest.query.create("a.bogus.example.", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+    m = isctest.query.create("badds.example.", "SOA")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+    m = isctest.query.create("a.secure.example.", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+    m = isctest.query.create("a.fakenode.secure.example.", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noadflag(res)
+
+    ns4 = servers["ns4"]
+    response = ns4.rndc("secroots -", log=False)
+    assert hasmatch("^bogus.example: expiry", response)
+    assert hasmatch("^badds.example: expiry", response)
+    assert hasmatch("^secure.example: expiry", response)
+    assert hasmatch("^fakenode.secure.example: expiry", response)
+
+    # secure.example and badds.example used the default nta-duration
+    # (configured as 12s in ns4/named1.conf), but the nta recheck interval
+    # is configured to 9s, so at t=10 the NTAs for secure.example and
+    # fakenode.secure.example should both be lifted, while badds.example
+    # should still be going.
+    delay = start + 10 - time.time()
+    if delay > 0:
+        time.sleep(delay)
+
+    m = isctest.query.create("b.secure.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+
+    m = isctest.query.create("b.fakenode.secure.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.nxdomain(res)
+    isctest.check.adflag(res)
+
+    m = isctest.query.create("badds.example.", "SOA")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+    # bogus.example was set to expire in 20s, so at t=13
+    # it should still be NTA'd, but badds.example used the default
+    # lifetime of 12s, so it should revert to SERVFAIL now.
+    delay = start + 13 - time.time()
+    if delay > 0:
+        time.sleep(delay)
+
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) <= 2
+
+    response = ns4.rndc("secroots -", log=False)
+    assert hasmatch("bogus.example: expiry", response)
+    assert not hasmatch("badds.example: expiry", response)
+
+    m = isctest.query.create("b.bogus.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+
+    m = isctest.query.create("a.badds.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.servfail(res)
+    isctest.check.noadflag(res)
+
+    m = isctest.query.create("c.secure.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+
+    # at t=21, all the NTAs should have expired.
+    delay = start + 21 - time.time()
+    if delay > 0:
+        time.sleep(delay)
+
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) == 0
+
+    m = isctest.query.create("d.secure.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+
+    m = isctest.query.create("c.bogus.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.servfail(res)
+    isctest.check.noadflag(res)
+
+
+def test_nta_removals(servers):
+    ns4 = servers["ns4"]
+    ns4.rndc("nta badds.example", log=False)
+
+    response = ns4.rndc("nta -d", log=False)
+    assert hasmatch("^badds.example/_default: expiry", response)
+
+    m = isctest.query.create("a.badds.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+    response = ns4.rndc("nta -remove badds.example", log=False)
+    assert "Negative trust anchor removed: badds.example" in response
+
+    response = ns4.rndc("nta -d", log=False)
+    assert not hasmatch("^badds.example/_default: expiry", response)
+
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.servfail(res)
+    isctest.check.noadflag(res)
+
+    # remove non-existent NTA three times
+    ns4.rndc("nta -r foo", log=False)
+    ns4.rndc("nta -remove foo", log=False)
+    response = ns4.rndc("nta -r foo", log=False)
+    assert "not found" in response
+
+
+def test_nta_restarts(servers):
+    global start
+    assert start, "test_nta_restarts must be run as part of the full NTA test"
+
+    # test NTA persistence across restarts
+    ns4 = servers["ns4"]
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) == 0
+
+    start = time.time()
+    ns4.rndc("nta -f -l 30s bogus.example", log=False)
+    ns4.rndc("nta -f -l 10s badds.example", log=False)
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) == 2
+
+    # stop the server
+    ns4.stop()
+
+    # wait 14s before restarting. badds.example's NTA (lifetime=10s) should
+    # have expired, and bogus.example should still be running.
+    delay = start + 14 - time.time()
+    if delay > 0:
+        time.sleep(delay)
+    ns4.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
+
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) == 1
+    assert hasmatch("^bogus.example/_default: expiry", response)
+
+    m = isctest.query.create("a.badds.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.servfail(res)
+
+    m = isctest.query.create("a.bogus.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+    ns4.rndc("nta -r bogus.example", log=False)
+
+
+def test_nta_regular(servers):
+    global start
+    assert start, "test_nta_regular must be run as part of the full NTA test"
+
+    # check "regular" attribute in NTA file
+    ns4 = servers["ns4"]
+
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) == 0
+
+    # secure.example validates with AD=1
+    m = isctest.query.create("a.secure.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+
+    # stop the server, update _default.nta, restart
+    ns4.stop()
+    now = time.localtime()
+    future = str(now.tm_year + 20) + "0101010000"
+    with open("ns4/_default.nta", "w", encoding="utf-8") as f:
+        f.write(f"secure.example. regular {future}")
+
+    ns4.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
+
+    # NTA active; secure.example. should now return an AD=0 answer.
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+    # nta-recheck is configured as 9s, so at t=12 the NTA for
+    # secure.example. should be lifted as it is not a "forced" NTA.
+    start = time.mktime(now)
+    delay = start + 12 - time.time()
+    if delay > 0:
+        time.sleep(delay)
+
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) == 0
+
+    # NTA lifted; secure.example. flush the cache to trigger a new query,
+    # and it should now return an AD=1 answer.
+    ns4.rndc("flushtree secure.example", log=False)
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+
+
+def test_nta_forced(servers):
+    global start
+    assert start, "test_nta_regular must be run as part of the full NTA test"
+
+    # check "forced" attribute in NTA file
+    ns4 = servers["ns4"]
+
+    # just to be certain, clean up any existing NTA first
+    ns4.rndc("nta -r secure.example", log=False)
+
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) == 0
+
+    # secure.example validates with AD=1
+    m = isctest.query.create("a.secure.example", "A")
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+
+    # stop the server, update _default.nta, restart
+    ns4.stop()
+    now = time.localtime()
+    future = str(now.tm_year + 20) + "0101010000"
+    with open("ns4/_default.nta", "w", encoding="utf-8") as f:
+        f.write(f"secure.example. forced {future}")
+
+    ns4.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
+
+    # NTA active; secure.example. should now return an AD=0 answer
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+    # nta-recheck is configured as 9s. at t=12 the NTA for
+    # secure.example. should NOT be lifted as it is "forced".
+    start = time.mktime(now)
+    delay = start + 12 - time.time()
+    if delay > 0:
+        time.sleep(delay)
+
+    # NTA lifted; secure.example. should still return an AD=0 answer
+    ns4.rndc("flushtree secure.example", log=False)
+    res = isctest.query.tcp(m, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+
+
+def test_nta_clamping(servers):
+    ns4 = servers["ns4"]
+
+    # clean up any existing NTA
+    ns4.rndc("nta -r secure.example", log=False)
+
+    # stop the server, update _default.nta, restart
+    ns4.stop()
+    now = time.localtime()
+    future = str(now.tm_year + 20) + "0101010000"
+    with open("ns4/_default.nta", "w", encoding="utf-8") as f:
+        f.write(f"secure.example. forced {future}")
+
+    ns4.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
+
+    # check that NTA lifetime read from file is clamped to 1 week.
+    response = ns4.rndc("nta -d", log=False)
+    assert active(response) == 1
+
+    nta = next((s for s in response.splitlines() if " expiry" in s), None)
+    assert nta is not None
+
+    nta = nta.split(" ")
+    expiry = f"{nta[2]} {nta[3]}"
+    then = time.mktime(time.strptime(expiry, "%d-%b-%Y %H:%M:%S.000"))
+    nextweek = time.mktime(now) + (86400 * 7)
+
+    # normally there's no more than a few seconds difference between the
+    # clamped expiration date and the calculated date for next week,
+    # but add a 3600 second fudge factor to allow for daylight savings
+    # changes.
+    assert abs(nextweek - then < 3610)
+
+    # remove the NTA
+    ns4.rndc("nta -r secure.example", log=False)
+
+
+def test_nta_forward(servers):
+    ns9 = servers["ns9"]
+
+    m = isctest.query.create("badds.example", "SOA")
+    res = isctest.query.tcp(m, "10.53.0.9")
+    isctest.check.servfail(res)
+    isctest.check.empty_answer(res)
+    isctest.check.noadflag(res)
+
+    # add NTA and expect resolution to succeed
+    ns9.rndc("nta badds.example", log=False)
+    res = isctest.query.tcp(m, "10.53.0.9")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.answer, 2)
+    isctest.check.noadflag(res)
+
+    # remove NTA and expect resolution to fail again
+    ns9.rndc("nta -remove badds.example", log=False)
+    res = isctest.query.tcp(m, "10.53.0.9")
+    isctest.check.servfail(res)
+    isctest.check.empty_answer(res)
+    isctest.check.noadflag(res)