diff --git a/Sanity/caching-forwarder-dnssec/main.fmf b/Sanity/caching-forwarder-dnssec/main.fmf new file mode 100644 index 0000000..d84d444 --- /dev/null +++ b/Sanity/caching-forwarder-dnssec/main.fmf @@ -0,0 +1,11 @@ +summary: Configure bind as caching and validating forwarder +test: ./test.sh +framework: beakerlib +description: | + Configures named as a caching forwarder. Keep dnssec-validation enabled and try to + workaround for buggy nameservers provided from the network. +require+: + - bind +recommend+: + - bind-utils + - sed diff --git a/Sanity/caching-forwarder-dnssec/test.sh b/Sanity/caching-forwarder-dnssec/test.sh new file mode 100755 index 0000000..0db5e87 --- /dev/null +++ b/Sanity/caching-forwarder-dnssec/test.sh @@ -0,0 +1,211 @@ +#!/bin/bash +# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +. /usr/share/beakerlib/beakerlib.sh || exit 1 + +get_servers_conf() { + local RESOLV_CONF=${1:-/etc/resolv.conf} + # contains extra space at the end! + awk '$1 == "nameserver" { printf "%s ", $2 }' "$RESOLV_CONF" +} + +get_servers() { + # avoids systemd-resolved breaking dnssec + 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) + for CONF in "${CONF_FILES[@]}" + do + # intentionally do not prefer local resolv.conf, because systemd-resolved is breaking it often + if [ -r "$CONF" ]; then + SERVERS=$(get_servers_conf "$CONF") + if [ -n "$SERVERS" ]; then + echo "$SERVERS" + break + fi + fi + done +} + +dnssec_servers() { + local SERVERS="$(get_servers)" + if [ -z "$SERVERS" ]; then + rlFail "No nameservers obtained!" + return 1 + fi + local DELV=$(type -p delv 2>/dev/null) + local DIG=$(type -p dig 2>/dev/null) + local FAILED_SERVERS="" + local SECURE_SERVERS="" + + for NS in ${SERVERS}; do + if [ -n "$DELV" ]; then + + if $DELV @$NS | grep -q '^; fully validated'; then + SECURE_SERVERS+="$NS " + else + FAILED_SERVERS+="$NS " + fi + elif [ -n "$DIG" ]; then + + if $DIG +noall +answer +dnssec @$NS | grep -qw RRSIG; then + SECURE_SERVERS+="$NS " + else + FAILED_SERVERS+="$NS " + fi + fi + done + if [ -z "$SECURE_SERVERS" ]; then + rlFail "No servers from ${SERVERS} support DNSSEC! Fix the infrastructure!" + return 1 + fi + + echo "$SECURE_SERVERS" + if [ -n "$FAILED_SERVERS" ]; then + rlLogWarning "Servers not supporting DNSSEC: ${FAILED_SERVERS}" + fi +} + +make_forwarders() +{ + echo 'forwarders {'; + for NS in ${@} + do + printf "\t%s;\n" $NS + done + echo '}; # autogenerated' +} + +# Prints formatted used options in bind config +print_options() +{ + named-checkconf -px "$@" | sed -ne '/^options {/,/^};/ p' +} + +# Check whether option in $1 is used in options {} global block +has_option() +{ + local OPTION="$1" + print_options | 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/" +} + +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/" +} + +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 "SECURE_SERVERS=\"$(dnssec_servers)\"" || rlFail "No secure servers obtained" + rlFileBackup --missing-ok /etc/named/forwarders.conf + rlFileBackup /etc/named.conf + rlRun "make_forwarders ${SECURE_SERVERS} > /etc/named/forwarders.conf" 0 + if ! has_option forwarders; then + rlLog "Inserting include to generated forwarders" + rlRun "sed -i -e '/^s*options\s*{/ a include \"/etc/named/forwarders.conf\";' /etc/named.conf" + fi + rlRun "named-checkconf" 0 "Test generated configuration is acccepted" + rlRun "rlServiceStop named" + rlFileBackup --missing-ok /var/named/dynamic/managed-keys.bind{,.jnl} + rlRun "rm -f /var/named/dynamic/managed-keys.bind{,.jnl}" + rlRun "rlServiceStart named" + rlPhaseEnd + + rlPhaseStartTest "Basic test" + buDigSuccessSecure @localhost . DNSKEY + buDigSuccessSecure @localhost + + KEYID=$(buDigKskId @localhost .) + rlRun "rndc secroots" + rlRun "grep \"^./RSASHA256/$KEYID\" /var/named/data/named.secroots" 0 "Check trust anchor is trusted" + rlPhaseEnd + + rlPhaseStartTest "Host tests" + for H in example.{org,com,net} fedoraproject.org isc.org + do + buDigSuccessSecure @localhost $H A + buDigSuccessSecure @localhost $H AAAA + done + for H in {org,com,net} + do + buDigSuccessSecure @localhost $H NS + buDigSuccessSecure @localhost $H DS + done + for H in {a,d,f}.root-servers.net + do + buDigSuccessInsecure @localhost $H A + buDigSuccessInsecure @localhost $H AAAA + done + [ "$DEBUG" = y ] && PS1="test-debug $PS1" $SHELL -i + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "popd" + rlRun "rm -f /etc/named/forwarders.conf" + rlRun "rm -r $tmp" 0 "Remove tmp directory" + rlFileRestore + rlRun "rlServiceRestore named" + rlPhaseEnd +rlJournalEnd