Files
bind9/bin/tests/system/nsec3/tests.sh
Matthijs Mekking 10055d44e3 Fix setnsec3param hang on shutdown
When performing the 'setnsec3param' task, zones that are not loaded will have
their task rescheduled. We should do this only if the zone load is still
pending, this prevents zones that failed to load get stuck in a busy wait and
causing a hang on shutdown.
2021-06-28 10:35:34 +02:00

338 lines
9.5 KiB
Bash

#!/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 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
# shellcheck source=kasp.sh
. ../kasp.sh
# Log errors and increment $ret.
log_error() {
echo_i "error: $1"
ret=$((ret+1))
}
# Call dig with default options.
dig_with_opts() {
$DIG +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" "$@"
}
# Call rndc.
rndccmd() {
"$RNDC" -c ../common/rndc.conf -p "$CONTROLPORT" -s "$@"
}
# Set zone name ($1) and policy ($2) for testing nsec3.
set_zone_policy() {
ZONE=$1
POLICY=$2
}
# Set expected NSEC3 parameters: flags ($1), iterations ($2), and
# salt length ($3).
set_nsec3param() {
FLAGS=$1
ITERATIONS=$2
SALTLEN=$3
# Reset salt.
SALT=""
}
# The apex NSEC3PARAM record indicates that it is signed.
_wait_for_nsec3param() {
dig_with_opts +noquestion "@${SERVER}" "$ZONE" NSEC3PARAM > "dig.out.test$n.wait" || return 1
grep "${ZONE}\..*IN.*NSEC3PARAM.*1.*0.*${ITERATIONS}.*${SALT}" "dig.out.test$n.wait" > /dev/null || return 1
grep "${ZONE}\..*IN.*RRSIG" "dig.out.test$n.wait" > /dev/null || return 1
return 0
}
# The apex NSEC record indicates that it is signed.
_wait_for_nsec() {
dig_with_opts +noquestion "@${SERVER}" "$ZONE" NSEC > "dig.out.test$n.wait" || return 1
grep "NS SOA" "dig.out.test$n.wait" > /dev/null || return 1
grep "${ZONE}\..*IN.*RRSIG" "dig.out.test$n.wait" > /dev/null || return 1
grep "${ZONE}\..*IN.*NSEC3PARAM" "dig.out.test$n.wait" > /dev/null && return 1
return 0
}
# Wait for the zone to be signed.
wait_for_zone_is_signed() {
n=$((n+1))
ret=0
echo_i "wait for ${ZONE} to be signed ($n)"
if [ "$1" = "nsec3" ]; then
retry_quiet 10 _wait_for_nsec3param || log_error "wait for ${ZONE} to be signed failed"
else
retry_quiet 10 _wait_for_nsec || log_error "wait for ${ZONE} to be signed failed"
fi
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
}
# Test: check NSEC in answers
_check_nsec_nsec3param()
{
dig_with_opts +noquestion @$SERVER "${ZONE}" NSEC3PARAM > "dig.out.test$n.nsec3param.$ZONE" || return 1
grep "NSEC3PARAM" "dig.out.test$n.nsec3param.$ZONE" > /dev/null && return 1
return 0
}
_check_nsec_nxdomain()
{
dig_with_opts @$SERVER "nosuchname.${ZONE}" > "dig.out.test$n.nxdomain.$ZONE" || return 1
grep "${ZONE}.*IN.*NSEC.*NS.*SOA.*RRSIG.*NSEC.*DNSKEY" "dig.out.test$n.nxdomain.$ZONE" > /dev/null || return 1
grep "NSEC3" "dig.out.test$n.nxdomain.$ZONE" > /dev/null && return 1
return 0
}
check_nsec()
{
n=$((n+1))
echo_i "check NSEC3PARAM response for zone ${ZONE} ($n)"
ret=0
retry_quiet 10 _check_nsec_nsec3param || log_error "unexpected NSEC3PARAM in response for zone ${ZONE}"
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
n=$((n+1))
echo_i "check NXDOMAIN response for zone ${ZONE} ($n)"
ret=0
retry_quiet 10 _check_nsec_nxdomain || log_error "bad NXDOMAIN response for zone ${ZONE}"
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
}
# Test: check NSEC3 parameters in answers
_check_nsec3_nsec3param()
{
dig_with_opts +noquestion @$SERVER "${ZONE}" NSEC3PARAM > "dig.out.test$n.nsec3param.$ZONE" || return 1
grep "${ZONE}.*0.*IN.*NSEC3PARAM.*1.*0.*${ITERATIONS}.*${SALT}" "dig.out.test$n.nsec3param.$ZONE" > /dev/null || return 1
if [ -z "$SALT" ]; then
SALT=`awk '$4 == "NSEC3PARAM" { print $8 }' dig.out.test$n.nsec3param.$ZONE`
fi
return 0
}
_check_nsec3_nxdomain()
{
dig_with_opts @$SERVER "nosuchname.${ZONE}" > "dig.out.test$n.nxdomain.$ZONE" || return 1
grep ".*\.${ZONE}.*IN.*NSEC3.*1.${FLAGS}.*${ITERATIONS}.*${SALT}" "dig.out.test$n.nxdomain.$ZONE" > /dev/null || return 1
return 0
}
check_nsec3()
{
n=$((n+1))
echo_i "check that NSEC3PARAM 1 0 ${ITERATIONS} is published zone ${ZONE} ($n)"
ret=0
retry_quiet 10 _check_nsec3_nsec3param || log_error "bad NSEC3PARAM response for ${ZONE}"
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
n=$((n+1))
echo_i "check NXDOMAIN response has correct NSEC3 1 ${FLAGS} ${ITERATIONS} ${SALT} for zone ${ZONE} ($n)"
ret=0
retry_quiet 10 _check_nsec3_nxdomain || log_error "bad NXDOMAIN response for zone ${ZONE}"
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
}
start_time="$(TZ=UTC date +%s)"
status=0
n=0
# Zone: nsec-to-nsec3.kasp.
set_zone_policy "nsec-to-nsec3.kasp" "nsec"
set_server "ns3" "10.53.0.3"
echo_i "initial check zone ${ZONE}"
check_nsec
dnssec_verify
# Zone: nsec3.kasp.
set_zone_policy "nsec3.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-dynamic.kasp.
set_zone_policy "nsec3-dynamic.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-change.kasp.
set_zone_policy "nsec3-change.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-dynamic-change.kasp.
set_zone_policy "nsec3-dynamic-change.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-to-nsec.kasp.
set_zone_policy "nsec3-to-nsec.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-to-optout.kasp.
set_zone_policy "nsec3-to-optout.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-from-optout.kasp.
set_zone_policy "nsec3-from-optout.kasp" "optout"
set_nsec3param "1" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-other.kasp.
set_zone_policy "nsec3-other.kasp" "nsec3-other"
set_nsec3param "1" "11" "0"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Reconfig named.
echo_i "reconfig dnssec-policy to trigger nsec3 rollovers"
copy_setports ns3/named2.conf.in ns3/named.conf
rndc_reconfig ns3 10.53.0.3
# Zone: nsec-to-nsec3.kasp. (reconfigured)
set_zone_policy "nsec-to-nsec3.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
# Zone: nsec3.kasp. (same)
set_zone_policy "nsec3.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
# Zone: nsec3-dyamic.kasp. (same)
set_zone_policy "nsec3-dynamic.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
# Zone: nsec3-change.kasp. (reconfigured)
set_zone_policy "nsec3-change.kasp" "nsec3-other"
set_nsec3param "1" "11" "0"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
# Zone: nsec3-dynamic-change.kasp. (reconfigured)
set_zone_policy "nsec3-dynamic-change.kasp" "nsec3-other"
set_nsec3param "1" "11" "0"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
# Zone: nsec3-to-nsec.kasp. (reconfigured)
set_zone_policy "nsec3-to-nsec.kasp" "nsec"
set_nsec3param "1" "11" "0"
echo_i "check zone ${ZONE} after reconfig"
check_nsec
dnssec_verify
# Zone: nsec3-to-optout.kasp. (reconfigured)
# DISABLED:
# There is a bug in the nsec3param building code that thinks when the
# optout bit is changed, the chain already exists. [GL #2216]
#set_zone_policy "nsec3-to-optout.kasp" "optout"
#set_nsec3param "1" "5" "8"
#echo_i "check zone ${ZONE} after reconfig"
#check_nsec3
#dnssec_verify
# Zone: nsec3-from-optout.kasp. (reconfigured)
# DISABLED:
# There is a bug in the nsec3param building code that thinks when the
# optout bit is changed, the chain already exists. [GL #2216]
#set_zone_policy "nsec3-from-optout.kasp" "nsec3"
#set_nsec3param "0" "5" "8"
#echo_i "check zone ${ZONE} after reconfig"
#check_nsec3
#dnssec_verify
# Zone: nsec3-other.kasp. (same)
set_zone_policy "nsec3-other.kasp" "nsec3-other"
set_nsec3param "1" "11" "0"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
# Using rndc signing -nsec3param (should fail)
set_zone_policy "nsec3-change.kasp" "nsec3-other"
echo_i "use rndc signing -nsec3param ${ZONE} to change NSEC3 settings"
rndccmd $SERVER signing -nsec3param 1 1 12 ffff $ZONE > rndc.signing.test$n.$ZONE || log_error "failed to call rndc signing -nsec3param $ZONE"
grep "zone uses dnssec-policy, use rndc dnssec command instead" rndc.signing.test$n.$ZONE > /dev/null || log_error "rndc signing -nsec3param should fail"
check_nsec3
dnssec_verify
# Test NSEC3 and NSEC3PARAM is the same after restart
set_zone_policy "nsec3.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "check zone ${ZONE} before restart"
check_nsec3
dnssec_verify
# Restart named, NSEC3 should stay the same.
ret=0
echo "stop ns3"
$PERL ../stop.pl --use-rndc --port ${CONTROLPORT} nsec3 ${DIR} || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
ret=0
echo "start ns3"
start_server --noclean --restart --port ${PORT} nsec3 ${DIR}
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
prevsalt="${SALT}"
set_zone_policy "nsec3.kasp" "nsec3"
set_nsec3param "0" "5" "8"
SALT="${prevsalt}"
echo_i "check zone ${ZONE} after restart has salt ${SALT}"
check_nsec3
dnssec_verify
# Zone: nsec3-fails-to-load.kasp. (should be fixed after reload)
cp ns3/template.db.in ns3/nsec3-fails-to-load.kasp.db
rndc_reload ns3 10.53.0.3
set_zone_policy "nsec3-fails-to-load.kasp" "nsec3"
set_nsec3param "0" "5" "8"
echo_i "check zone ${ZONE} after reload"
check_nsec3
dnssec_verify
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1