bind9/bin/tests/system/unknown/tests.sh
Ondřej Surý 967776d94d
Validate DNS message CLASS early in request processing
Reject requests with unsupported or misused CLASS values before
further processing.  Only IN, CH, HS, RESERVED0 (for DNS Cookies),
ANY (for TKEY negotiation), and NONE (for DNS UPDATE) are accepted;
all other classes return NOTIMP.  Misuse of NONE or ANY outside
their allowed contexts returns FORMERR.

This adds further protection against bugs of the same general class
as YWH-PGM40640-70 and YWH-PGM40640-73.
2026-05-07 13:32:15 +02:00

241 lines
6.4 KiB
Bash

#!/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.
set -e
. ../conf.sh
status=0
n=0
DIGOPTS="-p ${PORT}"
dig_cmd() {
# shellcheck disable=SC2086
"$DIG" $DIGOPTS "$@" | grep -v '^;'
}
dig_full() {
# shellcheck disable=SC2086
"$DIG" $DIGOPTS "$@"
}
n=$((n + 1))
echo_i "querying for various representations of an IN A record ($n)"
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do
ret=0
dig_cmd +short @10.53.0.1 a$i.example a in >dig.out.$i.test$n
echo 10.0.0.1 | diff - dig.out.$i.test$n || ret=1
if [ $ret != 0 ]; then
echo_i "#$i failed"
fi
status=$((status + ret))
done
n=$((n + 1))
echo_i "querying for various representations of an IN TXT record ($n)"
for i in 1 2 3 4 5 6 7; do
ret=0
dig_cmd +short @10.53.0.1 txt$i.example txt in >dig.out.$i.test$n
echo '"hello"' | diff - dig.out.$i.test$n || ret=1
if [ $ret != 0 ]; then
echo_i "#$i failed"
fi
status=$((status + ret))
done
n=$((n + 1))
echo_i "querying for various representations of an IN TYPE123 record ($n)"
for i in 1 2 3; do
ret=0
dig_cmd +short @10.53.0.1 unk$i.example type123 in >dig.out.$i.test$n
echo '\# 1 00' | diff - dig.out.$i.test$n || ret=1
if [ $ret != 0 ]; then
echo_i "#$i failed"
fi
status=$((status + ret))
done
n=$((n + 1))
echo_i "querying for NULL record ($n)"
ret=0
dig_cmd +short @10.53.0.1 null.example null in >dig.out.test$n
echo '\# 1 00' | diff - dig.out.test$n || ret=1
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
n=$((n + 1))
echo_i "querying for empty NULL record ($n)"
ret=0
dig_cmd +short @10.53.0.1 empty.example null in >dig.out.test$n
echo '\# 0' | diff - dig.out.test$n || ret=1
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
n=$((n + 1))
echo_i "querying for various representations of a CLASS10 TYPE1 record ($n)"
for i in 1 2; do
ret=0
dig_full @10.53.0.1 a$i.example a class10 >dig.out.$i.test$n
grep -q "NOTIMP" dig.out.$i.test$n || ret=1
if [ $ret != 0 ]; then
echo_i "#$i failed"
fi
status=$((status + ret))
done
n=$((n + 1))
echo_i "querying for various representations of a CLASS10 TXT record ($n)"
for i in 1 2 3 4; do
ret=0
dig_full @10.53.0.1 txt$i.example txt class10 >dig.out.$i.test$n
grep -q "NOTIMP" dig.out.$i.test$n || ret=1
if [ $ret != 0 ]; then
echo_i "#$i failed"
fi
status=$((status + ret))
done
n=$((n + 1))
echo_i "querying for various representations of a CLASS10 TYPE123 record ($n)"
for i in 1 2; do
ret=0
dig_full @10.53.0.1 unk$i.example type123 class10 >dig.out.$i.test$n
grep -q "NOTIMP" dig.out.$i.test$n || ret=1
if [ $ret != 0 ]; then
echo_i "#$i failed"
fi
status=$((status + ret))
done
n=$((n + 1))
echo_i "querying for SOAs of zone that should have failed to load ($n)"
for i in 1 2 3 4; do
ret=0
$DIG $DIGOPTS @10.53.0.1 broken$i. soa in >dig.out.$i.test$n || ret=1
grep "SERVFAIL" dig.out.$i.test$n >/dev/null || ret=1
if [ $ret != 0 ]; then
echo_i "#$i failed"
fi
status=$((status + ret))
done
n=$((n + 1))
echo_i "checking large unknown record loading on primary ($n)"
for try in 0 1 2 3 4 5 6 7 8 9; do
ret=0
dig_cmd @10.53.0.1 +tcp +short large.example TYPE45234 >dig.out.$i.test$n
diff -s large.out dig.out.$i.test$n >/dev/null || {
ret=1
echo_i "diff failed"
}
[ "$ret" -eq 0 ] && break
sleep 1
done
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
n=$((n + 1))
echo_i "checking large unknown record loading on secondary ($n)"
for try in 0 1 2 3 4 5 6 7 8 9; do
ret=0
dig_cmd @10.53.0.2 +tcp +short large.example TYPE45234 >dig.out.$i.test$n
diff -s large.out dig.out.$i.test$n >/dev/null || {
ret=1
echo_i "diff failed"
}
[ "$ret" -eq 0 ] && break
sleep 1
done
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "stop and restart secondary"
stop_server ns2
start_server --noclean --restart --port ${PORT} ns2
# server may be answering queries before zones are loaded,
# so retry a few times if this query fails
n=$((n + 1))
echo_i "checking large unknown record loading on secondary ($n)"
for try in 0 1 2 3 4 5 6 7 8 9; do
ret=0
dig_cmd @10.53.0.2 +tcp +short large.example TYPE45234 >dig.out.$i.test$n
diff -s large.out dig.out.$i.test$n >/dev/null || {
ret=1
echo_i "diff failed"
}
[ "$ret" -eq 0 ] && break
sleep 1
done
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
n=$((n + 1))
echo_i "checking large unknown record loading on inline secondary ($n)"
ret=0
dig_cmd @10.53.0.3 +tcp +short large.example TYPE45234 >dig.out.test$n
diff large.out dig.out.test$n >/dev/null || {
ret=1
echo_i "diff failed"
}
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "stop and restart inline secondary"
stop_server ns3
start_server --noclean --restart --port ${PORT} ns3
# server may be answering queries before zones are loaded,
# so retry a few times if this query fails
n=$((n + 1))
echo_i "checking large unknown record loading on inline secondary ($n)"
for try in 0 1 2 3 4 5 6 7 8 9; do
ret=0
dig_cmd @10.53.0.3 +tcp +short large.example TYPE45234 >dig.out.$i.test$n
diff large.out dig.out.$i.test$n >/dev/null || {
ret=1
echo_i "diff failed"
}
[ "$ret" -eq 0 ] && break
sleep 1
done
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
n=$((n + 1))
echo_i "check that '"'"\\#"'"' is not treated as the unknown escape sequence ($n)"
ret=0
dig_cmd @10.53.0.1 +tcp +short txt8.example txt >dig.out.test$n
echo '"#" "2" "0145"' | diff - dig.out.test$n || ret=1
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
n=$((n + 1))
echo_i "check that 'TXT \# text' is not treated as the unknown escape sequence ($n)"
ret=0
dig_cmd @10.53.0.1 +tcp +short txt9.example txt >dig.out.test$n
echo '"#" "text"' | diff - dig.out.test$n || ret=1
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
n=$((n + 1))
echo_i "check that 'TYPE353 \# cat' produces 'not a valid number' ($n)"
ret=0
$CHECKZONE nan.bad zones/nan.bad >check.out 2>&1 && ret=1
grep "not a valid number" check.out >/dev/null || ret=1
[ $ret = 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1