Merge branch '37-implement-geoff-huston-s-trusted-key-sentinel-feature' into 'master'

Implement Geoff Huston's trusted key sentinel feature

Closes #37

See merge request isc-projects/bind9!123
This commit is contained in:
Ondřej Surý 2018-04-18 12:27:03 -04:00
commit 4d59a96b98
27 changed files with 831 additions and 12 deletions

View file

@ -1,3 +1,6 @@
4926. [func] Add root key sentinel support. To disable, add
'root-key-sentinel no;' to named.conf. [GL #37]
4925. [func] Several configuration options that define intervals
can now take TTL value suffixes (for example, 2h or 1d)
in addition to integer parameters. These include

View file

@ -195,6 +195,7 @@ options {\n\
resolver-nonbackoff-tries 3;\n\
resolver-retry-interval 800; /* in milliseconds */\n\
# rfc2308-type1 <obsolete>;\n\
root-key-sentinel yes;\n\
servfail-ttl 1;\n\
# sortlist <none>\n\
stale-answer-enable false;\n\

View file

@ -4682,6 +4682,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
INSIST(result == ISC_R_SUCCESS);
view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
obj = NULL;
result = named_config_get(maps, "root-key-sentinel", &obj);
INSIST(result == ISC_R_SUCCESS);
view->root_key_sentinel = cfg_obj_asboolean(obj);
CHECK(configure_view_acl(vconfig, config, named_g_config,
"allow-query-cache-on", NULL, actx,
named_g_mctx, &view->cacheonacl));

View file

@ -65,7 +65,7 @@ PARALLEL = rpzrecurse serve-stale dnssec \
masterfile masterformat metadata mkeys \
names notify nslookup nsupdate nzd2nzf \
padding pending pipelined \
reclimit redirect resolver rndc rpz \
reclimit redirect resolver rndc rootkeysentinel rpz \
rrchecker rrl rrsetorder rsabigexponent runtime \
sfcache smartsign sortlist \
spf staticstub statistics statschannel stub synthfromdnssec \

View file

@ -96,16 +96,16 @@ PARALLELDIRS="acl additional addzone allow-query auth autosign \
fetchlimit filter-aaaa formerr forward \
geoip glue idna inline integrity ixfr keepalive \
legacy limits logfileconfig \
masterfile masterformat metadata mkeys \
names notify nslookup nsupdate nzd2nzf \
padding pending pipelined \
reclimit redirect resolver rndc rpz rpzrecurse \
rrchecker rrl rrsetorder rsabigexponent runtime \
serve-stale sfcache smartsign sortlist \
spf staticstub statistics statschannel stub synthfromdnssec \
tcp tools tsig tsiggss \
unknown upforwd verify views wildcard \
xfer xferquota zero zonechecks"
masterfile masterformat metadata mkeys \
names notify nslookup nsupdate nzd2nzf \
padding pending pipelined \
reclimit redirect resolver rndc rootkeysentinel rpz rpzrecurse \
rrchecker rrl rrsetorder rsabigexponent runtime \
serve-stale sfcache smartsign sortlist \
spf staticstub statistics statschannel stub synthfromdnssec \
tcp tools tsig tsiggss \
unknown upforwd verify views wildcard \
xfer xferquota zero zonechecks"
SUBDIRS="$SEQUENTIALDIRS $PARALLELDIRS"
@ -234,6 +234,12 @@ echo_i() {
done
}
echo_ic() {
echo "$@" | while read LINE ; do
echoinfo "I:$SYSTESTDIR: $LINE"
done
}
cat_i() {
while read LINE ; do
echoinfo "I:$SYSTESTDIR:$LINE"

View file

@ -0,0 +1,23 @@
#!/bin/sh
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
rm -f dig.out.ns?.test*
rm -f */dsset-*
rm -f */named.conf
rm -f */named.memstats
rm -f */named.run
rm -f */trusted.conf
rm -f ns1/K.*
rm -f ns1/root.db
rm -f ns1/root.db.signed
rm -f ns2/Kexample.*
rm -f ns2/example.db
rm -f ns2/example.db.signed

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
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-enable yes;
dnssec-validation yes;
};
zone "." {
type master;
file "root.db.signed";
};
include "trusted.conf";

View file

@ -0,0 +1,22 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
. IN SOA marka.isc.org. a.root.servers.nil. (
2018031400 ; 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

View file

@ -0,0 +1,43 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
zone=.
infile=root.db.in
zonefile=root.db
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA256 -b 1024 -n zone $zone`
keyid=`expr ${keyname} : 'K.+008+\(.*\)'`
(cd ../ns2 && $SHELL sign.sh ${keyid:-00000} )
cp ../ns2/dsset-example$TP .
cat $infile $keyname.key > $zonefile
$SIGNER -P -g -r $RANDFILE -o $zone $zonefile > /dev/null
# Configure the resolving server with a trusted key.
cat $keyname.key | grep -v '^; ' | $PERL -n -e '
local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split;
local $key = join("", @rest);
print <<EOF
trusted-keys {
"$dn" $flags $proto $alg "$key";
};
EOF
' > trusted.conf
cp trusted.conf ../ns2/trusted.conf
cp trusted.conf ../ns3/trusted.conf
cp trusted.conf ../ns4/trusted.conf

View file

@ -0,0 +1,19 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2018031400 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
ns2 A 10.53.0.2

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
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; };
recursion no;
notify yes;
dnssec-enable yes;
dnssec-validation yes;
};
zone "example" {
type master;
file "example.db.signed";
};
include "trusted.conf";

View file

@ -0,0 +1,40 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
oldid=${1:-00000}
newid=`expr \( ${oldid} + 1000 \) % 65536`
newid=`expr "0000${newid}" : '.*\(.....\)$'`
badid=`expr \( ${oldid} + 7777 \) % 65536`
badid=`expr "0000${badid}" : '.*\(.....\)$'`
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
zone=example.
infile=example.db.in
zonefile=example.db
keyname1=`$KEYGEN -q -r $RANDFILE -a DSA -b 768 -n zone $zone`
keyname2=`$KEYGEN -q -r $RANDFILE -a DSA -b 768 -n zone $zone`
cat $infile $keyname1.key $keyname2.key >$zonefile
echo root-key-sentinel-is-ta-$oldid A 10.53.0.1 >> $zonefile
echo root-key-sentinel-not-ta-$oldid A 10.53.0.2 >> $zonefile
echo root-key-sentinel-is-ta-$newid A 10.53.0.3 >> $zonefile
echo root-key-sentinel-not-ta-$newid A 10.53.0.4 >> $zonefile
echo old-is-ta CNAME root-key-sentinel-is-ta-$oldid >> $zonefile
echo old-not-ta CNAME root-key-sentinel-not-ta-$oldid >> $zonefile
echo new-is-ta CNAME root-key-sentinel-is-ta-$newid >> $zonefile
echo new-not-ta CNAME root-key-sentinel-not-ta-$newid >> $zonefile
echo bad-is-ta CNAME root-key-sentinel-is-ta-$badid >> $zonefile
echo bad-not-ta CNAME root-key-sentinel-not-ta-$badid >> $zonefile
$SIGNER -P -g -r $RANDFILE -o $zone -k $keyname1 $zonefile $keyname2 > /dev/null

View file

@ -0,0 +1,2 @@
. NS a.root-servers.nil.
a.root-servers.nil. A 10.53.0.1

View file

@ -0,0 +1,32 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
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; };
recursion yes;
notify yes;
dnssec-enable yes;
dnssec-validation yes;
root-key-sentinel yes;
};
zone "." {
type hint;
file "hint.db";
};
include "trusted.conf";

View file

@ -0,0 +1,2 @@
. NS a.root-servers.nil.
a.root-servers.nil. A 10.53.0.1

View file

@ -0,0 +1,32 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
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;
notify yes;
dnssec-enable yes;
dnssec-validation yes;
root-key-sentinel no;
};
zone "." {
type hint;
file "hint.db";
};
include "trusted.conf";

View file

@ -0,0 +1,25 @@
#!/bin/sh -e
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
$SHELL clean.sh
test -r $RANDFILE || $GENRANDOM 800 $RANDFILE
copy_setports ns1/named.conf.in ns1/named.conf
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named.conf.in ns4/named.conf
cd ns1
$SHELL sign.sh

View file

@ -0,0 +1,286 @@
#!/bin/sh
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
status=0
n=0
rm -f dig.out.*
DIGOPTS="+tcp +noadd +nosea +nostat +nocmd +dnssec -p ${PORT}"
newtest() {
n=`expr $n + 1`
case $# in
1)
echo_i "$1 ($n)"
;;
2)
echo_i "$1"
echo_ic "$2 ($n)"
;;
esac
ret=0
}
newtest "get test ids"
$DIG $DIGOPTS . dnskey +short +rrcomm @10.53.0.1 > dig.out.ns1.test$n || ret=1
oldid=`sed -n 's/.*key id = //p' < dig.out.ns1.test$n`
oldid=`expr "0000${oldid}" : '.*\(.....\)$'`
newid=`expr \( ${oldid} + 1000 \) % 65536`
newid=`expr "0000${newid}" : '.*\(.....\)$'`
badid=`expr \( ${oldid} + 7777 \) % 65536`
badid=`expr "0000${badid}" : '.*\(.....\)$'`
echo_i "test id: oldid=${oldid} (configured)"
echo_i "test id: newid=${newid} (not configured)"
echo_i "test id: badid=${badid}"
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check authoritative server (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.2 example SOA > dig.out.ns2.test$n
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check test zone resolves with 'root-key-sentinel yes;'" " (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 example SOA > dig.out.ns3.test$n
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-is-ta with old ta and" " 'root-key-sentinel yes;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-is-ta-${oldid}.example A > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with old ta and" " 'root-key-sentinel yes;' (expect SERVFAIL)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-not-ta-${oldid}.example A > dig.out.ns3.test$n || ret=1
grep "status: SERVFAIL" dig.out.ns3.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with old ta, CD=1 and" " 'root-key-sentinel yes;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 +cd root-key-sentinel-not-ta-${oldid}.example A > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-is-ta with new ta and" " 'root-key-sentinel yes;' (expect SERVFAIL)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-is-ta-${newid}.example A > dig.out.ns3.test$n || ret=1
grep "status: SERVFAIL" dig.out.ns3.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-is-ta with new ta, CD=1 and" " 'root-key-sentinel yes;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 +cd root-key-sentinel-is-ta-${newid}.example A > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with new ta and" " 'root-key-sentinel yes;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-not-ta-${newid}.example A > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
newtest "check root-key-sentinel-is-ta with bad ta and" " 'root-key-sentinel yes;' (expect SERVFAIL)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-is-ta-${badid}.example A > dig.out.ns3.test$n || ret=1
grep "status: SERVFAIL" dig.out.ns3.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-is-ta with bad ta, CD=1 and" " 'root-key-sentinel yes;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.3 +cd root-key-sentinel-is-ta-${badid}.example A > dig.out.ns3.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with bad ta and" " 'root-key-sentinel yes;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-not-ta-${bad}.example A > dig.out.ns3.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
newtest "check root-key-sentinel-is-ta with out-of-range ta and" " 'root-key-sentinel yes;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-is-ta-72345.example A > dig.out.ns3.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with out-of-range ta and" " 'root-key-sentinel yes;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-not-ta-72345.example A > dig.out.ns3.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
newtest "check root-key-sentinel-is-ta with no-zero-pad ta and" " 'root-key-sentinel yes;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-is-ta-1234.example A > dig.out.ns3.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with no-zero-pad ta and" " 'root-key-sentinel yes;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.3 root-key-sentinel-not-ta-1234.example A > dig.out.ns3.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
newtest "check CNAME to root-key-sentinel-is-ta with old ta and" " 'root-key-sentinel yes;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 old-is-ta.example A > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
grep "old-is-ta.*CNAME.root-key-sentinel-is-ta-${oldid}.example." dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-not-ta with old ta and" " 'root-key-sentinel yes;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 old-not-ta.example A > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
grep "old-not-ta.*CNAME.root-key-sentinel-not-ta-${oldid}.example." dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-is-ta with new ta and" " 'root-key-sentinel yes;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 new-is-ta.example A > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
grep "new-is-ta.*CNAME.root-key-sentinel-is-ta-${newid}.example." dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-not-ta with new ta and" " 'root-key-sentinel yes;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.3 new-not-ta.example A > dig.out.ns3.test$n || ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
grep "new-not-ta.*CNAME.root-key-sentinel-not-ta-${newid}.example." dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-is-ta with bad ta and" " 'root-key-sentinel yes;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.3 bad-is-ta.example A > dig.out.ns3.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
grep "bad-is-ta.*CNAME.root-key-sentinel-is-ta-${badid}.example" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-not-ta with bad ta and" " 'root-key-sentinel yes;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.3 bad-not-ta.example A > dig.out.ns3.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
grep "bad-not-ta.*CNAME.root-key-sentinel-not-ta-${badid}.example." dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check test zone resolves with 'root-key-sentinel no;'" " (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 example SOA > dig.out.ns4.test$n
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-is-ta with old ta and" " 'root-key-sentinel no;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-is-ta-${oldid}.example A > dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with old ta and" " 'root-key-sentinel no;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-not-ta-${oldid}.example A > dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-is-ta with new ta and" " 'root-key-sentinel no;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-is-ta-${newid}.example A > dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with new ta and" " 'root-key-sentinel no;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-not-ta-${newid}.example A > dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
newtest "check root-key-sentinel-is-ta with bad ta and" " 'root-key-sentinel no;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-is-ta-${badid}.example A > dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with bad ta and" " 'root-key-sentinel no;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-not-ta-${bad}.example A > dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
newtest "check root-key-sentinel-is-ta with out-of-range ta and" " 'root-key-sentinel no;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-is-ta-72345.example A > dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with out-of-range ta and" " 'root-key-sentinel no;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-not-ta-72345.example A > dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
newtest "check root-key-sentinel-is-ta with no-zero-pad ta and" " 'root-key-sentinel no;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-is-ta-1234.example A > dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check root-key-sentinel-not-ta with no-zero-pad ta and" " 'root-key-sentinel no;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.4 root-key-sentinel-not-ta-1234.example A > dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
newtest "check CNAME to root-key-sentinel-is-ta with old ta and" " 'root-key-sentinel no;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 old-is-ta.example A > dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
grep "old-is-ta.*CNAME.root-key-sentinel-is-ta-${oldid}.example." dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-not-ta with old ta and" " 'root-key-sentinel no;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 old-not-ta.example A > dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
grep "old-not-ta.*CNAME.root-key-sentinel-not-ta-${oldid}.example." dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-is-ta with new ta and" " 'root-key-sentinel no;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 new-is-ta.example A > dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
grep "new-is-ta.*CNAME.root-key-sentinel-is-ta-${newid}.example." dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-not-ta with new ta and" " 'root-key-sentinel no;' (expect NOERROR)"
$DIG $DIGOPTS @10.53.0.4 new-not-ta.example A > dig.out.ns4.test$n || ret=1
grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
grep "new-not-ta.*CNAME.root-key-sentinel-not-ta-${newid}.example." dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-is-ta with bad ta and" " 'root-key-sentinel no;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.4 bad-is-ta.example A > dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
grep "bad-is-ta.*CNAME.root-key-sentinel-is-ta-${badid}.example" dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
newtest "check CNAME to root-key-sentinel-not-ta with bad ta and" " 'root-key-sentinel no;' (expect NXDOMAIN)"
$DIG $DIGOPTS @10.53.0.4 bad-not-ta.example A > dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
grep "bad-not-ta.*CNAME.root-key-sentinel-not-ta-${badid}.example." dig.out.ns4.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View file

@ -5845,6 +5845,17 @@ options {
</listitem>
</varlistentry>
<varlistentry>
<term><command>root-key-sentinel</command></term>
<listitem>
<para>
Respond to root key sentinel probes as described in
draft-ietf-dnsop-kskroll-sentinel-08. The default is
<userinput>yes</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>maintain-ixfr-base</command></term>
<listitem>

View file

@ -71,6 +71,13 @@
using (now obsolete) idnkit-1 library.
</para>
</listitem>
<listitem>
<para>
Add root key sentinel support which enables resolvers to test
which trust anchors are configured for the root. To disable, add
'root-key-sentinel no;' to named.conf.
</para>
</listitem>
</itemizedlist>
</section>

View file

@ -318,6 +318,7 @@ options {
} ];
rfc2308-type1 <boolean>; // not yet implemented
root-delegation-only [ exclude { <quoted_string>; ... } ];
root-key-sentinel <boolean>;
rrset-order { [ class <string> ] [ type <string> ] [ name
<quoted_string> ] <string> <string>; ... };
secroots-file <quoted_string>;
@ -643,6 +644,7 @@ view <string> [ <class> ] {
dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text>
} ];
rfc2308-type1 <boolean>; // not yet implemented
root-key-sentinel <boolean>;
root-delegation-only [ exclude { <quoted_string>; ... } ];
rrset-order { [ class <string> ] [ type <string> ] [ name
<quoted_string> ] <string> <string>; ... };

View file

@ -125,6 +125,7 @@ struct dns_view {
isc_boolean_t requireservercookie;
isc_boolean_t synthfromdnssec;
isc_boolean_t trust_anchor_telemetry;
isc_boolean_t root_key_sentinel;
dns_transfer_format_t transfer_format;
dns_acl_t * cacheacl;
dns_acl_t * cacheonacl;

View file

@ -242,6 +242,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->requireservercookie = ISC_FALSE;
view->synthfromdnssec = ISC_TRUE;
view->trust_anchor_telemetry = ISC_TRUE;
view->root_key_sentinel = ISC_TRUE;
view->new_zone_dir = NULL;
view->new_zone_file = NULL;
view->new_zone_db = NULL;

View file

@ -1958,6 +1958,7 @@ view_clauses[] = {
{ "response-policy", &cfg_type_rpz, 0 },
{ "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
{ "root-delegation-only", &cfg_type_optional_exclude, 0 },
{ "root-key-sentinel", &cfg_type_boolean, 0 },
{ "rrset-order", &cfg_type_rrsetorder, 0 },
{ "send-cookie", &cfg_type_boolean, 0 },
{ "servfail-ttl", &cfg_type_ttlval, 0 },

View file

@ -75,6 +75,10 @@ struct ns_query {
isc_boolean_t authoritative;
isc_boolean_t is_zone;
} redirect;
dns_keytag_t root_key_sentinel_keyid;
isc_boolean_t root_key_sentinel_is_ta;
isc_boolean_t root_key_sentinel_not_ta;
};
#define NS_QUERYATTR_RECURSIONOK 0x0001

View file

@ -36,6 +36,7 @@
#include <dns/dnsrps.h>
#include <dns/dnssec.h>
#include <dns/events.h>
#include <dns/keytable.h>
#include <dns/message.h>
#include <dns/ncache.h>
#include <dns/nsec.h>
@ -700,6 +701,9 @@ query_reset(ns_client_t *client, isc_boolean_t everything) {
client->query.isreferral = ISC_FALSE;
client->query.dns64_options = 0;
client->query.dns64_ttl = ISC_UINT32_MAX;
client->query.root_key_sentinel_keyid = 0;
client->query.root_key_sentinel_is_ta = ISC_FALSE;
client->query.root_key_sentinel_not_ta = ISC_FALSE;
}
static void
@ -5118,6 +5122,68 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) {
return (ns__query_start(&qctx));
}
static isc_boolean_t
get_root_key_sentinel_id(query_ctx_t *qctx, const char *ndata) {
unsigned int v = 0;
int i;
for (i = 0; i < 5; i++) {
if (ndata[i] < '0' || ndata[i] > '9') {
return (ISC_FALSE);
}
v *= 10;
v += ndata[i] - '0';
}
if (v > 65535U) {
return (ISC_FALSE);
}
qctx->client->query.root_key_sentinel_keyid = v;
return (ISC_TRUE);
}
/*%
* Find out if the query is for a root key sentinel and if so, record the type
* of root key sentinel query and the key id that is being checked for.
*
* The code is assuming a zero padded decimal field of width 5.
*/
static void
root_key_sentinel_detect(query_ctx_t *qctx) {
const char *ndata = (const char *)qctx->client->query.qname->ndata;
if (qctx->client->query.qname->length > 30 && ndata[0] == 29 &&
strncasecmp(ndata + 1, "root-key-sentinel-is-ta-", 24) == 0)
{
if (!get_root_key_sentinel_id(qctx, ndata + 25)) {
return;
}
qctx->client->query.root_key_sentinel_is_ta = ISC_TRUE;
/*
* Simplify processing by disabling agressive
* negative caching.
*/
qctx->findcoveringnsec = ISC_FALSE;
ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
NS_LOGMODULE_QUERY, ISC_LOG_INFO,
"root-key-sentinel-is-ta query label found");
} else if (qctx->client->query.qname->length > 31 && ndata[0] == 30 &&
strncasecmp(ndata + 1, "root-key-sentinel-not-ta-", 25) == 0)
{
if (!get_root_key_sentinel_id(qctx, ndata + 26)) {
return;
}
qctx->client->query.root_key_sentinel_not_ta = ISC_TRUE;
/*
* Simplify processing by disabling agressive
* negative caching.
*/
qctx->findcoveringnsec = ISC_FALSE;
ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
NS_LOGMODULE_QUERY, ISC_LOG_INFO,
"root-key-sentinel-not-ta query label found");
}
}
/*%
* Starting point for a client query or a chaining query.
*
@ -5158,6 +5224,18 @@ ns__query_start(query_ctx_t *qctx) {
return (query_done(qctx));
}
/*
* Setup for root key sentinel processing.
*/
if (qctx->client->view->root_key_sentinel &&
qctx->client->query.restarts == 0 &&
(qctx->qtype == dns_rdatatype_a ||
qctx->qtype == dns_rdatatype_aaaa) &&
(qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)
{
root_key_sentinel_detect(qctx);
}
/*
* First we must find the right database.
*/
@ -6339,6 +6417,91 @@ query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) {
return (ISC_R_SUCCESS);
}
/*%
* Check the configured trust anchors for a root zone trust anchor
* with a key id that matches qctx->client->query.root_key_sentinel_keyid.
*
* Return ISC_TRUE when found, otherwise return ISC_FALSE.
*/
static isc_boolean_t
has_ta(query_ctx_t *qctx) {
dns_keytable_t *keytable = NULL;
dns_keynode_t *keynode = NULL;
isc_result_t result;
result = dns_view_getsecroots(qctx->client->view, &keytable);
if (result != ISC_R_SUCCESS) {
return (ISC_FALSE);
}
result = dns_keytable_find(keytable, dns_rootname, &keynode);
while (result == ISC_R_SUCCESS) {
dns_keynode_t *nextnode = NULL;
dns_keytag_t keyid = dst_key_id(dns_keynode_key(keynode));
if (keyid == qctx->client->query.root_key_sentinel_keyid) {
dns_keytable_detachkeynode(keytable, &keynode);
dns_keytable_detach(&keytable);
return (ISC_TRUE);
}
result = dns_keytable_nextkeynode(keytable, keynode, &nextnode);
dns_keytable_detachkeynode(keytable, &keynode);
keynode = nextnode;
}
dns_keytable_detach(&keytable);
return (ISC_FALSE);
}
/*%
* Check if a root key sentinel SERVFAIL should be returned.
*/
static isc_boolean_t
root_key_sentinel_return_servfail(query_ctx_t *qctx, isc_result_t result) {
/*
* Are we looking at a "root-key-sentinel" query?
*/
if (!qctx->client->query.root_key_sentinel_is_ta &&
!qctx->client->query.root_key_sentinel_not_ta)
{
return (ISC_FALSE);
}
/*
* We only care about the query if 'result' indicates we have a cached
* answer.
*/
switch (result) {
case ISC_R_SUCCESS:
case DNS_R_CNAME:
case DNS_R_DNAME:
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NCACHENXRRSET:
break;
default:
return (ISC_FALSE);
}
/*
* Do we meet the specified conditions to return SERVFAIL?
*/
if (!qctx->is_zone &&
qctx->rdataset->trust == dns_trust_secure &&
((qctx->client->query.root_key_sentinel_is_ta && !has_ta(qctx)) ||
(qctx->client->query.root_key_sentinel_not_ta && has_ta(qctx))))
{
return (ISC_TRUE);
}
/*
* As special processing may only be triggered by the original QNAME,
* disable it after following a CNAME/DNAME.
*/
qctx->client->query.root_key_sentinel_is_ta = ISC_FALSE;
qctx->client->query.root_key_sentinel_not_ta = ISC_FALSE;
return (ISC_FALSE);
}
/*%
* Continue after doing a database lookup or returning from
* recursion, and call out to the next function depending on the
@ -6362,6 +6525,19 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
return (query_done(qctx));
}
/*
* If required, handle special "root-key-sentinel-is-ta-<keyid>" and
* "root-key-sentinel-not-ta-<keyid>" labels by returning SERVFAIL.
*/
if (root_key_sentinel_return_servfail(qctx, result)) {
/*
* Don't record this response in the SERVFAIL cache.
*/
qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
QUERY_ERROR(qctx, DNS_R_SERVFAIL);
return (query_done(qctx));
}
switch (result) {
case ISC_R_SUCCESS:
return (query_prepresponse(qctx));
@ -10855,7 +11031,7 @@ ns_query_start(ns_client_t *client) {
client->query.attributes &= ~NS_QUERYATTR_SECURE;
/*
* Set NS_CLIENTATTR_WANTDNSSEC if the client has set AD in the query.
* Set NS_CLIENTATTR_WANTAD if the client has set AD in the query.
* This allows AD to be returned on queries without DO set.
*/
if ((message->flags & DNS_MESSAGEFLAG_AD) != 0)

View file

@ -1821,6 +1821,19 @@
./bin/tests/system/rndc/ns6/named.conf.in CONF-C 2016,2018
./bin/tests/system/rndc/setup.sh SH 2011,2012,2013,2014,2016,2017,2018
./bin/tests/system/rndc/tests.sh SH 2011,2012,2013,2014,2015,2016,2017,2018
./bin/tests/system/rootkeysentinel/clean.sh SH 2018
./bin/tests/system/rootkeysentinel/ns1/named.conf.in CONF-C 2018
./bin/tests/system/rootkeysentinel/ns1/root.db.in ZONE 2018
./bin/tests/system/rootkeysentinel/ns1/sign.sh SH 2018
./bin/tests/system/rootkeysentinel/ns2/example.db.in ZONE 2018
./bin/tests/system/rootkeysentinel/ns2/named.conf.in CONF-C 2018
./bin/tests/system/rootkeysentinel/ns2/sign.sh SH 2018
./bin/tests/system/rootkeysentinel/ns3/hint.db ZONE 2018
./bin/tests/system/rootkeysentinel/ns3/named.conf.in CONF-C 2018
./bin/tests/system/rootkeysentinel/ns4/hint.db ZONE 2018
./bin/tests/system/rootkeysentinel/ns4/named.conf.in CONF-C 2018
./bin/tests/system/rootkeysentinel/setup.sh SH 2018
./bin/tests/system/rootkeysentinel/tests.sh SH 2018
./bin/tests/system/rpz/.gitignore X 2017,2018
./bin/tests/system/rpz/Makefile.in MAKE 2017,2018
./bin/tests/system/rpz/ckdnsrps.sh SH 2017,2018