Commit d86f1d00 authored by Michał Kępień's avatar Michał Kępień

Verify mirror zone AXFRs

Update axfr_commit() so that all incoming versions of a mirror zone
transferred using AXFR are verified before being used.  If zone
verification fails, discard the received version of the zone, wait until
the next refresh and retry.
parent eaf1c0f6
......@@ -8,5 +8,13 @@
# information regarding copyright ownership.
rm -f */*.conf
rm -f */*.db
rm -f */*.mirror
rm -f */*.prev
rm -f */*.signed
rm -f */K*
rm -f */db-*
rm -f */dsset-*
rm -f */named.memstats
rm -f */named.run
rm -f dig.out.*
......@@ -9,6 +9,15 @@
* information regarding copyright ownership.
*/
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
......@@ -19,3 +28,18 @@ options {
listen-on-v6 { none; };
recursion no;
};
zone "verify-axfr" {
type master;
file "verify-axfr.db.signed";
};
zone "verify-unsigned" {
type master;
file "verify.db.in";
};
zone "verify-untrusted" {
type master;
file "verify-untrusted.db.signed";
};
#!/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
keys_to_trust=""
ORIGINAL_SERIAL=`awk '$2 == "SOA" {print $5}' verify.db.in`
UPDATED_SERIAL_BAD=`expr ${ORIGINAL_SERIAL} + 1`
UPDATED_SERIAL_GOOD=`expr ${ORIGINAL_SERIAL} + 2`
for variant in axfr untrusted; do
zone=verify-$variant
infile=verify.db.in
zonefile=verify-$variant.db
keyname1=`$KEYGEN -a RSASHA256 -f KSK $zone 2> /dev/null`
keyname2=`$KEYGEN -a RSASHA256 $zone 2> /dev/null`
cat $infile $keyname1.key $keyname2.key > $zonefile
# Prepare a properly signed version of the zone ("*.original.signed").
$SIGNER -P -o $zone $zonefile > /dev/null
cp $zonefile.signed $zonefile.original.signed
# Prepare a version of the zone with a bogus SOA RRSIG ("*.bad.signed").
sed "s/${ORIGINAL_SERIAL}/${UPDATED_SERIAL_BAD}/;" $zonefile.signed > $zonefile.bad.signed
# Prepare another properly signed version of the zone ("*.good.signed").
sed "s/${ORIGINAL_SERIAL}/${UPDATED_SERIAL_GOOD}/;" $zonefile > $zonefile.good
$SIGNER -P -o $zone $zonefile.good > /dev/null
rm -f $zonefile.good
# Except for the "verify-untrusted" zone, declare the KSK used for
# signing the zone to be a trust anchor for ns3.
if [ "$variant" != "untrusted" ]; then
keys_to_trust="$keys_to_trust $keyname1"
fi
done
keyfile_to_trusted_keys $keys_to_trust > trusted-mirror.conf
; 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 3600
@ SOA ns2 hostmaster 2000010100 3600 1200 604800 3600
@ NS ns2
ns2 A 10.53.0.2
......@@ -9,6 +9,15 @@
* information regarding copyright ownership.
*/
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
......@@ -24,3 +33,26 @@ zone "." {
type hint;
file "../../common/root.hint";
};
zone "verify-axfr" {
type slave;
masters { 10.53.0.2; };
mirror yes;
file "verify-axfr.db.mirror";
};
zone "verify-unsigned" {
type slave;
masters { 10.53.0.2; };
mirror yes;
file "verify-unsigned.db.mirror";
};
zone "verify-untrusted" {
type slave;
masters { 10.53.0.2; };
mirror yes;
file "verify-untrusted.db.mirror";
};
include "../ns2/trusted-mirror.conf";
......@@ -17,3 +17,8 @@ $SHELL clean.sh
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
( cd ns2 && $SHELL -e sign.sh )
cat ns2/verify-axfr.db.bad.signed > ns2/verify-axfr.db.signed
cat ns2/verify-untrusted.db.original.signed > ns2/verify-untrusted.db.signed
......@@ -12,6 +12,7 @@
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
DIGOPTS="-p ${PORT} +dnssec +time=1 +tries=1 +multi"
RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
# Wait until the transfer of the given zone to ns3 either completes successfully
......@@ -51,5 +52,54 @@ reload_zone() {
status=0
n=0
ORIGINAL_SERIAL=`awk '$2 == "SOA" {print $5}' ns2/verify.db.in`
UPDATED_SERIAL_BAD=`expr ${ORIGINAL_SERIAL} + 1`
UPDATED_SERIAL_GOOD=`expr ${ORIGINAL_SERIAL} + 2`
n=`expr $n + 1`
echo_i "checking that an unsigned mirror zone is rejected ($n)"
ret=0
wait_for_transfer verify-unsigned
$DIG $DIGOPTS @10.53.0.3 +norec verify-unsigned SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "verify-unsigned.*Zone contains no DNSSEC keys" > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that a mirror zone signed using an untrusted key is rejected ($n)"
ret=0
nextpartreset ns3/named.run
wait_for_transfer verify-untrusted
$DIG $DIGOPTS @10.53.0.3 +norec verify-untrusted SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "verify-untrusted.*No trusted KSK DNSKEY found" > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that an AXFR of an incorrectly signed mirror zone is rejected ($n)"
ret=0
nextpartreset ns3/named.run
wait_for_transfer verify-axfr
$DIG $DIGOPTS @10.53.0.3 +norec verify-axfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "No correct RSASHA256 signature for verify-axfr SOA" > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that an AXFR of an updated, correctly signed mirror zone is accepted ($n)"
ret=0
nextpart ns3/named.run > /dev/null
cat ns2/verify-axfr.db.good.signed > ns2/verify-axfr.db.signed
reload_zone verify-axfr ${UPDATED_SERIAL_GOOD}
$RNDCCMD 10.53.0.3 retransfer verify-axfr > /dev/null 2>&1
wait_for_transfer verify-axfr
$DIG $DIGOPTS @10.53.0.3 +norec verify-axfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.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
......@@ -334,6 +334,7 @@ axfr_commit(dns_xfrin_ctx_t *xfr) {
CHECK(axfr_apply(xfr));
CHECK(dns_db_endload(xfr->db, &xfr->axfr));
CHECK(dns_zone_verifydb(xfr->zone, xfr->db, NULL));
result = ISC_R_SUCCESS;
failure:
......
......@@ -15305,6 +15305,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
goto same_master;
case DNS_R_TOOMANYRECORDS:
case DNS_R_VERIFYFAILURE:
DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime);
inc_stats(zone, dns_zonestatscounter_xfrfail);
break;
......
......@@ -1599,6 +1599,8 @@
./bin/tests/system/mirror/ns1/named.conf.in CONF-C 2018
./bin/tests/system/mirror/ns1/root.db.in ZONE 2018
./bin/tests/system/mirror/ns2/named.conf.in CONF-C 2018
./bin/tests/system/mirror/ns2/sign.sh SH 2018
./bin/tests/system/mirror/ns2/verify.db.in ZONE 2018
./bin/tests/system/mirror/ns3/named.conf.in CONF-C 2018
./bin/tests/system/mirror/setup.sh SH 2018
./bin/tests/system/mirror/tests.sh SH 2018
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment