Merge #12 Introduce test checking iterative resolver
This commit is contained in:
commit
0b4c79d740
2 changed files with 402 additions and 0 deletions
31
Sanity/caching-resolver-dnssec/main.fmf
Normal file
31
Sanity/caching-resolver-dnssec/main.fmf
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
summary: Configure bind as caching and validating iterative resolver
|
||||
test: ./test.sh
|
||||
framework: beakerlib
|
||||
description: |
|
||||
Configures named as a caching iterative resolver. Keep dnssec-validation enabled and try to
|
||||
start resolution from root servers hints.
|
||||
|
||||
Test signed zones are validated and include ad bit. Check unsigned zones are
|
||||
missing ad bit in responses. Requires public root-servers.net and other zone nameservers are directly accessible.
|
||||
recommend+:
|
||||
- sed
|
||||
- awk
|
||||
adjust:
|
||||
- recommend+:
|
||||
- bind
|
||||
- bind-utils
|
||||
environment+:
|
||||
PACKAGE: bind
|
||||
when: component is not defined or component == bind
|
||||
- recommend+:
|
||||
- bind9.16
|
||||
- bind9.16-utils
|
||||
environment+:
|
||||
PACKAGE: bind9.16
|
||||
when: component == bind9.16
|
||||
- recommend+:
|
||||
- bind9-next
|
||||
- bind9-next-utils
|
||||
environment+:
|
||||
PACKAGE: bind9-next
|
||||
when: component == bind9-next
|
||||
371
Sanity/caching-resolver-dnssec/test.sh
Executable file
371
Sanity/caching-resolver-dnssec/test.sh
Executable file
|
|
@ -0,0 +1,371 @@
|
|||
#!/bin/bash
|
||||
# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
|
||||
. /usr/share/beakerlib/beakerlib.sh || exit 1
|
||||
|
||||
: ${CLEAN_ANCHORS:=y}
|
||||
: ${NAMED_OPTIONS:=}
|
||||
# How many times to check basic root check
|
||||
: ${BASIC_TRIES:=3}
|
||||
# How many times to check host checks
|
||||
: ${HOSTS_TRIES:=3}
|
||||
# On which host check pass require successful responses?
|
||||
: ${HOSTS_PASSING:=2}
|
||||
# Delay after named service start
|
||||
: ${DELAY_START:=5}
|
||||
# Delay between tests
|
||||
: ${DELAY_TEST:=5}
|
||||
|
||||
bu_FALLBACK_SERVERS="8.8.8.8 8.8.4.4 9.9.9.9"
|
||||
bu_DELV=$(type -p delv 2>/dev/null)
|
||||
bu_DIG=$(type -p dig 2>/dev/null)
|
||||
# Servers which failed DNSSEC-awareness check
|
||||
bu_FAILED_SERVERS=""
|
||||
bu_ROOT_HINTS=/var/named/named.ca
|
||||
|
||||
buGetRootServerAddresses4() {
|
||||
local HINTS="${1:-$bu_ROOT_HINTS}"
|
||||
# a.root-servers.net. 518400 IN A 198.41.0.4
|
||||
# A.ROOT-SERVERS.NET. 3600000 A 198.41.0.4
|
||||
awk -v IGNORECASE=1 -- '$1 ~ /[a-m]\.root-servers\.net\./ && $3 == "A" { print $4 } $3 == "IN" && $4 == "A" { print $5 }' "$HINTS"
|
||||
}
|
||||
|
||||
buGetRootServerAddresses6() {
|
||||
local HINTS="${1:-$bu_ROOT_HINTS}"
|
||||
awk -v IGNORECASE=1 -- '$1 ~ /[a-m]\.root-servers\.net\./ && $3 == "AAAA" { print $4 } $3 == "IN" && $4 == "AAAA" { print $5 }' "$HINTS"
|
||||
}
|
||||
|
||||
# Get list of nameservers from resolv.conf file on standard output
|
||||
buGetServersConf() {
|
||||
local RESOLV_CONF=${1:-/etc/resolv.conf}
|
||||
awk '$1 == "nameserver" { printf "%s%s", DL, $2; DL=" " }' "$RESOLV_CONF"
|
||||
}
|
||||
|
||||
# Get list of resolv-conf (like) files, which might contain useful DNS servers
|
||||
# Ordered in preference, tries to avoid DNSSEC-unaware servers
|
||||
buGetCandidateResolvConf() {
|
||||
local -a CONF_FILES=()
|
||||
systemctl is-active --quiet NetworkManager && CONF_FILES+=("/run/NetworkManager/no-stub-resolv.conf")
|
||||
systemctl is-active --quiet systemd-resolved && CONF_FILES+=("/run/systemd/resolve/resolv.conf")
|
||||
CONF_FILES+=("/etc/resolv.conf")
|
||||
echo "${CONF_FILES[@]}"
|
||||
}
|
||||
|
||||
# Print list of nameservers addresses, space separated.
|
||||
# No check on them is done.
|
||||
buGetNameservers() {
|
||||
# avoids systemd-resolved breaking dnssec, prefer communication with remote servers directly
|
||||
for CONF in $(buGetCandidateResolvConf)
|
||||
do
|
||||
local SERVERS
|
||||
# intentionally do not prefer local resolv.conf, because systemd-resolved is breaking it often
|
||||
if [ -r "$CONF" ] && SERVERS=$(buGetServersConf "$CONF") && [ -n "$SERVERS" ]; then
|
||||
echo "$SERVERS"
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Test server IP addresses give as parameters to find those, who
|
||||
# are security-aware.
|
||||
# Param1: space separated IP addresses of DNS servers
|
||||
buCheckSecureNameservers() {
|
||||
local SERVERS="$1"
|
||||
bu_SECURE_SERVERS=""
|
||||
|
||||
if [ -z "$bu_DELV" ] && [ -z "$bu_DIG" ]; then
|
||||
rlFail "Both delv and dig from bind-utils are missing!"
|
||||
return 1
|
||||
fi
|
||||
for NS in ${SERVERS}; do
|
||||
# use tcp to fail faster on ipv6 global route not available
|
||||
if [ -n "$bu_DELV" ]; then
|
||||
if $bu_DELV +tcp @$NS | grep -q '^; fully validated'; then
|
||||
bu_SECURE_SERVERS+="$NS "
|
||||
else
|
||||
bu_FAILED_SERVERS+="$NS "
|
||||
fi
|
||||
elif [ -n "$bu_DIG" ]; then
|
||||
|
||||
if $bu_DIG +tcp +noall +answer +dnssec @$NS | grep -qw RRSIG; then
|
||||
bu_SECURE_SERVERS+="$NS "
|
||||
else
|
||||
bu_FAILED_SERVERS+="$NS "
|
||||
fi
|
||||
fi
|
||||
done
|
||||
[ -n "$bu_SECURE_SERVERS" ]
|
||||
}
|
||||
|
||||
# Try to find DNSSEC capable network provided forwarders.
|
||||
# If that fails try to verify $bu_FALLBACK_SERVERS works and use them.
|
||||
# If no working server is found, call rlDie to stop the test.
|
||||
# Outputs found servers into bu_SECURE_SERVERS and bu_FAILED_SERVERS
|
||||
# variables
|
||||
buGetSecureNameservers() {
|
||||
bu_FAILED_SERVERS=""
|
||||
local SERVERS=""
|
||||
|
||||
# avoids systemd-resolved breaking dnssec, prefer communication with remote servers directly
|
||||
for CONF in $(buGetCandidateResolvConf)
|
||||
do
|
||||
# intentionally do not prefer local resolv.conf, because systemd-resolved is breaking it often
|
||||
if [ -r "$CONF" ] && SERVERS=$(buGetServersConf "$CONF") && [ -n "$SERVERS" ]; then
|
||||
rlLogDebug "Checking servers from $CONF..."
|
||||
buCheckSecureNameservers "$SERVERS" && break
|
||||
fi
|
||||
done
|
||||
if [ -z "${bu_SECURE_SERVERS}${bu_FAILED_SERVERS}" ]; then
|
||||
rlDie "No nameservers obtained, tried files: $(buGetCandidateResolvConf)"
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$bu_SECURE_SERVERS" ]; then
|
||||
rlLog "Found resolv files..."
|
||||
for CONF in $(buGetCandidateResolvConf)
|
||||
do
|
||||
rlRun -l "cat $CONF"
|
||||
done
|
||||
rlLog "Versions of network provided nameservers..."
|
||||
for NS in ${SERVERS}
|
||||
do
|
||||
rlRun -l "dig @$NS txt ch version.bind" 0-255
|
||||
done
|
||||
if [ -n "$bu_FALLBACK_SERVERS" ]; then
|
||||
# If we have access to public DNS servers, use them instead. They are known to support DNSSEC.
|
||||
buCheckSecureNameservers "$bu_FALLBACK_SERVERS"
|
||||
rlLogWarning "No network provided servers (${SERVERS}) support DNSSEC! Fix the infrastructure!"
|
||||
SERVERS+=" $bu_FALLBACK_SERVERS"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$bu_SECURE_SERVERS" ]; then
|
||||
rlDie "No servers from ${SERVERS} support DNSSEC! Fix the infrastructure!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -n "$bu_FAILED_SERVERS" ]; then
|
||||
rlLogWarning "Servers not supporting DNSSEC: ${bu_FAILED_SERVERS}"
|
||||
fi
|
||||
rlLogInfo "Found security-aware servers: $bu_SECURE_SERVERS"
|
||||
}
|
||||
|
||||
# Create bind forwarder configuration from servers entered as parameters
|
||||
buMakeForwarders()
|
||||
{
|
||||
echo 'forwarders {';
|
||||
for NS in "$@"
|
||||
do
|
||||
printf "\t%s;\n" $NS
|
||||
done
|
||||
echo '}; # autogenerated'
|
||||
}
|
||||
|
||||
# Prints formatted used options in bind config
|
||||
buPrintOptions()
|
||||
{
|
||||
named-checkconf -px "$@" | sed -ne '/^options {/,/^};/ p'
|
||||
}
|
||||
|
||||
# Check whether option in $1 is used in options {} global block
|
||||
buHasOption()
|
||||
{
|
||||
local OPTION="$1"
|
||||
buPrintOptions | grep -qw "^\s*${OPTION}"
|
||||
}
|
||||
|
||||
# Filter dig to print only desired section
|
||||
# Input is dig output
|
||||
buDigGetSection()
|
||||
{
|
||||
local SECTION="${1:-ANSWER}"
|
||||
sed -ne "/^;; ${SECTION} SECTION:/,/^$/ p" | grep -vE '^(\s*$|;.*$)'
|
||||
}
|
||||
|
||||
# Filter dig to print only desired value from double comment lines
|
||||
# Input is dig output
|
||||
buDigGetField()
|
||||
{
|
||||
local FIELD="$1"
|
||||
grep "^;;.*\s${FIELD}:" | sed -e "s/.*\s${FIELD}:\s*\([^;,]*\)\([;,].*\|$\)/\1/"
|
||||
}
|
||||
|
||||
# Filter dig input to print pseudosection contents only
|
||||
buDigPseudosection()
|
||||
{
|
||||
sed -ne "/^;; OPT PSEUDOSECTION:/,/^;; QUESTION SECTION/ p" | grep -vE '^;; (OPT PSEUDO|QUESTION )SECTION:'
|
||||
}
|
||||
|
||||
# Filter dig to print only desired value from single comment lines
|
||||
# Useful for pseudosection
|
||||
# Input is dig output
|
||||
buDigGetField1()
|
||||
{
|
||||
local FIELD="$1"
|
||||
grep "^;\s\(.*\s\)\?${FIELD}:" | sed -e "s/.*\s${FIELD}:\s*\([^;,]*\)\([;,].*\|$\)/\1/"
|
||||
}
|
||||
|
||||
# just receive any response, no matter what status
|
||||
buDig()
|
||||
{
|
||||
rlRun -s "dig $*"
|
||||
}
|
||||
|
||||
# Ensure reply has noerror status
|
||||
buDigSuccess()
|
||||
{
|
||||
rlRun -s "dig $*"
|
||||
local STATUS="$(buDigGetField status < $rlRun_LOG)"
|
||||
rlAssertEquals "Check result was positive" "$STATUS" NOERROR
|
||||
}
|
||||
|
||||
# Ensure reply is signed and verified
|
||||
buDigSuccessSecure()
|
||||
{
|
||||
rlRun -s "dig $*"
|
||||
local STATUS="$(buDigGetField status < $rlRun_LOG)"
|
||||
rlAssertEquals "Check dig result was positive" "$STATUS" NOERROR
|
||||
local FLAGS="$(buDigGetField flags < $rlRun_LOG)"
|
||||
rlRun "echo $FLAGS | grep -w ad" 0 "Check dig result has AD bit set"
|
||||
}
|
||||
|
||||
# Ensure reply is positive but insecure
|
||||
buDigSuccessInsecure()
|
||||
{
|
||||
rlRun -s "dig $*"
|
||||
local STATUS="$(buDigGetField status < $rlRun_LOG)"
|
||||
rlAssertEquals "Check dig result was positive" "$STATUS" NOERROR
|
||||
local FLAGS="$(buDigGetField flags < $rlRun_LOG)"
|
||||
rlRun "echo $FLAGS | grep -vw ad" 0 "Check dig result has AD bit unset"
|
||||
}
|
||||
|
||||
# Extract KSK key id from dig
|
||||
buDigKskId()
|
||||
{
|
||||
dig +nocrypto +short -t dnskey "$@" | awk '$1 == 257 { sub("]", "", $7); print $7 }'
|
||||
}
|
||||
|
||||
|
||||
rlJournalStart
|
||||
rlPhaseStartSetup
|
||||
rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory"
|
||||
rlRun "pushd $tmp"
|
||||
rlRun "set -o pipefail"
|
||||
rlRun "named -V"
|
||||
rlRun "dig -v"
|
||||
rlFileBackup /etc/named.conf
|
||||
rlRun "named-checkconf" 0 "Test generated configuration is acccepted"
|
||||
rlRun "rlServiceStop named"
|
||||
if [ "$CLEAN_ANCHORS" = y ]; then
|
||||
rlFileBackup --clean /var/named/dynamic/managed-keys.bind{,.jnl}
|
||||
rlRun "rm -f /var/named/dynamic/managed-keys.bind{,.jnl}"
|
||||
fi
|
||||
rlAssertExists $bu_ROOT_HINTS
|
||||
# use buCheckSecureNameservers
|
||||
rlRun "HINTS4=\"$(buGetRootServerAddresses4 $bu_ROOT_HINTS)\""
|
||||
rlRun "HINTS6=\"$(buGetRootServerAddresses6 $bu_ROOT_HINTS)\""
|
||||
rlRun "HINTS4_NUM=$(echo \"$HINTS4\" | wc -l)"
|
||||
rlRun "HINTS6_NUM=$(echo \"$HINTS6\" | wc -l)"
|
||||
HINTS4_WORKS=''
|
||||
HINTS6_WORKS=''
|
||||
if [ "$NAMED_OPTIONS" = auto ]; then
|
||||
# TODO: is this complication desirable?
|
||||
if [ "$HINTS4_NUM" -gt 0 ] && buCheckSecureNameservers "$HINTS4"; then
|
||||
SECURE_SERVERS4="$bu_SECURE_SERVERS"
|
||||
FAILED_SERVERS4="$bu_FAILED_SERVERS"
|
||||
HINTS4_WORKS=y
|
||||
fi
|
||||
if [ "$HINTS6_NUM" -gt 0 ] && buCheckSecureNameservers "$HINTS6"; then
|
||||
SECURE_SERVERS6="$bu_SECURE_SERVERS"
|
||||
FAILED_SERVERS6="$bu_FAILED_SERVERS"
|
||||
[ -n "$FAILED_SERVERS4" ] && bu_FAILED_SERVERS+=" $FAILED_SERVERS4"
|
||||
[ -n "$SECURE_SERVERS4" ] && bu_SECURE_SERVERS+=" $SECURE_SERVERS4"
|
||||
HINTS6_WORKS=y
|
||||
fi
|
||||
if [ "$HINTS4_WORKS" = y ] && [ -z "$HINTS6_WORKS" ]; then
|
||||
rlRun "NAMED_OPTIONS='-4'"
|
||||
elif [ "$HINTS6_WORKS" = y ] && [ -z "$HINTS4_WORKS" ]; then
|
||||
rlRun "NAMED_OPTIONS='-6'"
|
||||
else
|
||||
rlRun "NAMED_OPTIONS=''"
|
||||
fi
|
||||
else
|
||||
rlRun "buCheckSecureNameservers \"$HINTS4 $HINTS6\"" && HINTS4_WORKS=y && HINTS4_WORKS=y
|
||||
fi
|
||||
if [ -n "$NAMED_OPTIONS" ]; then
|
||||
rlFileBackup /etc/sysconfig/named
|
||||
echo "OPTIONS+=\"$NAMED_OPTIONS\"" >> /etc/sysconfig/named
|
||||
rlRun "grep OPTIONS /etc/sysconfig/named"
|
||||
fi
|
||||
SKIP_TEST=''
|
||||
if [ -z "$HINTS6_WORKS" ] && [ -z "$HINTS4_WORKS" ]
|
||||
then
|
||||
SKIP_TEST=y
|
||||
rlLogWarning "No root-servers reachable, skipping the test."
|
||||
fi
|
||||
WORKING_NUM=0
|
||||
for NSIP in ${bu_SECURE_SERVERS}; do
|
||||
WORKING_NUM=$((WORKING_NUM+1))
|
||||
done
|
||||
rlAssertGreater "Check we have at least some working root servers" "$WORKING_NUM" 5
|
||||
rlLog "Working root-servers: $bu_SECURE_SERVERS"
|
||||
[ -n "$bu_FAILED_SERVERS" ] && rlLogWarning "Failed root-servers: $bu_FAILED_SERVERS"
|
||||
|
||||
HAS_MANAGED_KEYS=''
|
||||
rndc -h 2>&1 | grep -q 'managed-keys status' && HAS_MANAGED_KEYS='y'
|
||||
rlPhaseEnd
|
||||
|
||||
if [ "$SKIP_TEST" != y ]; then
|
||||
|
||||
for I in {1..3}; do
|
||||
rlPhaseStartTest "Basic test #$I"
|
||||
rlRun "rlServiceStart named"
|
||||
# give it chance to warm up
|
||||
sleep ${DELAY_START}
|
||||
buDigSuccessSecure @localhost . DNSKEY
|
||||
buDigSuccessSecure @localhost
|
||||
|
||||
KEYID=$(buDigKskId @localhost .)
|
||||
rlAssertNotEquals "Check keyId is not empty." "$KEYID" ""
|
||||
rlAssertGreater "Check keyId is non-zero" "$KEYID" 0
|
||||
rlRun "rndc secroots"
|
||||
rlRun "grep \"^./RSASHA256/$KEYID\" /var/named/data/named.secroots" 0 "Check trust anchor is trusted"
|
||||
[ "$HAS_MANAGED_KEYS" = y ] && rlRun "rndc managed-keys status"
|
||||
rlPhaseEnd
|
||||
sleep ${DELAY_TEST}
|
||||
done
|
||||
|
||||
DIG_SEC=buDig
|
||||
DIG_INSEC=buDig
|
||||
|
||||
for I in $(seq $HOSTS_TRIES); do
|
||||
rlPhaseStartTest "Host tests #$I"
|
||||
if [ "$I" = "$HOSTS_PASSING" ]; then
|
||||
DIG_SEC=buDigSuccessSecure
|
||||
DIG_INSEC=buDigSuccessInsecure
|
||||
fi
|
||||
for H in example.{org,com,net} fedoraproject.org isc.org
|
||||
do
|
||||
$DIG_SEC @localhost $H A
|
||||
$DIG_SEC @localhost $H AAAA
|
||||
done
|
||||
for H in {org,com,net}
|
||||
do
|
||||
$DIG_SEC @localhost $H NS
|
||||
$DIG_SEC @localhost $H DS
|
||||
done
|
||||
for H in {a,d,f}.root-servers.net ipv4only.arpa
|
||||
do
|
||||
$DIG_INSEC @localhost $H A
|
||||
$DIG_INSEC @localhost $H AAAA
|
||||
done
|
||||
rlPhaseEnd
|
||||
sleep ${DELAY_TEST}
|
||||
done
|
||||
fi
|
||||
|
||||
rlPhaseStartCleanup
|
||||
[ "$DEBUG" = y ] && PS1="test-debug $PS1" $SHELL -i
|
||||
rlRun "popd"
|
||||
rlRun "rm -r $tmp" 0 "Remove tmp directory"
|
||||
rlFileRestore
|
||||
rlRun "rlServiceRestore named"
|
||||
rlPhaseEnd
|
||||
rlJournalEnd
|
||||
Loading…
Add table
Add a link
Reference in a new issue