diff options
Diffstat (limited to 'bin/tests/system/conf.sh.common')
-rw-r--r-- | bin/tests/system/conf.sh.common | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/bin/tests/system/conf.sh.common b/bin/tests/system/conf.sh.common new file mode 100644 index 0000000..90059dd --- /dev/null +++ b/bin/tests/system/conf.sh.common @@ -0,0 +1,738 @@ +#!/bin/sh +# +# 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. + +testsock6() { + if test -n "$PERL" && $PERL -e "use IO::Socket::INET6;" 2> /dev/null + then + $PERL "$TOP_SRCDIR/bin/tests/system/testsock6.pl" "$@" + else + false + fi +} + +export LANG=C + + +# +# Common lists of system tests to run. +# +# The following tests are hard-coded to use ports 5300 and 9953. For +# this reason, these must be run sequentially. +# +# Sequential tests that only run on unix/linux should be added to +# SEQUENTIAL_UNIX in conf.sh.in +# +SEQUENTIAL_COMMON="" + +# +# These tests can use ports assigned by the caller (other than 5300 +# and 9953). Because separate blocks of ports can be used for teach +# test, these tests can be run in parallel. +# +# Parallel tests that only run on unix/linux should be added to +# PARALLEL_UNIX in conf.sh.in; +# +# Note: some of the longer-running tests such as serve-stale and +# rpzrecurse are scheduled first, in order to get more benefit from +# parallelism. +# +PARALLEL_COMMON=" +rpzrecurse +serve-stale +dupsigs +acl +additional +addzone +allow-query +auth +autosign +builtin +cacheclean +case +catz +cds +checkconf +checknames +checkzone +database +digdelv +dlz +dns64 +dsdigest +ecdsa +eddsa +ednscompliance +emptyzones +fetchlimit +formerr +forward +geoip2 +glue +idna +include-multiplecfg +inline +integrity +ixfr +journal +keepalive +limits +masterfile +masterformat +metadata +mirror +mkeys +names +notify +nsec3 +nslookup +nsupdate +padding +pending +reclimit +redirect +resolver +rndc +rootkeysentinel +rpz +rrchecker +rrl +rrsetorder +rsabigexponent +runtime +sfcache +smartsign +sortlist +spf +staticstub +statistics +statschannel +stub +synthfromdnssec +tkey +tools +tsig +tsiggss +ttl +unknown +upforwd +verify +views +wildcard +xfer +xferquota +zero +zonechecks" + +# +# Set up color-coded test output +# +if [ ${SYSTEMTEST_FORCE_COLOR:-0} -eq 1 ] || test -t 1 && type tput > /dev/null 2>&1 && tput setaf 7 > /dev/null 2>&1 ; then + export COLOR_END=$(tput setaf 4) # blue + export COLOR_FAIL=$(tput setaf 1) # red + export COLOR_INFO=$(tput bold) # bold + export COLOR_NONE=$(tput sgr0) + export COLOR_PASS=$(tput setaf 2) # green + export COLOR_START=$(tput setaf 4) # blue + export COLOR_WARN=$(tput setaf 3) # yellow +else + # set to empty strings so printf succeeds + export COLOR_END='' + export COLOR_FAIL='' + export COLOR_INFO='' + export COLOR_NONE='' + export COLOR_PASS='' + export COLOR_START='' + export COLOR_WARN='' +fi + +export SYSTESTDIR="$(basename $PWD)" + +if type printf > /dev/null 2>&1 +then + echofail () { + printf "${COLOR_FAIL}%s${COLOR_NONE}\n" "$*" + } + echowarn () { + printf "${COLOR_WARN}%s${COLOR_NONE}\n" "$*" + } + echopass () { + printf "${COLOR_PASS}%s${COLOR_NONE}\n" "$*" + } + echoinfo () { + printf "${COLOR_INFO}%s${COLOR_NONE}\n" "$*" + } + echostart () { + printf "${COLOR_START}%s${COLOR_NONE}\n" "$*" + } + echoend () { + printf "${COLOR_END}%s${COLOR_NONE}\n" "$*" + } + echo_i() { + printf '%s\n' "$*" | while IFS= read -r __LINE ; do + echoinfo "I:$SYSTESTDIR:$__LINE" + done + } + + echo_ic() { + printf '%s\n' "$*" | while IFS= read -r __LINE ; do + echoinfo "I:$SYSTESTDIR: $__LINE" + done + } + + echo_d() { + printf '%s\n' "$*" | while IFS= read -r __LINE ; do + echoinfo "D:$SYSTESTDIR:$__LINE" + done + } +else + echofail () { + echo "$*" + } + echowarn () { + echo "$*" + } + echopass () { + echo "$*" + } + echoinfo () { + echo "$*" + } + echostart () { + echo "$*" + } + echoend () { + echo "$*" + } + + echo_i() { + echo "$@" | while IFS= read -r __LINE ; do + echoinfo "I:$SYSTESTDIR:$__LINE" + done + } + + echo_ic() { + echo "$@" | while IFS= read -r __LINE ; do + echoinfo "I:$SYSTESTDIR: $__LINE" + done + } + + echo_d() { + echo "$@" | while IFS= read -r __LINE ; do + echoinfo "D:$SYSTESTDIR:$__LINE" + done + } +fi + +cat_i() { + while IFS= read -r __LINE ; do + echoinfo "I:$SYSTESTDIR:$__LINE" + done +} + +cat_d() { + while IFS= read -r __LINE ; do + echoinfo "D:$SYSTESTDIR:$__LINE" + done +} + +digcomp() { + { output=$($PERL $TOP_SRCDIR/bin/tests/system/digcomp.pl "$@"); result=$?; } || true + [ -n "$output" ] && { echo "digcomp failed:"; echo "$output"; } | cat_i + return $result +} + +start_server() { + $PERL "$TOP_SRCDIR/bin/tests/system/start.pl" "$SYSTESTDIR" "$@" +} + +stop_server() { + $PERL "$TOP_SRCDIR/bin/tests/system/stop.pl" "$SYSTESTDIR" "$@" +} + +send() { + $PERL "$TOP_SRCDIR/bin/tests/system/send.pl" "$@" +} + +# +# Useful variables in test scripts +# + +# The following script sets the following algorithm-related variables. These +# are selected randomly at runtime from a list of supported algorithms. The +# randomization is deterministic and remains stable for a period of time for a +# given platform. +# +# Default algorithm for testing. +# DEFAULT_ALGORITHM +# DEFAULT_ALGORITHM_NUMBER +# DEFAULT_BITS +# +# This is an alternative algorithm for test cases that require more than one +# algorithm (for example algorithm rollover). Must be different from +# DEFAULT_ALGORITHM. +# ALTERNATIVE_ALGORITHM +# ALTERNATIVE_ALGORITHM_NUMBER +# ALTERNATIVE_BITS +# +# This is an algorithm that is used for tests against the "disable-algorithms" +# configuration option. Must be different from above algorithms. +# DISABLED_ALGORITHM +# DISABLED_ALGORITHM_NUMBER +# DISABLED_BITS +# +# There are multiple algoritms sets to choose from (see get_algorithms.py). To +# override the default choice, set the ALGORITHM_SET env var (see mkeys system +# test for example). +eval "$($PYTHON "$TOP_SRCDIR/bin/tests/system/get_algorithms.py")" + +# Default HMAC algorithm. +# also update common/rndc.conf and common/rndc.key when updating DEFAULT_HMAC +export DEFAULT_HMAC=hmac-sha256 + +# +# Useful functions in test scripts +# + +# assert_int_equal: compare two integer variables, $1 and $2 +# +# If $1 and $2 are equal, return 0; if $1 and $2 are not equal, report +# the error using the description of the tested variable provided in $3 +# and return 1. +assert_int_equal() { + found="$1" + expected="$2" + description="$3" + + if [ "${expected}" -ne "${found}" ]; then + echo_i "incorrect ${description}: got ${found}, expected ${expected}" + return 1 + fi + + return 0 +} + +# keyfile_to_keys_section: helper function for keyfile_to_*_keys() which +# converts keyfile data into a key-style trust anchor configuration +# section using the supplied parameters +keyfile_to_keys() { + section_name=$1 + key_prefix=$2 + shift + shift + echo "$section_name {" + for keyname in $*; do + awk '!/^; /{ + printf "\t\""$1"\" " + printf "'"$key_prefix "'" + printf $4 " " $5 " " $6 " \"" + for (i=7; i<=NF; i++) printf $i + printf "\";\n" + }' $keyname.key + done + echo "};" +} + +# keyfile_to_dskeys_section: helper function for keyfile_to_*_dskeys() +# converts keyfile data into a DS-style trust anchor configuration +# section using the supplied parameters +keyfile_to_dskeys() { + section_name=$1 + key_prefix=$2 + shift + shift + echo "$section_name {" + for keyname in $*; do + $DSFROMKEY $keyname.key | \ + awk '!/^; /{ + printf "\t\""$1"\" " + printf "'"$key_prefix "'" + printf $4 " " $5 " " $6 " \"" + for (i=7; i<=NF; i++) printf $i + printf "\";\n" + }' + done + echo "};" +} + +# keyfile_to_trusted_keys: convert key data contained in the keyfile(s) +# provided to a "trust-keys" section suitable for including in a +# resolver's configuration file +keyfile_to_trusted_keys() { + keyfile_to_keys "trusted-keys" "" $* +} + +# keyfile_to_static_keys: convert key data contained in the keyfile(s) +# provided to a *static-key* "trust-anchors" section suitable for including in +# a resolver's configuration file +keyfile_to_static_keys() { + keyfile_to_keys "trust-anchors" "static-key" $* +} + +# keyfile_to_initial_keys: convert key data contained in the keyfile(s) +# provided to an *initial-key* "trust-anchors" section suitable for including +# in a resolver's configuration file +keyfile_to_initial_keys() { + keyfile_to_keys "trust-anchors" "initial-key" $* +} + +# keyfile_to_static_ds_keys: convert key data contained in the keyfile(s) +# provided to a *static-ds* "trust-anchors" section suitable for including in a +# resolver's configuration file +keyfile_to_static_ds() { + keyfile_to_dskeys "trust-anchors" "static-ds" $* +} + +# keyfile_to_initial_ds_keys: convert key data contained in the keyfile(s) +# provided to an *initial-ds* "trust-anchors" section suitable for including +# in a resolver's configuration file +keyfile_to_initial_ds() { + keyfile_to_dskeys "trust-anchors" "initial-ds" $* +} + +# keyfile_to_key_id: convert a key file name to a key ID +# +# For a given key file name (e.g. "Kexample.+013+06160") provided as $1, +# print the key ID with leading zeros stripped ("6160" for the +# aforementioned example). +keyfile_to_key_id() { + echo "$1" | sed "s/.*+0\{0,4\}//" +} + +# private_type_record: write a private type record recording the state of the +# signing process +# +# For a given zone ($1), algorithm number ($2) and key file ($3), print the +# private type record with default type value of 65534, indicating that the +# signing process for this key is completed. +private_type_record() { + _zone=$1 + _algorithm=$2 + _keyfile=$3 + + _id=$(keyfile_to_key_id "$_keyfile") + + printf "%s. 0 IN TYPE65534 %s 5 %02x%04x0000\n" "$_zone" "\\#" "$_algorithm" "$_id" +} + +# nextpart*() - functions for reading files incrementally +# +# These functions aim to facilitate looking for (or waiting for) +# messages which may be logged more than once throughout the lifetime of +# a given named instance by outputting just the part of the file which +# has been appended since the last time we read it. +# +# Calling some of these functions causes temporary *.prev files to be +# created that need to be cleaned up manually (usually by a given system +# test's clean.sh script). +# +# Note that unlike other nextpart*() functions, nextpartread() is not +# meant to be directly used in system tests; its sole purpose is to +# reduce code duplication below. +# +# A quick usage example: +# +# $ echo line1 > named.log +# $ echo line2 >> named.log +# $ nextpart named.log +# line1 +# line2 +# $ echo line3 >> named.log +# $ nextpart named.log +# line3 +# $ nextpart named.log +# $ echo line4 >> named.log +# $ nextpartpeek named.log +# line4 +# $ nextpartpeek named.log +# line4 +# $ nextpartreset named.log +# $ nextpartpeek named.log +# line1 +# line2 +# line3 +# line4 +# $ nextpart named.log +# line1 +# line2 +# line3 +# line4 +# $ nextpart named.log +# $ + +# nextpartreset: reset the marker used by nextpart() and nextpartpeek() +# so that it points to the start of the given file +nextpartreset() { + echo "0" > $1.prev +} + +# nextpartread: read everything that's been appended to a file since the +# last time nextpart() was called and print it to stdout, print the +# total number of lines read from that file so far to file descriptor 3 +nextpartread() { + [ -f $1.prev ] || nextpartreset $1 + prev=$(cat $1.prev) + awk "NR > $prev "'{ print } + END { print NR > "/dev/stderr" }' $1 2>&3 +} + +# nextpart: read everything that's been appended to a file since the +# last time nextpart() was called +nextpart() { + nextpartread $1 3> $1.prev.tmp + mv $1.prev.tmp $1.prev +} + +# nextpartpeek: read everything that's been appended to a file since the +# last time nextpart() was called +nextpartpeek() { + nextpartread $1 3> /dev/null +} + +# _search_log: look for message $1 in file $2 with nextpart(). +_search_log() ( + msg="$1" + file="$2" + nextpart "$file" | grep -F -e "$msg" > /dev/null +) + +# _search_log_re: same as _search_log but the message is an grep -E regex +_search_log_re() ( + msg="$1" + file="$2" + nextpart "$file" | grep -E -e "$msg" > /dev/null +) + +# _search_log_peek: look for message $1 in file $2 with nextpartpeek(). +_search_log_peek() ( + msg="$1" + file="$2" + nextpartpeek "$file" | grep -F -e "$msg" > /dev/null +) + +# wait_for_log: wait until message $2 in file $3 appears. Bail out after +# $1 seconds. This needs to be used in conjunction with a prior call to +# nextpart() or nextpartreset() on the same file to guarantee the offset is +# set correctly. Tests using wait_for_log() are responsible for cleaning up +# the created <file>.prev files. +wait_for_log() ( + timeout="$1" + msg="$2" + file="$3" + retry_quiet "$timeout" _search_log "$msg" "$file" && return 0 + echo_i "exceeded time limit waiting for literal '$msg' in $file" + return 1 +) + +# wait_for_log_re: same as wait_for_log, but the message is an grep -E regex +wait_for_log_re() ( + timeout="$1" + msg="$2" + file="$3" + retry_quiet "$timeout" _search_log_re "$msg" "$file" && return 0 + echo_i "exceeded time limit waiting for regex '$msg' in $file" + return 1 +) + +# wait_for_log_peek: similar to wait_for_log() but peeking, so the file offset +# does not change. +wait_for_log_peek() ( + timeout="$1" + msg="$2" + file="$3" + retry_quiet "$timeout" _search_log_peek "$msg" "$file" && return 0 + echo_i "exceeded time limit waiting for literal '$msg' in $file" + return 1 +) + +# _retry: keep running a command until it succeeds, up to $1 times, with +# one-second intervals, optionally printing a message upon every attempt +_retry() { + __retries="${1}" + shift + + while :; do + if "$@"; then + return 0 + fi + __retries=$((__retries-1)) + if [ "${__retries}" -gt 0 ]; then + if [ "${__retry_quiet}" -ne 1 ]; then + echo_i "retrying" + fi + sleep 1 + else + return 1 + fi + done +} + +# retry: call _retry() in verbose mode +retry() { + __retry_quiet=0 + _retry "$@" +} + +# retry_quiet: call _retry() in silent mode +retry_quiet() { + __retry_quiet=1 + _retry "$@" +} + +# _repeat: keep running command up to $1 times, unless it fails +_repeat() ( + __retries="${1}" + shift + while :; do + if ! "$@"; then + return 1 + fi + __retries=$((__retries-1)) + if [ "${__retries}" -le 0 ]; then + break + fi + done + return 0 +) + +_times() { + awk "BEGIN{ for(i = 1; i <= $1; i++) print i}"; +} + +rndc_reload() { + $RNDC -c ../common/rndc.conf -s $2 -p ${CONTROLPORT} reload $3 2>&1 | sed 's/^/'"I:$SYSTESTDIR:$1"' /' + # reloading single zone is synchronous, if we're reloading whole server + # we need to wait for reload to finish + if [ -z "$3" ]; then + for _ in $(_times 10); do + $RNDC -c ../common/rndc.conf -s $2 -p ${CONTROLPORT} status | grep "reload/reconfig in progress" > /dev/null || break + sleep 1 + done + fi +} + +rndc_reconfig() { + seconds=${3:-10} + $RNDC -c ../common/rndc.conf -s "$2" -p "${CONTROLPORT}" reconfig 2>&1 | sed 's/^/'"I:$SYSTESTDIR:$1"' /' + for _ in $(_times "$seconds"); do + "$RNDC" -c ../common/rndc.conf -s "$2" -p "${CONTROLPORT}" status | grep "reload/reconfig in progress" > /dev/null || break + sleep 1 + done +} + +# rndc_dumpdb: call "rndc dumpdb [...]" and wait until it completes +# +# The first argument is the name server instance to send the command to, in the +# form of "nsX" (where "X" is the instance number), e.g. "ns5". The remaining +# arguments, if any, are appended to the rndc command line after "dumpdb". +# +# Control channel configuration for the name server instance to send the +# command to must match the contents of bin/tests/system/common/rndc.conf. +# +# rndc output is stored in a file called rndc.out.test${n}; the "n" variable is +# required to be set by the calling tests.sh script. +# +# Return 0 if the dump completes successfully; return 1 if rndc returns an exit +# code other than 0 or if the "; Dump complete" string does not appear in the +# dump within 10 seconds. +rndc_dumpdb() { + __ret=0 + __dump_complete=0 + __server="${1}" + __ip="10.53.0.$(echo "${__server}" | tr -c -d "0-9")" + + shift + ${RNDC} -c ../common/rndc.conf -p "${CONTROLPORT}" -s "${__ip}" dumpdb "$@" > "rndc.out.test${n}" 2>&1 || __ret=1 + + for _ in 0 1 2 3 4 5 6 7 8 9 + do + if grep '^; Dump complete$' "${__server}/named_dump.db" > /dev/null; then + mv "${__server}/named_dump.db" "${__server}/named_dump.db.test${n}" + __dump_complete=1 + break + fi + sleep 1 + done + + if [ ${__dump_complete} -eq 0 ]; then + echo_i "timed out waiting for 'rndc dumpdb' to finish" + __ret=1 + fi + + return ${__ret} +} + +# get_dig_xfer_stats: extract transfer statistics from dig output stored +# in $1, converting them to a format used by some system tests. +get_dig_xfer_stats() { + LOGFILE="$1" + sed -n "s/^;; XFR size: .*messages \([0-9][0-9]*\).*/messages=\1/p" "${LOGFILE}" + sed -n "s/^;; XFR size: \([0-9][0-9]*\) records.*/records=\1/p" "${LOGFILE}" + sed -n "s/^;; XFR size: .*bytes \([0-9][0-9]*\).*/bytes=\1/p" "${LOGFILE}" +} + +# get_named_xfer_stats: from named log file $1, extract transfer +# statistics for the last transfer for peer $2 and zone $3 (from a log +# message which has to contain the string provided in $4), converting +# them to a format used by some system tests. +get_named_xfer_stats() { + LOGFILE="$1" + PEER="$(echo $2 | sed 's/\./\\./g')" + ZONE="$(echo $3 | sed 's/\./\\./g')" + MESSAGE="$4" + grep " ${PEER}#.*${MESSAGE}:" "${LOGFILE}" | \ + sed -n "s/.* '${ZONE}\/.* \([0-9][0-9]*\) messages.*/messages=\1/p" | tail -1 + grep " ${PEER}#.*${MESSAGE}:" "${LOGFILE}" | \ + sed -n "s/.* '${ZONE}\/.* \([0-9][0-9]*\) records.*/records=\1/p" | tail -1 + grep " ${PEER}#.*${MESSAGE}:" "${LOGFILE}" | \ + sed -n "s/.* '${ZONE}\/.* \([0-9][0-9]*\) bytes.*/bytes=\1/p" | tail -1 +} + +# copy_setports - Copy Configuration File and Replace Ports +# +# Convenience function to copy a configuration file, replacing the tokens +# QUERYPORT, CONTROLPORT and EXTRAPORT[1-8] with the values of the equivalent +# environment variables. (These values are set by test runner, which calls the +# scripts invoking this function.) +# +# Usage: +# copy_setports infile outfile +# +copy_setports() { + dir=$(echo "$TMPDIR" | sed 's/\//\\\//g') + + sed -e "s/@TMPDIR@/${dir}/g" \ + -e "s/@PORT@/${PORT}/g" \ + -e "s/@TLSPORT@/${TLSPORT}/g" \ + -e "s/@HTTPPORT@/${HTTPPORT}/g" \ + -e "s/@HTTPSPORT@/${HTTPSPORT}/g" \ + -e "s/@EXTRAPORT1@/${EXTRAPORT1}/g" \ + -e "s/@EXTRAPORT2@/${EXTRAPORT2}/g" \ + -e "s/@EXTRAPORT3@/${EXTRAPORT3}/g" \ + -e "s/@EXTRAPORT4@/${EXTRAPORT4}/g" \ + -e "s/@EXTRAPORT5@/${EXTRAPORT5}/g" \ + -e "s/@EXTRAPORT6@/${EXTRAPORT6}/g" \ + -e "s/@EXTRAPORT7@/${EXTRAPORT7}/g" \ + -e "s/@EXTRAPORT8@/${EXTRAPORT8}/g" \ + -e "s/@CONTROLPORT@/${CONTROLPORT}/g" \ + -e "s/@DEFAULT_ALGORITHM@/${DEFAULT_ALGORITHM}/g" \ + -e "s/@DEFAULT_ALGORITHM_NUMBER@/${DEFAULT_ALGORITHM_NUMBER}/g" \ + -e "s/@DEFAULT_BITS@/${DEFAULT_BITS}/g" \ + -e "s/@ALTERNATIVE_ALGORITHM@/${ALTERNATIVE_ALGORITHM}/g" \ + -e "s/@ALTERNATIVE_ALGORITHM_NUMBER@/${ALTERNATIVE_ALGORITHM_NUMBER}/g" \ + -e "s/@ALTERNATIVE_BITS@/${ALTERNATIVE_BITS}/g" \ + -e "s/@DEFAULT_HMAC@/${DEFAULT_HMAC}/g" \ + -e "s/@DISABLED_ALGORITHM@/${DISABLED_ALGORITHM}/g" \ + -e "s/@DISABLED_ALGORITHM_NUMBER@/${DISABLED_ALGORITHM_NUMBER}/g" \ + -e "s/@DISABLED_BITS@/${DISABLED_BITS}/g" \ + $1 > $2 +} |