1# Copyright (C) Internet Systems Consortium, Inc. ("ISC") 2# 3# This Source Code Form is subject to the terms of the Mozilla Public 4# License, v. 2.0. If a copy of the MPL was not distributed with this 5# file, you can obtain one at https://mozilla.org/MPL/2.0/. 6# 7# See the COPYRIGHT file distributed with this work for additional 8# information regarding copyright ownership. 9 10SYSTEMTESTTOP=.. 11. $SYSTEMTESTTOP/conf.sh 12 13DIGOPTS="-p ${PORT}" 14RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s" 15SEND="$PERL $SYSTEMTESTTOP/send.pl 10.53.0.4 ${EXTRAPORT1}" 16status=0 17n=0 18 19n=`expr $n + 1` 20echo_i "checking short DNAME from authoritative ($n)" 21ret=0 22$DIG $DIGOPTS a.short-dname.example @10.53.0.2 a > dig.out.ns2.short || ret=1 23grep "status: NOERROR" dig.out.ns2.short > /dev/null || ret=1 24if [ $ret != 0 ]; then echo_i "failed"; fi 25status=`expr $status + $ret` 26 27n=`expr $n + 1` 28echo_i "checking short DNAME from recursive ($n)" 29ret=0 30$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 31$DIG $DIGOPTS a.short-dname.example @10.53.0.7 a > dig.out.ns4.short || ret=1 32grep "status: NOERROR" dig.out.ns4.short > /dev/null || ret=1 33if [ $ret != 0 ]; then echo_i "failed"; fi 34status=`expr $status + $ret` 35 36n=`expr $n + 1` 37echo_i "checking long DNAME from authoritative ($n)" 38ret=0 39$DIG $DIGOPTS a.long-dname.example @10.53.0.2 a > dig.out.ns2.long || ret=1 40grep "status: NOERROR" dig.out.ns2.long > /dev/null || ret=1 41if [ $ret != 0 ]; then echo_i "failed"; fi 42status=`expr $status + $ret` 43 44n=`expr $n + 1` 45echo_i "checking long DNAME from recursive ($n)" 46ret=0 47$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 48$DIG $DIGOPTS a.long-dname.example @10.53.0.7 a > dig.out.ns4.long || ret=1 49grep "status: NOERROR" dig.out.ns4.long > /dev/null || ret=1 50if [ $ret != 0 ]; then echo_i "failed"; fi 51status=`expr $status + $ret` 52 53n=`expr $n + 1` 54echo_i "checking (too) long DNAME from authoritative ($n)" 55ret=0 56$DIG $DIGOPTS 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.2 a > dig.out.ns2.toolong || ret=1 57grep "status: YXDOMAIN" dig.out.ns2.toolong > /dev/null || ret=1 58if [ $ret != 0 ]; then echo_i "failed"; fi 59status=`expr $status + $ret` 60 61n=`expr $n + 1` 62echo_i "checking (too) long DNAME from recursive with cached DNAME ($n)" 63ret=0 64$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 65$DIG $DIGOPTS 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.7 a > dig.out.ns4.cachedtoolong || ret=1 66grep "status: YXDOMAIN" dig.out.ns4.cachedtoolong > /dev/null || ret=1 67grep '^long-dname\.example\..*DNAME.*long' dig.out.ns4.cachedtoolong > /dev/null || ret=1 68if [ $ret != 0 ]; then echo_i "failed"; fi 69status=`expr $status + $ret` 70 71n=`expr $n + 1` 72echo_i "checking (too) long DNAME from recursive without cached DNAME ($n)" 73ret=0 74$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 75$DIG $DIGOPTS 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglong.toolong-dname.example @10.53.0.7 a > dig.out.ns4.uncachedtoolong || ret=1 76grep "status: YXDOMAIN" dig.out.ns4.uncachedtoolong > /dev/null || ret=1 77grep '^toolong-dname\.example\..*DNAME.*long' dig.out.ns4.uncachedtoolong > /dev/null || ret=1 78if [ $ret != 0 ]; then echo_i "failed"; fi 79status=`expr $status + $ret` 80 81find_records() { 82 owner_name="$1" 83 rr_type="$2" 84 file="$3" 85 awk '$1 == "'"$owner_name"'" && $4 == "'"$rr_type"'" { print }' < "$file" 86} 87 88count_records() { 89 owner_name="$1" 90 rr_type="$2" 91 file="$3" 92 find_records "$owner_name" "$rr_type" "$file" | wc -l 93} 94 95exactly_one_record_exists_for() { 96 owner_name="$1" 97 rr_type="$2" 98 file="$3" 99 test "$(count_records "$owner_name" "$rr_type" "$file")" -eq 1 100} 101 102no_records_exist_for() { 103 owner_name="$1" 104 rr_type="$2" 105 file="$3" 106 test "$(count_records "$owner_name" "$rr_type" "$file")" -eq 0 107} 108 109ensure_no_ds_in_bitmap() { 110 owner_name="$1" 111 rr_type="$2" 112 file="$3" 113 case "$rr_type" in 114 NSEC) start_index=6 ;; 115 NSEC3) start_index=10 ;; 116 *) exit 1 ;; 117 esac 118 find_records "$owner_name" "$rr_type" "$file" | awk '{ for (i='"$start_index"'; i<=NF; i++) if ($i == "DS") exit 1 }' 119} 120 121n=`expr $n + 1` 122echo_i "checking secure delegation prepared using CNAME chaining ($n)" 123ret=0 124# QNAME exists, so the AUTHORITY section should only contain an NS RRset and a 125# DS RRset. 126$DIG $DIGOPTS @10.53.0.2 cname.wildcard-secure.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 127# Ensure that the AUTHORITY section contains the expected NS and DS RRsets. 128exactly_one_record_exists_for "delegation.wildcard-secure.example." NS dig.out.2.$n || ret=1 129exactly_one_record_exists_for "delegation.wildcard-secure.example." DS dig.out.2.$n || ret=1 130if [ $ret != 0 ]; then echo_i "failed"; fi 131status=`expr $status + $ret` 132 133n=`expr $n + 1` 134echo_i "checking secure delegation prepared using wildcard expansion + CNAME chaining ($n)" 135ret=0 136# QNAME does not exist, so the AUTHORITY section should contain an NS RRset, an 137# NSEC record proving nonexistence of QNAME, and a DS RRset at the zone cut. 138$DIG $DIGOPTS @10.53.0.2 a-nonexistent-name.wildcard-secure.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 139# Ensure that the AUTHORITY section contains the expected NS and DS RRsets. 140exactly_one_record_exists_for "delegation.wildcard-secure.example." NS dig.out.2.$n || ret=1 141exactly_one_record_exists_for "delegation.wildcard-secure.example." DS dig.out.2.$n || ret=1 142# Check NSEC records in the AUTHORITY section. 143no_records_exist_for "wildcard-secure.example." NSEC dig.out.2.$n || ret=1 144exactly_one_record_exists_for "*.wildcard-secure.example." NSEC dig.out.2.$n || ret=1 145no_records_exist_for "cname.wildcard-secure.example." NSEC dig.out.2.$n || ret=1 146no_records_exist_for "delegation.wildcard-secure.example." NSEC dig.out.2.$n || ret=1 147if [ $ret != 0 ]; then echo_i "failed"; fi 148status=`expr $status + $ret` 149 150n=`expr $n + 1` 151echo_i "checking insecure delegation prepared using CNAME chaining, NSEC ($n)" 152ret=0 153# QNAME exists, so the AUTHORITY section should only contain an NS RRset and a 154# single NSEC record proving nonexistence of a DS RRset at the zone cut. 155$DIG $DIGOPTS @10.53.0.2 cname.wildcard-nsec.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 156# Ensure that the AUTHORITY section contains an NS RRset without an associated 157# DS RRset. 158exactly_one_record_exists_for "delegation.wildcard-nsec.example." NS dig.out.2.$n || ret=1 159no_records_exist_for "delegation.wildcard-nsec.example." DS dig.out.2.$n || ret=1 160# Check NSEC records in the AUTHORITY section. 161no_records_exist_for "wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 162no_records_exist_for "*.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 163no_records_exist_for "cname.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 164exactly_one_record_exists_for "delegation.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 165# Ensure the NSEC record for the zone cut does not have the DS bit set in the 166# type bit map. 167ensure_no_ds_in_bitmap "delegation.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 168if [ $ret != 0 ]; then echo_i "failed"; fi 169status=`expr $status + $ret` 170 171n=`expr $n + 1` 172echo_i "checking insecure delegation prepared using wildcard expansion + CNAME chaining, NSEC, QNAME #1 ($n)" 173ret=0 174# QNAME does not exist, so the AUTHORITY section should contain an NS RRset and 175# NSEC records proving nonexistence of both QNAME and a DS RRset at the zone 176# cut. In this test case, these two NSEC records are different. 177$DIG $DIGOPTS @10.53.0.2 a-nonexistent-name.wildcard-nsec.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 178# Ensure that the AUTHORITY section contains an NS RRset without an associated 179# DS RRset. 180exactly_one_record_exists_for "delegation.wildcard-nsec.example." NS dig.out.2.$n || ret=1 181no_records_exist_for "delegation.wildcard-nsec.example." DS dig.out.2.$n || ret=1 182# Check NSEC records in the AUTHORITY section. 183no_records_exist_for "wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 184exactly_one_record_exists_for "*.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 185no_records_exist_for "cname.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 186exactly_one_record_exists_for "delegation.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 187# Ensure the NSEC record for the zone cut does not have the DS bit set in the 188# type bit map. 189ensure_no_ds_in_bitmap "delegation.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 190if [ $ret != 0 ]; then echo_i "failed"; fi 191status=`expr $status + $ret` 192 193n=`expr $n + 1` 194echo_i "checking insecure delegation prepared using wildcard expansion + CNAME chaining, NSEC, QNAME #2 ($n)" 195ret=0 196# QNAME does not exist, so the AUTHORITY section should contain an NS RRset and 197# NSEC records proving nonexistence of both QNAME and a DS RRset at the zone 198# cut. In this test case, the same NSEC record proves nonexistence of both the 199# QNAME and the DS RRset at the zone cut. 200$DIG $DIGOPTS @10.53.0.2 z-nonexistent-name.wildcard-nsec.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 201# Ensure that the AUTHORITY section contains an NS RRset without an associated 202# DS RRset. 203exactly_one_record_exists_for "delegation.wildcard-nsec.example." NS dig.out.2.$n || ret=1 204no_records_exist_for "delegation.wildcard-nsec.example." DS dig.out.2.$n || ret=1 205# Check NSEC records in the AUTHORITY section. 206no_records_exist_for "wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 207no_records_exist_for "*.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 208no_records_exist_for "cname.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 209exactly_one_record_exists_for "delegation.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 210# Ensure the NSEC record for the zone cut does not have the DS bit set in the 211# type bit map. 212ensure_no_ds_in_bitmap "delegation.wildcard-nsec.example." NSEC dig.out.2.$n || ret=1 213if [ $ret != 0 ]; then echo_i "failed"; fi 214status=`expr $status + $ret` 215 216# Relevant NSEC3 hashes: 217# 218# - existing names: 219# 220# $ nsec3hash - 1 0 wildcard-nsec3.example. 221# 38IVP9CN0LBISO6H3V5REQCKMTHLI5AN (salt=-, hash=1, iterations=0) 222# $ nsec3hash - 1 0 cname.wildcard-nsec3.example. 223# 3DV6GNNVR0O8LA4DC4CHL2JTVNHT8Q1D (salt=-, hash=1, iterations=0) 224# $ nsec3hash - 1 0 delegation.wildcard-nsec3.example. 225# AVKOGGGVJHFSLQA68TILKFKJ94AV4MNC (salt=-, hash=1, iterations=0) 226# $ nsec3hash - 1 0 *.wildcard-nsec3.example. 227# Q64D8L8HLSB3L98S59PM8OSSMI7SMQA2 (salt=-, hash=1, iterations=0) 228# 229# - nonexistent names: 230# 231# $ nsec3hash - 1 0 a-nonexistent-name.wildcard-nsec3.example. 232# PST9IH6M0DG3M139CO3G12NUP4ER88SH (salt=-, hash=1, iterations=0) 233# $ nsec3hash - 1 0 z-nonexistent-name.wildcard-nsec3.example. 234# SG2DEHEAOGCKP7FTNQAUVC3I3TIPJH0J (salt=-, hash=1, iterations=0) 235 236n=`expr $n + 1` 237echo_i "checking insecure delegation prepared using CNAME chaining, NSEC3 ($n)" 238ret=0 239# QNAME exists, so the AUTHORITY section should only contain an NS RRset and a 240# single NSEC3 record proving nonexistence of a DS RRset at the zone cut. 241$DIG $DIGOPTS @10.53.0.2 cname.wildcard-nsec3.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 242# Ensure that the AUTHORITY section contains an NS RRset without an associated 243# DS RRset. 244exactly_one_record_exists_for "delegation.wildcard-nsec3.example." NS dig.out.2.$n || ret=1 245no_records_exist_for "delegation.wildcard-nsec3.example." DS dig.out.2.$n || ret=1 246# Check NSEC3 records in the AUTHORITY section. 247no_records_exist_for "38IVP9CN0LBISO6H3V5REQCKMTHLI5AN.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 248no_records_exist_for "3DV6GNNVR0O8LA4DC4CHL2JTVNHT8Q1D.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 249exactly_one_record_exists_for "AVKOGGGVJHFSLQA68TILKFKJ94AV4MNC.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 250no_records_exist_for "Q64D8L8HLSB3L98S59PM8OSSMI7SMQA2.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 251# Ensure the NSEC3 record matching the zone cut does not have the DS bit set in 252# the type bit map. 253ensure_no_ds_in_bitmap "AVKOGGGVJHFSLQA68TILKFKJ94AV4MNC.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 254if [ $ret != 0 ]; then echo_i "failed"; fi 255status=`expr $status + $ret` 256 257n=`expr $n + 1` 258echo_i "checking insecure delegation prepared using wildcard expansion + CNAME chaining, NSEC3, QNAME #1 ($n)" 259ret=0 260# QNAME does not exist, so the AUTHORITY section should contain an NS RRset and 261# NSEC3 records proving nonexistence of both QNAME and a DS RRset at the zone 262# cut. In this test case, these two NSEC3 records are different. 263$DIG $DIGOPTS @10.53.0.2 z-nonexistent-name.wildcard-nsec3.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 264# Ensure that the AUTHORITY section contains an NS RRset without an associated 265# DS RRset. 266exactly_one_record_exists_for "delegation.wildcard-nsec3.example." NS dig.out.2.$n || ret=1 267no_records_exist_for "delegation.wildcard-nsec3.example." DS dig.out.2.$n || ret=1 268# Check NSEC3 records in the AUTHORITY section. 269no_records_exist_for "38IVP9CN0LBISO6H3V5REQCKMTHLI5AN.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 270no_records_exist_for "3DV6GNNVR0O8LA4DC4CHL2JTVNHT8Q1D.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 271exactly_one_record_exists_for "AVKOGGGVJHFSLQA68TILKFKJ94AV4MNC.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 272exactly_one_record_exists_for "Q64D8L8HLSB3L98S59PM8OSSMI7SMQA2.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 273# Ensure the NSEC3 record matching the zone cut does not have the DS bit set in 274# the type bit map. 275ensure_no_ds_in_bitmap "AVKOGGGVJHFSLQA68TILKFKJ94AV4MNC.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 276if [ $ret != 0 ]; then echo_i "failed"; fi 277status=`expr $status + $ret` 278 279n=`expr $n + 1` 280echo_i "checking insecure delegation prepared using wildcard expansion + CNAME chaining, NSEC3, QNAME #2 ($n)" 281ret=0 282# QNAME does not exist, so the AUTHORITY section should contain an NS RRset and 283# NSEC3 records proving nonexistence of both QNAME and a DS RRset at the zone 284# cut. In this test case, the same NSEC3 record proves nonexistence of both the 285# QNAME and the DS RRset at the zone cut. 286$DIG $DIGOPTS @10.53.0.2 a-nonexistent-name.wildcard-nsec3.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 287# Ensure that the AUTHORITY section contains an NS RRset without an associated 288# DS RRset. 289exactly_one_record_exists_for "delegation.wildcard-nsec3.example." NS dig.out.2.$n || ret=1 290no_records_exist_for "delegation.wildcard-nsec3.example." DS dig.out.2.$n || ret=1 291# Check NSEC3 records in the AUTHORITY section. 292no_records_exist_for "38IVP9CN0LBISO6H3V5REQCKMTHLI5AN.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 293no_records_exist_for "3DV6GNNVR0O8LA4DC4CHL2JTVNHT8Q1D.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 294exactly_one_record_exists_for "AVKOGGGVJHFSLQA68TILKFKJ94AV4MNC.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 295no_records_exist_for "Q64D8L8HLSB3L98S59PM8OSSMI7SMQA2.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 296# Ensure the NSEC3 record matching the zone cut does not have the DS bit set in 297# the type bit map. 298ensure_no_ds_in_bitmap "AVKOGGGVJHFSLQA68TILKFKJ94AV4MNC.wildcard-nsec3.example." NSEC3 dig.out.2.$n || ret=1 299if [ $ret != 0 ]; then echo_i "failed"; fi 300status=`expr $status + $ret` 301 302# Relevant NSEC3 hashes: 303# 304# - existing names with corresponding NSEC3 records: 305# 306# $ nsec3hash - 1 0 *.wildcard-nsec3-optout.example. 307# 2JGSPT59VJ7R9SQB5B9P6HPM5JBATOOO (salt=-, hash=1, iterations=0) 308# $ nsec3hash - 1 0 cname.wildcard-nsec3-optout.example. 309# OKRFKC9SS1O60E8U2980UD62MUSMKGUG (salt=-, hash=1, iterations=0) 310# $ nsec3hash - 1 0 wildcard-nsec3-optout.example. 311# SS5M1RUBSGMANEQ1VLRDDEC6SOAT7HNI (salt=-, hash=1, iterations=0) 312# 313# - existing name with no corresponding NSEC3 record due to opt-out: 314# 315# $ nsec3hash - 1 0 delegation.wildcard-nsec3-optout.example. 316# UFP8PVECFTD57HU5PUD2HE0ES37QEOAP (salt=-, hash=1, iterations=0) 317# 318# - nonexistent names: 319# 320# $ nsec3hash - 1 0 b-nonexistent-name.wildcard-nsec3-optout.example. 321# 3J38JE2OU0O7B4CE2ADMBBKJ5HT994S5 (salt=-, hash=1, iterations=0) 322# $ nsec3hash - 1 0 z-nonexistent-name.wildcard-nsec3-optout.example. 323# V7OTS4791T9SU0HKVL93EVNAJ9JH2CH3 (salt=-, hash=1, iterations=0) 324 325n=`expr $n + 1` 326echo_i "checking insecure delegation prepared using CNAME chaining, NSEC3 with opt-out ($n)" 327ret=0 328# QNAME exists, so the AUTHORITY section should only contain an NS RRset and a 329# single NSEC3 record proving nonexistence of a DS RRset at the zone cut. 330$DIG $DIGOPTS @10.53.0.2 cname.wildcard-nsec3-optout.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 331# Ensure that the AUTHORITY section contains an NS RRset without an associated 332# DS RRset. 333exactly_one_record_exists_for "delegation.wildcard-nsec3-optout.example." NS dig.out.2.$n || ret=1 334no_records_exist_for "delegation.wildcard-nsec3-optout.example." DS dig.out.2.$n || ret=1 335# Check NSEC3 records in the AUTHORITY section. 336no_records_exist_for "2JGSPT59VJ7R9SQB5B9P6HPM5JBATOOO.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 337no_records_exist_for "OKRFKC9SS1O60E8U2980UD62MUSMKGUG.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 338exactly_one_record_exists_for "SS5M1RUBSGMANEQ1VLRDDEC6SOAT7HNI.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 339# Ensure the NSEC3 record covering the zone cut does not have the DS bit set in 340# the type bit map. 341ensure_no_ds_in_bitmap "SS5M1RUBSGMANEQ1VLRDDEC6SOAT7HNI.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 342if [ $ret != 0 ]; then echo_i "failed"; fi 343status=`expr $status + $ret` 344 345n=`expr $n + 1` 346echo_i "checking insecure delegation prepared using wildcard expansion + CNAME chaining, NSEC3 with opt-out, QNAME #1 ($n)" 347ret=0 348# QNAME does not exist, so the AUTHORITY section should contain an NS RRset and 349# NSEC3 records proving nonexistence of both QNAME and a DS RRset at the zone 350# cut. In this test case, these two NSEC3 records are different. 351$DIG $DIGOPTS @10.53.0.2 b-nonexistent-name.wildcard-nsec3-optout.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 352# Ensure that the AUTHORITY section contains an NS RRset without an associated 353# DS RRset. 354exactly_one_record_exists_for "delegation.wildcard-nsec3-optout.example." NS dig.out.2.$n || ret=1 355no_records_exist_for "delegation.wildcard-nsec3-optout.example." DS dig.out.2.$n || ret=1 356# Check NSEC3 records in the AUTHORITY section. 357exactly_one_record_exists_for "2JGSPT59VJ7R9SQB5B9P6HPM5JBATOOO.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 358no_records_exist_for "OKRFKC9SS1O60E8U2980UD62MUSMKGUG.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 359exactly_one_record_exists_for "SS5M1RUBSGMANEQ1VLRDDEC6SOAT7HNI.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 360# Ensure the NSEC3 record covering the zone cut does not have the DS bit set in 361# the type bit map. 362ensure_no_ds_in_bitmap "SS5M1RUBSGMANEQ1VLRDDEC6SOAT7HNI.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 363if [ $ret != 0 ]; then echo_i "failed"; fi 364status=`expr $status + $ret` 365 366n=`expr $n + 1` 367echo_i "checking insecure delegation prepared using wildcard expansion + CNAME chaining, NSEC3 with opt-out, QNAME #2 ($n)" 368ret=0 369# QNAME does not exist, so the AUTHORITY section should contain an NS RRset and 370# NSEC3 records proving nonexistence of both QNAME and a DS RRset at the zone 371# cut. In this test case, the same NSEC3 record proves nonexistence of both the 372# QNAME and the DS RRset at the zone cut. 373$DIG $DIGOPTS @10.53.0.2 z-nonexistent-name.wildcard-nsec3-optout.example A +norec +dnssec > dig.out.2.$n 2>&1 || ret=1 374# Ensure that the AUTHORITY section contains an NS RRset without an associated 375# DS RRset. 376exactly_one_record_exists_for "delegation.wildcard-nsec3-optout.example." NS dig.out.2.$n || ret=1 377no_records_exist_for "delegation.wildcard-nsec3-optout.example." DS dig.out.2.$n || ret=1 378# Check NSEC3 records in the AUTHORITY section. 379no_records_exist_for "2JGSPT59VJ7R9SQB5B9P6HPM5JBATOOO.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 380no_records_exist_for "OKRFKC9SS1O60E8U2980UD62MUSMKGUG.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 381exactly_one_record_exists_for "SS5M1RUBSGMANEQ1VLRDDEC6SOAT7HNI.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 382# Ensure the NSEC3 record covering the zone cut does not have the DS bit set in 383# the type bit map. 384ensure_no_ds_in_bitmap "SS5M1RUBSGMANEQ1VLRDDEC6SOAT7HNI.wildcard-nsec3-optout.example." NSEC3 dig.out.2.$n || ret=1 385if [ $ret != 0 ]; then echo_i "failed"; fi 386status=`expr $status + $ret` 387 388n=`expr $n + 1` 389echo_i "checking CNAME to DNAME from authoritative ($n)" 390ret=0 391$DIG $DIGOPTS cname.example @10.53.0.2 a > dig.out.ns2.cname 392grep "status: NOERROR" dig.out.ns2.cname > /dev/null || ret=1 393if [ $ret != 0 ]; then echo_i "failed"; fi 394status=`expr $status + $ret` 395 396n=`expr $n + 1` 397echo_i "checking CNAME to DNAME from recursive" 398ret=0 399$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 400$DIG $DIGOPTS cname.example @10.53.0.7 a > dig.out.ns4.cname 401grep "status: NOERROR" dig.out.ns4.cname > /dev/null || ret=1 402grep '^cname.example.' dig.out.ns4.cname > /dev/null || ret=1 403grep '^cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 404grep '^a.cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 405grep '^a.target.example.' dig.out.ns4.cname > /dev/null || ret=1 406if [ $ret != 0 ]; then echo_i "failed"; fi 407status=`expr $status + $ret` 408 409n=`expr $n + 1` 410echo_i "checking DNAME is returned with synthesized CNAME before DNAME ($n)" 411ret=0 412$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 413$DIG $DIGOPTS @10.53.0.7 name.synth-then-dname.example.broken A > dig.out.test$n 414grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 415grep '^name.synth-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1 416grep '^synth-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1 417if [ $ret != 0 ]; then echo_i "failed"; fi 418status=`expr $status + $ret` 419 420n=`expr $n + 1` 421echo_i "checking DNAME is returned with CNAME to synthesized CNAME before DNAME ($n)" 422ret=0 423$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 424$DIG $DIGOPTS @10.53.0.7 cname-to-synth2-then-dname.example.broken A > dig.out.test$n 425grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 426grep '^cname-to-synth2-then-dname\.example\.broken\..*CNAME.*name\.synth2-then-dname\.example\.broken.$' dig.out.test$n > /dev/null || ret=1 427grep '^name\.synth2-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1 428grep '^synth2-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1 429if [ $ret != 0 ]; then echo_i "failed"; fi 430status=`expr $status + $ret` 431 432n=`expr $n + 1` 433echo_i "checking CNAME loops are detected ($n)" 434ret=0 435$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 436$DIG $DIGOPTS @10.53.0.7 loop.example > dig.out.test$n 437grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 438grep "ANSWER: 17" dig.out.test$n > /dev/null || ret=1 439if [ $ret != 0 ]; then echo_i "failed"; fi 440status=`expr $status + $ret` 441 442n=`expr $n + 1` 443echo_i "checking CNAME to external delegated zones is handled ($n)" 444ret=0 445$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 446$DIG $DIGOPTS @10.53.0.7 a.example > dig.out.test$n 447grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 448grep "ANSWER: 2" dig.out.test$n > /dev/null || ret=1 449if [ $ret != 0 ]; then echo_i "failed"; fi 450status=`expr $status + $ret` 451 452n=`expr $n + 1` 453echo_i "checking CNAME to internal delegated zones is handled ($n)" 454ret=0 455$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 456$DIG $DIGOPTS @10.53.0.7 b.example > dig.out.test$n 457grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 458grep "ANSWER: 2" dig.out.test$n > /dev/null || ret=1 459if [ $ret != 0 ]; then echo_i "failed"; fi 460status=`expr $status + $ret` 461 462n=`expr $n + 1` 463echo_i "checking CNAME to signed external delegation is handled ($n)" 464ret=0 465$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 466$DIG $DIGOPTS @10.53.0.7 c.example > dig.out.$n 467grep "status: NOERROR" dig.out.$n > /dev/null || ret=1 468if [ $ret != 0 ]; then echo_i "failed"; fi 469status=`expr $status + $ret` 470 471n=`expr $n + 1` 472echo_i "checking CNAME to signed internal delegation is handled ($n)" 473ret=0 474$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 475$DIG $DIGOPTS @10.53.0.7 d.example > dig.out.$n 476grep "status: NOERROR" dig.out.$n > /dev/null || ret=1 477if [ $ret != 0 ]; then echo_i "failed"; fi 478status=`expr $status + $ret` 479 480n=`expr $n + 1` 481echo_i "checking CNAME chains in various orders ($n)" 482ret=0 483$RNDCCMD 10.53.0.7 null --- start test$n - step 1 --- 2>&1 | sed 's/^/ns7 /' | cat_i 484echo "cname,cname,cname|1,2,3,4,s1,s2,s3,s4" | $SEND 485$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.1.$n 2>&1 486grep 'status: NOERROR' dig.out.1.$n > /dev/null 2>&1 || ret=1 487grep 'ANSWER: 2' dig.out.1.$n > /dev/null 2>&1 || ret=1 488$RNDCCMD 10.53.0.7 null --- start test$n - step 2 --- 2>&1 | sed 's/^/ns7 /' | cat_i 489$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 490echo "cname,cname,cname|1,1,2,2,3,4,s4,s3,s1" | $SEND 491$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.2.$n 2>&1 492grep 'status: NOERROR' dig.out.2.$n > /dev/null 2>&1 || ret=1 493grep 'ANSWER: 2' dig.out.2.$n > /dev/null 2>&1 || ret=1 494$RNDCCMD 10.53.0.7 null --- start test$n - step 3 --- 2>&1 | sed 's/^/ns7 /' | cat_i 495$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 496echo "cname,cname,cname|2,1,3,4,s3,s1,s2,s4" | $SEND 497$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.3.$n 2>&1 498grep 'status: NOERROR' dig.out.3.$n > /dev/null 2>&1 || ret=1 499grep 'ANSWER: 2' dig.out.3.$n > /dev/null 2>&1 || ret=1 500$RNDCCMD 10.53.0.7 null --- start test$n - step 4 --- 2>&1 | sed 's/^/ns7 /' | cat_i 501$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 502echo "cname,cname,cname|4,3,2,1,s4,s3,s2,s1" | $SEND 503$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.4.$n 2>&1 504grep 'status: NOERROR' dig.out.4.$n > /dev/null 2>&1 || ret=1 505grep 'ANSWER: 2' dig.out.4.$n > /dev/null 2>&1 || ret=1 506echo "cname,cname,cname|4,3,2,1,s4,s3,s2,s1" | $SEND 507$RNDCCMD 10.53.0.7 null --- start test$n - step 5 --- 2>&1 | sed 's/^/ns7 /' | cat_i 508$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 509$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.5.$n 2>&1 510grep 'status: NOERROR' dig.out.5.$n > /dev/null 2>&1 || ret=1 511grep 'ANSWER: 2' dig.out.5.$n > /dev/null 2>&1 || ret=1 512$RNDCCMD 10.53.0.7 null --- start test$n - step 6 --- 2>&1 | sed 's/^/ns7 /' | cat_i 513$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 514echo "cname,cname,cname|4,3,3,3,s1,s1,1,3,4" | $SEND 515$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.6.$n 2>&1 516grep 'status: NOERROR' dig.out.6.$n > /dev/null 2>&1 || ret=1 517grep 'ANSWER: 2' dig.out.6.$n > /dev/null 2>&1 || ret=1 518if [ $ret != 0 ]; then echo_i "failed"; fi 519status=`expr $status + $ret` 520 521n=`expr $n + 1` 522echo_i "checking that only the initial CNAME is cached ($n)" 523ret=0 524$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 525echo "cname,cname,cname|1,2,3,4,s1,s2,s3,s4" | $SEND 526$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 527$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.1.$n 2>&1 528sleep 1 529$DIG $DIGOPTS +noall +answer @10.53.0.7 cname1.domain.nil > dig.out.2.$n 2>&1 530ttl=`awk '{print $2}' dig.out.2.$n` 531[ "$ttl" -eq 86400 ] || ret=1 532if [ $ret != 0 ]; then echo_i "failed"; fi 533status=`expr $status + $ret` 534 535n=`expr $n + 1` 536echo_i "checking DNAME chains in various orders ($n)" 537ret=0 538$RNDCCMD 10.53.0.7 null --- start test$n - step 1 --- 2>&1 | sed 's/^/ns7 /' | cat_i 539$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 540echo "dname,dname|5,4,3,2,1,s5,s4,s3,s2,s1" | $SEND 541$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.1.$n 2>&1 542grep 'status: NOERROR' dig.out.1.$n > /dev/null 2>&1 || ret=1 543grep 'ANSWER: 3' dig.out.1.$n > /dev/null 2>&1 || ret=1 544$RNDCCMD 10.53.0.7 null --- start test$n - step 2 --- 2>&1 | sed 's/^/ns7 /' | cat_i 545$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 546echo "dname,dname|5,4,3,2,1,s5,s4,s3,s2,s1" | $SEND 547$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.2.$n 2>&1 548grep 'status: NOERROR' dig.out.2.$n > /dev/null 2>&1 || ret=1 549grep 'ANSWER: 3' dig.out.2.$n > /dev/null 2>&1 || ret=1 550$RNDCCMD 10.53.0.7 null --- start test$n - step 3 --- 2>&1 | sed 's/^/ns7 /' | cat_i 551$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 552echo "dname,dname|2,3,s1,s2,s3,s4,1" | $SEND 553$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.3.$n 2>&1 554grep 'status: NOERROR' dig.out.3.$n > /dev/null 2>&1 || ret=1 555grep 'ANSWER: 3' dig.out.3.$n > /dev/null 2>&1 || ret=1 556$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 557if [ $ret != 0 ]; then echo_i "failed"; fi 558status=`expr $status + $ret` 559 560n=`expr $n + 1` 561echo_i "checking external CNAME/DNAME chains in various orders ($n)" 562ret=0 563$RNDCCMD 10.53.0.7 null --- start test$n - step 1 --- 2>&1 | sed 's/^/ns7 /' | cat_i 564echo "xname,dname|1,2,3,4,s1,s2,s3,s4" | $SEND 565$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.1.$n 2>&1 566grep 'status: NOERROR' dig.out.1.$n > /dev/null 2>&1 || ret=1 567grep 'ANSWER: 2' dig.out.1.$n > /dev/null 2>&1 || ret=1 568$RNDCCMD 10.53.0.7 null --- start test$n - step 2 --- 2>&1 | sed 's/^/ns7 /' | cat_i 569$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 570echo "xname,dname|s2,2,s1,1,4,s4,3" | $SEND 571$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.2.$n 2>&1 572grep 'status: NOERROR' dig.out.2.$n > /dev/null 2>&1 || ret=1 573grep 'ANSWER: 2' dig.out.2.$n > /dev/null 2>&1 || ret=1 574$RNDCCMD 10.53.0.7 null --- start test$n - step 3 --- 2>&1 | sed 's/^/ns7 /' | cat_i 575$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 576echo "xname,dname|s2,2,2,2" | $SEND 577$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.3.$n 2>&1 578grep 'status: SERVFAIL' dig.out.3.$n > /dev/null 2>&1 || ret=1 579$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 580if [ $ret != 0 ]; then echo_i "failed"; fi 581status=`expr $status + $ret` 582 583n=`expr $n + 1` 584echo_i "checking explicit DNAME query ($n)" 585ret=0 586$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 587$DIG $DIGOPTS @10.53.0.7 dname short-dname.example > dig.out.7.$n 2>&1 588grep 'status: NOERROR' dig.out.7.$n > /dev/null 2>&1 || ret=1 589if [ $ret != 0 ]; then echo_i "failed"; fi 590status=`expr $status + $ret` 591 592n=`expr $n + 1` 593echo_i "checking DNAME via ANY query ($n)" 594ret=0 595$RNDCCMD 10.53.0.7 null --- start test$n --- 2>&1 | sed 's/^/ns7 /' | cat_i 596$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i 597$DIG $DIGOPTS @10.53.0.7 any short-dname.example > dig.out.7.$n 2>&1 598grep 'status: NOERROR' dig.out.7.$n > /dev/null 2>&1 || ret=1 599if [ $ret != 0 ]; then echo_i "failed"; fi 600status=`expr $status + $ret` 601 602# Regression test for CVE-2021-25215 (authoritative server). 603n=`expr $n + 1` 604echo_i "checking DNAME resolution via itself (authoritative) ($n)" 605ret=0 606$DIG $DIGOPTS @10.53.0.2 DNAME self.domain0.self.domain0.nil. > dig.out.2.$n 2>&1 607grep 'status: NOERROR' dig.out.2.$n > /dev/null 2>&1 || ret=1 608if [ $ret != 0 ]; then echo_i "failed"; fi 609status=`expr $status + $ret` 610 611# Regression test for CVE-2021-25215 (recursive resolver). 612n=`expr $n + 1` 613echo_i "checking DNAME resolution via itself (recursive) ($n)" 614ret=0 615$DIG $DIGOPTS @10.53.0.7 DNAME self.example.self.example.dname. > dig.out.7.$n 2>&1 616grep 'status: NOERROR' dig.out.7.$n > /dev/null 2>&1 || ret=1 617if [ $ret != 0 ]; then echo_i "failed"; fi 618status=`expr $status + $ret` 619 620echo_i "exit status: $status" 621[ $status -eq 0 ] || exit 1 622