1#!/bin/sh
2#
3# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
4#
5# This Source Code Form is subject to the terms of the Mozilla Public
6# License, v. 2.0. If a copy of the MPL was not distributed with this
7# file, you can obtain one at https://mozilla.org/MPL/2.0/.
8#
9# See the COPYRIGHT file distributed with this work for additional
10# information regarding copyright ownership.
11
12#
13# Common configuration data for system tests, to be sourced into
14# other shell scripts.
15#
16
17# Find the top of the BIND9 tree.
18TOP=@abs_top_builddir@
19
20# Default algorithm for testing
21DEFAULT_ALGORITHM=RSASHA256
22DEFAULT_ALGORITHM_NUMBER=8
23DEFAULT_BITS=1280
24
25# Provide TMPDIR variable for tests that need it.
26TMPDIR=${TMPDIR:-/tmp}
27
28# must be different from DEFAULT_ALGORITHM
29ALTERNATIVE_ALGORITHM=RSASHA1
30ALTERNATIVE_ALGORITHM_NUMBER=5
31ALTERNATIVE_BITS=1280
32
33# This is an algorithm that is used for tests against the
34# "disable-algorithms" configuration option.  Must be different from above
35# algorithms.
36DISABLED_ALGORITHM=ECDSAP384SHA384
37DISABLED_ALGORITHM_NUMBER=14
38DISABLED_BITS=384
39
40NAMED=$TOP/bin/named/named
41# We must use "named -l" instead of "lwresd" because argv[0] is lost
42# if the program is libtoolized.
43LWRESD="$TOP/bin/named/named -l"
44DIG=$TOP/bin/dig/dig
45DELV=$TOP/bin/delv/delv
46RNDC=$TOP/bin/rndc/rndc
47NSUPDATE=$TOP/bin/nsupdate/nsupdate
48DDNSCONFGEN=$TOP/bin/confgen/ddns-confgen
49TSIGKEYGEN=$TOP/bin/confgen/tsig-keygen
50RNDCCONFGEN=$TOP/bin/confgen/rndc-confgen
51KEYGEN=$TOP/bin/dnssec/dnssec-keygen
52KEYFRLAB=$TOP/bin/dnssec/dnssec-keyfromlabel
53SIGNER=$TOP/bin/dnssec/dnssec-signzone
54REVOKE=$TOP/bin/dnssec/dnssec-revoke
55SETTIME=$TOP/bin/dnssec/dnssec-settime
56DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey
57HOST=$TOP/bin/dig/host
58IMPORTKEY=$TOP/bin/dnssec/dnssec-importkey
59CHECKDS=$TOP/bin/python/dnssec-checkds
60COVERAGE=$TOP/bin/python/dnssec-coverage
61KEYMGR=$TOP/bin/python/dnssec-keymgr
62CHECKZONE=$TOP/bin/check/named-checkzone
63CHECKCONF=$TOP/bin/check/named-checkconf
64PK11GEN="$TOP/bin/pkcs11/pkcs11-keygen -q -s ${SLOT:-0} -p ${HSMPIN:-1234}"
65PK11LIST="$TOP/bin/pkcs11/pkcs11-list -s ${SLOT:-0} -p ${HSMPIN:-1234}"
66PK11DEL="$TOP/bin/pkcs11/pkcs11-destroy -s ${SLOT:-0} -p ${HSMPIN:-1234} -w 0"
67JOURNALPRINT=$TOP/bin/tools/named-journalprint
68VERIFY=$TOP/bin/dnssec/dnssec-verify
69ARPANAME=$TOP/bin/tools/arpaname
70RESOLVE=$TOP/lib/samples/resolve
71RRCHECKER=$TOP/bin/tools/named-rrchecker
72GENRANDOM=$TOP/bin/tools/genrandom
73NSLOOKUP=$TOP/bin/dig/nslookup
74DNSTAPREAD=$TOP/bin/tools/dnstap-read
75MDIG=$TOP/bin/tools/mdig
76NZD2NZF=$TOP/bin/tools/named-nzd2nzf
77FSTRM_CAPTURE=@FSTRM_CAPTURE@
78FEATURETEST=$TOP/bin/tests/system/feature-test
79
80RANDFILE=$TOP/bin/tests/system/random.data
81
82BIGKEY=$TOP/bin/tests/system/rsabigexponent/bigkey
83GENCHECK=$TOP/bin/tests/system/rndc/gencheck
84KEYCREATE=$TOP/bin/tests/system/tkey/keycreate
85KEYDELETE=$TOP/bin/tests/system/tkey/keydelete
86LWTEST=$TOP/bin/tests/system/lwresd/lwtest
87MAKEJOURNAL=$TOP/bin/tests/makejournal
88PIPEQUERIES=$TOP/bin/tests/system/pipelined/pipequeries
89SAMPLEUPDATE=$TOP/lib/samples/sample-update
90
91# we don't want a KRB5_CONFIG setting breaking the tests
92KRB5_CONFIG=/dev/null
93# use local keytab instead of default /etc/krb5.keytab
94KRB5_KTNAME=dns.keytab
95
96# the amount of fake "entropy" to generate with GENRANDOM in
97# system tests
98RANDOMSIZE=4096
99
100# The "stress" test is not run by default since it creates enough
101# load on the machine to make it unusable to other users.
102# The "dialup", "delzone", and "dupsigs" tests are also not run by
103# default because they take a very long time to complete.
104#
105# List of tests hard-coded to use ports 5300 and 9953. For this
106# reason, these must be run sequentially.
107SEQUENTIALDIRS="ecdsa eddsa gost lwresd @PKCS11_TEST@ tkey"
108
109# List of tests that use ports assigned by caller (other than 5300
110# and 9953). Because separate blocks of ports can be used for teach
111# test, these tests can be run in parallel.
112#
113# Note: some of the longer-running tests are scheduled first,
114# in order to get more benefit from parallelism.
115PARALLELDIRS="dnssec rpzrecurse \
116	acl additional addzone allow-query auth autosign \
117	builtin cacheclean case catz chain \
118	checkconf checknames checkzone \
119	@CHECKDS@ @COVERAGE@ @KEYMGR@ \
120	cookie database digdelv dlv dlz dlzexternal \
121	dns64 @DNSTAP@ dscp dsdigest dyndb \
122	ednscompliance emptyzones \
123	fetchlimit filter-aaaa formerr forward \
124	geoip geoip2 glue idna inline integrity ixfr \
125	legacy limits logfileconfig \
126	masterfile masterformat metadata mkeys \
127	names notify nslookup nsupdate nzd2nzf \
128	pending pipelined \
129	reclimit redirect resolver rndc rootkeysentinel rpz \
130	rrchecker rrl rrsetorder rsabigexponent runtime \
131	sfcache smartsign sortlist \
132	spf staticstub statistics statschannel stub \
133	tcp tsig tsiggss \
134	unknown upforwd verify views wildcard \
135	xfer xferquota zero zonechecks"
136
137SUBDIRS="$SEQUENTIALDIRS $PARALLELDIRS"
138
139# Things that are different on Windows
140KILL=kill
141DIFF=diff
142DOS2UNIX=true
143# There's no trailing period on Windows
144TP=.
145
146# Use the CONFIG_SHELL detected by configure for tests
147SHELL=@SHELL@
148
149# CURL will be empty if no program was found by configure
150CURL=@CURL@
151
152# XMLLINT will be empty if no program was found by configure
153XMLLINT=@XMLLINT@
154
155# XSLTPROC will be empty if no program was found by configure
156XSLTPROC=@XSLTPROC@
157
158# PERL will be an empty string if no perl interpreter was found.
159PERL=@PERL@
160
161testsock6() {
162	if test -n "$PERL" \
163		&& $PERL -e "use IO::Socket::INET6;" 2> /dev/null \
164		&& grep "^#define WANT_IPV6 1" "$TOP/config.h" > /dev/null 2>&1
165	then
166		$PERL "$TOP/bin/tests/system/testsock6.pl" "$@"
167	else
168		false
169	fi
170}
171
172# Windows process management leave empty
173PSSUSPEND=
174
175PYTHON=@PYTHON@
176
177#
178# Determine if we support various optional features.
179#
180CHECK_DSA=@CHECK_DSA@
181HAVEXMLSTATS=@XMLSTATS@
182HAVEJSONSTATS=@JSONSTATS@
183ZLIB=@ZLIB@
184NZD=@NZD_TOOLS@
185
186. ${TOP}/version
187
188#
189# Set up color-coded test output
190#
191if [ ${SYSTEMTEST_FORCE_COLOR:-0} -eq 1 ] || test -t 1 && type tput > /dev/null 2>&1 && tput setaf 7 > /dev/null 2>&1 ; then
192    COLOR_END=`tput setaf 4`    # blue
193    COLOR_FAIL=`tput setaf 1`   # red
194    COLOR_INFO=`tput bold`      # bold
195    COLOR_NONE=`tput sgr0`
196    COLOR_PASS=`tput setaf 2`   # green
197    COLOR_START=`tput setaf 4`  # blue
198    COLOR_WARN=`tput setaf 3`   # yellow
199else
200    # set to empty strings so printf succeeds
201    COLOR_END=''
202    COLOR_FAIL=''
203    COLOR_INFO=''
204    COLOR_NONE=''
205    COLOR_PASS=''
206    COLOR_START=''
207    COLOR_WARN=''
208fi
209
210SYSTESTDIR="`basename $PWD`"
211
212if type printf > /dev/null 2>&1
213then
214	echofail () {
215		printf "${COLOR_FAIL}%s${COLOR_NONE}\n" "$*"
216	}
217	echowarn () {
218		printf "${COLOR_WARN}%s${COLOR_NONE}\n" "$*"
219	}
220	echopass () {
221		printf "${COLOR_PASS}%s${COLOR_NONE}\n" "$*"
222	}
223	echoinfo () {
224		printf "${COLOR_INFO}%s${COLOR_NONE}\n" "$*"
225	}
226	echostart () {
227		printf "${COLOR_START}%s${COLOR_NONE}\n" "$*"
228	}
229	echoend () {
230		printf "${COLOR_END}%s${COLOR_NONE}\n" "$*"
231	}
232	echo_i() {
233	    printf '%s\n' "$*" | while read -r __LINE ; do
234	       echoinfo "I:$SYSTESTDIR:$__LINE"
235	    done
236	}
237
238	echo_ic() {
239	    printf '%s\n' "$*" | while read -r __LINE ; do
240	       echoinfo "I:$SYSTESTDIR:  $__LINE"
241	    done
242	}
243
244	echo_d() {
245	    printf '%s\n' "$*" | while read -r __LINE ; do
246	       echoinfo "D:$SYSTESTDIR:$__LINE"
247	    done
248	}
249else
250	echofail () {
251		echo "$*"
252	}
253	echowarn () {
254		echo "$*"
255	}
256	echopass () {
257		echo "$*"
258	}
259	echoinfo () {
260		echo "$*"
261	}
262	echostart () {
263		echo "$*"
264	}
265	echoend () {
266		echo "$*"
267	}
268
269	echo_i() {
270	    echo "$@" | while read -r __LINE ; do
271	       echoinfo "I:$SYSTESTDIR:$__LINE"
272	    done
273	}
274
275	echo_ic() {
276	    echo "$@" | while read -r __LINE ; do
277	       echoinfo "I:$SYSTESTDIR:  $__LINE"
278	    done
279	}
280
281	echo_d() {
282	    echo "$@" | while read -r __LINE ; do
283	       echoinfo "D:$SYSTESTDIR:$__LINE"
284	    done
285	}
286fi
287
288cat_i() {
289    while read -r __LINE ; do
290       echoinfo "I:$SYSTESTDIR:$__LINE"
291    done
292}
293
294cat_d() {
295    while read -r __LINE ; do
296       echoinfo "D:$SYSTESTDIR:$__LINE"
297    done
298}
299
300
301digcomp() {
302    output=`$PERL $SYSTEMTESTTOP/digcomp.pl "$@"`
303    result=$?
304    [ -n "$output" ] &&  { echo "digcomp failed:"; echo "$output"; } | cat_i
305    return $result
306}
307
308#
309# Useful functions in test scripts
310#
311
312# assert_int_equal: compare two integer variables, $1 and $2
313#
314# If $1 and $2 are equal, return 0; if $1 and $2 are not equal, report
315# the error using the description of the tested variable provided in $3
316# and return 1.
317assert_int_equal() {
318	found="$1"
319	expected="$2"
320	description="$3"
321
322	if [ "${expected}" -ne "${found}" ]; then
323		echo_i "incorrect ${description}: got ${found}, expected ${expected}"
324		return 1
325	fi
326
327	return 0
328}
329
330# keyfile_to_keys_section: helper function for keyfile_to_*_keys() which
331# converts keyfile data into a configuration section using the supplied
332# parameters
333keyfile_to_keys_section() {
334    section_name=$1
335    key_prefix=$2
336    shift
337    shift
338    echo "$section_name {"
339    for keyname in $*; do
340	awk '!/^; /{
341	    printf "\t\""$1"\" "
342	    printf "'"$key_prefix"'"
343	    printf $4 " " $5 " " $6 " \""
344	    for (i=7; i<=NF; i++) printf $i
345	    printf "\";\n"
346	}' $keyname.key
347    done
348    echo "};"
349}
350
351# keyfile_to_trusted_keys: convert key data contained in the keyfile(s)
352# provided to a "trusted-keys" section suitable for including in a
353# resolver's configuration file
354keyfile_to_trusted_keys() {
355    keyfile_to_keys_section "trusted-keys" "" $*
356}
357
358# keyfile_to_managed_keys: convert key data contained in the keyfile(s)
359# provided to a "managed-keys" section suitable for including in a
360# resolver's configuration file
361keyfile_to_managed_keys() {
362    keyfile_to_keys_section "managed-keys" "initial-key " $*
363}
364
365# keyfile_to_key_id: convert a key file name to a key ID
366#
367# For a given key file name (e.g. "Kexample.+013+06160") provided as $1,
368# print the key ID with leading zeros stripped ("6160" for the
369# aforementioned example).
370keyfile_to_key_id() {
371	echo "$1" | sed "s/.*+0\{0,4\}//"
372}
373
374# nextpart*() - functions for reading files incrementally
375#
376# These functions aim to facilitate looking for (or waiting for)
377# messages which may be logged more than once throughout the lifetime of
378# a given named instance by outputting just the part of the file which
379# has been appended since the last time we read it.
380#
381# Calling some of these functions causes temporary *.prev files to be
382# created that need to be cleaned up manually (usually by a given system
383# test's clean.sh script).
384#
385# Note that unlike other nextpart*() functions, nextpartread() is not
386# meant to be directly used in system tests; its sole purpose is to
387# reduce code duplication below.
388#
389# A quick usage example:
390#
391#     $ echo line1 > named.log
392#     $ echo line2 >> named.log
393#     $ nextpart named.log
394#     line1
395#     line2
396#     $ echo line3 >> named.log
397#     $ nextpart named.log
398#     line3
399#     $ nextpart named.log
400#     $ echo line4 >> named.log
401#     $ nextpartpeek named.log
402#     line4
403#     $ nextpartpeek named.log
404#     line4
405#     $ nextpartreset named.log
406#     $ nextpartpeek named.log
407#     line1
408#     line2
409#     line3
410#     line4
411#     $ nextpart named.log
412#     line1
413#     line2
414#     line3
415#     line4
416#     $ nextpart named.log
417#     $
418
419# nextpartreset: reset the marker used by nextpart() and nextpartpeek()
420# so that it points to the start of the given file
421nextpartreset() {
422    echo "0" > $1.prev
423}
424
425# nextpartread: read everything that's been appended to a file since the
426# last time nextpart() was called and print it to stdout, print the
427# total number of lines read from that file so far to stderr
428nextpartread() {
429    [ -f $1.prev ] || nextpartreset $1
430    prev=`cat $1.prev`
431    awk "NR > $prev "'{ print }
432         END          { print NR > "/dev/stderr" }' $1
433}
434
435# nextpart: read everything that's been appended to a file since the
436# last time nextpart() was called
437nextpart() {
438	nextpartread $1 2> $1.prev.tmp
439	mv $1.prev.tmp $1.prev
440}
441
442# nextpartpeek: read everything that's been appended to a file since the
443# last time nextpart() was called
444nextpartpeek() {
445	nextpartread $1 2> /dev/null
446}
447
448# _search_log: look for message $1 in file $2 with nextpart().
449_search_log() (
450	msg="$1"
451	file="$2"
452	nextpart "$file" | grep -F "$msg" > /dev/null
453)
454
455# _search_log_peek: look for message $1 in file $2 with nextpartpeek().
456_search_log_peek() (
457	msg="$1"
458	file="$2"
459	nextpartpeek "$file" | grep -F "$msg" > /dev/null
460)
461
462# wait_for_log: wait until message $2 in file $3 appears.  Bail out after
463# $1 seconds.  This needs to be used in conjunction with a prior call to
464# nextpart() or nextpartreset() on the same file to guarantee the offset is
465# set correctly.  Tests using wait_for_log() are responsible for cleaning up
466# the created <file>.prev files.
467wait_for_log() (
468	timeout="$1"
469	msg="$2"
470	file="$3"
471	retry_quiet "$timeout" _search_log "$msg" "$file" && return 0
472	echo_i "exceeded time limit waiting for '$msg' in $file"
473        return 1
474)
475
476# wait_for_log_peek: similar to wait_for_log() but peeking, so the file offset
477# does not change.
478wait_for_log_peek() (
479	timeout="$1"
480	msg="$2"
481	file="$3"
482	retry_quiet "$timeout" _search_log_peek "$msg" "$file" && return 0
483	echo_i "exceeded time limit waiting for '$msg' in $file"
484        return 1
485)
486
487# _retry: keep running a command until it succeeds, up to $1 times, with
488# one-second intervals, optionally printing a message upon every attempt
489_retry() {
490	__retries="${1}"
491	shift
492
493	while :; do
494		if "$@"; then
495			return 0
496		fi
497		__retries=$((__retries-1))
498		if [ "${__retries}" -gt 0 ]; then
499			if [ "${__retry_quiet}" -ne 1 ]; then
500				echo_i "retrying"
501			fi
502			sleep 1
503		else
504			return 1
505		fi
506	done
507}
508
509# retry: call _retry() in verbose mode
510retry() {
511	__retry_quiet=0
512	_retry "$@"
513}
514
515# retry_quiet: call _retry() in silent mode
516retry_quiet() {
517	__retry_quiet=1
518	_retry "$@"
519}
520
521# _repeat: keep running command up to $1 times, unless it fails
522_repeat() (
523    __retries="${1}"
524    shift
525    while :; do
526        if ! "$@"; then
527            return 1
528        fi
529        __retries=$((__retries-1))
530        if [ "${__retries}" -le 0 ]; then
531            break
532        fi
533    done
534    return 0
535)
536
537# rndc_dumpdb: call "rndc dumpdb [...]" and wait until it completes
538#
539# The first argument is the name server instance to send the command to, in the
540# form of "nsX" (where "X" is the instance number), e.g. "ns5".  The remaining
541# arguments, if any, are appended to the rndc command line after "dumpdb".
542#
543# Control channel configuration for the name server instance to send the
544# command to must match the contents of bin/tests/system/common/rndc.conf.
545#
546# rndc output is stored in a file called rndc.out.test${n}; the "n" variable is
547# required to be set by the calling tests.sh script.
548#
549# Return 0 if the dump completes successfully; return 1 if rndc returns an exit
550# code other than 0 or if the "; Dump complete" string does not appear in the
551# dump within 10 seconds.
552rndc_dumpdb() {
553	__ret=0
554	__dump_complete=0
555	__server="${1}"
556	__ip="10.53.0.`echo "${__server}" | tr -c -d "0-9"`"
557
558	shift
559	${RNDC} -c ../common/rndc.conf -p "${CONTROLPORT}" -s "${__ip}" dumpdb "$@" > "rndc.out.test${n}" 2>&1 || __ret=1
560
561	for _ in 0 1 2 3 4 5 6 7 8 9
562	do
563		if grep '^; Dump complete$' "${__server}/named_dump.db" > /dev/null; then
564			mv "${__server}/named_dump.db" "${__server}/named_dump.db.test${n}"
565			__dump_complete=1
566			break
567		fi
568		sleep 1
569	done
570
571	if [ ${__dump_complete} -eq 0 ]; then
572		echo_i "timed out waiting for 'rndc dumpdb' to finish"
573		__ret=1
574	fi
575
576	return ${__ret}
577}
578
579# copy_setports - Copy Configuration File and Replace Ports
580#
581# Convenience function to copy a configuration file, replacing the tokens
582# QUERYPORT, CONTROLPORT and EXTRAPORT[1-8] with the values of the equivalent
583# environment variables. (These values are set by "run.sh", which calls the
584# scripts invoking this function.)
585#
586# Usage:
587#   copy_setports infile outfile
588
589copy_setports() {
590    sed -e "s/@PORT@/${PORT}/g" \
591	-e "s/@EXTRAPORT1@/${EXTRAPORT1}/g" \
592	-e "s/@EXTRAPORT2@/${EXTRAPORT2}/g" \
593	-e "s/@EXTRAPORT3@/${EXTRAPORT3}/g" \
594	-e "s/@EXTRAPORT4@/${EXTRAPORT4}/g" \
595	-e "s/@EXTRAPORT5@/${EXTRAPORT5}/g" \
596	-e "s/@EXTRAPORT6@/${EXTRAPORT6}/g" \
597	-e "s/@EXTRAPORT7@/${EXTRAPORT7}/g" \
598	-e "s/@EXTRAPORT8@/${EXTRAPORT8}/g" \
599	-e "s/@CONTROLPORT@/${CONTROLPORT}/g" \
600	-e "s/@DEFAULT_ALGORITHM@/${DEFAULT_ALGORITHM}/g" \
601	-e "s/@DEFAULT_ALGORITHM_NUMBER@/${DEFAULT_ALGORITHM_NUMBER}/g" \
602	-e "s/@DEFAULT_BITS@/${DEFAULT_BITS}/g" \
603	-e "s/@ALTERNATIVE_ALGORITHM@/${ALTERNATIVE_ALGORITHM}/g" \
604	-e "s/@ALTERNATIVE_ALGORITHM_NUMBER@/${ALTERNATIVE_ALGORITHM_NUMBER}/g" \
605	-e "s/@ALTERNATIVE_BITS@/${ALTERNATIVE_BITS}/g" \
606	-e "s/@DISABLED_ALGORITHM@/${DISABLED_ALGORITHM}/g" \
607	-e "s/@DISABLED_ALGORITHM_NUMBER@/${DISABLED_ALGORITHM_NUMBER}/g" \
608	-e "s/@DISABLED_BITS@/${DISABLED_BITS}/g" \
609	$1 > $2
610}
611
612#
613# Export command paths
614#
615export ARPANAME
616export BIGKEY
617export CHECKZONE
618export CYGWIN
619export DESCRIPTION
620export DIG
621export FEATURETEST
622export FSTRM_CAPTURE
623export GENCHECK
624export JOURNALPRINT
625export KEYCREATE
626export KEYDELETE
627export KEYFRLAB
628export KEYGEN
629export KEYSETTOOL
630export KEYSIGNER
631export KRB5_CONFIG
632export KRB5_KTNAME
633export LWRESD
634export LWTEST
635export MAKEJOURNAL
636export MDIG
637export NAMED
638export NSLOOKUP
639export NSUPDATE
640export NZD2NZF
641export PERL
642export PIPEQUERIES
643export PK11DEL
644export PK11GEN
645export PK11LIST
646export PSSUSPEND
647export PYTHON
648export RANDFILE
649export RESOLVE
650export RNDC
651export RRCHECKER
652export SAMPLEUPDATE
653export SIGNER
654export SUBDIRS
655export TMPDIR
656