Version in base suite: 9.20.26-1~deb13u1 Base version: bind9_9.20.26-1~deb13u1 Target version: bind9_9.20.29-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/b/bind9/bind9_9.20.26-1~deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/b/bind9/bind9_9.20.29-1~deb13u1.dsc /srv/release.debian.org/tmp/VqkGLzeUi9/bind9-9.20.29/bin/tests/system/checkconf/bad-embedded-null-00.conf |binary /srv/release.debian.org/tmp/VqkGLzeUi9/bind9-9.20.29/bin/tests/system/checkconf/bad-embedded-null-01.conf |binary /srv/release.debian.org/tmp/VqkGLzeUi9/bind9-9.20.29/bin/tests/system/checkconf/good-embedded-null-00.conf |binary bind9-9.20.29/ChangeLog | 3 bind9-9.20.29/Makefile.in | 1 bind9-9.20.29/NEWS | 3 bind9-9.20.29/bin/Makefile.in | 1 bind9-9.20.29/bin/check/Makefile.in | 1 bind9-9.20.29/bin/confgen/Makefile.in | 1 bind9-9.20.29/bin/confgen/keygen.c | 28 bind9-9.20.29/bin/confgen/keygen.h | 3 bind9-9.20.29/bin/confgen/rndc-confgen.c | 17 bind9-9.20.29/bin/confgen/rndc-confgen.rst | 6 bind9-9.20.29/bin/confgen/tsig-keygen.c | 11 bind9-9.20.29/bin/delv/Makefile.in | 1 bind9-9.20.29/bin/dig/Makefile.in | 1 bind9-9.20.29/bin/dig/dig.c | 55 bind9-9.20.29/bin/dig/dighost.c | 28 bind9-9.20.29/bin/dig/nslookup.c | 10 bind9-9.20.29/bin/dnssec/Makefile.in | 1 bind9-9.20.29/bin/dnssec/dnssec-ksr.c | 1 bind9-9.20.29/bin/dnssec/dnssec-signzone.c | 78 bind9-9.20.29/bin/dnssec/dnssec-verify.c | 5 bind9-9.20.29/bin/dnssec/dnssectool.c | 15 bind9-9.20.29/bin/named/Makefile.am | 1 bind9-9.20.29/bin/named/Makefile.in | 10 bind9-9.20.29/bin/named/config.c | 11 bind9-9.20.29/bin/named/geoip.c | 3 bind9-9.20.29/bin/named/include/named/tkeyconf.h | 4 bind9-9.20.29/bin/named/main.c | 15 bind9-9.20.29/bin/named/server.c | 42 bind9-9.20.29/bin/named/tkeyconf.c | 32 bind9-9.20.29/bin/nsupdate/Makefile.in | 1 bind9-9.20.29/bin/plugins/Makefile.in | 1 bind9-9.20.29/bin/rndc/Makefile.in | 1 bind9-9.20.29/bin/tests/Makefile.in | 1 bind9-9.20.29/bin/tests/system/COOKBOOK.md | 41 bind9-9.20.29/bin/tests/system/Makefile.am | 15 bind9-9.20.29/bin/tests/system/Makefile.in | 121 bind9-9.20.29/bin/tests/system/README.md | 14 bind9-9.20.29/bin/tests/system/_common/options-dual.conf.j2 | 3 bind9-9.20.29/bin/tests/system/_common/options.conf.j2 | 3 bind9-9.20.29/bin/tests/system/_common/options/listen-dual.conf.j2 | 2 bind9-9.20.29/bin/tests/system/_common/options/listen.conf.j2 | 2 bind9-9.20.29/bin/tests/system/_common/options/server.conf.j2 | 2 bind9-9.20.29/bin/tests/system/_common/options/sources-dual.conf.j2 | 2 bind9-9.20.29/bin/tests/system/_common/options/sources-v6.conf.j2 | 3 bind9-9.20.29/bin/tests/system/_common/options/sources.conf.j2 | 3 bind9-9.20.29/bin/tests/system/_common/zones.conf.j2 | 2 bind9-9.20.29/bin/tests/system/_common/zones/ns.partial.db.j2 | 5 bind9-9.20.29/bin/tests/system/_common/zones/soa.partial.db.j2 | 4 bind9-9.20.29/bin/tests/system/acl/ns2/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/acl/ns2/named2.conf.j2 | 23 bind9-9.20.29/bin/tests/system/acl/ns2/named3.conf.j2 | 25 bind9-9.20.29/bin/tests/system/acl/ns2/named4.conf.j2 | 27 bind9-9.20.29/bin/tests/system/acl/ns2/named5.conf.j2 | 25 bind9-9.20.29/bin/tests/system/acl/ns3/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/acl/ns4/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/additional/ns1/https.db | 46 bind9-9.20.29/bin/tests/system/additional/ns1/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/additional/ns1/named2.conf.j2 | 18 bind9-9.20.29/bin/tests/system/additional/ns1/named3.conf.j2 | 18 bind9-9.20.29/bin/tests/system/additional/ns1/named4.conf.j2 | 18 bind9-9.20.29/bin/tests/system/additional/ns2/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/additional/ns2/root.db | 1 bind9-9.20.29/bin/tests/system/additional/ns3/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/additional/tests_https_alias.py | 101 bind9-9.20.29/bin/tests/system/addzone/ns1/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/addzone/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/addzone/ns2/named2.conf.j2 | 25 bind9-9.20.29/bin/tests/system/addzone/ns2/named3.conf.j2 | 29 bind9-9.20.29/bin/tests/system/addzone/ns3/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/addzone/ns3/named2.conf.j2 | 11 bind9-9.20.29/bin/tests/system/allow_query/ns1/named.conf.j2 | 7 bind9-9.20.29/bin/tests/system/allow_query/ns2/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named02.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named03.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named04.conf.j2 | 12 bind9-9.20.29/bin/tests/system/allow_query/ns2/named05.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named06.conf.j2 | 12 bind9-9.20.29/bin/tests/system/allow_query/ns2/named07.conf.j2 | 12 bind9-9.20.29/bin/tests/system/allow_query/ns2/named08.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named09.conf.j2 | 12 bind9-9.20.29/bin/tests/system/allow_query/ns2/named10.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named11.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named12.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named21.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named22.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named23.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named24.conf.j2 | 12 bind9-9.20.29/bin/tests/system/allow_query/ns2/named25.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named26.conf.j2 | 12 bind9-9.20.29/bin/tests/system/allow_query/ns2/named27.conf.j2 | 12 bind9-9.20.29/bin/tests/system/allow_query/ns2/named28.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named29.conf.j2 | 12 bind9-9.20.29/bin/tests/system/allow_query/ns2/named30.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named31.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named32.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named33.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named34.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named40.conf.j2 | 16 bind9-9.20.29/bin/tests/system/allow_query/ns2/named53.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named54.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named55.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named56.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns2/named57.conf.j2 | 10 bind9-9.20.29/bin/tests/system/allow_query/ns3/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/allow_query/ns3/named2.conf.j2 | 22 bind9-9.20.29/bin/tests/system/allow_query/ns3/named3.conf.j2 | 23 bind9-9.20.29/bin/tests/system/allow_query/ns3/named4.conf.j2 | 23 bind9-9.20.29/bin/tests/system/allow_query_on/ns1/named.conf.j2 | 64 bind9-9.20.29/bin/tests/system/allow_query_on/ns1/redirect.db | 12 bind9-9.20.29/bin/tests/system/allow_query_on/ns1/root.db | 11 bind9-9.20.29/bin/tests/system/allow_query_on/tests_allow_query_on.py | 34 bind9-9.20.29/bin/tests/system/auth/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/auth/ns2/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/authsock.pl | 94 bind9-9.20.29/bin/tests/system/autosign/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/autosign/ns2/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/autosign/ns3/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/autosign/ns4/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/autosign/ns5/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/bailiwick/ns4/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/builtin/ns1/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/builtin/ns2/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/builtin/ns3/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/cacheclean/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/cacheclean/ns2/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/cacheclean/tests.sh | 16 bind9-9.20.29/bin/tests/system/camp/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/camp/ns2/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/camp/ns3/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/camp/ns9/hints.db | 13 bind9-9.20.29/bin/tests/system/camp/ns9/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/cap_glues/ns1/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/cap_glues/ns2/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/cap_glues/ns3/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/cap_glues/ns3/root.hint | 3 bind9-9.20.29/bin/tests/system/case/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/case/ns2/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/catz/ns1/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/catz/ns2/named.conf.j2 | 34 bind9-9.20.29/bin/tests/system/catz/ns2/named7.conf.j2 | 30 bind9-9.20.29/bin/tests/system/catz/ns3/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/catz/ns4/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/cdnxdomain/ns1/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/cdnxdomain/ns2/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/cdnxdomain/tests_cdnxdomain.py | 15 bind9-9.20.29/bin/tests/system/chain/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/chain/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/chain/ns5/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/chain/ns7/named.conf.j2 | 29 bind9-9.20.29/bin/tests/system/chain/ns7/root.hint | 3 bind9-9.20.29/bin/tests/system/chain/prereq.sh | 26 bind9-9.20.29/bin/tests/system/checkconf/bad-catz-zone-primary-dup.conf | 6 bind9-9.20.29/bin/tests/system/checkconf/bad-controls-duplicate.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/bad-empty-endpoints.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/bad-inline-secondary.conf | 16 bind9-9.20.29/bin/tests/system/checkconf/bad-kasp-max-zone-ttl.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/bad-mirror-zonename.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/bad-options-query-source-address-v4-v6.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/bad-parental-agents-def-view2.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-key.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-key2.conf | 10 bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-notfound.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-tls.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/bad-query-source-address-v4-none.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/bad-query-source-address-v6-none.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/bad-random-device.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/bad-rrl-table-size.conf | 14 bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-2.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-3.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-4.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/check-dup-records-fail.conf | 8 bind9-9.20.29/bin/tests/system/checkconf/check-mx-cname-fail.conf | 8 bind9-9.20.29/bin/tests/system/checkconf/check-mx-fail.conf | 8 bind9-9.20.29/bin/tests/system/checkconf/check-names-fail.conf | 8 bind9-9.20.29/bin/tests/system/checkconf/check-root-static-ds.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/check-srv-cname-fail.conf | 8 bind9-9.20.29/bin/tests/system/checkconf/check-wildcard-no.conf | 6 bind9-9.20.29/bin/tests/system/checkconf/check-wildcard.conf | 6 bind9-9.20.29/bin/tests/system/checkconf/deprecated.conf | 32 bind9-9.20.29/bin/tests/system/checkconf/good-dot-doh-tls-nokeycert.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/good-ds-key-1.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/good-ds-key-2.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/good-key-directory.conf | 72 bind9-9.20.29/bin/tests/system/checkconf/good-key-view.conf | 14 bind9-9.20.29/bin/tests/system/checkconf/good-nonempty-trust-anchors.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/good-options-query-source-address-v4-none.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/good-options-query-source-address-v6-none.conf | 2 bind9-9.20.29/bin/tests/system/checkconf/good-quoted-key-names.conf | 17 bind9-9.20.29/bin/tests/system/checkconf/good-remote-servers-cycle.conf | 27 bind9-9.20.29/bin/tests/system/checkconf/good-remote-servers-named.conf | 4 bind9-9.20.29/bin/tests/system/checkconf/warn-chaos-recursion.conf | 12 bind9-9.20.29/bin/tests/system/checkds/CA/CA.cfg | 121 bind9-9.20.29/bin/tests/system/checkds/CA/CA.pem | 29 bind9-9.20.29/bin/tests/system/checkds/CA/README | 2 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.pem | 68 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.pem | 68 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.pem | 64 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.key | 6 bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/index.txt | 9 bind9-9.20.29/bin/tests/system/checkds/CA/index.txt.attr | 1 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52001.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52002.pem | 64 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52003.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52004.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52005.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52006.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52007.pem | 68 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52008.pem | 68 bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52009.pem | 69 bind9-9.20.29/bin/tests/system/checkds/CA/private/CA.key | 39 bind9-9.20.29/bin/tests/system/checkds/CA/serial | 1 bind9-9.20.29/bin/tests/system/checkds/dhparam3072.pem | 11 bind9-9.20.29/bin/tests/system/checkds/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/checkds/ns10/named.conf.j2 | 35 bind9-9.20.29/bin/tests/system/checkds/ns2/named.conf.j2 | 40 bind9-9.20.29/bin/tests/system/checkds/ns2/ns2.db.in | 2 bind9-9.20.29/bin/tests/system/checkds/ns3/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/checkds/ns4/named.conf.j2 | 35 bind9-9.20.29/bin/tests/system/checkds/ns5/named.conf.j2 | 40 bind9-9.20.29/bin/tests/system/checkds/ns5/ns2.db.in | 2 bind9-9.20.29/bin/tests/system/checkds/ns6/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/checkds/ns7/named.conf.j2 | 35 bind9-9.20.29/bin/tests/system/checkds/ns8/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/checkds/ns9/named.conf.j2 | 38 bind9-9.20.29/bin/tests/system/checkds/ns9/setup.sh | 1 bind9-9.20.29/bin/tests/system/checkds/tests_checkds.py | 9 bind9-9.20.29/bin/tests/system/checknames/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/checknames/ns2/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/checknames/ns3/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/checknames/ns4/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/checknames/ns5/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/checkzone/tests.sh | 119 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-afsdb.db | 2 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-brid.db | 17 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-dsync.db | 6 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-hhit.db | 6 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-opengpgkey.db | 20 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-openpgpkey.db | 20 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-smimea.db | 2 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-type66.db | 17 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-type69.db | 6 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-no-leading-zero.db | 5 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-three-digits.db | 5 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-too-short.db | 5 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-trailing-garbage.db | 5 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-no-leading-zero.db | 5 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-three-digits.db | 5 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-too-short.db | 5 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-trailing-garbage.db | 5 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nimloc.db | 10 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsap-empty.db | 4 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsap-odd-nibble.db | 4 bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsec3-length.db | 2 bind9-9.20.29/bin/tests/system/cipher_suites/ns1/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/cipher_suites/ns2/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/cipher_suites/ns3/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/cipher_suites/ns4/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/cipher_suites/ns5/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/cipher_suites/prereq.sh | 21 bind9-9.20.29/bin/tests/system/cipher_suites/tests_cipher_suites.py | 7 bind9-9.20.29/bin/tests/system/class/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/class/ns2/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/class/ns3/named.conf.j2 | 26 bind9-9.20.29/bin/tests/system/cname_dname_negcache/ns1/named.conf.j2 | 12 bind9-9.20.29/bin/tests/system/cname_dname_negcache/ns3/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/cname_recursion/ns1/catalog.db | 16 bind9-9.20.29/bin/tests/system/cname_recursion/ns1/external.db | 18 bind9-9.20.29/bin/tests/system/cname_recursion/ns1/member.db | 16 bind9-9.20.29/bin/tests/system/cname_recursion/ns1/named.conf.j2 | 44 bind9-9.20.29/bin/tests/system/cname_recursion/ns1/root.db | 18 bind9-9.20.29/bin/tests/system/cname_recursion/ns2/added.db | 16 bind9-9.20.29/bin/tests/system/cname_recursion/ns2/internal.db | 16 bind9-9.20.29/bin/tests/system/cname_recursion/ns2/named.conf.j2 | 45 bind9-9.20.29/bin/tests/system/cname_recursion/tests_cname_recursion.py | 87 bind9-9.20.29/bin/tests/system/conf.sh | 4 bind9-9.20.29/bin/tests/system/conftest.py | 34 bind9-9.20.29/bin/tests/system/cookie/ns1/named.conf.j2 | 27 bind9-9.20.29/bin/tests/system/cookie/ns2/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/cookie/ns3/named.conf.j2 | 27 bind9-9.20.29/bin/tests/system/cookie/ns4/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/cookie/ns5/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/cookie/ns6/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/cookie/ns7/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/cookie/ns8/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/cpu/ns1/named.conf.j2 | 8 bind9-9.20.29/bin/tests/system/cpu/prereq.sh | 21 bind9-9.20.29/bin/tests/system/cpu/tests_sh_cpu.py | 9 bind9-9.20.29/bin/tests/system/database/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/dialup/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/dialup/ns2/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/dialup/ns3/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/digdelv/common.py | 56 bind9-9.20.29/bin/tests/system/digdelv/conftest.py | 41 bind9-9.20.29/bin/tests/system/digdelv/ns1/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/digdelv/ns2/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/digdelv/ns3/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/digdelv/prereq.sh | 21 bind9-9.20.29/bin/tests/system/digdelv/tests.sh | 1822 ---------- bind9-9.20.29/bin/tests/system/digdelv/tests_dig.py | 983 +++++ bind9-9.20.29/bin/tests/system/digdelv/tests_digdelv_delv.py | 321 + bind9-9.20.29/bin/tests/system/digdelv/tests_mdig.py | 82 bind9-9.20.29/bin/tests/system/digdelv/tests_others.py | 59 bind9-9.20.29/bin/tests/system/digdelv/tests_sh_digdelv.py | 37 bind9-9.20.29/bin/tests/system/digdelv/yamlget.py | 34 bind9-9.20.29/bin/tests/system/dispatch/ns1/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/dispatch/ns2/named.conf.j2 | 28 bind9-9.20.29/bin/tests/system/dlzexternal/driver/Makefile.in | 1 bind9-9.20.29/bin/tests/system/dlzexternal/ns1/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/dlzexternal/prereq.sh | 21 bind9-9.20.29/bin/tests/system/dlzexternal/tests_sh_dlzexternal.py | 9 bind9-9.20.29/bin/tests/system/dns64/ns1/example.db | 3 bind9-9.20.29/bin/tests/system/dns64/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/dns64/ns1/named2.conf.j2 | 17 bind9-9.20.29/bin/tests/system/dns64/ns1/named3.conf.j2 | 17 bind9-9.20.29/bin/tests/system/dns64/ns2/named.conf.j2 | 26 bind9-9.20.29/bin/tests/system/dns64/ns3/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/dns64/ns4/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/dns64/tests.sh | 23 bind9-9.20.29/bin/tests/system/dns64_dname/ns1/named.conf.j2 | 8 bind9-9.20.29/bin/tests/system/dns64_dname/ns2/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/dns64_dname/ns2/root.hint | 2 bind9-9.20.29/bin/tests/system/dnssec/conf/keystore-keydirectory.conf.j2 | 10 bind9-9.20.29/bin/tests/system/dnssec/kasp.conf.j2 | 8 bind9-9.20.29/bin/tests/system/dnssec/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/dnssec/ns2/example.db.in | 18 bind9-9.20.29/bin/tests/system/dnssec/ns2/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/dnssec/ns2/sign.sh | 41 bind9-9.20.29/bin/tests/system/dnssec/ns3/named.conf.j2 | 38 bind9-9.20.29/bin/tests/system/dnssec/ns3/sign.sh | 44 bind9-9.20.29/bin/tests/system/dnssec/ns4/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/dnssec/ns4/named2.conf.j2 | 23 bind9-9.20.29/bin/tests/system/dnssec/ns4/named3.conf.j2 | 23 bind9-9.20.29/bin/tests/system/dnssec/ns4/named4.conf.j2 | 27 bind9-9.20.29/bin/tests/system/dnssec/ns5/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/dnssec/ns5/named2.conf.j2 | 19 bind9-9.20.29/bin/tests/system/dnssec/ns6/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/dnssec/ns7/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/dnssec/ns8/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/dnssec/ns9/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/dnssec/prereq.sh | 21 bind9-9.20.29/bin/tests/system/dnssec/tests.sh | 32 bind9-9.20.29/bin/tests/system/dnssec/tests_keygen.py | 73 bind9-9.20.29/bin/tests/system/dnssec/tests_sh_dnssec.py | 5 bind9-9.20.29/bin/tests/system/dnssec/tests_validation.py | 41 bind9-9.20.29/bin/tests/system/dnssec_bypass/ns1/named.conf.j2 | 7 bind9-9.20.29/bin/tests/system/dnssec_bypass/ns2/named.conf.j2 | 7 bind9-9.20.29/bin/tests/system/dnssec_bypass/ns3/named.conf.j2 | 7 bind9-9.20.29/bin/tests/system/dnssec_bypass/ns4/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/dnssec_cname_response/ans2/ans.py | 297 - bind9-9.20.29/bin/tests/system/dnssec_cname_response/ns3/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/dnssec_nsec3/ns2/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/dnssec_parent_rrsig/ns2/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/dnssec_py/ans4/ans.py | 9 bind9-9.20.29/bin/tests/system/dnssec_py/ans4/delegationtrap_ans.py | 153 bind9-9.20.29/bin/tests/system/dnssec_py/ans4/noqname_mismatch.py | 154 bind9-9.20.29/bin/tests/system/dnssec_py/ns1/named.conf.j2 | 8 bind9-9.20.29/bin/tests/system/dnssec_py/ns2/named.conf.j2 | 8 bind9-9.20.29/bin/tests/system/dnssec_py/ns3/named.conf.j2 | 8 bind9-9.20.29/bin/tests/system/dnssec_py/ns9/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/dnssec_py/tests_delegationtrap.py | 118 bind9-9.20.29/bin/tests/system/dnssec_py/tests_findnoqname_mismatch.py | 101 bind9-9.20.29/bin/tests/system/dnssec_wildcard/ns2/named.conf.j2 | 26 bind9-9.20.29/bin/tests/system/dnstap/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/dnstap/ns2/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/dnstap/ns3/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/dnstap/ns4/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/dnstap/ns5/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/dnstap/tests_sh_dnstap.py | 1 bind9-9.20.29/bin/tests/system/doth/ns1/named.conf.j2 | 40 bind9-9.20.29/bin/tests/system/doth/ns2/named.conf.j2 | 41 bind9-9.20.29/bin/tests/system/doth/ns3/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/doth/ns4/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/doth/ns5/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/doth/prereq.sh | 26 bind9-9.20.29/bin/tests/system/doth/tests_gnutls.py | 9 bind9-9.20.29/bin/tests/system/doth/tests_malicious.py | 7 bind9-9.20.29/bin/tests/system/doth/tests_sh_doth.py | 10 bind9-9.20.29/bin/tests/system/doth/tests_sslyze.py | 9 bind9-9.20.29/bin/tests/system/dsdigest/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/dsdigest/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/dsdigest/ns3/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/dsdigest/ns4/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/dyndb/driver/Makefile.in | 1 bind9-9.20.29/bin/tests/system/dyndb/ns1/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/dyndb/prereq.sh | 21 bind9-9.20.29/bin/tests/system/dyndb/tests_sh_dyndb.py | 9 bind9-9.20.29/bin/tests/system/ecdsa/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/ecdsa/ns2/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/ecdsa/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/eddsa/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/eddsa/ns2/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/eddsa/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/eddsa/prereq.sh | 20 bind9-9.20.29/bin/tests/system/eddsa/tests_sh_eddsa.py | 9 bind9-9.20.29/bin/tests/system/ednscompliance/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/emptyzones/ns1/named.conf.j2 | 26 bind9-9.20.29/bin/tests/system/enginepkcs11/ns1/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/enginepkcs11/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/enginepkcs11/prereq.sh | 36 bind9-9.20.29/bin/tests/system/enginepkcs11/tests_sh_enginepkcs11.py | 10 bind9-9.20.29/bin/tests/system/expiredglue/ns1/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/expiredglue/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/expiredglue/ns3/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/expiredglue/ns4/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/expiredglue/ns4/root.hint | 3 bind9-9.20.29/bin/tests/system/fetchlimit/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/fetchlimit/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named.conf.j2 | 28 bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named2.conf.j2 | 25 bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named3.conf.j2 | 25 bind9-9.20.29/bin/tests/system/fetchlimit/ns3/root.hint | 3 bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named2.conf.j2 | 25 bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named3.conf.j2 | 25 bind9-9.20.29/bin/tests/system/fetchlimit/ns5/root.hint | 3 bind9-9.20.29/bin/tests/system/fetchlimit/prereq.sh | 21 bind9-9.20.29/bin/tests/system/fetchlimit/tests.sh | 5 bind9-9.20.29/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py | 9 bind9-9.20.29/bin/tests/system/filters/ans6/ans.py | 97 bind9-9.20.29/bin/tests/system/filters/common.py | 1 bind9-9.20.29/bin/tests/system/filters/ns1/named.conf.j2 | 36 bind9-9.20.29/bin/tests/system/filters/ns2/named.conf.j2 | 36 bind9-9.20.29/bin/tests/system/filters/ns3/named.conf.j2 | 36 bind9-9.20.29/bin/tests/system/filters/ns4/named.conf.j2 | 34 bind9-9.20.29/bin/tests/system/filters/ns5/named.conf.j2 | 50 bind9-9.20.29/bin/tests/system/filters/tests_filter_a_dns64.py | 34 bind9-9.20.29/bin/tests/system/filters/tests_filter_aaaa_dns64.py | 38 bind9-9.20.29/bin/tests/system/filters/tests_filter_dns64.py | 31 bind9-9.20.29/bin/tests/system/formerr/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/forward/ans6/ans.py | 104 bind9-9.20.29/bin/tests/system/forward/ns1/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/forward/ns10/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/forward/ns2/named-tls.conf.j2 | 38 bind9-9.20.29/bin/tests/system/forward/ns2/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/forward/ns3/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/forward/ns3/named2.conf.j2 | 20 bind9-9.20.29/bin/tests/system/forward/ns4/named-tls.conf.j2 | 42 bind9-9.20.29/bin/tests/system/forward/ns4/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/forward/ns5/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/forward/ns7/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/forward/ns8/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/forward/ns8/root.db | 13 bind9-9.20.29/bin/tests/system/forward/ns9/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/forward/ns9/named2.conf.j2 | 22 bind9-9.20.29/bin/tests/system/forward/ns9/named3.conf.j2 | 22 bind9-9.20.29/bin/tests/system/forward/ns9/named4.conf.j2 | 22 bind9-9.20.29/bin/tests/system/forward/ns9/root.db | 13 bind9-9.20.29/bin/tests/system/forward/prereq.sh | 21 bind9-9.20.29/bin/tests/system/fwdfirst/ans3/ans.py | 40 bind9-9.20.29/bin/tests/system/fwdfirst/ns4/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/fwdfirst/ns5/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/geoip2/conf/bad-asnum.conf | 17 bind9-9.20.29/bin/tests/system/geoip2/conf/good-options.conf | 1 bind9-9.20.29/bin/tests/system/geoip2/ns2/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named10.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named11.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named12.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named13.conf.j2 | 29 bind9-9.20.29/bin/tests/system/geoip2/ns2/named2.conf.j2 | 20 bind9-9.20.29/bin/tests/system/geoip2/ns2/named3.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named4.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named5.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named6.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named7.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named8.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/ns2/named9.conf.j2 | 17 bind9-9.20.29/bin/tests/system/geoip2/prereq.sh | 20 bind9-9.20.29/bin/tests/system/geoip2/tests.sh | 14 bind9-9.20.29/bin/tests/system/geoip2/tests_sh_geoip2.py | 9 bind9-9.20.29/bin/tests/system/glue/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/hooks/driver/Makefile.in | 1 bind9-9.20.29/bin/tests/system/hooks/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/host/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/idna/ns1/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/mars.conf | 4 bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/named.conf.j2 | 8 bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/zone1.conf | 4 bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/zone2.conf | 4 bind9-9.20.29/bin/tests/system/inline/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/inline/ns2/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/inline/ns3/named.conf.j2 | 29 bind9-9.20.29/bin/tests/system/inline/ns4/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/inline/ns5/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/inline/ns5/named2.conf.j2 | 15 bind9-9.20.29/bin/tests/system/inline/ns6/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/inline/ns7/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/inline/ns8/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/integrity/ns1/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/isctest/__init__.py | 2 bind9-9.20.29/bin/tests/system/isctest/asyncserver.py | 15 bind9-9.20.29/bin/tests/system/isctest/instance.py | 18 bind9-9.20.29/bin/tests/system/isctest/kasp.py | 33 bind9-9.20.29/bin/tests/system/isctest/mark.py | 81 bind9-9.20.29/bin/tests/system/isctest/query.py | 65 bind9-9.20.29/bin/tests/system/isctest/rndc.py | 256 + bind9-9.20.29/bin/tests/system/isctest/template.py | 66 bind9-9.20.29/bin/tests/system/isctest/zone.py | 1 bind9-9.20.29/bin/tests/system/ixfr/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/ixfr/ns3/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/ixfr/ns4/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/ixfr/ns5/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/ixfr/prereq.sh | 21 bind9-9.20.29/bin/tests/system/ixfr_nonminimal/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/ixfr_nonminimal/ns3/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/ixfr_nonminimal/prereq.sh | 16 bind9-9.20.29/bin/tests/system/journal/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/journal/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/kasp/ns1/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/kasp/ns2/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/kasp/ns3/ed25519.conf | 18 bind9-9.20.29/bin/tests/system/kasp/ns3/ed448.conf | 18 bind9-9.20.29/bin/tests/system/kasp/ns3/named-common.conf.j2 | 17 bind9-9.20.29/bin/tests/system/kasp/ns3/named-fips.conf.j2 | 8 bind9-9.20.29/bin/tests/system/kasp/ns4/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/kasp/ns5/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/kasp/ns6/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/keepalive/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/keepalive/ns2/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/keepalive/ns3/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/ksr/ns1/named.conf.j2 | 39 bind9-9.20.29/bin/tests/system/legacy/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/legacy/ns10/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/legacy/ns2/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/legacy/ns3/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/legacy/ns4/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/legacy/ns5/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/legacy/ns6/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/legacy/ns7/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/legacy/ns8/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/legacy/ns9/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/limits/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.abspath.conf.j2 | 32 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.conf.j2 | 28 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.dir.conf.j2 | 22 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.inc.conf.j2 | 32 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.iso8601-utc.conf.j2 | 18 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.iso8601.conf.j2 | 18 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.pipe.conf.j2 | 22 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.plain.conf.j2 | 28 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.plainlog.conf.j2 | 18 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.sym.conf.j2 | 22 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.ts.conf.j2 | 32 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.unlimited.conf.j2 | 32 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.vers.conf.j2 | 32 bind9-9.20.29/bin/tests/system/masterfile/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/masterfile/ns2/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/masterformat/ns1/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/masterformat/ns2/named.conf.j2 | 7 bind9-9.20.29/bin/tests/system/masterformat/ns3/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/masterformat/ns4/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/masterformat/ns4/named2.conf.j2 | 14 bind9-9.20.29/bin/tests/system/migrate2kasp/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/migrate2kasp/ns4/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/mirror/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/mirror/ns2/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/mirror/ns3/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/mirror_root_zone/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/mismatchtcp/ans2/ans.py | 38 bind9-9.20.29/bin/tests/system/mismatchtcp/ns1/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/mkeys/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/mkeys/ns1/named2.conf.j2 | 17 bind9-9.20.29/bin/tests/system/mkeys/ns1/named3.conf.j2 | 17 bind9-9.20.29/bin/tests/system/mkeys/ns2/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/mkeys/ns3/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/mkeys/ns4/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/mkeys/ns5/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/mkeys/ns6/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/mkeys/ns7/named.conf.j2 | 28 bind9-9.20.29/bin/tests/system/multisigner/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/multisigner/ns4/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/multisigner/ns5/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/multisigner/tests_multisigner.py | 77 bind9-9.20.29/bin/tests/system/names/ns1/named.conf.j2 | 12 bind9-9.20.29/bin/tests/system/notify/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/notify/ns2/named-tls.conf.j2 | 38 bind9-9.20.29/bin/tests/system/notify/ns2/named.conf.j2 | 35 bind9-9.20.29/bin/tests/system/notify/ns3/named-tls.conf.j2 | 42 bind9-9.20.29/bin/tests/system/notify/ns3/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/notify/ns4/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/notify/ns5/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsec/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/nsec/ns2/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/nsec/ns3/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/nsec3/common.py | 70 bind9-9.20.29/bin/tests/system/nsec3/ns2/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/nsec3/ns3/named-common.conf.j2 | 17 bind9-9.20.29/bin/tests/system/nsec3/ns3/named-fips.conf.j2 | 8 bind9-9.20.29/bin/tests/system/nsec3/ns4/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/nsec3/ns5/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/nsec3/ns6/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_change.py | 27 bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_initial.py | 25 bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_reconfig.py | 34 bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_reload.py | 3 bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_restart.py | 12 bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_retransfer.py | 8 bind9-9.20.29/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/nsec_grandparent/ans1/ans.py | 456 ++ bind9-9.20.29/bin/tests/system/nsec_grandparent/ns2/named.conf.j2 | 27 bind9-9.20.29/bin/tests/system/nsec_grandparent/tests_nsec_grandparent.py | 450 ++ bind9-9.20.29/bin/tests/system/nsec_ixfr/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsec_ixfr/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsec_piggyback/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsec_piggyback/ns3/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/nsec_synthesis/ns2/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/nsec_synthesis/ns3/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/ans1/ans.py | 216 + bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/ns2/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/tests_nsec_wildcard_wrong_zone.py | 159 bind9-9.20.29/bin/tests/system/nslookup/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns1/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns3/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns4/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns4/root.hint | 3 bind9-9.20.29/bin/tests/system/nsupdate/ns1/grant-external.test.db.in | 10 bind9-9.20.29/bin/tests/system/nsupdate/ns1/named.conf.j2 | 61 bind9-9.20.29/bin/tests/system/nsupdate/ns1/tls.conf.j2 | 38 bind9-9.20.29/bin/tests/system/nsupdate/ns10/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/nsupdate/ns2/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/nsupdate/ns3/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsupdate/ns5/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsupdate/ns6/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/nsupdate/ns7/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsupdate/ns7/named2.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsupdate/ns8/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsupdate/ns9/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nsupdate/prereq.sh | 21 bind9-9.20.29/bin/tests/system/nsupdate/setup.sh | 1 bind9-9.20.29/bin/tests/system/nsupdate/tests.sh | 26 bind9-9.20.29/bin/tests/system/nsupdate/tests_sh_nsupdate.py | 15 bind9-9.20.29/bin/tests/system/nta/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/nta/ns2/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/nta/ns3/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nta/ns4/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/nta/ns9/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/nta/tests_nta.py | 40 bind9-9.20.29/bin/tests/system/nzd2nzf/ns1/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/optout/ns2/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/attacker.db | 5 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/example.db | 4 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/named.conf.j2 | 42 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/root.db | 6 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/dnamezone.db | 8 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/named.conf.j2 | 42 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/nszone.db | 8 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/dnamezone.db | 8 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/named.conf.j2 | 43 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/nszone.db | 8 bind9-9.20.29/bin/tests/system/outofzone_zonecut/tests_outofzone_zonecut.py | 102 bind9-9.20.29/bin/tests/system/padding/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/padding/ns2/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/padding/ns3/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/padding/ns4/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/pending/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/pending/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/pending/ns3/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/pending/ns4/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/pipelined/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/pipelined/ns2/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/pipelined/ns3/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/pipelined/ns4/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/proxy/ns1/named.conf.j2 | 40 bind9-9.20.29/bin/tests/system/proxy/ns3/named.conf.j2 | 38 bind9-9.20.29/bin/tests/system/proxy/prereq.sh | 21 bind9-9.20.29/bin/tests/system/proxy/tests_sh_proxy.py | 9 bind9-9.20.29/bin/tests/system/qmin/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/qmin/ns5/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/qmin/ns6/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/qmin/ns7/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/qpcache_rrsig_any/ans3/ans.py | 73 bind9-9.20.29/bin/tests/system/qpcache_rrsig_any/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/query_source/ns1/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/query_source/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/query_source/ns3/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/query_source/ns3/root.hint | 3 bind9-9.20.29/bin/tests/system/query_source/ns4/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/query_source/ns4/root.hint | 3 bind9-9.20.29/bin/tests/system/query_source/ns5/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/randomizens/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/randomizens/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/randomizens/ns3/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/randomizens/ns4/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/randomizens/ns5/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/randomizens/ns6/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/reclimit/ans2/ans.pl | 235 - bind9-9.20.29/bin/tests/system/reclimit/ans2/ans.py | 79 bind9-9.20.29/bin/tests/system/reclimit/ans4/ans.pl | 240 - bind9-9.20.29/bin/tests/system/reclimit/ans4/ans.py | 44 bind9-9.20.29/bin/tests/system/reclimit/ans7/ans.pl | 88 bind9-9.20.29/bin/tests/system/reclimit/ans7/ans.py | 41 bind9-9.20.29/bin/tests/system/reclimit/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/reclimit/ns3/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/reclimit/ns3/named2.conf.j2 | 19 bind9-9.20.29/bin/tests/system/reclimit/ns3/named3.conf.j2 | 19 bind9-9.20.29/bin/tests/system/reclimit/ns3/named4.conf.j2 | 19 bind9-9.20.29/bin/tests/system/reclimit/ns3/named5.conf.j2 | 19 bind9-9.20.29/bin/tests/system/reclimit/ns3/named6.conf.j2 | 19 bind9-9.20.29/bin/tests/system/reclimit/prereq.sh | 26 bind9-9.20.29/bin/tests/system/reclimit/reclimit_ans.py | 236 + bind9-9.20.29/bin/tests/system/reclimit/tests.sh | 68 bind9-9.20.29/bin/tests/system/reclimit/tests_sh_reclimit.py | 9 bind9-9.20.29/bin/tests/system/redirect/ns1/named.conf.j2 | 12 bind9-9.20.29/bin/tests/system/redirect/ns10/named.conf.j2 | 6 bind9-9.20.29/bin/tests/system/redirect/ns2/named.conf.j2 | 26 bind9-9.20.29/bin/tests/system/redirect/ns3/named.conf.j2 | 12 bind9-9.20.29/bin/tests/system/redirect/ns4/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/redirect/ns5/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/redirect/ns6/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/redirect/ns7/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/redirect/ns8/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/redirect/ns9/named.conf.j2 | 6 bind9-9.20.29/bin/tests/system/requirements.txt | 3 bind9-9.20.29/bin/tests/system/resend_loop/ns4/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/resolver/ns1/named.conf.j2 | 42 bind9-9.20.29/bin/tests/system/resolver/ns1/named2.conf.j2 | 28 bind9-9.20.29/bin/tests/system/resolver/ns11/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/resolver/ns4/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/resolver/ns5/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/resolver/ns6/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/resolver/ns7/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/resolver/ns7/named2.conf.j2 | 18 bind9-9.20.29/bin/tests/system/resolver/ns9/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/resolver/prereq.sh | 21 bind9-9.20.29/bin/tests/system/rfc5011/ns1/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/rndc/ns2/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/rndc/ns3/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/rndc/ns4/named.conf.j2 | 7 bind9-9.20.29/bin/tests/system/rndc/ns5/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/rndc/ns6/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/rndc/ns7/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/rndc/tests_cve_2023_3341.py | 1 bind9-9.20.29/bin/tests/system/rndc_confgen/tests_rndc_confgen.py | 49 bind9-9.20.29/bin/tests/system/rollover/common.py | 1 bind9-9.20.29/bin/tests/system/rollover/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/rollover/ns2/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/rollover/ns3/dynamic2inline.kasp.db | 27 bind9-9.20.29/bin/tests/system/rollover/ns3/lifetime.db.in | 27 bind9-9.20.29/bin/tests/system/rollover/ns3/named-algo-csk.conf.j2 | 59 bind9-9.20.29/bin/tests/system/rollover/ns3/named-algo-ksk-zsk.conf.j2 | 60 bind9-9.20.29/bin/tests/system/rollover/ns3/named-csk-roll1.conf.j2 | 61 bind9-9.20.29/bin/tests/system/rollover/ns3/named-csk-roll2.conf.j2 | 56 bind9-9.20.29/bin/tests/system/rollover/ns3/named-dynamic2inline.conf.j2 | 21 bind9-9.20.29/bin/tests/system/rollover/ns3/named-enable-dnssec.conf.j2 | 41 bind9-9.20.29/bin/tests/system/rollover/ns3/named-going-insecure.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover/ns3/named-ksk-3crowd.conf.j2 | 23 bind9-9.20.29/bin/tests/system/rollover/ns3/named-ksk-doubleksk.conf.j2 | 50 bind9-9.20.29/bin/tests/system/rollover/ns3/named-lifetime.conf.j2 | 45 bind9-9.20.29/bin/tests/system/rollover/ns3/named-manual.conf.j2 | 12 bind9-9.20.29/bin/tests/system/rollover/ns3/named-multisigner.conf.j2 | 34 bind9-9.20.29/bin/tests/system/rollover/ns3/named-straight2none.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover/ns3/named-zsk-prepub.conf.j2 | 50 bind9-9.20.29/bin/tests/system/rollover/ns3/named.common.conf.j2 | 27 bind9-9.20.29/bin/tests/system/rollover/ns3/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk-roll1.conf | 58 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk-roll2.conf | 58 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk1.conf | 50 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk2.conf | 50 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/enable-dnssec.conf | 52 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/going-insecure.conf | 21 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/ksk-zsk.conf | 92 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/ksk.conf | 60 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/lifetime.conf.j2 | 29 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/multisigner.conf.j2 | 22 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/zsk-prepub.conf | 52 bind9-9.20.29/bin/tests/system/rollover/ns4/named.common.conf.j2 | 27 bind9-9.20.29/bin/tests/system/rollover/setup.py | 50 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_csk_initial.py | 74 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_csk_reconfig.py | 361 + bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_initial.py | 71 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_reconfig.py | 381 ++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_csk_roll1.py | 454 ++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_csk_roll2.py | 430 ++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_dynamic2inline.py | 50 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_enable_dnssec.py | 231 + bind9-9.20.29/bin/tests/system/rollover/tests_rollover_going_insecure_initial.py | 63 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_going_insecure_reconfig.py | 117 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_ksk_doubleksk.py | 372 ++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_lifetime_initial.py | 60 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_lifetime_reconfig.py | 75 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_manual.py | 1 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_multisigner.py | 243 + bind9-9.20.29/bin/tests/system/rollover/tests_rollover_straight2none_initial.py | 61 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_straight2none_reconfig.py | 70 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_three_is_a_crowd.py | 112 bind9-9.20.29/bin/tests/system/rollover/tests_rollover_zsk_prepublication.py | 375 ++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/csk1.conf | 50 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/csk2.conf | 50 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/named.conf.j2 | 59 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_initial.py | 73 bind9-9.20.29/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_reconfig.py | 360 - bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/kasp.conf | 92 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.conf.j2 | 60 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_initial.py | 70 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_reconfig.py | 380 -- bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/kasp.conf | 58 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/named.conf.j2 | 61 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/tests_rollover_csk_roll1.py | 453 -- bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/kasp.conf | 58 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/named.conf.j2 | 56 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/tests_rollover_csk_roll2.py | 429 -- bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/dynamic2inline.kasp.db | 27 bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/tests_rollover_dynamic2inline.py | 41 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/kasp.conf | 52 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/named.conf.j2 | 41 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/tests_rollover_enable_dnssec.py | 230 - bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/kasp.conf | 21 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_initial.py | 62 bind9-9.20.29/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_reconfig.py | 116 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/kasp.conf | 60 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/tests_rollover_three_is_a_crowd.py | 111 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/kasp.conf | 60 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/named.conf.j2 | 50 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/tests_rollover_ksk_doubleksk.py | 371 -- bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/kasp.conf.j2 | 29 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/limit-lifetime.db | 27 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/longer-lifetime.db | 27 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/named.conf.j2 | 45 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/shorter-lifetime.db | 27 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/template.db.in | 27 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/unlimit-lifetime.db | 27 bind9-9.20.29/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_initial.py | 44 bind9-9.20.29/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_reconfig.py | 59 bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/kasp.conf.j2 | 22 bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/named.conf.j2 | 34 bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/template.db.in | 27 bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_multisigner/tests_rollover_multisigner.py | 238 - bind9-9.20.29/bin/tests/system/rollover_straight2none/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/kasp.conf | 21 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_initial.py | 60 bind9-9.20.29/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_reconfig.py | 69 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns1/root.db.j2.manual | 31 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns2/named.conf.j2 | 49 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns2/template.db.j2.manual | 40 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/kasp.conf | 52 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/named.common.conf.j2 | 47 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/named.conf.j2 | 50 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/template.db.j2.manual | 34 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/trusted.conf.j2 | 5 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/tests_rollover_zsk_prepublication.py | 374 -- bind9-9.20.29/bin/tests/system/rootkeysentinel/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns2/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns3/hint.db | 13 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns4/hint.db | 13 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns4/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/rpz/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/rpz/ns10/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/rpz/ns11/0.0.127.in-addr.arpa.db | 3 bind9-9.20.29/bin/tests/system/rpz/ns11/named.conf.j2 | 27 bind9-9.20.29/bin/tests/system/rpz/ns11/nsdname.db | 6 bind9-9.20.29/bin/tests/system/rpz/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/rpz/ns3/named.conf.j2 | 82 bind9-9.20.29/bin/tests/system/rpz/ns3/named1.conf.j2 | 82 bind9-9.20.29/bin/tests/system/rpz/ns3/outofzone.db.in | 29 bind9-9.20.29/bin/tests/system/rpz/ns4/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/rpz/ns5/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/rpz/ns6/named.conf.j2 | 26 bind9-9.20.29/bin/tests/system/rpz/ns7/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/rpz/ns8/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/rpz/ns9/named.conf.j2 | 21 bind9-9.20.29/bin/tests/system/rpz/setup.sh | 3 bind9-9.20.29/bin/tests/system/rpz/testlib/Makefile.in | 1 bind9-9.20.29/bin/tests/system/rpz/tests.sh | 13 bind9-9.20.29/bin/tests/system/rpz/tests_rpz_6407.py | 20 bind9-9.20.29/bin/tests/system/rpz/tests_rpz_outofzone.py | 32 bind9-9.20.29/bin/tests/system/rpz/tests_sh_rpz.py | 1 bind9-9.20.29/bin/tests/system/rpz/tests_sh_rpz_dnsrps.py | 1 bind9-9.20.29/bin/tests/system/rpzextra/ns2/named.conf.j2 | 36 bind9-9.20.29/bin/tests/system/rpzextra/ns3/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/rpzrecurse/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.clientip.conf | 18 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.clientip2.conf | 18 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.conf.header.j2 | 21 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.conf.j2 | 6 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.default.conf | 6 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.invalidprefixlength.conf | 14 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.log.conf | 20 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.max.conf | 142 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard1.conf | 16 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard2.conf | 18 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard3.conf | 16 bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named1.conf.j2 | 16 bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named2.conf.j2 | 22 bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named3.conf.j2 | 18 bind9-9.20.29/bin/tests/system/rpzrecurse/ns4/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/rpzrecurse/prereq.sh | 21 bind9-9.20.29/bin/tests/system/rrl/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/rrl/ns2/named.conf.j2 | 38 bind9-9.20.29/bin/tests/system/rrl/ns3/named.conf.j2 | 36 bind9-9.20.29/bin/tests/system/rrl/ns4/named.conf.j2 | 40 bind9-9.20.29/bin/tests/system/rrsetorder/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/rrsetorder/ns2/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/rrsetorder/ns3/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/rrsetorder/ns4/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/rrsetorder/ns5/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/rsabigexponent/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/rsabigexponent/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/rsabigexponent/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/runtime/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/runtime/ns2/named1.conf.j2 | 16 bind9-9.20.29/bin/tests/system/runtime/ns2/named2.conf.j2 | 7 bind9-9.20.29/bin/tests/system/runtime/ns2/named3.conf.j2 | 7 bind9-9.20.29/bin/tests/system/runtime/ns2/named4.conf.j2 | 7 bind9-9.20.29/bin/tests/system/runtime/ns2/named5.conf.j2 | 7 bind9-9.20.29/bin/tests/system/runtime/ns2/named6.conf.j2 | 9 bind9-9.20.29/bin/tests/system/runtime/ns2/named7.conf.j2 | 6 bind9-9.20.29/bin/tests/system/runtime/ns2/named8.conf.j2 | 53 bind9-9.20.29/bin/tests/system/runtime/tests.sh | 14 bind9-9.20.29/bin/tests/system/selfpointedglue/ns1/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/selfpointedglue/ns2/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/selfpointedglue/ns3/named.conf.j2 | 12 bind9-9.20.29/bin/tests/system/selfpointedglue/ns4/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/selfpointedglue/ns4/root.hint | 14 bind9-9.20.29/bin/tests/system/selftest/tests_template.py | 90 bind9-9.20.29/bin/tests/system/send.pl | 33 bind9-9.20.29/bin/tests/system/serve_stale/ans2/ans.pl | 408 -- bind9-9.20.29/bin/tests/system/serve_stale/ans2/ans.py | 193 + bind9-9.20.29/bin/tests/system/serve_stale/ans8/ans.pl | 164 bind9-9.20.29/bin/tests/system/serve_stale/ans8/ans.py | 88 bind9-9.20.29/bin/tests/system/serve_stale/ans9/ans.py | 146 bind9-9.20.29/bin/tests/system/serve_stale/ns1/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/serve_stale/ns1/named1.conf.in | 1 bind9-9.20.29/bin/tests/system/serve_stale/ns1/named2.conf.in | 1 bind9-9.20.29/bin/tests/system/serve_stale/ns1/named3.conf.in | 3 bind9-9.20.29/bin/tests/system/serve_stale/ns1/named3.conf.j2 | 2 bind9-9.20.29/bin/tests/system/serve_stale/ns1/named4.conf.in | 1 bind9-9.20.29/bin/tests/system/serve_stale/ns1/root.db | 2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named1.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named2.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named3.conf.j2 | 22 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named4.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named5.conf.j2 | 20 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named6.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named7.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named8.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named9.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns4/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns5/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/serve_stale/ns6/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/serve_stale/ns7/named.conf.j2 | 32 bind9-9.20.29/bin/tests/system/serve_stale/ns7/named1.conf.j2 | 34 bind9-9.20.29/bin/tests/system/serve_stale/ns7/root.db | 2 bind9-9.20.29/bin/tests/system/serve_stale/prereq.sh | 21 bind9-9.20.29/bin/tests/system/serve_stale/serve_stale_ans.py | 223 + bind9-9.20.29/bin/tests/system/serve_stale/tests.sh | 269 - bind9-9.20.29/bin/tests/system/serve_stale/tests_serve_stale_ncache.py | 97 bind9-9.20.29/bin/tests/system/serve_stale/tests_serve_stale_tcp.py | 129 bind9-9.20.29/bin/tests/system/serve_stale/tests_sh_serve_stale.py | 5 bind9-9.20.29/bin/tests/system/sfcache/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/sfcache/ns2/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/sfcache/ns5/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/sfcache_cname/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/sfcache_cname/ns2/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/shutdown/ns1/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/shutdown/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/shutdown/resolver/named.conf.j2 | 4 bind9-9.20.29/bin/tests/system/sig0/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/sig0_https/ns1/named.conf.j2 | 7 bind9-9.20.29/bin/tests/system/sig0_https/tests_sig0_https.py | 111 bind9-9.20.29/bin/tests/system/sortlist/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/spf/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/srtt/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/srtt/ns6/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/ssumaxtype/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/ssutoctou/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/staticstub/conf/bad02.conf | 4 bind9-9.20.29/bin/tests/system/staticstub/ns1/named.conf.j2 | 8 bind9-9.20.29/bin/tests/system/staticstub/ns2/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/staticstub/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/staticstub/ns4/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/statistics/ns1/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/statistics/ns2/named.conf.j2 | 26 bind9-9.20.29/bin/tests/system/statistics/ns2/named1.conf.j2 | 26 bind9-9.20.29/bin/tests/system/statistics/ns2/named2.conf.j2 | 26 bind9-9.20.29/bin/tests/system/statistics/ns3/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/statistics/prereq.sh | 21 bind9-9.20.29/bin/tests/system/statschannel/generic.py | 13 bind9-9.20.29/bin/tests/system/statschannel/ns1/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/statschannel/ns2/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/statschannel/ns2/named2.conf.j2 | 19 bind9-9.20.29/bin/tests/system/statschannel/ns3/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/statschannel/prereq.sh | 31 bind9-9.20.29/bin/tests/system/statschannel/tests_sh_statschannel.py | 9 bind9-9.20.29/bin/tests/system/stress/ns2/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/stress/ns3/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/stress/ns4/named.conf.j2 | 12 bind9-9.20.29/bin/tests/system/stress/prereq.sh | 21 bind9-9.20.29/bin/tests/system/stub/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/stub/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/stub/ns3/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/stub/ns4/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/stub/ns5/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/svcb_alias/ns1/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/svcb_alias/ns1/root.hint | 2 bind9-9.20.29/bin/tests/system/svcb_alias/ns2/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/svcb_alias/ns2/root.db | 5 bind9-9.20.29/bin/tests/system/svcb_alias/setup.sh | 36 bind9-9.20.29/bin/tests/system/svcb_alias/tests_svcb_alias.py | 88 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns1/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns2/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns3/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns4/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns5/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns6/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/tcp/1996-alloc_dnsbuf-crash-test.pkt | 12 bind9-9.20.29/bin/tests/system/tcp/ans6/ans.py | 156 bind9-9.20.29/bin/tests/system/tcp/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/tcp/ns2/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/tcp/ns3/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/tcp/ns4/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/tcp/ns5/named.conf.j2 | 29 bind9-9.20.29/bin/tests/system/tcp/ns7/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/tcp/tests.sh | 228 - bind9-9.20.29/bin/tests/system/tcp/tests_sh_tcp.py | 26 bind9-9.20.29/bin/tests/system/tcp/tests_tcp.py | 480 ++ bind9-9.20.29/bin/tests/system/timeouts/ns1/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/timeouts/tests_tcp_timeouts.py | 1 bind9-9.20.29/bin/tests/system/tkey/nooptions/example.db | 5 bind9-9.20.29/bin/tests/system/tkey/nooptions/named.conf | 13 bind9-9.20.29/bin/tests/system/tkey/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/tkey/tests_no_options.py | 109 bind9-9.20.29/bin/tests/system/tkeyleak/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/tkeyleak/prereq.sh | 21 bind9-9.20.29/bin/tests/system/tkeyleak/tests_tkeyleak.py | 8 bind9-9.20.29/bin/tests/system/transport_acl/ns1/named.conf.j2 | 31 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-http-plain-proxy.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-http-plain.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https-proxy-encrypted.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https-proxy-plain.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-proxy.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls-proxy-encrypted.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls-proxy-plain.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/transport_change/prereq.sh | 22 bind9-9.20.29/bin/tests/system/transport_change/tests_sh_transport_change.py | 9 bind9-9.20.29/bin/tests/system/tsig/ns1/named-md5.conf.j2 | 4 bind9-9.20.29/bin/tests/system/tsig/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/tsig/tests.sh | 2 bind9-9.20.29/bin/tests/system/tsiggss/authsock.pl | 91 bind9-9.20.29/bin/tests/system/tsiggss/ns1/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/tsiggss/prereq.sh | 27 bind9-9.20.29/bin/tests/system/tsiggss/tests.sh | 2 bind9-9.20.29/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py | 9 bind9-9.20.29/bin/tests/system/tsiggss/tests_sh_tsiggss.py | 10 bind9-9.20.29/bin/tests/system/ttl/ns1/named.conf.j2 | 22 bind9-9.20.29/bin/tests/system/ttl/ns2/named.conf.j2 | 19 bind9-9.20.29/bin/tests/system/unknown/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/unknown/ns2/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/unknown/ns3/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/upforwd/ns1/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/upforwd/ns2/named.conf.j2 | 12 bind9-9.20.29/bin/tests/system/upforwd/ns3/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/upforwd/ns3/named2.conf.j2 | 20 bind9-9.20.29/bin/tests/system/upforwd/prereq.sh | 21 bind9-9.20.29/bin/tests/system/verify/tests_verify.py | 206 + bind9-9.20.29/bin/tests/system/verify/zones/bad-nsec3param-hash.db.j2.manual | 7 bind9-9.20.29/bin/tests/system/verify/zones/genzones.sh | 16 bind9-9.20.29/bin/tests/system/verify/zones/good-bad-nsec3param-hash.db.j2.manual | 8 bind9-9.20.29/bin/tests/system/verify/zones/no-nsec+non-zero-nsec3param-flags.db.j2.manual | 10 bind9-9.20.29/bin/tests/system/verify/zones/nsec+non-zero-nsec3param-flags.db.j2.manual | 9 bind9-9.20.29/bin/tests/system/verify/zones/nsec-badnsec3param-hash.db.j2.manual | 8 bind9-9.20.29/bin/tests/system/verify/zones/nseconly-nsec3param.db.j2.manual | 8 bind9-9.20.29/bin/tests/system/views/ns1/named.conf.j2 | 11 bind9-9.20.29/bin/tests/system/views/ns2/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/views/ns2/named2.conf.j2 | 32 bind9-9.20.29/bin/tests/system/views/ns2/named3.conf.j2 | 17 bind9-9.20.29/bin/tests/system/views/ns3/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/views/ns3/named2.conf.j2 | 25 bind9-9.20.29/bin/tests/system/views/ns5/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/wildcard/ns1/named.conf.j2 | 23 bind9-9.20.29/bin/tests/system/wildcard/ns2/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/wildcard/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/wildcard/ns4/named.conf.j2 | 12 bind9-9.20.29/bin/tests/system/wildcard/ns5/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/xfer/ans11/ans.py | 343 - bind9-9.20.29/bin/tests/system/xfer/ans5/ans.py | 31 bind9-9.20.29/bin/tests/system/xfer/ans9/ans.py | 211 - bind9-9.20.29/bin/tests/system/xfer/ns1/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/xfer/ns1/named2.conf.j2 | 15 bind9-9.20.29/bin/tests/system/xfer/ns1/named3.conf.j2 | 15 bind9-9.20.29/bin/tests/system/xfer/ns2/named.conf.j2 | 25 bind9-9.20.29/bin/tests/system/xfer/ns3/named.conf.j2 | 26 bind9-9.20.29/bin/tests/system/xfer/ns4/named.conf.j2 | 24 bind9-9.20.29/bin/tests/system/xfer/ns6/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/xfer/ns7/named.conf.j2 | 20 bind9-9.20.29/bin/tests/system/xfer/ns8/named.conf.j2 | 14 bind9-9.20.29/bin/tests/system/xfer/prereq.sh | 30 bind9-9.20.29/bin/tests/system/xfer/tests_xfer.py | 10 bind9-9.20.29/bin/tests/system/xfer_servers_list/ns1/named.conf.j2 | 16 bind9-9.20.29/bin/tests/system/xfer_servers_list/ns2/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/xfer_servers_list/ns3/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/xfer_servers_list/ns4/named.conf.j2 | 13 bind9-9.20.29/bin/tests/system/xferquota/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/xferquota/ns2/named.conf.j2 | 15 bind9-9.20.29/bin/tests/system/xferquota/ns3/named.conf.j2 | 17 bind9-9.20.29/bin/tests/system/zero/ns1/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/zero/ns2/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/zero/ns3/named.conf.j2 | 10 bind9-9.20.29/bin/tests/system/zero/ns4/named.conf.j2 | 9 bind9-9.20.29/bin/tests/system/zero/prereq.sh | 21 bind9-9.20.29/bin/tests/system/zonechecks/ns1/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/zonechecks/ns2/named.conf.j2 | 18 bind9-9.20.29/bin/tests/system/zonechecks/tests_sh_zonechecks.py | 1 bind9-9.20.29/bin/tools/Makefile.in | 1 bind9-9.20.29/bin/tools/dnstap-read.c | 22 bind9-9.20.29/bin/tools/mdig.c | 72 bind9-9.20.29/bin/tools/named-rrchecker.c | 2 bind9-9.20.29/config.h.in | 6 bind9-9.20.29/configure | 104 bind9-9.20.29/configure.ac | 15 bind9-9.20.29/contrib/gitchangelog/gitchangelog.py | 4 bind9-9.20.29/debian/changelog | 26 bind9-9.20.29/doc/Makefile.in | 1 bind9-9.20.29/doc/arm/Makefile.in | 1 bind9-9.20.29/doc/arm/changelog.rst | 3 bind9-9.20.29/doc/arm/notes.rst | 3 bind9-9.20.29/doc/arm/platforms.inc.rst | 4 bind9-9.20.29/doc/arm/reference.rst | 12 bind9-9.20.29/doc/changelog/changelog-9.20.27.rst | 193 + bind9-9.20.29/doc/changelog/changelog-9.20.28.rst | 18 bind9-9.20.29/doc/changelog/changelog-9.20.29.rst | 443 ++ bind9-9.20.29/doc/man/Makefile.in | 1 bind9-9.20.29/doc/man/rndc-confgen.8in | 6 bind9-9.20.29/doc/misc/Makefile.in | 1 bind9-9.20.29/doc/notes/notes-9.20.27.rst | 102 bind9-9.20.29/doc/notes/notes-9.20.28.rst | 18 bind9-9.20.29/doc/notes/notes-9.20.29.rst | 367 ++ bind9-9.20.29/fuzz/Makefile.in | 1 bind9-9.20.29/fuzz/dns_message_checksig.c | 3 bind9-9.20.29/fuzz/dns_rdata_fromwire_text.c | 1 bind9-9.20.29/lib/Makefile.in | 1 bind9-9.20.29/lib/dns/Makefile.in | 1 bind9-9.20.29/lib/dns/acl.c | 8 bind9-9.20.29/lib/dns/adb.c | 3 bind9-9.20.29/lib/dns/cache.c | 4 bind9-9.20.29/lib/dns/catz.c | 248 - bind9-9.20.29/lib/dns/dnstap.c | 4 bind9-9.20.29/lib/dns/dst_parse.c | 10 bind9-9.20.29/lib/dns/dst_parse.h | 4 bind9-9.20.29/lib/dns/ede.c | 6 bind9-9.20.29/lib/dns/geoip2.c | 16 bind9-9.20.29/lib/dns/hmac_link.c | 18 bind9-9.20.29/lib/dns/include/dns/cache.h | 8 bind9-9.20.29/lib/dns/include/dns/ede.h | 12 bind9-9.20.29/lib/dns/include/dns/geoip.h | 3 bind9-9.20.29/lib/dns/include/dns/name.h | 7 bind9-9.20.29/lib/dns/include/dns/rdatalist.h | 11 bind9-9.20.29/lib/dns/include/dns/rdataset.h | 82 bind9-9.20.29/lib/dns/include/dns/rdataslab.h | 1 bind9-9.20.29/lib/dns/include/dns/rpz.h | 25 bind9-9.20.29/lib/dns/include/dns/stats.h | 17 bind9-9.20.29/lib/dns/include/dns/validator.h | 23 bind9-9.20.29/lib/dns/include/dns/view.h | 5 bind9-9.20.29/lib/dns/kasp.c | 2 bind9-9.20.29/lib/dns/master.c | 43 bind9-9.20.29/lib/dns/masterdump.c | 45 bind9-9.20.29/lib/dns/message.c | 21 bind9-9.20.29/lib/dns/name.c | 17 bind9-9.20.29/lib/dns/ncache.c | 48 bind9-9.20.29/lib/dns/opensslecdsa_link.c | 3 bind9-9.20.29/lib/dns/openssleddsa_link.c | 24 bind9-9.20.29/lib/dns/opensslrsa_link.c | 31 bind9-9.20.29/lib/dns/qp.c | 4 bind9-9.20.29/lib/dns/qpcache.c | 175 bind9-9.20.29/lib/dns/qpzone.c | 118 bind9-9.20.29/lib/dns/rbt-zonedb.c | 102 bind9-9.20.29/lib/dns/rbtdb.c | 74 bind9-9.20.29/lib/dns/rdata/generic/eui48_108.c | 11 bind9-9.20.29/lib/dns/rdata/generic/eui64_109.c | 12 bind9-9.20.29/lib/dns/rdata/in_1/svcb_64.c | 33 bind9-9.20.29/lib/dns/rdata/in_1/wks_11.c | 4 bind9-9.20.29/lib/dns/rdatalist.c | 203 - bind9-9.20.29/lib/dns/rdataset.c | 29 bind9-9.20.29/lib/dns/rdataslab.c | 120 bind9-9.20.29/lib/dns/resolver.c | 157 bind9-9.20.29/lib/dns/rpz.c | 371 +- bind9-9.20.29/lib/dns/ssu.c | 4 bind9-9.20.29/lib/dns/stats.c | 291 - bind9-9.20.29/lib/dns/tkey.c | 9 bind9-9.20.29/lib/dns/tsig.c | 94 bind9-9.20.29/lib/dns/validator.c | 660 ++- bind9-9.20.29/lib/dns/xfrin.c | 193 - bind9-9.20.29/lib/dns/zone.c | 75 bind9-9.20.29/lib/dns/zoneverify.c | 181 bind9-9.20.29/lib/isc/Makefile.in | 1 bind9-9.20.29/lib/isc/httpd.c | 4 bind9-9.20.29/lib/isc/include/isc/endian.h | 2 bind9-9.20.29/lib/isc/include/isc/lex.h | 2 bind9-9.20.29/lib/isc/include/isc/queue.h | 1 bind9-9.20.29/lib/isc/include/isc/ratelimiter.h | 4 bind9-9.20.29/lib/isc/include/isc/stats.h | 13 bind9-9.20.29/lib/isc/include/isc/time.h | 8 bind9-9.20.29/lib/isc/include/isc/util.h | 21 bind9-9.20.29/lib/isc/include/isc/work.h | 18 bind9-9.20.29/lib/isc/lex.c | 20 bind9-9.20.29/lib/isc/netmgr/http.c | 27 bind9-9.20.29/lib/isc/netmgr/netmgr-int.h | 5 bind9-9.20.29/lib/isc/netmgr/netmgr.c | 4 bind9-9.20.29/lib/isc/netmgr/streamdns.c | 12 bind9-9.20.29/lib/isc/netmgr/tlsstream.c | 15 bind9-9.20.29/lib/isc/netmgr/udp.c | 7 bind9-9.20.29/lib/isc/ratelimiter.c | 2 bind9-9.20.29/lib/isc/sockaddr.c | 6 bind9-9.20.29/lib/isc/stats.c | 32 bind9-9.20.29/lib/isc/time.c | 145 bind9-9.20.29/lib/isc/work.c | 18 bind9-9.20.29/lib/isccc/Makefile.in | 1 bind9-9.20.29/lib/isccc/alist.c | 4 bind9-9.20.29/lib/isccc/cc.c | 1 bind9-9.20.29/lib/isccc/sexpr.c | 16 bind9-9.20.29/lib/isccfg/Makefile.in | 1 bind9-9.20.29/lib/isccfg/aclconf.c | 15 bind9-9.20.29/lib/isccfg/check.c | 24 bind9-9.20.29/lib/isccfg/kaspconf.c | 176 bind9-9.20.29/lib/isccfg/parser.c | 2 bind9-9.20.29/lib/ns/Makefile.in | 1 bind9-9.20.29/lib/ns/client.c | 1 bind9-9.20.29/lib/ns/include/ns/client.h | 1 bind9-9.20.29/lib/ns/interfacemgr.c | 4 bind9-9.20.29/lib/ns/query.c | 262 - bind9-9.20.29/srcid | 2 bind9-9.20.29/tests/Makefile.in | 1 bind9-9.20.29/tests/bench/Makefile.in | 1 bind9-9.20.29/tests/dns/Makefile.am | 3 bind9-9.20.29/tests/dns/Makefile.in | 93 bind9-9.20.29/tests/dns/badcache_test.c | 2 bind9-9.20.29/tests/dns/db_test.c | 1 bind9-9.20.29/tests/dns/dnssecsignstats_test.c | 217 + bind9-9.20.29/tests/dns/ede_test.c | 2 bind9-9.20.29/tests/dns/keytable_test.c | 2 bind9-9.20.29/tests/dns/master_test.c | 24 bind9-9.20.29/tests/dns/message_test.c | 219 + bind9-9.20.29/tests/dns/name_test.c | 159 bind9-9.20.29/tests/dns/ncache_test.c | 302 + bind9-9.20.29/tests/dns/qp_test.c | 2 bind9-9.20.29/tests/dns/qpdb_test.c | 131 bind9-9.20.29/tests/dns/qpzone_test.c | 117 bind9-9.20.29/tests/dns/rbtdb_test.c | 284 + bind9-9.20.29/tests/dns/rdataset_test.c | 154 bind9-9.20.29/tests/dns/skr_test.c | 1 bind9-9.20.29/tests/isc/Makefile.in | 1 bind9-9.20.29/tests/isc/dnsstream_utils_test_data.h | 1096 ++---- bind9-9.20.29/tests/isc/doh_test.c | 15 bind9-9.20.29/tests/isc/lex_test.c | 152 bind9-9.20.29/tests/isc/proxyheader_test.c | 13 bind9-9.20.29/tests/isc/stats_test.c | 16 bind9-9.20.29/tests/isc/tcpdns_test.c | 46 bind9-9.20.29/tests/isc/time_test.c | 360 + bind9-9.20.29/tests/isc/work_test.c | 7 bind9-9.20.29/tests/isccfg/Makefile.in | 1 bind9-9.20.29/tests/isccfg/duration_test.c | 1 bind9-9.20.29/tests/libtest/Makefile.in | 1 bind9-9.20.29/tests/libtest/dns.c | 1 bind9-9.20.29/tests/ns/Makefile.in | 1 bind9-9.20.29/util/check-make-install.sh.in | 39 1348 files changed, 25588 insertions(+), 25070 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpwo6qeum5/bind9_9.20.26-1~deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpwo6qeum5/bind9_9.20.29-1~deb13u1.dsc: no acceptable signature found diff -Nru bind9-9.20.26/ChangeLog bind9-9.20.29/ChangeLog --- bind9-9.20.26/ChangeLog 2026-07-20 14:47:53.944848109 +0000 +++ bind9-9.20.29/ChangeLog 2026-09-11 19:41:01.414328914 +0000 @@ -18,6 +18,9 @@ development. Regular users should refer to :ref:`Release Notes ` for changes relevant to them. +.. include:: ../changelog/changelog-9.20.29.rst +.. include:: ../changelog/changelog-9.20.28.rst +.. include:: ../changelog/changelog-9.20.27.rst .. include:: ../changelog/changelog-9.20.26.rst .. include:: ../changelog/changelog-9.20.25.rst .. include:: ../changelog/changelog-9.20.24.rst diff -Nru bind9-9.20.26/Makefile.in bind9-9.20.29/Makefile.in --- bind9-9.20.26/Makefile.in 2026-07-20 14:49:10.003568158 +0000 +++ bind9-9.20.29/Makefile.in 2026-09-11 19:42:17.980174673 +0000 @@ -330,6 +330,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/NEWS bind9-9.20.29/NEWS --- bind9-9.20.26/NEWS 2026-07-20 14:47:53.944848109 +0000 +++ bind9-9.20.29/NEWS 2026-09-11 19:41:01.414328914 +0000 @@ -18,6 +18,9 @@ development. Regular users should refer to :ref:`Release Notes ` for changes relevant to them. +.. include:: ../changelog/changelog-9.20.29.rst +.. include:: ../changelog/changelog-9.20.28.rst +.. include:: ../changelog/changelog-9.20.27.rst .. include:: ../changelog/changelog-9.20.26.rst .. include:: ../changelog/changelog-9.20.25.rst .. include:: ../changelog/changelog-9.20.24.rst diff -Nru bind9-9.20.26/bin/Makefile.in bind9-9.20.29/bin/Makefile.in --- bind9-9.20.26/bin/Makefile.in 2026-07-20 14:49:10.018568502 +0000 +++ bind9-9.20.29/bin/Makefile.in 2026-09-11 19:42:17.995175038 +0000 @@ -270,6 +270,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/check/Makefile.in bind9-9.20.29/bin/check/Makefile.in --- bind9-9.20.26/bin/check/Makefile.in 2026-07-20 14:49:10.048569192 +0000 +++ bind9-9.20.29/bin/check/Makefile.in 2026-09-11 19:42:18.025175769 +0000 @@ -289,6 +289,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/confgen/Makefile.in bind9-9.20.29/bin/confgen/Makefile.in --- bind9-9.20.26/bin/confgen/Makefile.in 2026-07-20 14:49:10.077569858 +0000 +++ bind9-9.20.29/bin/confgen/Makefile.in 2026-09-11 19:42:18.052176427 +0000 @@ -288,6 +288,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/confgen/keygen.c bind9-9.20.29/bin/confgen/keygen.c --- bind9-9.20.26/bin/confgen/keygen.c 2026-07-20 14:47:53.567840690 +0000 +++ bind9-9.20.29/bin/confgen/keygen.c 2026-09-11 19:41:01.052320206 +0000 @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -88,6 +89,33 @@ } } +/*% + * Reject invalid key names and make them safe for embedding into + * rndc.conf and named.conf. + */ +void +makesafe_keyname(const char *keyname, char *namebuf, size_t length) { + dns_fixedname_t fixed; + dns_name_t *name = dns_fixedname_initname(&fixed); + isc_result_t result; + isc_buffer_t b; + + if (keyname == NULL || keyname[0] == '\0') { + fatal("key name must not be empty"); + } + result = dns_name_fromstring(name, keyname, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fatal("invalid key name: %s", isc_result_totext(result)); + } + + isc_buffer_init(&b, namebuf, length); + result = dns_name_totext(name, DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, + &b); + if (result != ISC_R_SUCCESS) { + fatal("invalid key name: %s", isc_result_totext(result)); + } +} + /*% * Generate a key of size 'keysize' and place it in 'key_txtbuffer' */ diff -Nru bind9-9.20.26/bin/confgen/keygen.h bind9-9.20.29/bin/confgen/keygen.h --- bind9-9.20.26/bin/confgen/keygen.h 2026-07-20 14:47:53.567840690 +0000 +++ bind9-9.20.29/bin/confgen/keygen.h 2026-09-11 19:41:01.052320206 +0000 @@ -24,6 +24,9 @@ ISC_LANG_BEGINDECLS void +makesafe_keyname(const char *keyname, char *namebuf, size_t length); + +void generate_key(isc_mem_t *mctx, dns_secalg_t alg, int keysize, isc_buffer_t *key_txtbuffer); diff -Nru bind9-9.20.26/bin/confgen/rndc-confgen.c bind9-9.20.29/bin/confgen/rndc-confgen.c --- bind9-9.20.26/bin/confgen/rndc-confgen.c 2026-07-20 14:47:53.567840690 +0000 +++ bind9-9.20.29/bin/confgen/rndc-confgen.c 2026-09-11 19:41:01.052320206 +0000 @@ -91,6 +91,7 @@ char key_txtsecret[256]; isc_mem_t *mctx = NULL; isc_result_t result = ISC_R_SUCCESS; + char namebuf[DNS_NAME_FORMATSIZE]; const char *keyname = NULL; const char *serveraddr = NULL; dns_secalg_t alg; @@ -123,7 +124,7 @@ isc_commandline_errprint = false; while ((ch = isc_commandline_parse(argc, argv, - "aA:b:c:hk:Mmp:r:s:t:u:Vy")) != -1) + "aA:b:c:hk:Mmp:qr:s:t:u:Vy")) != -1) { switch (ch) { case 'a': @@ -213,6 +214,8 @@ usage(EXIT_FAILURE); } + makesafe_keyname(keyname, namebuf, sizeof(namebuf)); + if (alg == DST_ALG_HMACMD5) { fprintf(stderr, "warning: use of hmac-md5 for RNDC keys " "is deprecated; hmac-sha256 is now " @@ -231,7 +234,7 @@ if (keyonly) { write_key_file(keyfile, chrootdir == NULL ? user : NULL, - keyname, &key_txtbuffer, alg); + namebuf, &key_txtbuffer, alg); if (!quiet) { printf("wrote key file \"%s\"\n", keyfile); } @@ -243,7 +246,7 @@ snprintf(buf, len, "%s%s%s", chrootdir, (*keyfile != '/') ? "/" : "", keyfile); - write_key_file(buf, user, keyname, &key_txtbuffer, alg); + write_key_file(buf, user, namebuf, &key_txtbuffer, alg); if (!quiet) { printf("wrote key file \"%s\"\n", buf); } @@ -275,13 +278,13 @@ # allow { %s; } keys { \"%s\"; };\n\ # };\n\ # End of named.conf\n", - keyname, algname, + namebuf, algname, (int)isc_buffer_usedlength(&key_txtbuffer), - (char *)isc_buffer_base(&key_txtbuffer), keyname, - serveraddr, port, keyname, algname, + (char *)isc_buffer_base(&key_txtbuffer), namebuf, + serveraddr, port, namebuf, algname, (int)isc_buffer_usedlength(&key_txtbuffer), (char *)isc_buffer_base(&key_txtbuffer), serveraddr, - port, serveraddr, keyname); + port, serveraddr, namebuf); } if (show_final_mem) { diff -Nru bind9-9.20.26/bin/confgen/rndc-confgen.rst bind9-9.20.29/bin/confgen/rndc-confgen.rst --- bind9-9.20.26/bin/confgen/rndc-confgen.rst 2026-07-20 14:47:53.567840690 +0000 +++ bind9-9.20.29/bin/confgen/rndc-confgen.rst 2026-09-11 19:41:01.052320206 +0000 @@ -72,8 +72,10 @@ .. option:: -k keyname - This option specifies the key name of the :iscman:`rndc` authentication key. This must be a - valid domain name. The default is ``rndc-key``. + This option specifies the key name of the :iscman:`rndc` + authentication key. This must be a valid domain name and will + be sanitized using the domain name semantics. The default is + ``rndc-key``. .. option:: -p port diff -Nru bind9-9.20.26/bin/confgen/tsig-keygen.c bind9-9.20.29/bin/confgen/tsig-keygen.c --- bind9-9.20.26/bin/confgen/tsig-keygen.c 2026-07-20 14:47:53.567840690 +0000 +++ bind9-9.20.29/bin/confgen/tsig-keygen.c 2026-09-11 19:41:01.052320206 +0000 @@ -87,6 +87,7 @@ isc_buffer_t key_txtbuffer; char key_txtsecret[256]; isc_mem_t *mctx = NULL; + char namebuf[DNS_NAME_FORMATSIZE]; const char *keyname = NULL; const char *zone = NULL; const char *self_domain = NULL; @@ -230,6 +231,8 @@ } } + makesafe_keyname(keyname, namebuf, sizeof(namebuf)); + isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret)); generate_key(mctx, alg, keysize, &key_txtbuffer); @@ -246,7 +249,7 @@ algorithm %s;\n\ secret \"%.*s\";\n\ };\n", - keyname, algname, (int)isc_buffer_usedlength(&key_txtbuffer), + namebuf, algname, (int)isc_buffer_usedlength(&key_txtbuffer), (char *)isc_buffer_base(&key_txtbuffer)); if (!quiet) { @@ -258,7 +261,7 @@ update-policy {\n\ grant %s name %s ANY;\n\ };\n", - self_domain, keyname, self_domain); + self_domain, namebuf, self_domain); } else if (zone != NULL) { printf("\n\ # Then, in the \"zone\" definition statement for \"%s\",\n\ @@ -267,7 +270,7 @@ update-policy {\n\ grant %s zonesub ANY;\n\ };\n", - zone, keyname); + zone, namebuf); } else { printf("\n\ # Then, in the \"zone\" statement for each zone you wish to dynamically\n\ @@ -277,7 +280,7 @@ update-policy {\n\ grant %s zonesub ANY;\n\ };\n", - keyname); + namebuf); } printf("\n\ diff -Nru bind9-9.20.26/bin/delv/Makefile.in bind9-9.20.29/bin/delv/Makefile.in --- bind9-9.20.26/bin/delv/Makefile.in 2026-07-20 14:49:10.102570432 +0000 +++ bind9-9.20.29/bin/delv/Makefile.in 2026-09-11 19:42:18.076177011 +0000 @@ -275,6 +275,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/dig/Makefile.in bind9-9.20.29/bin/dig/Makefile.in --- bind9-9.20.26/bin/dig/Makefile.in 2026-07-20 14:49:10.131571098 +0000 +++ bind9-9.20.29/bin/dig/Makefile.in 2026-09-11 19:42:18.106177742 +0000 @@ -299,6 +299,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/dig/dig.c bind9-9.20.29/bin/dig/dig.c --- bind9-9.20.26/bin/dig/dig.c 2026-07-20 14:47:53.569840740 +0000 +++ bind9-9.20.29/bin/dig/dig.c 2026-09-11 19:41:01.054320254 +0000 @@ -2614,8 +2614,8 @@ static const char *dash_opts = "46bcdfhikmnpqrtvyx"; static bool dash_option(char *option, char *next, dig_lookup_t **lookup, - bool *open_type_class, bool *need_clone, bool config_only, int argc, - char **argv, bool *firstarg) { + bool *open_type_class, bool *need_clone, bool config_only, + bool *added_lookup) { char opt, *value, *ptr, *ptr2, *ptr3, *last; isc_result_t result; bool value_from_next; @@ -2783,10 +2783,7 @@ (*lookup)->trace_root = ((*lookup)->trace || (*lookup)->ns_search_only); (*lookup)->new_search = true; - if (*firstarg) { - printgreeting(argc, argv, *lookup); - *firstarg = false; - } + *added_lookup = true; ISC_LIST_APPEND(lookup_list, *lookup, link); debug("looking up %s", (*lookup)->textname); } @@ -2894,10 +2891,7 @@ (*lookup)->rdclass = dns_rdataclass_in; } (*lookup)->new_search = true; - if (*firstarg) { - printgreeting(argc, argv, *lookup); - *firstarg = false; - } + *added_lookup = true; ISC_LIST_APPEND(lookup_list, *lookup, link); } else { fprintf(stderr, "Invalid IP address %s\n", value); @@ -3011,8 +3005,9 @@ parse_args(bool is_batchfile, bool config_only, int argc, char **argv) { isc_result_t result; isc_textregion_t tr; - bool firstarg = true; + bool added_lookup = false; dig_lookup_t *lookup = NULL; + dig_lookup_t *last_existing_lookup = ISC_LIST_TAIL(lookup_list); dns_rdatatype_t rdtype; dns_rdataclass_t rdclass; bool open_type_class = true; @@ -3125,8 +3120,7 @@ if (rc <= 1) { if (dash_option(&rv[0][1], NULL, &lookup, &open_type_class, &need_clone, - config_only, argc, argv, - &firstarg)) + config_only, &added_lookup)) { rc--; rv++; @@ -3134,8 +3128,7 @@ } else { if (dash_option(&rv[0][1], rv[1], &lookup, &open_type_class, &need_clone, - config_only, argc, argv, - &firstarg)) + config_only, &added_lookup)) { rc--; rv++; @@ -3239,10 +3232,7 @@ lookup->trace_root = (lookup->trace || lookup->ns_search_only); lookup->new_search = true; - if (firstarg) { - printgreeting(argc, argv, lookup); - firstarg = false; - } + added_lookup = true; ISC_LIST_APPEND(lookup_list, lookup, link); debug("looking up %s", lookup->textname); } @@ -3251,6 +3241,26 @@ } /* + * The whole command line has now been parsed, so every option is in + * its final state. Build the greeting only now: deferring it until + * here is what lets the banner reflect options such as +[no]cmd, + * +short and +yaml that may follow the query name on the command line. + * + * The greeting belongs to the first lookup this call appended. Because + * lookup_list is global and may already hold lookups on entry (e.g. + * "dig foo -f batchfile" queues "foo" before the batch file's first + * line is parsed), that first lookup is the one right after + * last_existing_lookup, or the list head if the list was empty. + */ + if (added_lookup) { + dig_lookup_t *greeting = + (last_existing_lookup != NULL) + ? ISC_LIST_NEXT(last_existing_lookup, link) + : ISC_LIST_HEAD(lookup_list); + printgreeting(argc, argv, greeting); + } + + /* * If we have a batchfile, seed the lookup list with the * first entry, then trust the callback in dighost_shutdown * to get the rest @@ -3300,10 +3310,7 @@ strlcpy(lookup->textname, ".", sizeof(lookup->textname)); lookup->rdtype = dns_rdatatype_ns; lookup->rdtypeset = true; - if (firstarg) { - printgreeting(argc, argv, lookup); - firstarg = false; - } + printgreeting(argc, argv, lookup); ISC_LIST_APPEND(lookup_list, lookup, link); } if (!need_clone) { @@ -3391,7 +3398,7 @@ dig_comments(dig_lookup_t *lookup, const char *format, ...) { va_list args; - if (lookup->comments && !yaml) { + if (lookup->comments && !yaml && !short_form) { printf(";; "); va_start(args, format); diff -Nru bind9-9.20.26/bin/dig/dighost.c bind9-9.20.29/bin/dig/dighost.c --- bind9-9.20.26/bin/dig/dighost.c 2026-07-20 14:47:53.570840765 +0000 +++ bind9-9.20.29/bin/dig/dighost.c 2026-09-11 19:41:01.055320278 +0000 @@ -3417,6 +3417,17 @@ return true; } +/* + * Print the lookup's startup banner. It is skipped in +yaml mode, where + * the ";"-prefixed banner is not valid YAML and would corrupt the output. + */ +static void +print_cmdline(const dig_lookup_t *l) { + if (!yaml) { + printf("%s", l->cmdline); + } +} + static void force_next(dig_query_t *query) { dig_lookup_t *l = NULL; @@ -3459,7 +3470,7 @@ dighost_error("no response from %s", buf); } else { - printf("%s", l->cmdline); + print_cmdline(l); dighost_error("no servers could be reached"); } @@ -4136,7 +4147,7 @@ * Otherwise, print the cmdline and an error message, * and cancel the lookup. */ - printf("%s", l->cmdline); + print_cmdline(l); dighost_error("no servers could be reached"); if (exitcode < 9) { @@ -4829,6 +4840,7 @@ char *dst = NULL; size_t srclen, dstlen; int res; + isc_result_t result; /* * Copy name from 'buffer' to 'src' and terminate it with NULL. @@ -4848,7 +4860,7 @@ } resetlocale(LC_ALL); if (res != IDN2_OK) { - return ISC_R_SUCCESS; + CLEANUP(ISC_R_SUCCESS); } /* @@ -4856,14 +4868,18 @@ */ dstlen = strlen(dst); if (isc_buffer_length(buffer) < start + dstlen) { - return ISC_R_NOSPACE; + CLEANUP(ISC_R_NOSPACE); } isc_buffer_subtract(buffer, srclen); memmove(isc_buffer_used(buffer), dst, dstlen); isc_buffer_add(buffer, dstlen); - idn2_free(dst); - return ISC_R_SUCCESS; + result = ISC_R_SUCCESS; +cleanup: + if (dst != NULL) { + idn2_free(dst); + } + return result; } /*% diff -Nru bind9-9.20.26/bin/dig/nslookup.c bind9-9.20.29/bin/dig/nslookup.c --- bind9-9.20.26/bin/dig/nslookup.c 2026-07-20 14:47:53.570840765 +0000 +++ bind9-9.20.29/bin/dig/nslookup.c 2026-09-11 19:41:01.055320278 +0000 @@ -808,7 +808,7 @@ } } -static void +static isc_result_t readline_next_command(void *arg) { char *ptr = NULL; @@ -818,7 +818,7 @@ ptr = readline("> "); isc_loopmgr_nonblocking(loopmgr); if (ptr == NULL) { - return; + return ISC_R_SUCCESS; } if (*ptr != 0) { @@ -827,13 +827,17 @@ cmdline = cmdlinebuf; } free(ptr); + + return ISC_R_SUCCESS; } -static void +static isc_result_t fgets_next_command(void *arg) { UNUSED(arg); cmdline = fgets(cmdlinebuf, COMMSIZE, stdin); + + return ISC_R_SUCCESS; } noreturn static void diff -Nru bind9-9.20.26/bin/dnssec/Makefile.in bind9-9.20.29/bin/dnssec/Makefile.in --- bind9-9.20.26/bin/dnssec/Makefile.in 2026-07-20 14:49:10.168571948 +0000 +++ bind9-9.20.29/bin/dnssec/Makefile.in 2026-09-11 19:42:18.141178594 +0000 @@ -345,6 +345,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/dnssec/dnssec-ksr.c bind9-9.20.29/bin/dnssec/dnssec-ksr.c --- bind9-9.20.26/bin/dnssec/dnssec-ksr.c 2026-07-20 14:47:53.572840815 +0000 +++ bind9-9.20.29/bin/dnssec/dnssec-ksr.c 2026-09-11 19:41:01.058320351 +0000 @@ -18,6 +18,7 @@ #include #include +#include /* Required on GNU/Hurd */ #include #include #include diff -Nru bind9-9.20.26/bin/dnssec/dnssec-signzone.c bind9-9.20.29/bin/dnssec/dnssec-signzone.c --- bind9-9.20.26/bin/dnssec/dnssec-signzone.c 2026-07-20 14:47:53.574840865 +0000 +++ bind9-9.20.29/bin/dnssec/dnssec-signzone.c 2026-09-11 19:41:01.059320375 +0000 @@ -480,6 +480,30 @@ } } +static void +grow_arrays(unsigned int newarraysize, unsigned int *arraysize, + bool **wassignedby, bool **nowsignedby) { + bool *nwsb = isc_mem_cget(mctx, newarraysize, sizeof(bool)); + bool *nnsb = isc_mem_cget(mctx, newarraysize, sizeof(bool)); + unsigned int i; + + INSIST(newarraysize > *arraysize); + + for (i = 0; i < *arraysize; i++) { + nwsb[i] = (*wassignedby)[i]; + nnsb[i] = (*nowsignedby)[i]; + } + for (; i < newarraysize; i++) { + nwsb[i] = nnsb[i] = false; + } + + isc_mem_cput(mctx, *wassignedby, *arraysize, sizeof(bool)); + isc_mem_cput(mctx, *nowsignedby, *arraysize, sizeof(bool)); + *wassignedby = nwsb; + *nowsignedby = nnsb; + *arraysize = newarraysize; +} + /*% * Signs a set. Goes through contortions to decide if each RRSIG should * be dropped or retained, and then determines if any new SIGs need to @@ -495,10 +519,10 @@ isc_result_t result; bool nosigs = false; bool *wassignedby, *nowsignedby; - int arraysize; + unsigned int arraysize; dns_difftuple_t *tuple; dns_ttl_t ttl; - int i; + unsigned int i; char namestr[DNS_NAME_FORMATSIZE]; char typestr[DNS_RDATATYPE_FORMATSIZE]; char sigstr[SIG_FORMATSIZE]; @@ -524,7 +548,9 @@ vbprintf(1, "%s/%s:\n", namestr, typestr); + RWLOCK(&keylist_lock, isc_rwlocktype_read); arraysize = keycount; + RWUNLOCK(&keylist_lock, isc_rwlocktype_read); if (!nosigs) { arraysize += dns_rdataset_count(&sigset); } @@ -553,6 +579,15 @@ future = isc_serial_lt(now, rrsig.timesigned); key = keythatsigned(&rrsig); + + /* + * Grow arrays if needed. + */ + if (key != NULL && key->index >= arraysize) { + grow_arrays(key->index + 1, &arraysize, &wassignedby, + &nowsignedby); + } + offline = (key != NULL) ? key->pubkey : false; sig_format(&rrsig, sigstr, sizeof(sigstr)); expired = isc_serial_gt(now, rrsig.timeexpire); @@ -691,18 +726,31 @@ dns_rdataset_disassociate(&sigset); } + RWLOCK(&keylist_lock, isc_rwlocktype_read); for (key = ISC_LIST_HEAD(keylist); key != NULL; key = ISC_LIST_NEXT(key, link)) { + RWUNLOCK(&keylist_lock, isc_rwlocktype_read); if (REVOKE(key->key) && set->type != dns_rdatatype_dnskey) { + RWLOCK(&keylist_lock, isc_rwlocktype_read); continue; } + /* + * Grow arrays if needed. + */ + if (key->index >= arraysize) { + grow_arrays(key->index + 1, &arraysize, &wassignedby, + &nowsignedby); + } + if (nowsignedby[key->index]) { + RWLOCK(&keylist_lock, isc_rwlocktype_read); continue; } if (!issigningkey(key)) { + RWLOCK(&keylist_lock, isc_rwlocktype_read); continue; } @@ -715,21 +763,29 @@ dns_dnsseckey_t *curr; have_ksk = isksk(key); + RWLOCK(&keylist_lock, isc_rwlocktype_read); for (curr = ISC_LIST_HEAD(keylist); curr != NULL; curr = ISC_LIST_NEXT(curr, link)) { + RWUNLOCK(&keylist_lock, isc_rwlocktype_read); if (dst_key_alg(key->key) != dst_key_alg(curr->key)) { + RWLOCK(&keylist_lock, + isc_rwlocktype_read); continue; } if (REVOKE(curr->key)) { + RWLOCK(&keylist_lock, + isc_rwlocktype_read); continue; } if (isksk(curr)) { have_ksk = true; } + RWLOCK(&keylist_lock, isc_rwlocktype_read); } + RWUNLOCK(&keylist_lock, isc_rwlocktype_read); if (isksk(key) || !have_ksk || (iszsk(key) && !keyset_kskonly)) { @@ -756,17 +812,22 @@ * - Have key ID equal to the predecessor id. * - Have a successor that matches 'key' id. */ + RWLOCK(&keylist_lock, isc_rwlocktype_read); for (curr = ISC_LIST_HEAD(keylist); curr != NULL; curr = ISC_LIST_NEXT(curr, link)) { uint32_t suc; + RWUNLOCK(&keylist_lock, + isc_rwlocktype_read); if (dst_key_alg(key->key) != dst_key_alg(curr->key) || !iszsk(curr) || dst_key_id(curr->key) != pre) { + RWLOCK(&keylist_lock, + isc_rwlocktype_read); continue; } ret = dst_key_getnum(curr->key, @@ -775,8 +836,16 @@ if (ret != ISC_R_SUCCESS || dst_key_id(key->key) != suc) { + RWLOCK(&keylist_lock, + isc_rwlocktype_read); continue; } + if (curr->index >= arraysize) { + grow_arrays(curr->index + 1, + &arraysize, + &wassignedby, + &nowsignedby); + } /* * curr is the predecessor we were @@ -786,7 +855,10 @@ if (nowsignedby[curr->index]) { have_pre_sig = true; } + RWLOCK(&keylist_lock, + isc_rwlocktype_read); } + RWUNLOCK(&keylist_lock, isc_rwlocktype_read); } /* @@ -798,7 +870,9 @@ "signing with dnskey"); } } + RWLOCK(&keylist_lock, isc_rwlocktype_read); } + RWUNLOCK(&keylist_lock, isc_rwlocktype_read); isc_mem_cput(mctx, wassignedby, arraysize, sizeof(bool)); isc_mem_cput(mctx, nowsignedby, arraysize, sizeof(bool)); diff -Nru bind9-9.20.26/bin/dnssec/dnssec-verify.c bind9-9.20.29/bin/dnssec/dnssec-verify.c --- bind9-9.20.26/bin/dnssec/dnssec-verify.c 2026-07-20 14:47:53.574840865 +0000 +++ bind9-9.20.29/bin/dnssec/dnssec-verify.c 2026-09-11 19:41:01.059320375 +0000 @@ -65,12 +65,10 @@ const char *program = "dnssec-verify"; -static isc_stdtime_t now; static isc_mem_t *mctx = NULL; static dns_masterformat_t inputformat = dns_masterformat_text; static dns_db_t *gdb = NULL; /* The database */ static dns_dbversion_t *gversion = NULL; /* The database version */ -static dns_rdataclass_t gclass; /* The class */ static dns_name_t *gorigin = NULL; /* The database origin */ static bool ignore_kskflag = false; static bool keyset_kskonly = false; @@ -281,8 +279,6 @@ isc_result_totext(result)); } - now = isc_stdtime_now(); - rdclass = strtoclass(classname); setup_logging(mctx, &log); @@ -324,7 +320,6 @@ loadjournal(mctx, gdb, journal); } gorigin = dns_db_origin(gdb); - gclass = dns_db_class(gdb); gversion = NULL; result = dns_db_newversion(gdb, &gversion); diff -Nru bind9-9.20.26/bin/dnssec/dnssectool.c bind9-9.20.29/bin/dnssec/dnssectool.c --- bind9-9.20.26/bin/dnssec/dnssectool.c 2026-07-20 14:47:53.574840865 +0000 +++ bind9-9.20.29/bin/dnssec/dnssectool.c 2026-09-11 19:41:01.059320375 +0000 @@ -480,6 +480,8 @@ bool key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir, isc_mem_t *mctx, uint16_t min, uint16_t max, bool *exact) { + REQUIRE((min == 0 && max == 0) || min < max); + isc_result_t result; bool conflict = false; dns_dnsseckeylist_t matchkeys; @@ -647,12 +649,19 @@ ISC_LIST_INIT(kasplist); ISC_LIST_INIT(kslist); + /* Default key-directory key store. */ + result = cfg_keystore_fromconfig(NULL, mctx, lctx, engine, &kslist, + &ks); + if (result != ISC_R_SUCCESS) { + fatal("failed to configure default key-directory key-store: %s", + isc_result_totext(result)); + } + (void)cfg_map_get(config, "key-store", &keystores); for (element = cfg_list_first(keystores); element != NULL; element = cfg_list_next(element)) { cfg_obj_t *kconfig = cfg_listelt_value(element); - ks = NULL; result = cfg_keystore_fromconfig(kconfig, mctx, lctx, engine, &kslist, NULL); if (result != ISC_R_SUCCESS) { @@ -661,9 +670,7 @@ isc_result_totext(result)); } } - /* Default key-directory key store. */ - ks = NULL; - (void)cfg_keystore_fromconfig(NULL, mctx, lctx, engine, &kslist, &ks); + INSIST(ks != NULL); if (keydir != NULL) { /* '-K keydir' takes priority */ diff -Nru bind9-9.20.26/bin/named/Makefile.am bind9-9.20.29/bin/named/Makefile.am --- bind9-9.20.26/bin/named/Makefile.am 2026-07-20 14:47:53.574840865 +0000 +++ bind9-9.20.29/bin/named/Makefile.am 2026-09-11 19:41:01.060320399 +0000 @@ -107,6 +107,7 @@ $(MAXMINDDB_LIBS) \ $(DNSTAP_LIBS) \ $(LIBUV_LIBS) \ + $(LIBSCF_LIBS) \ $(ZLIB_LIBS) if HAVE_JSON_C diff -Nru bind9-9.20.26/bin/named/Makefile.in bind9-9.20.29/bin/named/Makefile.in --- bind9-9.20.26/bin/named/Makefile.in 2026-07-20 14:49:10.197572614 +0000 +++ bind9-9.20.29/bin/named/Makefile.in 2026-09-11 19:42:18.170179301 +0000 @@ -183,8 +183,9 @@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_3) \ - $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_5) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) \ + $(am__DEPENDENCIES_5) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent @@ -335,6 +336,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ @@ -546,8 +548,8 @@ named_LDADD = $(LIBISC_LIBS) $(LIBDNS_LIBS) $(LIBNS_LIBS) \ $(LIBISCCC_LIBS) $(LIBISCCFG_LIBS) $(OPENSSL_LIBS) \ $(LIBCAP_LIBS) $(LMDB_LIBS) $(MAXMINDDB_LIBS) $(DNSTAP_LIBS) \ - $(LIBUV_LIBS) $(ZLIB_LIBS) $(am__append_7) $(am__append_8) \ - $(am__append_9) + $(LIBUV_LIBS) $(LIBSCF_LIBS) $(ZLIB_LIBS) $(am__append_7) \ + $(am__append_8) $(am__append_9) all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am diff -Nru bind9-9.20.26/bin/named/config.c bind9-9.20.29/bin/named/config.c --- bind9-9.20.26/bin/named/config.c 2026-07-20 14:47:53.575840890 +0000 +++ bind9-9.20.29/bin/named/config.c 2026-09-11 19:41:01.060320399 +0000 @@ -671,7 +671,6 @@ const cfg_obj_t *key; const cfg_obj_t *tls; - skiplist: addr = cfg_tuple_get(cfg_listelt_value(element), "remoteselement"); key = cfg_tuple_get(cfg_listelt_value(element), "key"); @@ -696,14 +695,13 @@ for (size_t i = 0; i < s->seencount; i++) { if (strcasecmp(s->seen[i], listname) == 0) { - element = cfg_list_next(element); goto skiplist; } } grow_array(mctx, s->seen, s->seencount, s->seenallocated); - s->seen[s->seencount] = listname; + s->seen[s->seencount++] = listname; for (size_t i = 0; i < ARRAY_SIZE(remotesnames); i++) { tresult = named_config_getremotesdef( @@ -718,12 +716,17 @@ cfg_obj_log(addr, named_g_lctx, ISC_LOG_ERROR, "remote-servers \"%s\" not found", listname); + /* Pop the list from the active recursion stack. + */ + s->seencount--; return tresult; } result = getipandkeylist(defport, deftlsport, config, nestedlist, port, key, tls, mctx, s); + /* Pop the list from the active recursion stack. */ + s->seencount--; if (result != ISC_R_SUCCESS) { goto out; } @@ -799,6 +802,8 @@ } s->count++; + skiplist: + continue; } out: diff -Nru bind9-9.20.26/bin/named/geoip.c bind9-9.20.29/bin/named/geoip.c --- bind9-9.20.26/bin/named/geoip.c 2026-07-20 14:47:53.576840915 +0000 +++ bind9-9.20.29/bin/named/geoip.c 2026-09-11 19:41:01.061320423 +0000 @@ -83,6 +83,8 @@ NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "looking for GeoIP2 databases in '%s'", dir); + dns_geoip_invalidate(); + named_g_geoip->country = open_geoip2(dir, "GeoIP2-Country.mmdb", &geoip_country); if (named_g_geoip->country == NULL) { @@ -115,6 +117,7 @@ void named_geoip_unload(void) { #ifdef HAVE_GEOIP2 + dns_geoip_invalidate(); if (named_g_geoip->country != NULL) { MMDB_close(named_g_geoip->country); named_g_geoip->country = NULL; diff -Nru bind9-9.20.26/bin/named/include/named/tkeyconf.h bind9-9.20.29/bin/named/include/named/tkeyconf.h --- bind9-9.20.26/bin/named/include/named/tkeyconf.h 2026-07-20 14:47:53.577840940 +0000 +++ bind9-9.20.29/bin/named/include/named/tkeyconf.h 2026-09-11 19:41:01.062320447 +0000 @@ -27,10 +27,10 @@ dns_tkeyctx_t **tctxp); /*%< * Create a TKEY context and configure it, including the default DH key - * and default domain, according to 'options'. + * and default domain, according to 'options', if present. * * Requires: - *\li 'cfg' is a valid configuration options object. + *\li 'options' is NULL or a valid configuration options object. *\li 'mctx' is not NULL *\li 'tctx' is not NULL *\li '*tctx' is NULL diff -Nru bind9-9.20.26/bin/named/main.c bind9-9.20.29/bin/named/main.c --- bind9-9.20.26/bin/named/main.c 2026-07-20 14:47:53.578840965 +0000 +++ bind9-9.20.29/bin/named/main.c 2026-09-11 19:41:01.063320471 +0000 @@ -845,7 +845,7 @@ value = arg + 6; ptype = HTTPSPORT; } else if (strncmp(arg, "http=", 5) == 0) { - value = arg + 6; + value = arg + 5; ptype = HTTPPORT; } @@ -1082,6 +1082,7 @@ ns_server_t *sctx; #ifdef HAVE_LIBSCF char *instance = NULL; + isc_mem_t *smf_mctx = NULL; #endif /* ifdef HAVE_LIBSCF */ /* @@ -1099,8 +1100,13 @@ named_os_opendevnull(); #ifdef HAVE_LIBSCF - /* Check if named is under smf control, before chroot. */ - result = named_smf_get_instance(&instance, 0, named_g_mctx); + /* + * Check if named is under smf control, before chroot. This runs + * long before create_managers() sets up named_g_mctx, so use a + * private memory context for the instance name. + */ + isc_mem_create(&smf_mctx); + result = named_smf_get_instance(&instance, 0, smf_mctx); /* We don't care about instance, just check if we got one. */ if (result == ISC_R_SUCCESS) { named_smf_got_instance = 1; @@ -1108,8 +1114,9 @@ named_smf_got_instance = 0; } if (instance != NULL) { - isc_mem_free(named_g_mctx, instance); + isc_mem_free(smf_mctx, instance); } + isc_mem_destroy(&smf_mctx); #endif /* HAVE_LIBSCF */ /* diff -Nru bind9-9.20.26/bin/named/server.c bind9-9.20.29/bin/named/server.c --- bind9-9.20.26/bin/named/server.c 2026-07-20 14:47:53.580841015 +0000 +++ bind9-9.20.29/bin/named/server.c 2026-09-11 19:41:01.065320520 +0000 @@ -9474,23 +9474,20 @@ cachelist = tmpcachelist; /* Load the TKEY information from the configuration. */ - if (options != NULL) { - dns_tkeyctx_t *tkeyctx = NULL; + dns_tkeyctx_t *tkeyctx = NULL; - result = named_tkeyctx_fromconfig(options, named_g_mctx, - &tkeyctx); - if (result != ISC_R_SUCCESS) { - isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, - NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, - "configuring TKEY: %s", - isc_result_totext(result)); - goto cleanup_cachelist; - } - if (server->sctx->tkeyctx != NULL) { - dns_tkeyctx_destroy(&server->sctx->tkeyctx); - } - server->sctx->tkeyctx = tkeyctx; + result = named_tkeyctx_fromconfig(options, named_g_mctx, &tkeyctx); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "configuring TKEY: %s", + isc_result_totext(result)); + goto cleanup_cachelist; } + if (server->sctx->tkeyctx != NULL) { + dns_tkeyctx_destroy(&server->sctx->tkeyctx); + } + server->sctx->tkeyctx = tkeyctx; #ifdef HAVE_LMDB /* @@ -12573,7 +12570,11 @@ * if some of the views share a single cache. But since the * operation is lightweight we prefer simplicity here. */ - result = dns_view_flushnode(view, name, tree); + if (dns_name_equal(name, dns_rootname)) { + result = dns_view_flushcache(view, false); + } else { + result = dns_view_flushnode(view, name, tree); + } if (result != ISC_R_SUCCESS) { flushed = false; isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, @@ -13093,9 +13094,16 @@ */ isc_result_t named_smf_add_message(isc_buffer_t **text) { + isc_result_t result; + REQUIRE(text != NULL); - return putstr(text, "use svcadm(1M) to manage named"); + CHECK(putstr(text, "use svcadm(1M) to manage named")); + CHECK(putnull(text)); + + return ISC_R_SUCCESS; +cleanup: + return result; } #endif /* HAVE_LIBSCF */ diff -Nru bind9-9.20.26/bin/named/tkeyconf.c bind9-9.20.29/bin/named/tkeyconf.c --- bind9-9.20.26/bin/named/tkeyconf.c 2026-07-20 14:47:53.581841040 +0000 +++ bind9-9.20.29/bin/named/tkeyconf.c 2026-09-11 19:41:01.066320544 +0000 @@ -50,22 +50,26 @@ return result; } - result = cfg_map_get(options, "tkey-gssapi-credential", &obj); - if (result == ISC_R_SUCCESS) { - s = cfg_obj_asstring(obj); + if (options != NULL) { + result = cfg_map_get(options, "tkey-gssapi-credential", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(obj); - isc_buffer_constinit(&b, s, strlen(s)); - isc_buffer_add(&b, strlen(s)); - name = dns_fixedname_initname(&fname); - CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL)); - CHECK(dst_gssapi_acquirecred(name, false, &tctx->gsscred)); - } + isc_buffer_constinit(&b, s, strlen(s)); + isc_buffer_add(&b, strlen(s)); + name = dns_fixedname_initname(&fname); + CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, + NULL)); + CHECK(dst_gssapi_acquirecred(name, false, + &tctx->gsscred)); + } - obj = NULL; - result = cfg_map_get(options, "tkey-gssapi-keytab", &obj); - if (result == ISC_R_SUCCESS) { - s = cfg_obj_asstring(obj); - tctx->gssapi_keytab = isc_mem_strdup(mctx, s); + obj = NULL; + result = cfg_map_get(options, "tkey-gssapi-keytab", &obj); + if (result == ISC_R_SUCCESS) { + s = cfg_obj_asstring(obj); + tctx->gssapi_keytab = isc_mem_strdup(mctx, s); + } } *tctxp = tctx; diff -Nru bind9-9.20.26/bin/nsupdate/Makefile.in bind9-9.20.29/bin/nsupdate/Makefile.in --- bind9-9.20.26/bin/nsupdate/Makefile.in 2026-07-20 14:49:10.223573212 +0000 +++ bind9-9.20.29/bin/nsupdate/Makefile.in 2026-09-11 19:42:18.196179934 +0000 @@ -281,6 +281,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/plugins/Makefile.in bind9-9.20.29/bin/plugins/Makefile.in --- bind9-9.20.26/bin/plugins/Makefile.in 2026-07-20 14:49:10.249573809 +0000 +++ bind9-9.20.29/bin/plugins/Makefile.in 2026-09-11 19:42:18.221180543 +0000 @@ -305,6 +305,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/rndc/Makefile.in bind9-9.20.29/bin/rndc/Makefile.in --- bind9-9.20.26/bin/rndc/Makefile.in 2026-07-20 14:49:10.274574383 +0000 +++ bind9-9.20.29/bin/rndc/Makefile.in 2026-09-11 19:42:18.246181152 +0000 @@ -275,6 +275,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/tests/Makefile.in bind9-9.20.29/bin/tests/Makefile.in --- bind9-9.20.26/bin/tests/Makefile.in 2026-07-20 14:49:10.303575049 +0000 +++ bind9-9.20.29/bin/tests/Makefile.in 2026-09-11 19:42:18.276181883 +0000 @@ -324,6 +324,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/tests/system/COOKBOOK.md bind9-9.20.29/bin/tests/system/COOKBOOK.md --- bind9-9.20.26/bin/tests/system/COOKBOOK.md 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/COOKBOOK.md 2026-09-11 19:41:01.070320640 +0000 @@ -69,34 +69,43 @@ ``` `demo/ns1/named.conf.j2` — the config template; the runner renders it to -`named.conf` at setup time, filling in the assigned ports. Templates inside -an `nsN`/`ansN` subdirectory also get an `ns` variable describing that -server, so the config doesn't hardcode its own address (`@ns.ip@` renders to -10.53.0.1 in ns1, 10.53.0.2 in ns2, ...): +`named.conf` at setup time, filling in the assigned ports: ```jinja options { - query-source address @ns.ip@; - notify-source @ns.ip@; - transfer-source @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; - recursion no; - dnssec-validation no; + {% include_indented "_common/options.conf.j2" %} + recursion no; + dnssec-validation no; }; {% include "_common/controls.conf.j2" %} zone "example" { - type primary; - file "example.db"; + type primary; + file "example.db"; }; ``` +The `_common/options.conf.j2` include expands to the standard plumbing +(configuring interfaces, source addresses, port and pid file). Write only the +options your test actually cares about below the include. When the standard +block doesn't fit, compose the pieces from `_common/options/` instead and put +anything nonstandard inline. + +The plumbing templates are built on the `ns` variable: templates inside an +`nsN`/`ansN` subdirectory automatically get one describing that server, so a +config never hardcodes its own address — `@ns.ip@` renders to 10.53.0.1 in +ns1, 10.53.0.2 in ns2, ..., and `@ns.ip6@` to the matching +fd92:7065:b8e:ffff::N address. Use it wherever a config refers to the +instance's own address; references to *other* servers stay literal. + The `_common/controls.conf.j2` include sets up the rndc control channel, so -the test (and the runner's shutdown sequence) can use `rndc`. +the test (and the runner's shutdown sequence) can use `rndc`. A resolver +instance would also include `_common/root.hint.conf` to get the standard +root hints (ns1 is the root server by convention). Inside an indented +section such as a view statement, use `{% include_indented "..." %}` instead +of `{% include %}` — it aligns the inserted block with the tag's own +indentation. `demo/ns1/example.db` — a plain zone file: diff -Nru bind9-9.20.26/bin/tests/system/Makefile.am bind9-9.20.29/bin/tests/system/Makefile.am --- bind9-9.20.26/bin/tests/system/Makefile.am 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/Makefile.am 2026-09-11 19:41:01.070320640 +0000 @@ -95,6 +95,7 @@ checkds \ checknames \ checkzone \ + cname_recursion \ cookie \ cpu \ database \ @@ -143,6 +144,7 @@ names \ notify \ nsec3 \ + nsec_wildcard_wrong_zone \ nslookup \ nsupdate \ nzd2nzf \ @@ -157,19 +159,6 @@ resolver \ rndc \ rollover \ - rollover_algo_csk \ - rollover_algo_ksk_zsk \ - rollover_csk_roll1 \ - rollover_csk_roll2 \ - rollover_dynamic2inline \ - rollover_enable_dnssec \ - rollover_going_insecure \ - rollover_ksk_3crowd \ - rollover_ksk_doubleksk \ - rollover_lifetime \ - rollover_multisigner \ - rollover_straight2none \ - rollover_zsk_prepub \ rootkeysentinel \ rpzextra \ rrchecker \ diff -Nru bind9-9.20.26/bin/tests/system/Makefile.in bind9-9.20.29/bin/tests/system/Makefile.in --- bind9-9.20.26/bin/tests/system/Makefile.in 2026-07-20 14:49:10.368576543 +0000 +++ bind9-9.20.29/bin/tests/system/Makefile.in 2026-09-11 19:42:18.340183441 +0000 @@ -558,6 +558,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ @@ -809,6 +810,7 @@ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ checkds \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ checknames \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ checkzone \ +@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ cname_recursion \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ cookie \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ cpu \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ database \ @@ -857,6 +859,7 @@ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ names \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ notify \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ nsec3 \ +@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ nsec_wildcard_wrong_zone \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ nslookup \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ nsupdate \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ nzd2nzf \ @@ -871,19 +874,6 @@ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ resolver \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rndc \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_algo_csk \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_algo_ksk_zsk \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_csk_roll1 \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_csk_roll2 \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_dynamic2inline \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_enable_dnssec \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_going_insecure \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_ksk_3crowd \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_ksk_doubleksk \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_lifetime \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_multisigner \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_straight2none \ -@HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rollover_zsk_prepub \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rootkeysentinel \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rpzextra \ @HAVE_PERL_TRUE@@HAVE_PYTEST_TRUE@@HAVE_PYTHON_TRUE@ rrchecker \ @@ -1546,6 +1536,13 @@ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +cname_recursion.log: cname_recursion + @p='cname_recursion'; \ + b='cname_recursion'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) cookie.log: cookie @p='cookie'; \ b='cookie'; \ @@ -1882,6 +1879,13 @@ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +nsec_wildcard_wrong_zone.log: nsec_wildcard_wrong_zone + @p='nsec_wildcard_wrong_zone'; \ + b='nsec_wildcard_wrong_zone'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) nslookup.log: nslookup @p='nslookup'; \ b='nslookup'; \ @@ -1979,97 +1983,6 @@ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_algo_csk.log: rollover_algo_csk - @p='rollover_algo_csk'; \ - b='rollover_algo_csk'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_algo_ksk_zsk.log: rollover_algo_ksk_zsk - @p='rollover_algo_ksk_zsk'; \ - b='rollover_algo_ksk_zsk'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_csk_roll1.log: rollover_csk_roll1 - @p='rollover_csk_roll1'; \ - b='rollover_csk_roll1'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_csk_roll2.log: rollover_csk_roll2 - @p='rollover_csk_roll2'; \ - b='rollover_csk_roll2'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_dynamic2inline.log: rollover_dynamic2inline - @p='rollover_dynamic2inline'; \ - b='rollover_dynamic2inline'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_enable_dnssec.log: rollover_enable_dnssec - @p='rollover_enable_dnssec'; \ - b='rollover_enable_dnssec'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_going_insecure.log: rollover_going_insecure - @p='rollover_going_insecure'; \ - b='rollover_going_insecure'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_ksk_3crowd.log: rollover_ksk_3crowd - @p='rollover_ksk_3crowd'; \ - b='rollover_ksk_3crowd'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_ksk_doubleksk.log: rollover_ksk_doubleksk - @p='rollover_ksk_doubleksk'; \ - b='rollover_ksk_doubleksk'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_lifetime.log: rollover_lifetime - @p='rollover_lifetime'; \ - b='rollover_lifetime'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_multisigner.log: rollover_multisigner - @p='rollover_multisigner'; \ - b='rollover_multisigner'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_straight2none.log: rollover_straight2none - @p='rollover_straight2none'; \ - b='rollover_straight2none'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -rollover_zsk_prepub.log: rollover_zsk_prepub - @p='rollover_zsk_prepub'; \ - b='rollover_zsk_prepub'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) rootkeysentinel.log: rootkeysentinel @p='rootkeysentinel'; \ diff -Nru bind9-9.20.26/bin/tests/system/README.md bind9-9.20.29/bin/tests/system/README.md --- bind9-9.20.26/bin/tests/system/README.md 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/README.md 2026-09-11 19:41:01.070320640 +0000 @@ -229,9 +229,6 @@ - `setup.sh`: Legacy shell test setup. New tests use templates and a `bootstrap()` function instead. -- `prereq.sh`: Legacy prerequisite check; when it exits non-zero, the test is - skipped. New tests use pytest marks (see `isctest/mark.py`). - ### Module Scope A module is a python file which contains test functions. Every system @@ -275,15 +272,8 @@ ```jinja options { - port @PORT@; - listen-on { 10.53.0.1; }; -}; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; + {% include_indented "_common/options.conf.j2" %} + tls-port @TLSPORT@; }; ``` diff -Nru bind9-9.20.26/bin/tests/system/_common/options/listen-dual.conf.j2 bind9-9.20.29/bin/tests/system/_common/options/listen-dual.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/options/listen-dual.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/_common/options/listen-dual.conf.j2 2026-09-11 19:41:01.070320640 +0000 @@ -0,0 +1,2 @@ +listen-on { @ns.ip@; }; +listen-on-v6 { @ns.ip6@; }; diff -Nru bind9-9.20.26/bin/tests/system/_common/options/listen.conf.j2 bind9-9.20.29/bin/tests/system/_common/options/listen.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/options/listen.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/_common/options/listen.conf.j2 2026-09-11 19:41:01.070320640 +0000 @@ -0,0 +1,2 @@ +listen-on { @ns.ip@; }; +listen-on-v6 { none; }; diff -Nru bind9-9.20.26/bin/tests/system/_common/options/server.conf.j2 bind9-9.20.29/bin/tests/system/_common/options/server.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/options/server.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/_common/options/server.conf.j2 2026-09-11 19:41:01.070320640 +0000 @@ -0,0 +1,2 @@ +port @PORT@; +pid-file "named.pid"; diff -Nru bind9-9.20.26/bin/tests/system/_common/options/sources-dual.conf.j2 bind9-9.20.29/bin/tests/system/_common/options/sources-dual.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/options/sources-dual.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/_common/options/sources-dual.conf.j2 2026-09-11 19:41:01.071320665 +0000 @@ -0,0 +1,2 @@ +{% include "_common/options/sources.conf.j2" %} +{% include "_common/options/sources-v6.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/_common/options/sources-v6.conf.j2 bind9-9.20.29/bin/tests/system/_common/options/sources-v6.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/options/sources-v6.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/_common/options/sources-v6.conf.j2 2026-09-11 19:41:01.071320665 +0000 @@ -0,0 +1,3 @@ +query-source-v6 address @ns.ip6@; +notify-source-v6 @ns.ip6@; +transfer-source-v6 @ns.ip6@; diff -Nru bind9-9.20.26/bin/tests/system/_common/options/sources.conf.j2 bind9-9.20.29/bin/tests/system/_common/options/sources.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/options/sources.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/_common/options/sources.conf.j2 2026-09-11 19:41:01.071320665 +0000 @@ -0,0 +1,3 @@ +query-source address @ns.ip@; +notify-source @ns.ip@; +transfer-source @ns.ip@; diff -Nru bind9-9.20.26/bin/tests/system/_common/options-dual.conf.j2 bind9-9.20.29/bin/tests/system/_common/options-dual.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/options-dual.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/_common/options-dual.conf.j2 2026-09-11 19:41:01.070320640 +0000 @@ -0,0 +1,3 @@ +{% include "_common/options/sources-dual.conf.j2" %} +{% include "_common/options/server.conf.j2" %} +{% include "_common/options/listen-dual.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/_common/options.conf.j2 bind9-9.20.29/bin/tests/system/_common/options.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/options.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/_common/options.conf.j2 2026-09-11 19:41:01.070320640 +0000 @@ -0,0 +1,3 @@ +{% include "_common/options/sources.conf.j2" %} +{% include "_common/options/server.conf.j2" %} +{% include "_common/options/listen.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/_common/zones/ns.partial.db.j2 bind9-9.20.29/bin/tests/system/_common/zones/ns.partial.db.j2 --- bind9-9.20.26/bin/tests/system/_common/zones/ns.partial.db.j2 2026-07-20 14:47:53.586841166 +0000 +++ bind9-9.20.29/bin/tests/system/_common/zones/ns.partial.db.j2 2026-09-11 19:41:01.071320665 +0000 @@ -1,2 +1,7 @@ +{% if ns.name != "." %} @zone.name@. NS @zone.ns.name@.@zone.name@. @zone.ns.name@.@zone.name@. A @zone.ns.ip@ +{% else %} +@zone.name@. NS @zone.name@. +@zone.name@. A 127.0.0.1 +{% endif %} diff -Nru bind9-9.20.26/bin/tests/system/_common/zones/soa.partial.db.j2 bind9-9.20.29/bin/tests/system/_common/zones/soa.partial.db.j2 --- bind9-9.20.26/bin/tests/system/_common/zones/soa.partial.db.j2 2026-07-20 14:47:53.586841166 +0000 +++ bind9-9.20.29/bin/tests/system/_common/zones/soa.partial.db.j2 2026-09-11 19:41:01.071320665 +0000 @@ -2,7 +2,11 @@ $ORIGIN @zone.name@. {% endif %} $TTL 300 +{% if zone.ns.name == "." %} +{% raw %}@{% endraw %} IN SOA @zone.name@. . ( +{% else %} {% raw %}@{% endraw %} IN SOA @zone.ns.name@.@zone.name@. . ( +{% endif %} 1 ; serial 20 ; refresh (20 seconds) 20 ; retry (20 seconds) diff -Nru bind9-9.20.26/bin/tests/system/_common/zones.conf.j2 bind9-9.20.29/bin/tests/system/_common/zones.conf.j2 --- bind9-9.20.26/bin/tests/system/_common/zones.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/_common/zones.conf.j2 2026-09-11 19:41:01.071320665 +0000 @@ -4,7 +4,7 @@ zone "@zone.name@" { type @zone.type@; {% if zone.type == "static-stub" %} - server-addresses { @zone.ns.ip@; }; + server-addresses { @zone.ns.ip@; }; {% else %} file "@zone.filepath@"; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/acl/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/acl/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/acl/ns2/named.conf.j2 2026-07-20 14:47:53.586841166 +0000 +++ bind9-9.20.29/bin/tests/system/acl/ns2/named.conf.j2 2026-09-11 19:41:01.072320689 +0000 @@ -11,25 +11,11 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; dnssec-validation no; @@ -45,10 +31,7 @@ secret "1234abcd8765"; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/acl/ns2/named2.conf.j2 bind9-9.20.29/bin/tests/system/acl/ns2/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/acl/ns2/named2.conf.j2 2026-07-20 14:47:53.586841166 +0000 +++ bind9-9.20.29/bin/tests/system/acl/ns2/named2.conf.j2 2026-09-11 19:41:01.072320689 +0000 @@ -11,25 +11,11 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; dnssec-validation no; @@ -45,10 +31,7 @@ secret "1234abcd8765"; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/acl/ns2/named3.conf.j2 bind9-9.20.29/bin/tests/system/acl/ns2/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/acl/ns2/named3.conf.j2 2026-07-20 14:47:53.586841166 +0000 +++ bind9-9.20.29/bin/tests/system/acl/ns2/named3.conf.j2 2026-09-11 19:41:01.072320689 +0000 @@ -11,25 +11,11 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; dnssec-validation no; @@ -55,13 +41,10 @@ }; acl accept { - 10.53.0.1; 10.53.0.2; + 10.53.0.1; @ns.ip@; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/acl/ns2/named4.conf.j2 bind9-9.20.29/bin/tests/system/acl/ns2/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/acl/ns2/named4.conf.j2 2026-07-20 14:47:53.586841166 +0000 +++ bind9-9.20.29/bin/tests/system/acl/ns2/named4.conf.j2 2026-09-11 19:41:01.072320689 +0000 @@ -11,25 +11,11 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; dnssec-validation no; @@ -50,17 +36,14 @@ }; acl rejectaddrs { - !10.53.0.1; !10.53.0.2; any; + !10.53.0.1; !@ns.ip@; any; }; acl check1 { !key one; 10.53.0.1; }; -acl check2 { !key two; 10.53.0.2; }; +acl check2 { !key two; @ns.ip@; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/acl/ns2/named5.conf.j2 bind9-9.20.29/bin/tests/system/acl/ns2/named5.conf.j2 --- bind9-9.20.26/bin/tests/system/acl/ns2/named5.conf.j2 2026-07-20 14:47:53.586841166 +0000 +++ bind9-9.20.29/bin/tests/system/acl/ns2/named5.conf.j2 2026-09-11 19:41:01.072320689 +0000 @@ -11,29 +11,15 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; dnssec-validation no; - allow-query-on { 10.53.0.2; }; + allow-query-on { @ns.ip@; }; blackhole { 10.53.0.8; }; }; @@ -47,10 +33,7 @@ secret "1234abcd8765"; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/acl/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/acl/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/acl/ns3/named.conf.j2 2026-07-20 14:47:53.587841191 +0000 +++ bind9-9.20.29/bin/tests/system/acl/ns3/named.conf.j2 2026-09-11 19:41:01.072320689 +0000 @@ -12,13 +12,7 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; allow-new-zones yes; @@ -26,11 +20,5 @@ dnssec-validation no; }; -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; diff -Nru bind9-9.20.26/bin/tests/system/acl/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/acl/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/acl/ns4/named.conf.j2 2026-07-20 14:47:53.587841191 +0000 +++ bind9-9.20.29/bin/tests/system/acl/ns4/named.conf.j2 2026-09-11 19:41:01.073320713 +0000 @@ -12,13 +12,7 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; allow-new-zones yes; @@ -26,14 +20,7 @@ dnssec-validation no; }; -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} zone "existing" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/additional/ns1/https.db bind9-9.20.29/bin/tests/system/additional/ns1/https.db --- bind9-9.20.26/bin/tests/system/additional/ns1/https.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/additional/ns1/https.db 2026-09-11 19:41:01.073320713 +0000 @@ -0,0 +1,46 @@ +$TTL 86400 +@ IN SOA ns1 hostmaster ( 3 8H 2H 4W 1D ); + NS ns1 +ns1 A 10.53.0.1 + +; AliasMode HTTPS records pointing at ServiceMode HTTPS RRsets. The +; target14 RRset has more records than DNS_RDATASET_MAXADDITIONAL (13), +; so additional-section processing of the alias target must give up on +; it; the target13 RRset is at the limit and is processed normally. +; +; The ServiceMode records point at "." (the owner name), so processing +; a target RRset for its own additional data adds the target's A record. +; That is how the test tells whether a target RRset was processed. +alias14 HTTPS 0 target14 +alias13 HTTPS 0 target13 + +target14 A 10.53.0.14 +target14 HTTPS 1 . +target14 HTTPS 2 . +target14 HTTPS 3 . +target14 HTTPS 4 . +target14 HTTPS 5 . +target14 HTTPS 6 . +target14 HTTPS 7 . +target14 HTTPS 8 . +target14 HTTPS 9 . +target14 HTTPS 10 . +target14 HTTPS 11 . +target14 HTTPS 12 . +target14 HTTPS 13 . +target14 HTTPS 14 . + +target13 A 10.53.0.13 +target13 HTTPS 1 . +target13 HTTPS 2 . +target13 HTTPS 3 . +target13 HTTPS 4 . +target13 HTTPS 5 . +target13 HTTPS 6 . +target13 HTTPS 7 . +target13 HTTPS 8 . +target13 HTTPS 9 . +target13 HTTPS 10 . +target13 HTTPS 11 . +target13 HTTPS 12 . +target13 HTTPS 13 . diff -Nru bind9-9.20.26/bin/tests/system/additional/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/additional/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/additional/ns1/named.conf.j2 2026-07-20 14:47:53.587841191 +0000 +++ bind9-9.20.29/bin/tests/system/additional/ns1/named.conf.j2 2026-09-11 19:41:01.073320713 +0000 @@ -12,28 +12,18 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; notify no; minimal-responses yes; }; -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { - type primary; - file "root.db"; + type primary; + file "root.db"; }; zone "rt.example" { @@ -60,3 +50,8 @@ type primary; file "nid.db"; }; + +zone "https.example" { + type primary; + file "https.db"; +}; diff -Nru bind9-9.20.26/bin/tests/system/additional/ns1/named2.conf.j2 bind9-9.20.29/bin/tests/system/additional/ns1/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/additional/ns1/named2.conf.j2 2026-07-20 14:47:53.588841216 +0000 +++ bind9-9.20.29/bin/tests/system/additional/ns1/named2.conf.j2 2026-09-11 19:41:01.073320713 +0000 @@ -12,28 +12,18 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; notify no; minimal-responses no; }; -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { - type primary; - file "root.db"; + type primary; + file "root.db"; }; zone "rt.example" { diff -Nru bind9-9.20.26/bin/tests/system/additional/ns1/named3.conf.j2 bind9-9.20.29/bin/tests/system/additional/ns1/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/additional/ns1/named3.conf.j2 2026-07-20 14:47:53.588841216 +0000 +++ bind9-9.20.29/bin/tests/system/additional/ns1/named3.conf.j2 2026-09-11 19:41:01.073320713 +0000 @@ -12,29 +12,19 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; notify no; minimal-any yes; minimal-responses no-auth; }; -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { - type primary; - file "root.db"; + type primary; + file "root.db"; }; zone "rt.example" { diff -Nru bind9-9.20.26/bin/tests/system/additional/ns1/named4.conf.j2 bind9-9.20.29/bin/tests/system/additional/ns1/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/additional/ns1/named4.conf.j2 2026-07-20 14:47:53.588841216 +0000 +++ bind9-9.20.29/bin/tests/system/additional/ns1/named4.conf.j2 2026-09-11 19:41:01.073320713 +0000 @@ -12,28 +12,18 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; notify no; minimal-responses no-auth-recursive; }; -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { - type primary; - file "root.db"; + type primary; + file "root.db"; }; zone "mx.example" { diff -Nru bind9-9.20.26/bin/tests/system/additional/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/additional/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/additional/ns2/named.conf.j2 2026-07-20 14:47:53.588841216 +0000 +++ bind9-9.20.29/bin/tests/system/additional/ns2/named.conf.j2 2026-09-11 19:41:01.074320737 +0000 @@ -12,19 +12,15 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; + {% include_indented "_common/options.conf.j2" %} recursion no; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; notify no; minimal-responses yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/additional/ns2/root.db bind9-9.20.29/bin/tests/system/additional/ns2/root.db --- bind9-9.20.26/bin/tests/system/additional/ns2/root.db 2026-07-20 14:47:53.589841241 +0000 +++ bind9-9.20.29/bin/tests/system/additional/ns2/root.db 2026-09-11 19:41:01.074320737 +0000 @@ -19,3 +19,4 @@ naptr2.example. NS ns1. nid.example. NS ns1. +https.example. NS ns1. diff -Nru bind9-9.20.26/bin/tests/system/additional/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/additional/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/additional/ns3/named.conf.j2 2026-07-20 14:47:53.589841241 +0000 +++ bind9-9.20.29/bin/tests/system/additional/ns3/named.conf.j2 2026-09-11 19:41:01.074320737 +0000 @@ -11,17 +11,10 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; minimal-responses no; }; diff -Nru bind9-9.20.26/bin/tests/system/additional/tests_https_alias.py bind9-9.20.29/bin/tests/system/additional/tests_https_alias.py --- bind9-9.20.26/bin/tests/system/additional/tests_https_alias.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/additional/tests_https_alias.py 2026-09-11 19:41:01.075320761 +0000 @@ -0,0 +1,101 @@ +# 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. + +import dns.message +import dns.name +import dns.rdatatype + +import isctest + + +def _query(ns, qname, qtype): + msg = isctest.query.create(qname, qtype) + res = isctest.query.udp(msg, ns.ip) + isctest.check.noerror(res) + return res + + +def _additional(res, target): + """ + Return the additional RRsets of 'res' keyed by type, checking that + all of them are owned by 'target'. + """ + owner = dns.name.from_text(target) + assert all(rrset.name == owner for rrset in res.additional), res.additional + return {rrset.rdtype: rrset for rrset in res.additional} + + +def test_https_alias_target_too_many_records(ns3): + """ + Resolve HTTPS AliasMode records whose targets are already cached, then + shut named down and check that nothing was leaked. + + The target of alias14 is a 14-record ServiceMode RRset, i.e. more than + DNS_RDATASET_MAXADDITIONAL. Following the alias clones the cached + target RRset into the caller's rdataset, and the subsequent additional + processing of that RRset fails with DNS_R_TOOMANYRECORDS. That error + used to be returned before the clone was disassociated, leaking a + reference to the cache node and its slab for every such query. + + The target of alias13 is at the limit and is processed normally. + + The limit bounds the processing of a target RRset for its own + additional data, not the inclusion of the target RRset itself, which + is added to the response before it is processed. The ServiceMode + records point at "." (the owner name), so processing a target RRset + adds the target's cached A record: it is present for target13 and + absent for target14. + """ + # Prime the cache with both target RRsets and their A records. + res = _query(ns3, "target14.https.example.", "HTTPS") + isctest.check.rr_count_eq(res.answer, 14) + res = _query(ns3, "target13.https.example.", "HTTPS") + isctest.check.rr_count_eq(res.answer, 13) + for target in ("target14", "target13"): + res = _query(ns3, f"{target}.https.example.", "A") + isctest.check.rr_count_eq(res.answer, 1) + + # The first pass resolves the aliases recursively, the second one is + # answered from the cache. + for _ in range(2): + # An error while collecting the additional data must not turn into + # a failed response (RFC 9460 section 4.2). + res = _query(ns3, "alias14.https.example.", "HTTPS") + expected = dns.message.from_text(""";ANSWER +alias14.https.example. 86400 IN HTTPS 0 target14.https.example. +""") + isctest.check.rrsets_equal(res.answer, expected.answer) + # The target RRset is returned in full, but as it is over the + # limit it is not processed, so its A record is not added. + target14 = _additional(res, "target14.https.example.") + assert set(target14) == {dns.rdatatype.HTTPS}, res.additional + isctest.check.rr_count_eq([target14[dns.rdatatype.HTTPS]], 14) + + # The alias at the limit is followed, its target is included, and + # the target is processed in turn, adding its A record. + res = _query(ns3, "alias13.https.example.", "HTTPS") + expected = dns.message.from_text(""";ANSWER +alias13.https.example. 86400 IN HTTPS 0 target13.https.example. +""") + isctest.check.rrsets_equal(res.answer, expected.answer) + target13 = _additional(res, "target13.https.example.") + assert set(target13) == {dns.rdatatype.HTTPS, dns.rdatatype.A}, res.additional + isctest.check.rr_count_eq([target13[dns.rdatatype.HTTPS]], 13) + expected = dns.message.from_text(""";ADDITIONAL +target13.https.example. 86400 IN A 10.53.0.13 +""") + isctest.check.rrsets_equal([target13[dns.rdatatype.A]], expected.additional) + + # Stop the server and check for leaked references. A leaked cache + # rdataset pins the cache database and its memory context, which shows + # up in named's memory tracking output at exit. + ns3.stop() + assert "outstanding memory" not in ns3.log diff -Nru bind9-9.20.26/bin/tests/system/addzone/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/addzone/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/addzone/ns1/named.conf.j2 2026-07-20 14:47:53.589841241 +0000 +++ bind9-9.20.29/bin/tests/system/addzone/ns1/named.conf.j2 2026-09-11 19:41:01.075320761 +0000 @@ -11,20 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; allow-query { any; }; allow-new-zones yes; @@ -32,10 +22,7 @@ dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "inlinesec.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/addzone/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/addzone/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/addzone/ns2/named.conf.j2 2026-07-20 14:47:53.590841266 +0000 +++ bind9-9.20.29/bin/tests/system/addzone/ns2/named.conf.j2 2026-09-11 19:41:01.076320785 +0000 @@ -12,26 +12,16 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-query { any; }; recursion no; allow-new-zones yes; dnssec-validation no; }; -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/addzone/ns2/named2.conf.j2 bind9-9.20.29/bin/tests/system/addzone/ns2/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/addzone/ns2/named2.conf.j2 2026-07-20 14:47:53.590841266 +0000 +++ bind9-9.20.29/bin/tests/system/addzone/ns2/named2.conf.j2 2026-09-11 19:41:01.076320785 +0000 @@ -11,33 +11,25 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; 10.53.0.4; }; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + listen-on { @ns.ip@; 10.53.0.4; }; listen-on-v6 { none; }; recursion no; dnssec-validation no; }; view internal { - match-clients { 10.53.0.2; }; + match-clients { @ns.ip@; }; allow-new-zones no; recursion yes; response-policy { zone "policy"; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "policy" { type primary; @@ -49,10 +41,7 @@ match-clients { any; }; allow-new-zones yes; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} }; # This view is only here to test that configuration context is cleaned diff -Nru bind9-9.20.26/bin/tests/system/addzone/ns2/named3.conf.j2 bind9-9.20.29/bin/tests/system/addzone/ns2/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/addzone/ns2/named3.conf.j2 2026-07-20 14:47:53.590841266 +0000 +++ bind9-9.20.29/bin/tests/system/addzone/ns2/named3.conf.j2 2026-09-11 19:41:01.076320785 +0000 @@ -11,16 +11,12 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; 10.53.0.4; 10.53.0.5; }; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + listen-on { @ns.ip@; 10.53.0.4; 10.53.0.5; }; listen-on-v6 { none; }; recursion no; new-zones-directory "new-zones"; @@ -28,16 +24,13 @@ }; view internal { - match-clients { 10.53.0.2; }; + match-clients { @ns.ip@; }; allow-new-zones no; recursion yes; response-policy { zone "policy"; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "policy" { type primary; @@ -49,20 +42,14 @@ match-clients { 10.53.0.5; }; allow-new-zones yes; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} }; view external { match-clients { any; }; allow-new-zones yes; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} }; # This view is only here to test that configuration context is cleaned diff -Nru bind9-9.20.26/bin/tests/system/addzone/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/addzone/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/addzone/ns3/named.conf.j2 2026-07-20 14:47:53.591841291 +0000 +++ bind9-9.20.29/bin/tests/system/addzone/ns3/named.conf.j2 2026-09-11 19:41:01.076320785 +0000 @@ -11,17 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-query { any; }; allow-transfer { any; }; recursion no; diff -Nru bind9-9.20.26/bin/tests/system/addzone/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/addzone/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/addzone/ns3/named2.conf.j2 2026-07-20 14:47:53.591841291 +0000 +++ bind9-9.20.29/bin/tests/system/addzone/ns3/named2.conf.j2 2026-09-11 19:41:01.077320809 +0000 @@ -11,17 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-query { any; }; allow-transfer { any; }; recursion no; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns1/named.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns1/named.conf.j2 2026-09-11 19:41:01.077320809 +0000 @@ -12,14 +12,13 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -12,20 +12,14 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named02.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named02.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named02.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named02.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { any; }; dnssec-validation no; @@ -23,10 +20,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named03.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named03.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named03.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named03.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { none; }; dnssec-validation no; @@ -23,10 +20,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named04.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named04.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named04.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named04.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -12,21 +12,15 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - allow-query { 10.53.0.2; }; + allow-query { @ns.ip@; }; dnssec-validation no; }; {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named05.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named05.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named05.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named05.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { 10.53.0.1; }; dnssec-validation no; @@ -23,10 +20,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named06.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named06.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named06.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named06.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -12,21 +12,15 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - allow-query {! 10.53.0.2; }; + allow-query {! @ns.ip@; }; dnssec-validation no; }; {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named07.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named07.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named07.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named07.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -11,13 +11,10 @@ * information regarding copyright ownership. */ -acl accept { 10.53.0.2; }; +acl accept { @ns.ip@; }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { accept; }; dnssec-validation no; @@ -25,10 +22,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named08.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named08.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named08.conf.j2 2026-07-20 14:47:53.592841316 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named08.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -14,10 +14,7 @@ acl accept { 10.53.0.1; }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { accept; }; dnssec-validation no; @@ -25,10 +22,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named09.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named09.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named09.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named09.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -11,13 +11,10 @@ * information regarding copyright ownership. */ -acl accept { 10.53.0.2; }; +acl accept { @ns.ip@; }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query {! accept; }; dnssec-validation no; @@ -25,10 +22,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named10.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named10.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named10.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named10.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -17,10 +17,7 @@ }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { key one; }; dnssec-validation no; @@ -28,10 +25,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named11.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named11.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named11.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named11.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -23,10 +23,7 @@ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { key one; }; dnssec-validation no; @@ -34,10 +31,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named12.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named12.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named12.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named12.conf.j2 2026-09-11 19:41:01.078320834 +0000 @@ -17,10 +17,7 @@ }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query {! key one; }; dnssec-validation no; @@ -28,10 +25,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named21.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named21.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named21.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named21.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -24,10 +21,7 @@ view "internal" { - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named22.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named22.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named22.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named22.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -26,10 +23,7 @@ allow-query { any; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named23.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named23.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named23.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named23.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -26,10 +23,7 @@ allow-query { none; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named24.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named24.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named24.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named24.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -24,12 +21,9 @@ view "internal" { - allow-query { 10.53.0.2; }; + allow-query { @ns.ip@; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named25.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named25.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named25.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named25.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -26,10 +23,7 @@ allow-query { 10.53.0.1; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named26.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named26.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named26.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named26.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -24,12 +21,9 @@ view "internal" { - allow-query {! 10.53.0.2; }; + allow-query {! @ns.ip@; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named27.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named27.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named27.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named27.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -11,13 +11,10 @@ * information regarding copyright ownership. */ -acl accept { 10.53.0.2; }; +acl accept { @ns.ip@; }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -28,10 +25,7 @@ allow-query { accept; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named28.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named28.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named28.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named28.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -14,10 +14,7 @@ acl accept { 10.53.0.1; }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -28,10 +25,7 @@ allow-query { accept; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named29.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named29.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named29.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named29.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -11,13 +11,10 @@ * information regarding copyright ownership. */ -acl accept { 10.53.0.2; }; +acl accept { @ns.ip@; }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -28,10 +25,7 @@ allow-query {! accept; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named30.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named30.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named30.conf.j2 2026-07-20 14:47:53.593841341 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named30.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -17,10 +17,7 @@ }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -31,10 +28,7 @@ allow-query { key one; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named31.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named31.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named31.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named31.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -23,10 +23,7 @@ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { key one; }; dnssec-validation no; @@ -38,10 +35,7 @@ allow-query { key one; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named32.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named32.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named32.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named32.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -17,10 +17,7 @@ }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -31,10 +28,7 @@ allow-query {! key one; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named33.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named33.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named33.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named33.conf.j2 2026-09-11 19:41:01.079320858 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { none; }; dnssec-validation no; @@ -27,10 +24,7 @@ allow-query { any; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named34.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named34.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named34.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named34.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { any; }; dnssec-validation no; @@ -27,10 +24,7 @@ allow-query { none; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named40.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named40.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named40.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named40.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -11,7 +11,7 @@ * information regarding copyright ownership. */ -acl accept { 10.53.0.2; }; +acl accept { @ns.ip@; }; acl badaccept { 10.53.0.1; }; @@ -26,20 +26,14 @@ }; options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; @@ -61,7 +55,7 @@ zone "addrallow.example" { type primary; file "generic.db"; - allow-query { 10.53.0.2; }; + allow-query { @ns.ip@; }; }; zone "addrnotallow.example" { @@ -73,7 +67,7 @@ zone "addrdisallow.example" { type primary; file "generic.db"; - allow-query { ! 10.53.0.2; }; + allow-query { ! @ns.ip@; }; }; zone "aclallow.example" { diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named53.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named53.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named53.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named53.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { none; }; dnssec-validation no; @@ -23,10 +20,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named54.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named54.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named54.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named54.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-query { any; }; dnssec-validation no; @@ -23,10 +20,7 @@ {% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named55.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named55.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named55.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named55.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -26,10 +23,7 @@ allow-query { none; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named56.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named56.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named56.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named56.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -26,10 +23,7 @@ allow-query { any; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns2/named57.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns2/named57.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns2/named57.conf.j2 2026-07-20 14:47:53.594841366 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns2/named57.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -25,10 +22,7 @@ view "internal" { allow-query-on { any; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "normal.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns3/named.conf.j2 2026-07-20 14:47:53.595841391 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns3/named.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,24 +12,10 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns3/named2.conf.j2 2026-07-20 14:47:53.595841391 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns3/named2.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,27 +12,13 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} allow-recursion { any; }; allow-recursion-on { none; }; - allow-query-cache-on { 10.53.0.3; }; + allow-query-cache-on { @ns.ip@; }; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns3/named3.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns3/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns3/named3.conf.j2 2026-07-20 14:47:53.595841391 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns3/named3.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,27 +12,16 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; 10.53.1.2; }; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + listen-on { @ns.ip@; 10.53.1.2; }; listen-on-v6 { none; }; - recursion yes; allow-recursion { any; }; allow-query-cache { any; }; - allow-query-cache-on { 10.53.0.3; }; # allow-recursion-on inherits + allow-query-cache-on { @ns.ip@; }; # allow-recursion-on inherits dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/allow_query/ns3/named4.conf.j2 bind9-9.20.29/bin/tests/system/allow_query/ns3/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query/ns3/named4.conf.j2 2026-07-20 14:47:53.595841391 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query/ns3/named4.conf.j2 2026-09-11 19:41:01.080320882 +0000 @@ -12,27 +12,16 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; 10.53.1.2; }; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + listen-on { @ns.ip@; 10.53.1.2; }; listen-on-v6 { none; }; - recursion yes; allow-recursion { any; }; allow-query-cache { any; }; - allow-recursion-on { 10.53.0.3; }; # allow-query-cache-on inherits + allow-recursion-on { @ns.ip@; }; # allow-query-cache-on inherits dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/allow_query_on/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/allow_query_on/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/allow_query_on/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query_on/ns1/named.conf.j2 2026-09-11 19:41:01.081320906 +0000 @@ -0,0 +1,64 @@ +options { + {% include_indented "_common/options.conf.j2" %} + recursion no; + dnssec-validation no; +}; + +{% include "_common/controls.conf.j2" %} + +view "vredirect" { + match-clients { 10.53.0.1; }; + zone "." { + type primary; + file "root.db"; + }; + + zone "." { + type redirect; + file "redirect.db"; + allow-query { any; }; + allow-query-on { none; }; + }; +}; + +view "vdlz1" { + match-clients { 10.53.0.2; }; + dlz other { + database "dlopen @TOP_BUILDDIR@/bin/tests/system/dlzexternal/driver/.libs/dlzexternal.so example.nil"; + search yes; + }; + allow-query { none; }; + allow-query-on { any; }; /* Ignored, as allow-query is none anyway */ + zone "." { + type primary; + file "root.db"; + }; +}; + +view "vdlz2" { + match-clients { 10.53.0.3; }; + dlz other { + database "dlopen @TOP_BUILDDIR@/bin/tests/system/dlzexternal/driver/.libs/dlzexternal.so example.nil"; + search yes; + }; + allow-query { any; }; + allow-query-on { 10.53.0.3; }; + zone "." { + type primary; + file "root.db"; + }; +}; + +view "vdlz3" { + match-clients { 10.53.0.4; }; + dlz other { + database "dlopen @TOP_BUILDDIR@/bin/tests/system/dlzexternal/driver/.libs/dlzexternal.so example.nil"; + search yes; + }; + allow-query { any; }; + allow-query-on { 10.53.0.1; }; + zone "." { + type primary; + file "root.db"; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/allow_query_on/ns1/redirect.db bind9-9.20.29/bin/tests/system/allow_query_on/ns1/redirect.db --- bind9-9.20.26/bin/tests/system/allow_query_on/ns1/redirect.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query_on/ns1/redirect.db 2026-09-11 19:41:01.081320906 +0000 @@ -0,0 +1,12 @@ +$TTL 300 +. IN SOA . a.root.servers.nil. ( + 2000042100 ; serial + 600 ; refresh + 600 ; retry + 1200 ; expire + 600 ; minimum +) +@ IN NS a.root-servers.nil. +*. IN A 100.100.100.2 +*. IN AAAA 2001:ffff:ffff::100.100.100.2 + diff -Nru bind9-9.20.26/bin/tests/system/allow_query_on/ns1/root.db bind9-9.20.29/bin/tests/system/allow_query_on/ns1/root.db --- bind9-9.20.26/bin/tests/system/allow_query_on/ns1/root.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query_on/ns1/root.db 2026-09-11 19:41:01.081320906 +0000 @@ -0,0 +1,11 @@ +$TTL 300 +. IN SOA . a.root.servers.nil. ( + 2000042100 ; serial + 600 ; refresh + 600 ; retry + 1200 ; expire + 600 ; minimum +) + +. NS a.root-servers.nil. +a.root-servers.nil. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/allow_query_on/tests_allow_query_on.py bind9-9.20.29/bin/tests/system/allow_query_on/tests_allow_query_on.py --- bind9-9.20.26/bin/tests/system/allow_query_on/tests_allow_query_on.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/allow_query_on/tests_allow_query_on.py 2026-09-11 19:41:01.081320906 +0000 @@ -0,0 +1,34 @@ +# 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. + +from dns.rcode import NOERROR, NXDOMAIN, REFUSED +from pytest import mark + +import isctest + + +@mark.parametrize( + "qname, qtype, srcip, rcode", + [ + ("a.root-servers.nil", "A", "10.53.0.1", NOERROR), + ("foo.", "A", "10.53.0.1", NXDOMAIN), + ("example.nil", "SOA", "10.53.0.2", REFUSED), + ("example.nil", "SOA", "10.53.0.3", REFUSED), + ("example.nil", "SOA", "10.53.0.4", NOERROR), + ], +) +def test_allow_query_on(ns1, qname, qtype, srcip, rcode): + msg = isctest.query.create(qname, qtype) + res = isctest.query.udp(msg, ns1.ip, source=srcip) + isctest.check.rcode(res, rcode) + if qname == "example.nil" and rcode == NOERROR: + assert res.answer + isctest.check.aaflag(res) diff -Nru bind9-9.20.26/bin/tests/system/auth/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/auth/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/auth/ns1/named.conf.j2 2026-07-20 14:47:53.595841391 +0000 +++ bind9-9.20.29/bin/tests/system/auth/ns1/named.conf.j2 2026-09-11 19:41:01.082320930 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + view main in { allow-transfer { any; }; diff -Nru bind9-9.20.26/bin/tests/system/auth/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/auth/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/auth/ns2/named.conf.j2 2026-07-20 14:47:53.596841416 +0000 +++ bind9-9.20.29/bin/tests/system/auth/ns2/named.conf.j2 2026-09-11 19:41:01.082320930 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone example.net { type secondary; primaries { 10.53.0.1; }; diff -Nru bind9-9.20.26/bin/tests/system/authsock.pl bind9-9.20.29/bin/tests/system/authsock.pl --- bind9-9.20.26/bin/tests/system/authsock.pl 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/authsock.pl 2026-09-11 19:41:01.082320930 +0000 @@ -0,0 +1,94 @@ +#!/usr/bin/env perl + +# 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. + +# test the update-policy external protocol + +require 5.6.0; + +use IO::File; +use IO::Socket::UNIX; +use Getopt::Long; + +my $path; +my $typeallowed = "A"; +my $pidfile = "authsock.pid"; +my $timeout = 0; + +GetOptions("path=s" => \$path, + "type=s" => \$typeallowed, + "pidfile=s" => \$pidfile, + "timeout=i" => \$timeout); + +STDOUT->autoflush(1); + +if (!defined($path)) { + print("Usage: authsock.pl --path= --type=type --pidfile=pidfile\n"); + exit(1); +} + +unlink($path); +my $server = IO::Socket::UNIX->new(Local => $path, Type => SOCK_STREAM, Listen => 8) or + die "unable to create socket $path"; +chmod 0777, $path; + +# setup our pidfile +open(my $pid,">",$pidfile) + or die "unable to open pidfile $pidfile"; +print $pid "$$\n"; +close($pid); + +if ($timeout != 0) { + # die after the given timeout + alarm($timeout); +} + +while (my $client = $server->accept()) { + $client->recv(my $buf, 8, 0); + my ($version, $req_len) = unpack('N N', $buf); + + if ($version != 1 || $req_len < 17) { + printf("Badly formatted request\n"); + $client->send(pack('N', 2)); + next; + } + + $client->recv(my $buf, $req_len - 8, 0); + + my ($signer, + $name, + $addr, + $type, + $key, + $key_data) = unpack('Z* Z* Z* Z* Z* N/a', $buf); + + if ($req_len != length($buf)+8) { + printf("Length mismatch %u %u\n", $req_len, length($buf)+8); + $client->send(pack('N', 2)); + next; + } + + printf("version=%u signer=%s name=%s addr=%s type=%s key=%s key_data_len=%u\n", + $version, $signer, $name, $addr, $type, $key, length($key_data)); + + my $result; + if ($typeallowed eq $type) { + $result = 1; + printf("allowed type %s == %s\n", $type, $typeallowed); + } else { + printf("disallowed type %s != %s\n", $type, $typeallowed); + $result = 0; + } + + $reply = pack('N', $result); + $client->send($reply); +} diff -Nru bind9-9.20.26/bin/tests/system/autosign/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/autosign/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/autosign/ns1/named.conf.j2 2026-07-20 14:47:53.596841416 +0000 +++ bind9-9.20.29/bin/tests/system/autosign/ns1/named.conf.j2 2026-09-11 19:41:01.082320930 +0000 @@ -14,27 +14,13 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/autosign/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/autosign/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/autosign/ns2/named.conf.j2 2026-07-20 14:47:53.597841441 +0000 +++ bind9-9.20.29/bin/tests/system/autosign/ns2/named.conf.j2 2026-09-11 19:41:01.083320954 +0000 @@ -14,28 +14,14 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation yes; dnssec-loadkeys-interval 30; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "autosign" { keys { @@ -71,10 +57,7 @@ nsec3param iterations 0 optout yes salt-length 0; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/autosign/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/autosign/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/autosign/ns3/named.conf.j2 2026-07-20 14:47:53.598841466 +0000 +++ bind9-9.20.29/bin/tests/system/autosign/ns3/named.conf.j2 2026-09-11 19:41:01.084320978 +0000 @@ -13,33 +13,17 @@ // NS3 -controls { /* empty */ }; - options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; allow-transfer { any; }; recursion no; - notify yes; dnssec-validation yes; dnssec-loadkeys-interval 10; allow-new-zones yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} # The default dnssec-policy "autosign" { @@ -122,10 +106,7 @@ }; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/autosign/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/autosign/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/autosign/ns4/named.conf.j2 2026-07-20 14:47:53.600841516 +0000 +++ bind9-9.20.29/bin/tests/system/autosign/ns4/named.conf.j2 2026-09-11 19:41:01.086321027 +0000 @@ -14,22 +14,14 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; dnssec-must-be-secure mustbesecure.example yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} include "trusted.conf"; include "private.conf"; diff -Nru bind9-9.20.26/bin/tests/system/autosign/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/autosign/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/autosign/ns5/named.conf.j2 2026-07-20 14:47:53.601841541 +0000 +++ bind9-9.20.29/bin/tests/system/autosign/ns5/named.conf.j2 2026-09-11 19:41:01.087321051 +0000 @@ -14,20 +14,12 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/bailiwick/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/bailiwick/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/bailiwick/ns4/named.conf.j2 2026-07-20 14:47:53.602841566 +0000 +++ bind9-9.20.29/bin/tests/system/bailiwick/ns4/named.conf.j2 2026-09-11 19:41:01.088321075 +0000 @@ -12,25 +12,11 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; qname-minimization off; }; -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/builtin/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/builtin/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/builtin/ns1/named.conf.j2 2026-07-20 14:47:53.602841566 +0000 +++ bind9-9.20.29/bin/tests/system/builtin/ns1/named.conf.j2 2026-09-11 19:41:01.088321075 +0000 @@ -11,21 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/builtin/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/builtin/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/builtin/ns2/named.conf.j2 2026-07-20 14:47:53.602841566 +0000 +++ bind9-9.20.29/bin/tests/system/builtin/ns2/named.conf.j2 2026-09-11 19:41:01.088321075 +0000 @@ -11,21 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; server-id hostname; dnssec-validation no; diff -Nru bind9-9.20.26/bin/tests/system/builtin/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/builtin/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/builtin/ns3/named.conf.j2 2026-07-20 14:47:53.602841566 +0000 +++ bind9-9.20.29/bin/tests/system/builtin/ns3/named.conf.j2 2026-09-11 19:41:01.088321075 +0000 @@ -11,21 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; hostname "this.is.a.test.of.hostname"; server-id "this.is.a.test.of.server-id"; diff -Nru bind9-9.20.26/bin/tests/system/cacheclean/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/cacheclean/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cacheclean/ns1/named.conf.j2 2026-07-20 14:47:53.604841616 +0000 +++ bind9-9.20.29/bin/tests/system/cacheclean/ns1/named.conf.j2 2026-09-11 19:41:01.090321124 +0000 @@ -12,21 +12,16 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; check-integrity no; minimal-responses no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/cacheclean/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/cacheclean/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cacheclean/ns2/named.conf.j2 2026-07-20 14:47:53.604841616 +0000 +++ bind9-9.20.29/bin/tests/system/cacheclean/ns2/named.conf.j2 2026-09-11 19:41:01.090321124 +0000 @@ -12,33 +12,15 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - notify yes; + {% include_indented "_common/options.conf.j2" %} disable-empty-zone 127.IN-ADDR.ARPA; - recursion yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "flushtest.example" { type forward; diff -Nru bind9-9.20.26/bin/tests/system/cacheclean/tests.sh bind9-9.20.29/bin/tests/system/cacheclean/tests.sh --- bind9-9.20.26/bin/tests/system/cacheclean/tests.sh 2026-07-20 14:47:53.604841616 +0000 +++ bind9-9.20.29/bin/tests/system/cacheclean/tests.sh 2026-09-11 19:41:01.090321124 +0000 @@ -275,5 +275,21 @@ if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) +n=$((n + 1)) +echo_i "check 'flushtree .' is equivalent to 'flush' ($n)" +ret=0 +clear_cache +dump_cache +grep -v DATE ns2/named_dump.db.test$n >ns2/named_dump.db.test$n.a +load_cache +dump_cache +grep -v DATE ns2/named_dump.db.test$n >ns2/named_dump.db.test$n.b +$RNDC $RNDCOPTS flushtree . || ret=1 +dump_cache +grep -v DATE ns2/named_dump.db.test$n >ns2/named_dump.db.test$n.c +cmp -s ns2/named_dump.db.test$n.a ns2/named_dump.db.test$n.b && ret=1 +cmp -s ns2/named_dump.db.test$n.a ns2/named_dump.db.test$n.c || ret=1 +status=$((status + ret)) + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff -Nru bind9-9.20.26/bin/tests/system/camp/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/camp/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/camp/ns1/named.conf.j2 2026-07-20 14:47:53.604841616 +0000 +++ bind9-9.20.29/bin/tests/system/camp/ns1/named.conf.j2 2026-09-11 19:41:01.090321124 +0000 @@ -14,17 +14,12 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/camp/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/camp/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/camp/ns2/named.conf.j2 2026-07-20 14:47:53.605841641 +0000 +++ bind9-9.20.29/bin/tests/system/camp/ns2/named.conf.j2 2026-09-11 19:41:01.091321147 +0000 @@ -14,17 +14,12 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "tld0" { type primary; file "tld0.db"; diff -Nru bind9-9.20.26/bin/tests/system/camp/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/camp/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/camp/ns3/named.conf.j2 2026-07-20 14:47:53.605841641 +0000 +++ bind9-9.20.29/bin/tests/system/camp/ns3/named.conf.j2 2026-09-11 19:41:01.091321147 +0000 @@ -14,27 +14,13 @@ // NS3 options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; max-query-count 150; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "final.tld0" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/camp/ns9/hints.db bind9-9.20.29/bin/tests/system/camp/ns9/hints.db --- bind9-9.20.26/bin/tests/system/camp/ns9/hints.db 2026-07-20 14:47:53.605841641 +0000 +++ bind9-9.20.29/bin/tests/system/camp/ns9/hints.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -; 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. - -. 60 IN NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/camp/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/camp/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/camp/ns9/named.conf.j2 2026-07-20 14:47:53.605841641 +0000 +++ bind9-9.20.29/bin/tests/system/camp/ns9/named.conf.j2 2026-09-11 19:41:01.091321147 +0000 @@ -14,14 +14,7 @@ // NS9 options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; max-recursion-queries 50; @@ -29,13 +22,6 @@ max-query-count 100; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { type hint; file "hints.db"; }; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/cap_glues/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/cap_glues/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cap_glues/ns1/named.conf.j2 2026-07-20 14:47:53.606841666 +0000 +++ bind9-9.20.29/bin/tests/system/cap_glues/ns1/named.conf.j2 2026-09-11 19:41:01.092321172 +0000 @@ -1,14 +1,11 @@ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/cap_glues/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/cap_glues/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cap_glues/ns2/named.conf.j2 2026-07-20 14:47:53.606841666 +0000 +++ bind9-9.20.29/bin/tests/system/cap_glues/ns2/named.conf.j2 2026-09-11 19:41:01.092321172 +0000 @@ -1,14 +1,11 @@ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "tld" { type primary; file "tld.db"; diff -Nru bind9-9.20.26/bin/tests/system/cap_glues/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/cap_glues/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cap_glues/ns3/named.conf.j2 2026-07-20 14:47:53.606841666 +0000 +++ bind9-9.20.29/bin/tests/system/cap_glues/ns3/named.conf.j2 2026-09-11 19:41:01.092321172 +0000 @@ -1,11 +1,5 @@ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; @@ -16,16 +10,6 @@ tcp-only yes; }; -zone "." { - type hint; - file "root.hint"; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/root.hint.conf" %} -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/cap_glues/ns3/root.hint bind9-9.20.29/bin/tests/system/cap_glues/ns3/root.hint --- bind9-9.20.26/bin/tests/system/cap_glues/ns3/root.hint 2026-07-20 14:47:53.606841666 +0000 +++ bind9-9.20.29/bin/tests/system/cap_glues/ns3/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/case/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/case/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/case/ns1/named.conf.j2 2026-07-20 14:47:53.607841691 +0000 +++ bind9-9.20.29/bin/tests/system/case/ns1/named.conf.j2 2026-09-11 19:41:01.093321196 +0000 @@ -12,22 +12,17 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; minimal-responses no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/case/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/case/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/case/ns2/named.conf.j2 2026-07-20 14:47:53.607841691 +0000 +++ bind9-9.20.29/bin/tests/system/case/ns2/named.conf.j2 2026-09-11 19:41:01.093321196 +0000 @@ -12,23 +12,18 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; - no-case-compress { 10.53.0.2; }; + no-case-compress { @ns.ip@; }; minimal-responses no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type secondary; file "example.bk"; diff -Nru bind9-9.20.26/bin/tests/system/catz/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/catz/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/catz/ns1/named.conf.j2 2026-07-20 14:47:53.608841716 +0000 +++ bind9-9.20.29/bin/tests/system/catz/ns1/named.conf.j2 2026-09-11 19:41:01.094321220 +0000 @@ -11,24 +11,14 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; allow-new-zones yes; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on port @EXTRAPORT1@ { 10.53.0.1; }; - listen-on tls ephemeral { 10.53.0.1; }; - listen-on-v6 { none; }; + listen-on port @EXTRAPORT1@ { @ns.ip@; }; + listen-on tls ephemeral { @ns.ip@; }; notify no; notify-delay 0; recursion no; @@ -184,6 +174,6 @@ }; key longlonglongname0123456789abcdef. { - secret "LaAnCU+Z"; - algorithm @DEFAULT_HMAC@; + secret "LaAnCU+Z"; + algorithm @DEFAULT_HMAC@; }; diff -Nru bind9-9.20.26/bin/tests/system/catz/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/catz/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/catz/ns2/named.conf.j2 2026-07-20 14:47:53.608841716 +0000 +++ bind9-9.20.29/bin/tests/system/catz/ns2/named.conf.j2 2026-09-11 19:41:01.094321220 +0000 @@ -17,20 +17,10 @@ {% set catalog5 = catalog5 | default(False) %} {% set duplicate_zone = duplicate_zone | default(False) %} -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} allow-transfer { any; }; notify no; notify-delay 0; @@ -118,20 +108,20 @@ {% endif %} zone "dom-existing.example" { - type primary; - file "dom-existing.example.db"; + type primary; + file "dom-existing.example.db"; }; zone "dom-existing-forward.example" { - type forward; - forward only; - forwarders { 10.53.0.1; }; + type forward; + forward only; + forwarders { 10.53.0.1; }; }; zone "dom-existing-forward-off.example" { - type forward; - forward only; - forwarders { }; + type forward; + forward only; + forwarders { }; }; zone "catalog0.example" { @@ -177,8 +167,8 @@ # to deal with that situation (see GL #3911). Make sure that this duplicate # zone comes after the the "catalog1.example" zone in the configuration file. zone "dom3.example" { - type secondary; - file "dom2.example.db"; + type secondary; + file "dom2.example.db"; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/catz/ns2/named7.conf.j2 bind9-9.20.29/bin/tests/system/catz/ns2/named7.conf.j2 --- bind9-9.20.26/bin/tests/system/catz/ns2/named7.conf.j2 2026-07-20 14:47:53.609841741 +0000 +++ bind9-9.20.29/bin/tests/system/catz/ns2/named7.conf.j2 2026-09-11 19:41:01.095321244 +0000 @@ -11,20 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} allow-transfer { any; }; notify no; notify-delay 0; @@ -39,20 +29,20 @@ # identical to named1.conf.in zone "dom-existing.example" { - type primary; - file "dom-existing.example.db"; + type primary; + file "dom-existing.example.db"; }; zone "dom-existing-forward.example" { - type forward; - forward only; - forwarders { 10.53.0.1; }; + type forward; + forward only; + forwarders { 10.53.0.1; }; }; zone "dom-existing-forward-off.example" { - type forward; - forward only; - forwarders { }; + type forward; + forward only; + forwarders { }; }; zone "catalog0.example" { diff -Nru bind9-9.20.26/bin/tests/system/catz/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/catz/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/catz/ns3/named.conf.j2 2026-07-20 14:47:53.609841741 +0000 +++ bind9-9.20.29/bin/tests/system/catz/ns3/named.conf.j2 2026-09-11 19:41:01.095321244 +0000 @@ -11,22 +11,12 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options-dual.conf.j2" %} allow-new-zones yes; - pid-file "named.pid"; provide-ixfr no; - listen-on { 10.53.0.3; }; - listen-on-v6 { fd92:7065:b8e:ffff::3; }; allow-transfer { any; }; notify no; notify-delay 0; diff -Nru bind9-9.20.26/bin/tests/system/catz/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/catz/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/catz/ns4/named.conf.j2 2026-07-20 14:47:53.609841741 +0000 +++ bind9-9.20.29/bin/tests/system/catz/ns4/named.conf.j2 2026-09-11 19:41:01.095321244 +0000 @@ -11,21 +11,11 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; + {% include_indented "_common/options-dual.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { fd92:7065:b8e:ffff::4; }; allow-transfer { any; }; notify no; notify-delay 0; @@ -43,7 +33,7 @@ default-primaries { 10.53.0.1 key tsig_key tls ephemeral; }; zone "catalog-self.example" min-update-interval 1s - default-primaries { 10.53.0.4; }; + default-primaries { @ns.ip@; }; }; }; diff -Nru bind9-9.20.26/bin/tests/system/cdnxdomain/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/cdnxdomain/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cdnxdomain/ns1/named.conf.j2 2026-07-20 14:47:53.610841766 +0000 +++ bind9-9.20.29/bin/tests/system/cdnxdomain/ns1/named.conf.j2 2026-09-11 19:41:01.096321268 +0000 @@ -1,23 +1,9 @@ // NS1 - validating resolver, forwards "example" to the signed NS2 -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; servfail-ttl 0; }; @@ -25,10 +11,7 @@ // Trust anchor for "example" (static-ds of NS2's KSK). include "trusted.conf"; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} // Resolve "example" only via the signed authoritative server. The static // trust anchor above lets the forwarded answers validate to dns_trust_secure. diff -Nru bind9-9.20.26/bin/tests/system/cdnxdomain/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/cdnxdomain/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cdnxdomain/ns2/named.conf.j2 2026-07-20 14:47:53.610841766 +0000 +++ bind9-9.20.29/bin/tests/system/cdnxdomain/ns2/named.conf.j2 2026-09-11 19:41:01.096321268 +0000 @@ -1,22 +1,9 @@ // NS2 - signed authoritative server for "example" -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/cdnxdomain/tests_cdnxdomain.py bind9-9.20.29/bin/tests/system/cdnxdomain/tests_cdnxdomain.py --- bind9-9.20.26/bin/tests/system/cdnxdomain/tests_cdnxdomain.py 2026-07-20 14:47:53.610841766 +0000 +++ bind9-9.20.29/bin/tests/system/cdnxdomain/tests_cdnxdomain.py 2026-09-11 19:41:01.096321268 +0000 @@ -82,7 +82,20 @@ def _serve(ns2, system_test_dir, variant): """Make ns2 serve the 'full' or 'empty' (a.example-less) signed zone.""" src = system_test_dir / "ns2" / f"example-{variant}.db.signed" - shutil.copyfile(src, system_test_dir / "ns2" / "example.db.signed") + dst = system_test_dir / "ns2" / "example.db.signed" + # Ensure that the modification time of 'dst' increases on + # file systems with seconds granuality. + st_ok = False + try: + st = os.stat(dst) + st_ok = True + except FileNotFoundError: + pass + shutil.copyfile(src, dst) + if st_ok: + st2 = os.stat(dst) + if int(st2.st_mtime) <= int(st.st_mtime): + os.utime(dst, (st2.st_atime, st.st_mtime + 1)) ns2.reload() diff -Nru bind9-9.20.26/bin/tests/system/chain/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/chain/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/chain/ns1/named.conf.j2 2026-07-20 14:47:53.612841816 +0000 +++ bind9-9.20.29/bin/tests/system/chain/ns1/named.conf.j2 2026-09-11 19:41:01.098321317 +0000 @@ -12,17 +12,11 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; +{% include "_common/controls.conf.j2" %} zone "." { type primary; file "root.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/chain/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/chain/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/chain/ns2/named.conf.j2 2026-07-20 14:47:53.612841816 +0000 +++ bind9-9.20.29/bin/tests/system/chain/ns2/named.conf.j2 2026-09-11 19:41:01.098321317 +0000 @@ -14,22 +14,14 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; -zone . { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/chain/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/chain/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/chain/ns5/named.conf.j2 2026-07-20 14:47:53.612841816 +0000 +++ bind9-9.20.29/bin/tests/system/chain/ns5/named.conf.j2 2026-09-11 19:41:01.098321317 +0000 @@ -14,22 +14,14 @@ // NS2 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "sub5.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/chain/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/chain/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/chain/ns7/named.conf.j2 2026-07-20 14:47:53.613841842 +0000 +++ bind9-9.20.29/bin/tests/system/chain/ns7/named.conf.j2 2026-09-11 19:41:01.099321341 +0000 @@ -12,15 +12,7 @@ */ options { - directory "."; - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { fd92:7065:b8e:ffff::7; }; - recursion yes; + {% include_indented "_common/options-dual.conf.j2" %} allow-recursion { any; }; dnssec-validation no; deny-answer-aliases { @@ -32,33 +24,20 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - key restart16 { secret "1234abcd8765"; algorithm @DEFAULT_HMAC@; }; -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view restart16 { match-clients { key restart16; none; }; max-query-restarts 16; - zone "." { - type hint; - file "root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} }; view default { - zone "." { - type hint; - file "root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} }; diff -Nru bind9-9.20.26/bin/tests/system/chain/ns7/root.hint bind9-9.20.29/bin/tests/system/chain/ns7/root.hint --- bind9-9.20.26/bin/tests/system/chain/ns7/root.hint 2026-07-20 14:47:53.613841842 +0000 +++ bind9-9.20.29/bin/tests/system/chain/ns7/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/chain/prereq.sh bind9-9.20.29/bin/tests/system/chain/prereq.sh --- bind9-9.20.26/bin/tests/system/chain/prereq.sh 2026-07-20 14:47:53.613841842 +0000 +++ bind9-9.20.29/bin/tests/system/chain/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -if ! ${PERL} -MNet::DNS::Nameserver -e ''; then - echo_i "perl Net::DNS::Nameserver module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-catz-zone-primary-dup.conf bind9-9.20.29/bin/tests/system/checkconf/bad-catz-zone-primary-dup.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-catz-zone-primary-dup.conf 2026-07-20 14:47:53.614841867 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-catz-zone-primary-dup.conf 2026-09-11 19:41:01.100321365 +0000 @@ -21,7 +21,7 @@ }; zone "catalog.example" { - type secondary; - file "catalog.example.db"; - primaries { 10.53.0.1; }; + type secondary; + file "catalog.example.db"; + primaries { 10.53.0.1; }; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-controls-duplicate.conf bind9-9.20.29/bin/tests/system/checkconf/bad-controls-duplicate.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-controls-duplicate.conf 2026-07-20 14:47:53.614841867 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-controls-duplicate.conf 2026-09-11 19:41:01.100321365 +0000 @@ -13,12 +13,12 @@ key rndc-key { algorithm "hmac-sha256"; - secret "xxxxxxxxxxxxxxxxxxxxxxxx"; + secret "xxxxxxxxxxxxxxxxxxxxxxxx"; }; key ddns-key { algorithm "hmac-sha256"; - secret "yyyyyyyyyyyyyyyyyyyyyyyy"; + secret "yyyyyyyyyyyyyyyyyyyyyyyy"; }; controls { Binary files /srv/release.debian.org/tmp/1mvoeOZTuW/bind9-9.20.26/bin/tests/system/checkconf/bad-embedded-null-00.conf and /srv/release.debian.org/tmp/VqkGLzeUi9/bind9-9.20.29/bin/tests/system/checkconf/bad-embedded-null-00.conf differ Binary files /srv/release.debian.org/tmp/1mvoeOZTuW/bind9-9.20.26/bin/tests/system/checkconf/bad-embedded-null-01.conf and /srv/release.debian.org/tmp/VqkGLzeUi9/bind9-9.20.29/bin/tests/system/checkconf/bad-embedded-null-01.conf differ diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-empty-endpoints.conf bind9-9.20.29/bin/tests/system/checkconf/bad-empty-endpoints.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-empty-endpoints.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-empty-endpoints.conf 2026-09-11 19:41:01.103321437 +0000 @@ -0,0 +1,4 @@ +http local { endpoints { }; }; +options { + listen-on port 10080 tls none http local { 127.0.0.1; }; +}; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-inline-secondary.conf bind9-9.20.29/bin/tests/system/checkconf/bad-inline-secondary.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-inline-secondary.conf 2026-07-20 14:47:53.618841967 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-inline-secondary.conf 2026-09-11 19:41:01.104321462 +0000 @@ -11,12 +11,12 @@ * information regarding copyright ownership. */ - /* - * An inline-signing secondary should be forced to have a file option - */ +/* + * An inline-signing secondary should be forced to have a file option + */ - zone "." { - type secondary; - inline-signing yes; - primaries { 10.53.0.1; }; - }; +zone "." { + type secondary; + inline-signing yes; + primaries { 10.53.0.1; }; +}; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-kasp-max-zone-ttl.conf bind9-9.20.29/bin/tests/system/checkconf/bad-kasp-max-zone-ttl.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-kasp-max-zone-ttl.conf 2026-07-20 14:47:53.620842017 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-kasp-max-zone-ttl.conf 2026-09-11 19:41:01.106321510 +0000 @@ -22,5 +22,5 @@ zone "example.net" { type primary; file "example.db"; - max-zone-ttl 600; + max-zone-ttl 600; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-mirror-zonename.conf bind9-9.20.29/bin/tests/system/checkconf/bad-mirror-zonename.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-mirror-zonename.conf 2026-07-20 14:47:53.623842092 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-mirror-zonename.conf 2026-09-11 19:41:01.109321582 +0000 @@ -12,6 +12,6 @@ */ zone "\0example" { - type mirror; - file "example.db"; + type mirror; + file "example.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-options-query-source-address-v4-v6.conf bind9-9.20.29/bin/tests/system/checkconf/bad-options-query-source-address-v4-v6.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-options-query-source-address-v4-v6.conf 2026-07-20 14:47:53.624842117 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-options-query-source-address-v4-v6.conf 2026-09-11 19:41:01.110321606 +0000 @@ -12,6 +12,6 @@ */ options { - query-source none; - query-source-v6 none; + query-source none; + query-source-v6 none; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-parental-agents-def-view2.conf bind9-9.20.29/bin/tests/system/checkconf/bad-parental-agents-def-view2.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-parental-agents-def-view2.conf 2026-07-20 14:47:53.624842117 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-parental-agents-def-view2.conf 2026-09-11 19:41:01.110321606 +0000 @@ -14,7 +14,7 @@ view "test" { remote-servers "net" { 192.168.1.2; - }; + }; zone "example.net" { type primary; file "example.net.db"; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-primaries-key.conf bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-key.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-primaries-key.conf 2026-07-20 14:47:53.625842142 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-key.conf 2026-09-11 19:41:01.111321631 +0000 @@ -12,6 +12,6 @@ */ zone example { - type secondary; - primaries { 1.2.3.4 key a..b; }; + type secondary; + primaries { 1.2.3.4 key a..b; }; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-primaries-key2.conf bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-key2.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-primaries-key2.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-key2.conf 2026-09-11 19:41:01.111321631 +0000 @@ -0,0 +1,10 @@ +key "akey" { + algorithm "hmac-sha256"; + secret "abcd"; +}; + +zone "junk" { + type secondary; + /* Invalid key name, empty label. */ + primaries { 1.2.3.4 key ".."; }; +}; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-primaries-notfound.conf bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-notfound.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-primaries-notfound.conf 2026-07-20 14:47:53.625842142 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-notfound.conf 2026-09-11 19:41:01.111321631 +0000 @@ -12,7 +12,7 @@ */ remote-servers "net" { - 192.168.1.2; + 192.168.1.2; }; zone "example.net" { diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-primaries-tls.conf bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-tls.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-primaries-tls.conf 2026-07-20 14:47:53.625842142 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-primaries-tls.conf 2026-09-11 19:41:01.111321631 +0000 @@ -12,6 +12,6 @@ */ zone example { - type secondary; - primaries { 1.2.3.4 tls a..b; }; + type secondary; + primaries { 1.2.3.4 tls a..b; }; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-query-source-address-v4-none.conf bind9-9.20.29/bin/tests/system/checkconf/bad-query-source-address-v4-none.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-query-source-address-v4-none.conf 2026-07-20 14:47:53.625842142 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-query-source-address-v4-none.conf 2026-09-11 19:41:01.112321655 +0000 @@ -12,5 +12,5 @@ */ server 1.2.3.4 { - query-source none; + query-source none; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-query-source-address-v6-none.conf bind9-9.20.29/bin/tests/system/checkconf/bad-query-source-address-v6-none.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-query-source-address-v6-none.conf 2026-07-20 14:47:53.626842167 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-query-source-address-v6-none.conf 2026-09-11 19:41:01.112321655 +0000 @@ -12,5 +12,5 @@ */ server fd92:7065:b8e:ffff::1 { - query-source-v6 none; + query-source-v6 none; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-random-device.conf bind9-9.20.29/bin/tests/system/checkconf/bad-random-device.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-random-device.conf 2026-07-20 14:47:53.626842167 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-random-device.conf 2026-09-11 19:41:01.112321655 +0000 @@ -12,5 +12,5 @@ */ options { - random-device "/dev/urandom"; + random-device "/dev/urandom"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-rrl-table-size.conf bind9-9.20.29/bin/tests/system/checkconf/bad-rrl-table-size.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-rrl-table-size.conf 2026-07-20 14:47:53.627842192 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-rrl-table-size.conf 2026-09-11 19:41:01.114321703 +0000 @@ -13,13 +13,13 @@ options { rate-limit { - responses-per-second 2; - all-per-second 50; - slip 3; - exempt-clients { 10.53.0.7; }; - log-only yes; + responses-per-second 2; + all-per-second 50; + slip 3; + exempt-clients { 10.53.0.7; }; + log-only yes; - min-table-size 0; - max-table-size 0; + min-table-size 0; + max-table-size 0; }; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-static-initial-2.conf bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-2.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-static-initial-2.conf 2026-07-20 14:47:53.628842217 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-2.conf 2026-09-11 19:41:01.114321703 +0000 @@ -13,5 +13,5 @@ trust-anchors { example. initial-ds 60724 5 1 "D74CF845955A0DFE604AF215E948E67D2EA94FF3"; - example. static-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; + example. static-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-static-initial-3.conf bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-3.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-static-initial-3.conf 2026-07-20 14:47:53.628842217 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-3.conf 2026-09-11 19:41:01.114321703 +0000 @@ -13,5 +13,5 @@ trust-anchors { example. static-ds 60724 5 1 "D74CF845955A0DFE604AF215E948E67D2EA94FF3"; - example. initial-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; + example. initial-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/bad-static-initial-4.conf bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-4.conf --- bind9-9.20.26/bin/tests/system/checkconf/bad-static-initial-4.conf 2026-07-20 14:47:53.628842217 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/bad-static-initial-4.conf 2026-09-11 19:41:01.114321703 +0000 @@ -12,6 +12,6 @@ */ trust-anchors { - example. initial-key 257 3 5 "AwEAAawvFp8GlBx8Qt6yaIqXkDe+nMkSk2HkTAG7qlVBo++AQwZ1j3Xl25IN4jsw0VTMbKUbafw9DYsVzztIwx1sNkKRLo6qP9SSkBL8RicQaafGtURtsYI3oqte5qqLve1CUpRD8J06Pg1xkOxsDlz9sQAyiQrOyvMbykJYkYrFYGLzYAgl/JtMyVVYlBl9pqxQuAPKYPOuO1axaad/wLN3+wTy/hcJfpvJpqzXlDF9bI5RmpoX/7geZ06vpcYJEoT0xkkmPlEl0ZjEDrm/WIaSWG0/CEDpHcOXFz4OEczMVpY+lnuFfKybwF1WHFn2BwVEOS6cMM6ukIjINQyrszHhWUU="; - example. static-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; + example. initial-key 257 3 5 "AwEAAawvFp8GlBx8Qt6yaIqXkDe+nMkSk2HkTAG7qlVBo++AQwZ1j3Xl25IN4jsw0VTMbKUbafw9DYsVzztIwx1sNkKRLo6qP9SSkBL8RicQaafGtURtsYI3oqte5qqLve1CUpRD8J06Pg1xkOxsDlz9sQAyiQrOyvMbykJYkYrFYGLzYAgl/JtMyVVYlBl9pqxQuAPKYPOuO1axaad/wLN3+wTy/hcJfpvJpqzXlDF9bI5RmpoX/7geZ06vpcYJEoT0xkkmPlEl0ZjEDrm/WIaSWG0/CEDpHcOXFz4OEczMVpY+lnuFfKybwF1WHFn2BwVEOS6cMM6ukIjINQyrszHhWUU="; + example. static-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/check-dup-records-fail.conf bind9-9.20.29/bin/tests/system/checkconf/check-dup-records-fail.conf --- bind9-9.20.26/bin/tests/system/checkconf/check-dup-records-fail.conf 2026-07-20 14:47:53.631842292 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/check-dup-records-fail.conf 2026-09-11 19:41:01.117321775 +0000 @@ -12,12 +12,12 @@ */ options { - check-integrity yes; // default is yes + check-integrity yes; // default is yes }; zone "check-dup-records" { - type primary; - file "check-dup-records.db"; - check-dup-records fail; + type primary; + file "check-dup-records.db"; + check-dup-records fail; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/check-mx-cname-fail.conf bind9-9.20.29/bin/tests/system/checkconf/check-mx-cname-fail.conf --- bind9-9.20.26/bin/tests/system/checkconf/check-mx-cname-fail.conf 2026-07-20 14:47:53.631842292 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/check-mx-cname-fail.conf 2026-09-11 19:41:01.117321775 +0000 @@ -12,11 +12,11 @@ */ options { - check-integrity yes; // default is yes + check-integrity yes; // default is yes }; zone "check-mx-cname" { - type primary; - file "check-mx-cname.db"; - check-mx-cname fail; + type primary; + file "check-mx-cname.db"; + check-mx-cname fail; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/check-mx-fail.conf bind9-9.20.29/bin/tests/system/checkconf/check-mx-fail.conf --- bind9-9.20.26/bin/tests/system/checkconf/check-mx-fail.conf 2026-07-20 14:47:53.632842317 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/check-mx-fail.conf 2026-09-11 19:41:01.118321800 +0000 @@ -12,11 +12,11 @@ */ options { - check-integrity yes; // default is yes + check-integrity yes; // default is yes }; zone "check-mx" { - type primary; - file "check-mx.db"; - check-mx fail; + type primary; + file "check-mx.db"; + check-mx fail; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/check-names-fail.conf bind9-9.20.29/bin/tests/system/checkconf/check-names-fail.conf --- bind9-9.20.26/bin/tests/system/checkconf/check-names-fail.conf 2026-07-20 14:47:53.632842317 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/check-names-fail.conf 2026-09-11 19:41:01.118321800 +0000 @@ -12,11 +12,11 @@ */ options { - check-integrity yes; // default is yes + check-integrity yes; // default is yes }; zone "check-names" { - type primary; - file "check-names.db"; - check-names fail; + type primary; + file "check-names.db"; + check-names fail; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/check-root-static-ds.conf bind9-9.20.29/bin/tests/system/checkconf/check-root-static-ds.conf --- bind9-9.20.26/bin/tests/system/checkconf/check-root-static-ds.conf 2026-07-20 14:47:53.632842317 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/check-root-static-ds.conf 2026-09-11 19:41:01.118321800 +0000 @@ -12,5 +12,5 @@ */ trust-anchors { - . static-ds 20326 8 2 "E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D"; + . static-ds 20326 8 2 "E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/check-srv-cname-fail.conf bind9-9.20.29/bin/tests/system/checkconf/check-srv-cname-fail.conf --- bind9-9.20.26/bin/tests/system/checkconf/check-srv-cname-fail.conf 2026-07-20 14:47:53.632842317 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/check-srv-cname-fail.conf 2026-09-11 19:41:01.118321800 +0000 @@ -12,11 +12,11 @@ */ options { - check-integrity yes; // default is yes + check-integrity yes; // default is yes }; zone "check-srv-cname" { - type primary; - file "check-srv-cname.db"; - check-srv-cname fail; + type primary; + file "check-srv-cname.db"; + check-srv-cname fail; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/check-wildcard-no.conf bind9-9.20.29/bin/tests/system/checkconf/check-wildcard-no.conf --- bind9-9.20.26/bin/tests/system/checkconf/check-wildcard-no.conf 2026-07-20 14:47:53.633842342 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/check-wildcard-no.conf 2026-09-11 19:41:01.119321824 +0000 @@ -12,7 +12,7 @@ */ zone "check-wildcard" { - type primary; - file "check-wildcard.db"; - check-wildcard no; + type primary; + file "check-wildcard.db"; + check-wildcard no; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/check-wildcard.conf bind9-9.20.29/bin/tests/system/checkconf/check-wildcard.conf --- bind9-9.20.26/bin/tests/system/checkconf/check-wildcard.conf 2026-07-20 14:47:53.633842342 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/check-wildcard.conf 2026-09-11 19:41:01.119321824 +0000 @@ -12,7 +12,7 @@ */ zone "check-wildcard" { - type primary; - file "check-wildcard.db"; - check-wildcard yes; + type primary; + file "check-wildcard.db"; + check-wildcard yes; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/deprecated.conf bind9-9.20.29/bin/tests/system/checkconf/deprecated.conf --- bind9-9.20.26/bin/tests/system/checkconf/deprecated.conf 2026-07-20 14:47:53.633842342 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/deprecated.conf 2026-09-11 19:41:01.119321824 +0000 @@ -19,8 +19,8 @@ dnssec-validation yes; max-zone-ttl 600; - dialup yes; - heartbeat-interval 60; + dialup yes; + heartbeat-interval 60; use-v4-udp-ports { range 1024 65535; }; use-v6-udp-ports { range 1024 65535; }; @@ -38,24 +38,24 @@ trusted-keys { fake.trusted. 257 3 8 - "AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF - FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX - bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD - X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz - W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS - Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq - QxA+Uk1ihz0="; + "AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF + FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX + bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD + X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz + W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS + Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq + QxA+Uk1ihz0="; }; managed-keys { fake.managed. initial-key 257 3 8 - "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3 - +/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kv - ArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF - 0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+e - oZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfd - RUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwN - R1AkUTV74bU="; + "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3 + +/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kv + ArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF + 0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+e + oZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfd + RUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwN + R1AkUTV74bU="; }; zone example.com { diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-dot-doh-tls-nokeycert.conf bind9-9.20.29/bin/tests/system/checkconf/good-dot-doh-tls-nokeycert.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-dot-doh-tls-nokeycert.conf 2026-07-20 14:47:53.634842367 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-dot-doh-tls-nokeycert.conf 2026-09-11 19:41:01.120321848 +0000 @@ -13,6 +13,6 @@ # In some cases a "tls" statement may omit key-file and cert-file. tls local-tls { - protocols {TLSv1.2;}; - remote-hostname "fqdn.example.com"; + protocols {TLSv1.2;}; + remote-hostname "fqdn.example.com"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-ds-key-1.conf bind9-9.20.29/bin/tests/system/checkconf/good-ds-key-1.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-ds-key-1.conf 2026-07-20 14:47:53.634842367 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-ds-key-1.conf 2026-09-11 19:41:01.121321872 +0000 @@ -13,5 +13,5 @@ trust-anchors { example. initial-ds 60724 5 1 "D74CF845955A0DFE604AF215E948E67D2EA94FF3"; - example. initial-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; + example. initial-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-ds-key-2.conf bind9-9.20.29/bin/tests/system/checkconf/good-ds-key-2.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-ds-key-2.conf 2026-07-20 14:47:53.634842367 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-ds-key-2.conf 2026-09-11 19:41:01.121321872 +0000 @@ -13,5 +13,5 @@ trust-anchors { example. static-ds 60724 5 1 "D74CF845955A0DFE604AF215E948E67D2EA94FF3"; - example. static-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; + example. static-key 257 3 5 "AwEAAZtP9+RAA+W33A97e+HnnH8WTXzCWiEICyWj1B6rvZ9hd50ysbody0NLx7b3vZ1bzMLxLSRAr/n3Wi0TDZ1fvCKZhennfW8Wlc7ulCvHntSQYfKHUP0YWEo84sQAqIi850N1aiddj6CidwFo9JNW/HQ+8yarfrnGMFhX2STtkE0hNJ/R6JYKmD2EH7k1nyqJd08ibrEt55DuV4BiUjyyERdVbsuwE60jVqAwCKyVBYXb2sI+zv1yPNDBIANd6KTgnq6YWzx5ZodQP3W4K7Z/Bk3EKmVCvrTKZK/ADLAKaL0/6DD07+1jXA4BiNyoZTLTapkudkGad+Rn6zqCkwuMmrU="; }; Binary files /srv/release.debian.org/tmp/1mvoeOZTuW/bind9-9.20.26/bin/tests/system/checkconf/good-embedded-null-00.conf and /srv/release.debian.org/tmp/VqkGLzeUi9/bind9-9.20.29/bin/tests/system/checkconf/good-embedded-null-00.conf differ diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-key-directory.conf bind9-9.20.29/bin/tests/system/checkconf/good-key-directory.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-key-directory.conf 2026-07-20 14:47:53.635842392 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-key-directory.conf 2026-09-11 19:41:01.121321872 +0000 @@ -12,59 +12,59 @@ */ dnssec-policy "internet" { - keys { - ksk key-directory lifetime unlimited algorithm ecdsa256; - zsk key-directory lifetime P90D algorithm ecdsa256; - }; + keys { + ksk key-directory lifetime unlimited algorithm ecdsa256; + zsk key-directory lifetime P90D algorithm ecdsa256; + }; - nsec3param iterations 0 optout no salt-length 8; + nsec3param iterations 0 optout no salt-length 8; }; dnssec-policy "intranet" { - keys { - ksk key-directory lifetime unlimited algorithm ecdsa256; - zsk key-directory lifetime P30D algorithm ecdsa256; - }; - nsec3param iterations 0 optout no salt-length 8; + keys { + ksk key-directory lifetime unlimited algorithm ecdsa256; + zsk key-directory lifetime P30D algorithm ecdsa256; + }; + nsec3param iterations 0 optout no salt-length 8; }; dnssec-policy "localhost" { - keys { - ksk key-directory lifetime unlimited algorithm ecdsa256; - zsk key-directory lifetime P30D algorithm ecdsa256; - }; - nsec3param iterations 0 optout no salt-length 8; + keys { + ksk key-directory lifetime unlimited algorithm ecdsa256; + zsk key-directory lifetime P30D algorithm ecdsa256; + }; + nsec3param iterations 0 optout no salt-length 8; }; options { - key-directory "global/keys"; + key-directory "global/keys"; }; view "localhost" { - match-clients { 127.0.0.1; ::1; }; - zone "example.com" IN { - type primary; - file "localhost/example.com.zone"; - dnssec-policy "localhost"; - }; + match-clients { 127.0.0.1; ::1; }; + zone "example.com" IN { + type primary; + file "localhost/example.com.zone"; + dnssec-policy "localhost"; + }; }; view "external" { - match-clients { 0/0; }; - key-directory "external/keys"; - zone "example.com" IN { - type primary; - file "external/example.com.zone"; - dnssec-policy "internet"; - }; + match-clients { 0/0; }; + key-directory "external/keys"; + zone "example.com" IN { + type primary; + file "external/example.com.zone"; + dnssec-policy "internet"; + }; }; view "internal" { - match-clients { ::/0; }; - key-directory "internal/keys"; - zone "example.com" IN { - type primary; - file "internal/example.com.zone"; - dnssec-policy "intranet"; - }; + match-clients { ::/0; }; + key-directory "internal/keys"; + zone "example.com" IN { + type primary; + file "internal/example.com.zone"; + dnssec-policy "intranet"; + }; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-key-view.conf bind9-9.20.29/bin/tests/system/checkconf/good-key-view.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-key-view.conf 2026-07-20 14:47:53.635842392 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-key-view.conf 2026-09-11 19:41:01.122321896 +0000 @@ -13,15 +13,15 @@ view aview { key akey { - algorithm hmac-sha256; - secret "9999abcd8765"; + algorithm hmac-sha256; + secret "9999abcd8765"; }; zone "azone" { type secondary; - file "azone.db"; - primaries { - 1.2.3.4 key "akey"; - }; - }; + file "azone.db"; + primaries { + 1.2.3.4 key "akey"; + }; + }; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-nonempty-trust-anchors.conf bind9-9.20.29/bin/tests/system/checkconf/good-nonempty-trust-anchors.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-nonempty-trust-anchors.conf 2026-07-20 14:47:53.636842417 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-nonempty-trust-anchors.conf 2026-09-11 19:41:01.123321920 +0000 @@ -16,5 +16,5 @@ }; trust-anchors { - example. static-ds 60724 5 2 "29E79B9064EE1A11DF3BFF19581DDFED7952C22CC204ACE17B6007EB1437E9E6"; + example. static-ds 60724 5 2 "29E79B9064EE1A11DF3BFF19581DDFED7952C22CC204ACE17B6007EB1437E9E6"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-options-query-source-address-v4-none.conf bind9-9.20.29/bin/tests/system/checkconf/good-options-query-source-address-v4-none.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-options-query-source-address-v4-none.conf 2026-07-20 14:47:53.637842442 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-options-query-source-address-v4-none.conf 2026-09-11 19:41:01.123321920 +0000 @@ -12,5 +12,5 @@ */ options { - query-source none; + query-source none; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-options-query-source-address-v6-none.conf bind9-9.20.29/bin/tests/system/checkconf/good-options-query-source-address-v6-none.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-options-query-source-address-v6-none.conf 2026-07-20 14:47:53.637842442 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-options-query-source-address-v6-none.conf 2026-09-11 19:41:01.123321920 +0000 @@ -12,5 +12,5 @@ */ options { - query-source-v6 none; + query-source-v6 none; }; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-quoted-key-names.conf bind9-9.20.29/bin/tests/system/checkconf/good-quoted-key-names.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-quoted-key-names.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-quoted-key-names.conf 2026-09-11 19:41:01.124321944 +0000 @@ -0,0 +1,17 @@ +/* + * Key names may be quoted or unquoted, in both definitions and + * references, and a hyphenated name works in either form. + */ +key rndc-key { + algorithm hmac-sha256; + secret "1234abcd8765"; +}; + +key "rndc_key" { + algorithm hmac-sha256; + secret "1234abcd8765"; +}; + +controls { + inet 127.0.0.1 port 953 allow { any; } keys { "rndc-key"; rndc_key; }; +}; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-remote-servers-cycle.conf bind9-9.20.29/bin/tests/system/checkconf/good-remote-servers-cycle.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-remote-servers-cycle.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-remote-servers-cycle.conf 2026-09-11 19:41:01.124321944 +0000 @@ -0,0 +1,27 @@ +/* + * Reference cycles in remote-servers lists are legal and resolve to + * the addresses reachable without following the cycle (GL #6287). + */ + +primaries "xfer-servers" { "xfer-servers"; }; +primaries "loop-tail" { 10.53.0.99; "loop-tail"; }; +primaries "loop-a" { "loop-b"; }; +primaries "loop-b" { "loop-a"; 10.53.0.99; }; + +zone "example" { + type primary; + file "example.db"; + also-notify { "xfer-servers"; }; +}; + +zone "cycle-tail" { + type secondary; + file "cycle-tail.db"; + primaries { "loop-tail"; }; +}; + +zone "cycle-mutual" { + type secondary; + file "cycle-mutual.db"; + primaries { "loop-a"; }; +}; diff -Nru bind9-9.20.26/bin/tests/system/checkconf/good-remote-servers-named.conf bind9-9.20.29/bin/tests/system/checkconf/good-remote-servers-named.conf --- bind9-9.20.26/bin/tests/system/checkconf/good-remote-servers-named.conf 2026-07-20 14:47:53.638842467 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/good-remote-servers-named.conf 2026-09-11 19:41:01.124321944 +0000 @@ -12,8 +12,8 @@ */ key foo { - algorithm hmac-sha256; - secret "9999abcd8765"; + algorithm hmac-sha256; + secret "9999abcd8765"; }; tls bar { diff -Nru bind9-9.20.26/bin/tests/system/checkconf/warn-chaos-recursion.conf bind9-9.20.29/bin/tests/system/checkconf/warn-chaos-recursion.conf --- bind9-9.20.26/bin/tests/system/checkconf/warn-chaos-recursion.conf 2026-07-20 14:47:53.644842618 +0000 +++ bind9-9.20.29/bin/tests/system/checkconf/warn-chaos-recursion.conf 2026-09-11 19:41:01.129322065 +0000 @@ -3,10 +3,10 @@ }; view chaos ch { - match-clients { any; }; - recursion yes; - zone "." { - type hint; - file "chaos.hints"; - }; + match-clients { any; }; + recursion yes; + zone "." { + type hint; + file "chaos.hints"; + }; }; diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/CA.cfg bind9-9.20.29/bin/tests/system/checkds/CA/CA.cfg --- bind9-9.20.26/bin/tests/system/checkds/CA/CA.cfg 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/CA.cfg 2026-09-11 19:41:01.189323514 +0000 @@ -0,0 +1,121 @@ +## How To +# To issue a certificate: +# +# 1. Generate the next certificate serial (if the file does not exist): +# xxd -l 8 -u -ps /dev/urandom > ./serial +# 2. Create the new certificate request (e.g. for foo.example.com): +# openssl req -config ./CA.cfg -new -subj "/CN=foo.example.com" \ +# -addext "subjectAltName=DNS:foo.example.com,IP:X.X.X.X" \ +# -newkey rsa -keyout ./certs/foo.example.com.key \ +# -out ./certs/foo.example.com.csr +# +# The above will generate request for an RSA-based certificate. One +# can issue an ECDSA-based certificate by replacing "-newkey rsa" with +# "-newkey ec -pkeyopt ec_paramgen_curve:secp384r1". +# +# 3. Issue the certificate: +# openssl ca -config ./CA.cfg -in ./certs/foo.example.com.csr \ +# -out ./certs/foo.example.com.pem +# +# To cleanup the internal database from expired certificates: +# +# 1. openssl ca -config ./CA.cfg -updatedb +# +# To revoke a certificate: +# +# 1. Revoke the certificate via file (e.g. for foo.example.com): +# openssl ca -config ./CA.cfg -revoke ./certs/foo.example.com.pem +# 2. Optionally remove the certificate file if you do not need it anymore: +# rm ./certs/foo.example.com.pem +# 3. Generate the certificate revocation list file: CRL (e.g. revoked.crl): +# openssl ca -config ./CA.cfg -gencrl > ./revoked.crl +# +# The key for CA was generated like follows +# openssl genrsa -out ./CA.key 3072 +# openssl req -x509 -new -key ./CA.key -days 10950 -out ./CA.pem +# +# See also: +# +# - https://jamielinux.com/docs/openssl-certificate-authority/index.html +# - https://www.openssl.org/docs/man1.1.1/man1/ca.html +# - https://www.openssl.org/docs/man1.1.1/man1/openssl-req.html +# - https://security.stackexchange.com/questions/74345/provide-subjectaltname-to-openssl-directly-on-the-command-line +# - https://security.stackexchange.com/a/190646 - for ECDSA certificates +# - https://gist.github.com/Soarez/9688998 +# - https://habr.com/ru/post/192446/ - Beware, your screen might "go Cyrillic"! + +# certificate authority configuration +[ca] +default_ca = CA_default # The default ca section + +[CA_default] +dir = . +new_certs_dir = $dir/newcerts # new certs dir (must be created) +certificate = $dir/CA.pem # The CA cert +private_key = $dir/private/CA.key # CA private key + +serial = $dir/serial # serial number file for the next certificate + # Update before issuing it: + # xxd -l 8 -u -ps /dev/urandom > ./serial +database = $dir/index.txt # (must be created manually: touch ./index.txt) + +default_days = 10950 # how long to certify for + +#default_crl_days = 30 # the number of days before the +default_crl_days = 10950 # next CRL is due. That is the + # days from now to place in the + # CRL nextUpdate field. If CRL + # is expired, certificate + # verifications will fail even + # for otherwise valid + # certificates. Clients might + # cache the CRL, so the expiry + # period should normally be + # relatively short (default: + # 30) for production CAs. + +default_md = sha256 # digest to use + +policy = policy_default # default policy +email_in_dn = no # Don't add the email into cert DN + +name_opt = ca_default # Subject name display option +cert_opt = ca_default # Certificate display option + +# We need the following in order to copy Subject Alt Name(s) from a +# request to the certificate. +copy_extensions = copy # copy extensions from request + +[policy_default] +countryName = optional +stateOrProvinceName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# default certificate requests settings +[req] +# Options for the `req` tool (`man req`). +default_bits = 3072 # for RSA only +distinguished_name = req_default +string_mask = utf8only +# SHA-1 is deprecated, so use SHA-256 instead. +default_md = sha256 +# do not encrypt the private key file +encrypt_key = no + +[req_default] +# See . +countryName = Country Name (2 letter code) +stateOrProvinceName = State or Province Name (full name) +localityName = Locality Name (e.g., city) +0.organizationName = Organization Name (e.g., company) +organizationalUnitName = Organizational Unit Name (e.g. department) +commonName = Common Name (e.g. server FQDN or YOUR name) +emailAddress = Email Address +# defaults +countryName_default = UA +stateOrProvinceName_default = Kharkiv Oblast +localityName_default = Kharkiv +0.organizationName_default = ISC +organizationalUnitName_default = Software Engeneering (BIND 9) diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/CA.pem bind9-9.20.29/bin/tests/system/checkds/CA/CA.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/CA.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/CA.pem 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE3TCCA0WgAwIBAgIUeZPKrvbGEBZaRc2jNczlIsJXyPYwDQYJKoZIhvcNAQEL +BQAwfTELMAkGA1UEBhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4G +A1UEBwwHS2hhcmtpdjEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0 +aXVtMRwwGgYDVQQDDBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDEyNDEyNDA1 +NFoYDzIwNTIwMTE3MTI0MDU0WjB9MQswCQYDVQQGEwJVQTEYMBYGA1UECAwPS2hh +cmtpdiBPYmxhc3QnMRAwDgYDVQQHDAdLaGFya2l2MSQwIgYDVQQKDBtJbnRlcm5l +dCBTeXN0ZW1zIENvbnNvcnRpdW0xHDAaBgNVBAMME2NhLnRlc3QuZXhhbXBsZS5j +b20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCi6hEegBzpUKbE1NTo +Z7uz7EMUY7TBckkiw/7ydTLKNa8YI4JpBguFvWQsDY0dGFJIoVwyHyNx3seW/LoI +B5zWPZ2xbOvLLceA+t2NZpbc98E7jUOVS123yED+nqlfZjCq9Zt0r/ezwnQtjnFF +ko1mcU4H9Jvg8aIgnU2AxE78zciU9CY8799pFFNThIjbooI8oVbfjbzbpmLzxjA5 +3rDmZBTh+ySTlMa2U2oT4WPjRltZWnJVegRRLpG95GnTbQ1fkJAbj1Iu10XTkCee +wBOqaA1UJem0a6pby5odE414Y7c0ETKcmaJtYENQyO0IJwZWDKtVe5OTIAklakia +eyFTCAw1h5tHCYLaJW/Yu2wlLl5RNQcRZ9+cWXnldTY+TI1iBjfmADjLdKJYUlhX +z7kWJtTi63Sdv6WYcEXxaWpxT+R3e2kaR/R7GOo4gdkWpX1siGlRteHHH2/36CSQ +ZD2etcTUpGW+KDHFR4grnEfL1rt9UgvCjpa4KcssmZtWSSUCAwEAAaNTMFEwHQYD +VR0OBBYEFHyJ6Fzr5R9ySATFj/uSCJz1YCY5MB8GA1UdIwQYMBaAFHyJ6Fzr5R9y +SATFj/uSCJz1YCY5MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggGB +AF3y0hvzyZWtmuG1JwIcOcc1aPl1KdRy8bao/5iHYGYYrsdDgcO5/e+y9S/izalc +TdW7SKB5iBOCiE8fBNtToCvGP+fxNxHijpAmTr37G5sWuSo1T1VYFizHWL+df/Ig +TcSvDrEjSnAwaEdNJUWtjoIC4VzNKTLtZf16QIATTzTZa3bfgSetpWS7LhLQbHod +CSGI2QB1LRbqGC+a1Y85QxHv81jWzPWPzXYvnOLrDdQyBMOBcxDzrN4b6zg+5Itz +qGYt+IS71jAH0IhxAyD/U5n1jGJv02BnSq0ynLEOD6gsnZjqAwPbt/PM9pGbtbXO +70Q9rxr+vQc1IISKAEiH3txaEPi10wU98d6LbInJvQrmgHo/ntet8skWNYuxlEzS +wvynuE9KvvQtOTodWt5AePtKrhHdxu527a4CHVp59nYUjKSdMKjvmhMRXM1cNjFE +rA/pyyhozR47w3RzHMJVHw2GJ2B/HeqmxpXr1CmJjoRP38QCR7N+mqiZy85Fq2j2 +8Q== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/README bind9-9.20.29/bin/tests/system/checkds/CA/README --- bind9-9.20.26/bin/tests/system/checkds/CA/README 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/README 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,2 @@ +Please take a look at the contents of the CA.cfg file for further +instructions and configurations options. diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.key 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCq9Z95YLiCPSevj5Xm +lB/ijFFlZb8AT2bHUyL1fmivBm8JfjSa/j3pZePAF7rltyChZANiAARek2p62nXM +ZAjk+PkvK4U27uHf+s1MYPFEtRZ7+QPPoAhnb64no5WKaB5jq88uIGJS54w+Hu/e +DWlkZbbk3/4aSPhodYSDEfuBWQ7Blkh/JNoR3azLCsUJeCQxOt835rM= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client01.example.com.pem 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,68 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207431 (0x6bb3183cdef52007) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 10 17:44:20 2022 GMT + Not After : Feb 3 17:44:20 2052 GMT + Subject: CN=srv01.client01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:5e:93:6a:7a:da:75:cc:64:08:e4:f8:f9:2f:2b: + 85:36:ee:e1:df:fa:cd:4c:60:f1:44:b5:16:7b:f9: + 03:cf:a0:08:67:6f:ae:27:a3:95:8a:68:1e:63:ab: + cf:2e:20:62:52:e7:8c:3e:1e:ef:de:0d:69:64:65: + b6:e4:df:fe:1a:48:f8:68:75:84:83:11:fb:81:59: + 0e:c1:96:48:7f:24:da:11:dd:ac:cb:0a:c5:09:78: + 24:31:3a:df:37:e6:b3 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.client01.example.com + Signature Algorithm: sha256WithRSAEncryption + 82:bd:eb:8f:4e:a5:d2:46:c7:d8:70:3c:34:1d:58:43:1b:81: + 16:5d:c2:b0:76:4b:a9:f2:10:14:23:e4:ef:dc:59:03:b6:7f: + b0:40:34:e5:d0:82:4b:95:a6:07:9a:45:51:94:cf:08:c2:4e: + c9:44:d5:f3:b6:ed:f2:a0:01:94:ad:e0:0e:0f:ab:85:6f:35: + 4b:07:c8:97:25:fb:69:ff:a1:99:bc:ec:70:6c:51:b5:32:95: + e9:c9:45:cf:45:e2:c5:5e:b1:59:a2:e1:f2:83:c8:87:68:c4: + 60:e2:db:50:6c:18:64:1b:9a:9a:cc:7c:e7:fd:d9:f2:b7:d1: + de:1d:ec:29:c9:58:db:7b:9a:a1:06:9a:ce:36:a0:45:10:dc: + 7d:81:24:21:34:30:4c:71:f9:fc:96:37:d6:cf:0d:9d:11:12: + c7:62:bc:19:5b:79:e5:e0:37:e8:17:36:4b:13:af:fa:2c:2e: + 36:d9:be:53:e1:c3:f9:bc:94:a6:7a:97:14:99:36:f9:14:38: + 11:20:3a:2a:9d:fd:64:63:d0:a2:8f:f0:99:a9:02:ca:57:48: + d2:7d:65:44:b6:85:a0:38:ec:e8:19:7e:c2:48:e3:1d:22:53: + cf:3b:d4:0a:98:e1:72:62:ec:8b:01:3f:5a:ea:26:2c:8c:16: + c3:80:5a:c2:5d:40:c5:65:1c:e2:9a:e3:d6:65:16:ee:dc:17: + 30:d8:26:87:92:d0:ef:c7:72:07:99:86:05:9e:49:35:41:33: + b9:bb:cb:1b:25:50:70:85:e3:0f:c7:b9:b2:37:00:1b:87:a2: + 47:97:34:5b:cd:dc:66:22:e5:de:25:ec:57:fe:37:75:2c:03: + 10:f4:d4:a7:cc:f5:4b:0b:ff:eb:d3:a6:78:2e:cd:8f:65:51: + a7:8c:ef:83:67:ec:94:13:c2:1f:74:74:55:7c:a3:0b:b7:2f: + 80:5a:62:04:1d:a2:c0:c1:de:b2:7d:31:3b:a1:fa:f7:40:a7: + bd:12:25:95:5b:8b +-----BEGIN CERTIFICATE----- +MIIDITCCAYmgAwIBAgIIa7MYPN71IAcwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIxMDE3NDQyMFoYDzIwNTIwMjAz +MTc0NDIwWjAlMSMwIQYDVQQDDBpzcnYwMS5jbGllbnQwMS5leGFtcGxlLmNvbTB2 +MBAGByqGSM49AgEGBSuBBAAiA2IABF6TanradcxkCOT4+S8rhTbu4d/6zUxg8US1 +Fnv5A8+gCGdvriejlYpoHmOrzy4gYlLnjD4e794NaWRltuTf/hpI+Gh1hIMR+4FZ +DsGWSH8k2hHdrMsKxQl4JDE63zfms6MpMCcwJQYDVR0RBB4wHIIac3J2MDEuY2xp +ZW50MDEuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggGBAIK9649OpdJGx9hw +PDQdWEMbgRZdwrB2S6nyEBQj5O/cWQO2f7BANOXQgkuVpgeaRVGUzwjCTslE1fO2 +7fKgAZSt4A4Pq4VvNUsHyJcl+2n/oZm87HBsUbUylenJRc9F4sVesVmi4fKDyIdo +xGDi21BsGGQbmprMfOf92fK30d4d7CnJWNt7mqEGms42oEUQ3H2BJCE0MExx+fyW +N9bPDZ0REsdivBlbeeXgN+gXNksTr/osLjbZvlPhw/m8lKZ6lxSZNvkUOBEgOiqd +/WRj0KKP8JmpAspXSNJ9ZUS2haA47OgZfsJI4x0iU8871AqY4XJi7IsBP1rqJiyM +FsOAWsJdQMVlHOKa49ZlFu7cFzDYJoeS0O/HcgeZhgWeSTVBM7m7yxslUHCF4w/H +ubI3ABuHokeXNFvN3GYi5d4l7Ff+N3UsAxD01KfM9UsL/+vTpnguzY9lUaeM74Nn +7JQTwh90dFV8owu3L4BaYgQdosDB3rJ9MTuh+vdAp70SJZVbiw== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.key 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDD1/sp/yNsAc9Z6TPhm +0xT0ZhSf/9XJD6daSpdUDJ/nEJKa+sBXDWJHuXrbNRqUK2qhZANiAATmRfpXEmxZ +ECOLelx2M+s7Qfq3HJCzLzMtRXvj5baloqKkFPRQnbDGOLrpRWWkZbkQMi+Tm9XY +z7QpW9xOyOymn1h2JPTF0UhVUutdsIWThe4+uMSxzQhZlRL/e5vuark= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client02-ns2.example.com.pem 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,68 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207432 (0x6bb3183cdef52008) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 11 13:21:12 2022 GMT + Not After : Feb 4 13:21:12 2052 GMT + Subject: CN=srv01.client02-ns2.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:e6:45:fa:57:12:6c:59:10:23:8b:7a:5c:76:33: + eb:3b:41:fa:b7:1c:90:b3:2f:33:2d:45:7b:e3:e5: + b6:a5:a2:a2:a4:14:f4:50:9d:b0:c6:38:ba:e9:45: + 65:a4:65:b9:10:32:2f:93:9b:d5:d8:cf:b4:29:5b: + dc:4e:c8:ec:a6:9f:58:76:24:f4:c5:d1:48:55:52: + eb:5d:b0:85:93:85:ee:3e:b8:c4:b1:cd:08:59:95: + 12:ff:7b:9b:ee:6a:b9 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.client02-ns2.example.com + Signature Algorithm: sha256WithRSAEncryption + 43:ec:0f:62:17:f6:f4:90:3b:7c:36:21:f2:18:94:a6:42:51: + 1e:1d:2a:43:8f:05:b7:8d:3c:ca:f0:20:2f:65:4b:be:48:ad: + 6a:0a:cc:2d:1f:d6:27:1d:af:4a:36:86:ed:0d:03:75:c5:71: + ec:58:9b:ec:f9:0f:e4:83:ef:6f:91:da:20:73:47:ac:e7:c7: + 8b:22:b2:d1:6e:a0:b0:d6:1c:4c:70:1e:74:08:1d:7f:61:06: + e5:be:f3:e8:c4:15:60:e2:b0:02:9b:f0:13:af:76:5b:a8:c7: + 91:2c:10:5f:0d:32:89:51:5a:7f:17:1b:7c:c6:46:97:ee:e7: + bb:8a:48:38:a2:52:d4:ff:3b:1c:ec:4a:a9:8c:a5:23:3a:04: + bb:d7:b8:ad:5b:69:7f:1d:be:ca:96:e0:eb:56:05:43:ee:c8: + ff:2c:48:03:00:c6:c2:ac:fc:4e:15:47:86:c5:33:ed:70:f6: + 98:bc:0b:07:b9:5b:1a:ec:fd:3c:bf:26:61:68:fc:db:02:55: + 07:ae:76:0e:be:ff:c5:b8:56:fb:52:54:a4:b1:2d:64:b4:1d: + 55:02:4f:da:06:bd:26:e4:22:d2:94:1f:7e:29:c4:97:10:d1: + 75:7d:41:53:be:46:52:70:b1:d9:ff:bb:9f:96:19:e3:a0:ba: + d0:4a:5a:8d:da:22:73:89:f0:4c:e6:18:80:53:be:bd:64:56: + 6a:c9:58:71:40:66:9e:4a:3e:31:3b:74:9e:6e:6a:f5:65:ca: + 93:06:52:00:74:65:a0:3a:eb:2e:56:56:d2:a5:4b:0e:85:17: + 25:78:cb:f3:f9:53:7b:85:f9:82:15:87:bc:36:70:b5:69:64: + 48:11:79:b9:2c:2e:cc:09:fd:0f:b0:b7:cd:97:3b:c7:0f:49: + 1a:fc:15:49:d6:1c:a9:dc:14:ff:44:d2:be:5a:36:00:66:0c: + d5:b8:bf:16:9e:60:27:79:c0:f5:b4:ff:2f:af:8c:b2:49:75: + 61:44:05:1a:e8:cd +-----BEGIN CERTIFICATE----- +MIIDKTCCAZGgAwIBAgIIa7MYPN71IAgwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIxMTEzMjExMloYDzIwNTIwMjA0 +MTMyMTEyWjApMScwJQYDVQQDDB5zcnYwMS5jbGllbnQwMi1uczIuZXhhbXBsZS5j +b20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATmRfpXEmxZECOLelx2M+s7Qfq3HJCz +LzMtRXvj5baloqKkFPRQnbDGOLrpRWWkZbkQMi+Tm9XYz7QpW9xOyOymn1h2JPTF +0UhVUutdsIWThe4+uMSxzQhZlRL/e5vuarmjLTArMCkGA1UdEQQiMCCCHnNydjAx +LmNsaWVudDAyLW5zMi5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAQ+wP +Yhf29JA7fDYh8hiUpkJRHh0qQ48Ft408yvAgL2VLvkitagrMLR/WJx2vSjaG7Q0D +dcVx7Fib7PkP5IPvb5HaIHNHrOfHiyKy0W6gsNYcTHAedAgdf2EG5b7z6MQVYOKw +ApvwE692W6jHkSwQXw0yiVFafxcbfMZGl+7nu4pIOKJS1P87HOxKqYylIzoEu9e4 +rVtpfx2+ypbg61YFQ+7I/yxIAwDGwqz8ThVHhsUz7XD2mLwLB7lbGuz9PL8mYWj8 +2wJVB652Dr7/xbhW+1JUpLEtZLQdVQJP2ga9JuQi0pQffinElxDRdX1BU75GUnCx +2f+7n5YZ46C60Epajdoic4nwTOYYgFO+vWRWaslYcUBmnko+MTt0nm5q9WXKkwZS +AHRloDrrLlZW0qVLDoUXJXjL8/lTe4X5ghWHvDZwtWlkSBF5uSwuzAn9D7C3zZc7 +xw9JGvwVSdYcqdwU/0TSvlo2AGYM1bi/Fp5gJ3nA9bT/L6+Mskl1YUQFGujN +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.key 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCQvnl9FD/mrb+KQaC8 +VMhKW2sxrYFHhZnUYBc3Luz/X3vECNVqLVc5asLu+NrkioyhZANiAAQ4mpvCaoKm +0VCKeHrRvmG+1LbT1qICl6RIUMDFHdgtIxklbpECHWnCd9bxqE9Kmh08aVqJQQry +4GRXGw6e359MezxC3CHILJWrs0xfVsRw7oqk5EbEnpj1yHuyc9dFk/A= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.client03-ns2-expired.example.com.pem 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207433 (0x6bb3183cdef52009) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Aug 14 05:00:00 2012 GMT + Not After : Aug 14 06:00:00 2012 GMT + Subject: CN=srv01.client03-ns2-expired.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:38:9a:9b:c2:6a:82:a6:d1:50:8a:78:7a:d1:be: + 61:be:d4:b6:d3:d6:a2:02:97:a4:48:50:c0:c5:1d: + d8:2d:23:19:25:6e:91:02:1d:69:c2:77:d6:f1:a8: + 4f:4a:9a:1d:3c:69:5a:89:41:0a:f2:e0:64:57:1b: + 0e:9e:df:9f:4c:7b:3c:42:dc:21:c8:2c:95:ab:b3: + 4c:5f:56:c4:70:ee:8a:a4:e4:46:c4:9e:98:f5:c8: + 7b:b2:73:d7:45:93:f0 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.client03-ns2-expired.example.com + Signature Algorithm: sha256WithRSAEncryption + 38:12:1f:5f:26:b6:8e:9b:3f:77:89:5a:b8:e8:46:78:c3:d6: + f0:0c:67:5f:d5:a3:9c:f6:f2:0a:ae:9c:87:74:9f:a3:5b:8a: + 27:58:47:e5:78:1a:e9:db:b5:cc:28:a7:f8:18:e3:e7:20:43: + cf:82:06:5d:a1:d0:82:ab:15:be:86:46:1e:e6:4d:ad:78:a4: + 16:6c:99:41:3d:29:21:c8:6b:9d:3d:4a:cd:93:37:1f:1c:88: + c7:ae:b6:7c:73:42:57:57:32:9d:e8:c6:e2:3e:da:12:57:3e: + c8:56:4a:bb:d4:01:fc:8e:30:8d:19:fe:61:3d:5e:02:64:65: + a2:46:b3:6e:ea:f9:cb:4e:f0:b9:f6:bc:6b:38:10:19:d0:93: + f8:f7:d9:4c:d2:87:2c:7f:dc:f5:00:c6:29:dd:00:5e:d2:f4: + df:52:fb:7a:5a:ad:98:36:77:72:1f:01:ed:48:91:48:16:2d: + 35:a5:15:21:98:ff:7e:5d:a1:45:c9:5f:9d:c2:3e:e5:98:e2: + ee:ce:4d:18:76:3d:8a:0a:64:9b:f1:19:9d:b6:82:af:1b:15: + d3:48:69:f1:9b:67:76:1b:41:8e:1d:69:d5:31:64:95:01:41: + 73:c1:a9:29:53:6b:f3:29:ad:e0:96:52:8e:3e:8d:c1:8e:d8: + b5:0c:94:5f:a2:6c:3c:0f:3e:5b:10:af:21:00:74:d0:b7:30: + 6c:44:fb:3d:09:46:8d:1d:e6:c2:e4:0a:5b:f4:eb:e1:71:c7: + d5:36:13:90:05:fe:65:16:61:24:b5:41:f2:10:bd:2c:c3:34: + 69:15:25:d1:32:f2:b3:d7:da:23:1b:e9:5b:33:63:43:c8:dc: + 68:f2:31:b5:93:0e:64:ea:9a:45:36:9f:96:44:38:1e:4e:d8: + 45:ba:37:68:06:4d:da:d4:16:d3:3e:77:86:4e:8d:58:d6:06: + a8:60:11:4d:d9:81:f3:85:2b:ee:58:50:6e:ea:2b:f7:84:00: + 9c:ec:a1:90:d4:94 +-----BEGIN CERTIFICATE----- +MIIDNzCCAZ+gAwIBAgIIa7MYPN71IAkwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMB4XDTEyMDgxNDA1MDAwMFoXDTEyMDgxNDA2 +MDAwMFowMTEvMC0GA1UEAwwmc3J2MDEuY2xpZW50MDMtbnMyLWV4cGlyZWQuZXhh +bXBsZS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ4mpvCaoKm0VCKeHrRvmG+ +1LbT1qICl6RIUMDFHdgtIxklbpECHWnCd9bxqE9Kmh08aVqJQQry4GRXGw6e359M +ezxC3CHILJWrs0xfVsRw7oqk5EbEnpj1yHuyc9dFk/CjNTAzMDEGA1UdEQQqMCiC +JnNydjAxLmNsaWVudDAzLW5zMi1leHBpcmVkLmV4YW1wbGUuY29tMA0GCSqGSIb3 +DQEBCwUAA4IBgQA4Eh9fJraOmz93iVq46EZ4w9bwDGdf1aOc9vIKrpyHdJ+jW4on +WEfleBrp27XMKKf4GOPnIEPPggZdodCCqxW+hkYe5k2teKQWbJlBPSkhyGudPUrN +kzcfHIjHrrZ8c0JXVzKd6MbiPtoSVz7IVkq71AH8jjCNGf5hPV4CZGWiRrNu6vnL +TvC59rxrOBAZ0JP499lM0ocsf9z1AMYp3QBe0vTfUvt6Wq2YNndyHwHtSJFIFi01 +pRUhmP9+XaFFyV+dwj7lmOLuzk0Ydj2KCmSb8RmdtoKvGxXTSGnxm2d2G0GOHWnV +MWSVAUFzwakpU2vzKa3gllKOPo3Bjti1DJRfomw8Dz5bEK8hAHTQtzBsRPs9CUaN +HebC5Apb9OvhccfVNhOQBf5lFmEktUHyEL0swzRpFSXRMvKz19ojG+lbM2NDyNxo +8jG1kw5k6ppFNp+WRDgeTthFujdoBk3a1BbTPneGTo1Y1gaoYBFN2YHzhSvuWFBu +6iv3hACc7KGQ1JQ= +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.key 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDB/BdYjkgkVy4gTuXX3 +20DWo80uWsQkKDwMeOoaQ2cYy5Cm2AdTALDdBihGKRfACPqhZANiAAQSoXsPefIp +9Y9qBtAogxRDjxlMKZE2MA8GplbnV5tYLJ78nKNO9uNvkEDVCf2Ulo4UaHRv6Ken +q4w1lvLWj12XXdG5IlvvMRWh4ettb6+xL4Dlpak48m/5ZRRwp6Ws4Ro= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt01.example.com.pem 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207425 (0x6bb3183cdef52001) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:18:52 2022 GMT + Not After : Feb 1 17:18:52 2052 GMT + Subject: CN=srv01.crt01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:12:a1:7b:0f:79:f2:29:f5:8f:6a:06:d0:28:83: + 14:43:8f:19:4c:29:91:36:30:0f:06:a6:56:e7:57: + 9b:58:2c:9e:fc:9c:a3:4e:f6:e3:6f:90:40:d5:09: + fd:94:96:8e:14:68:74:6f:e8:a7:a7:ab:8c:35:96: + f2:d6:8f:5d:97:5d:d1:b9:22:5b:ef:31:15:a1:e1: + eb:6d:6f:af:b1:2f:80:e5:a5:a9:38:f2:6f:f9:65: + 14:70:a7:a5:ac:e1:1a + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.crt01.example.com, IP Address:10.53.0.1, IP Address:FD92:7065:B8E:FFFF:0:0:0:1 + Signature Algorithm: sha256WithRSAEncryption + 79:0f:08:ab:18:cc:f9:7a:bd:47:21:99:a1:a3:76:04:7f:d7: + 08:33:91:49:3d:2d:fc:8d:ff:c5:c1:8d:b8:70:05:65:32:cd: + e2:26:21:49:19:66:a2:94:4f:42:7d:83:3c:4f:ed:c1:87:89: + 5b:73:2c:64:64:67:29:f5:73:83:23:72:b7:a8:2e:d6:9a:de: + 13:0c:ba:35:d3:38:b1:c4:51:7d:81:fc:25:ca:a6:d9:d2:fa: + bb:6d:1f:a4:61:90:50:2d:8a:ed:70:1a:eb:56:2f:fc:7b:f3: + 76:df:68:8d:e8:a4:7d:82:b9:5c:c6:cb:d8:06:f7:78:dc:a7: + 94:35:d4:83:98:28:51:36:1c:73:47:e4:5b:32:d2:cd:de:1c: + 44:f6:de:37:8a:46:d0:14:8d:71:e5:10:22:b1:f9:73:f7:1b: + 4f:82:e1:a1:00:73:18:17:71:a2:bf:a2:0c:59:aa:43:58:46: + 82:f8:38:c4:5a:5a:9f:13:d7:a9:54:1f:58:9b:5d:52:16:d3: + a0:ba:6b:aa:cf:68:3a:d1:12:9c:94:ac:78:6b:7e:bc:69:6c: + 75:07:5d:fb:68:cd:e8:8d:bb:8c:b0:7c:6c:9e:f6:a5:7c:32: + 74:ef:c5:b1:1f:1d:ec:7b:2f:79:c0:3b:52:60:9b:48:89:09: + b4:46:34:69:d3:7b:1b:15:ef:0c:dd:64:1d:58:fe:a7:0b:b1: + 9d:28:1f:1e:9e:3c:c0:b1:a6:38:ab:9d:54:24:0e:75:6c:9e: + 90:13:b9:39:dc:43:fe:37:e3:14:0f:78:7e:2b:56:a2:d2:60: + 51:57:88:3b:4c:cf:24:67:36:77:21:bb:c8:07:eb:48:f7:b0: + 1e:e4:99:61:84:15:bb:61:3a:21:55:df:31:43:67:73:8f:6b: + e9:04:83:be:2d:8b:94:39:89:cf:40:d5:04:f7:6b:c9:c6:8c: + 6e:36:0f:5d:7a:9b:57:86:36:76:2c:75:35:47:50:ed:9a:84: + 7e:37:83:b5:21:a2 +-----BEGIN CERTIFICATE----- +MIIDMzCCAZugAwIBAgIIa7MYPN71IAEwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIwODE3MTg1MloYDzIwNTIwMjAx +MTcxODUyWjAiMSAwHgYDVQQDDBdzcnYwMS5jcnQwMS5leGFtcGxlLmNvbTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABBKhew958in1j2oG0CiDFEOPGUwpkTYwDwamVudX +m1gsnvyco07242+QQNUJ/ZSWjhRodG/op6erjDWW8taPXZdd0bkiW+8xFaHh621v +r7EvgOWlqTjyb/llFHCnpazhGqM+MDwwOgYDVR0RBDMwMYIXc3J2MDEuY3J0MDEu +ZXhhbXBsZS5jb22HBAo1AAGHEP2ScGULjv//AAAAAAAAAAEwDQYJKoZIhvcNAQEL +BQADggGBAHkPCKsYzPl6vUchmaGjdgR/1wgzkUk9LfyN/8XBjbhwBWUyzeImIUkZ +ZqKUT0J9gzxP7cGHiVtzLGRkZyn1c4MjcreoLtaa3hMMujXTOLHEUX2B/CXKptnS ++rttH6RhkFAtiu1wGutWL/x783bfaI3opH2CuVzGy9gG93jcp5Q11IOYKFE2HHNH +5Fsy0s3eHET23jeKRtAUjXHlECKx+XP3G0+C4aEAcxgXcaK/ogxZqkNYRoL4OMRa +Wp8T16lUH1ibXVIW06C6a6rPaDrREpyUrHhrfrxpbHUHXftozeiNu4ywfGye9qV8 +MnTvxbEfHex7L3nAO1Jgm0iJCbRGNGnTexsV7wzdZB1Y/qcLsZ0oHx6ePMCxpjir +nVQkDnVsnpATuTncQ/434xQPeH4rVqLSYFFXiDtMzyRnNnchu8gH60j3sB7kmWGE +FbthOiFV3zFDZ3OPa+kEg74ti5Q5ic9A1QT3a8nGjG42D116m1eGNnYsdTVHUO2a +hH43g7Uhog== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.key 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC3sc7RaI9GyH5Z1e0D +WcccNjr43zpavmMqA8bcS9dBBjkiEdvGH47r3EIXTjp0f46hZANiAASjLTP9kpDc +A+82+aSokPFHab7ojmUI2uWzgmMcr5o3tHV8zkb7GRe8kHJPdLZFOfeWs0SFHK1q +26R2hu6OJz33YXjf4QSK65GLAWe2aTJUUBxWhtov7+Q9lLr3WwIUtRM= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt02-no-san.example.com.pem 2026-09-11 19:41:01.190323539 +0000 @@ -0,0 +1,64 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: 7760573232607207426 (0x6bb3183cdef52002) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:21:43 2022 GMT + Not After : Feb 1 17:21:43 2052 GMT + Subject: CN=srv01.crt02-no-san.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:a3:2d:33:fd:92:90:dc:03:ef:36:f9:a4:a8:90: + f1:47:69:be:e8:8e:65:08:da:e5:b3:82:63:1c:af: + 9a:37:b4:75:7c:ce:46:fb:19:17:bc:90:72:4f:74: + b6:45:39:f7:96:b3:44:85:1c:ad:6a:db:a4:76:86: + ee:8e:27:3d:f7:61:78:df:e1:04:8a:eb:91:8b:01: + 67:b6:69:32:54:50:1c:56:86:da:2f:ef:e4:3d:94: + ba:f7:5b:02:14:b5:13 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + Signature Algorithm: sha256WithRSAEncryption + 07:20:2a:a6:7a:52:52:ba:1e:b7:79:cf:e6:11:9c:ca:3f:43: + 2b:f3:d7:2e:74:74:57:81:a1:aa:e6:68:c9:fd:d1:a8:a6:5b: + a2:ff:ea:f7:f0:b7:46:dc:a0:5a:64:5f:ce:e7:0f:76:63:14: + 6d:c2:51:4b:30:ea:51:7e:4a:1b:d3:b2:f8:c2:3d:3f:c1:bf: + ad:db:4d:f8:28:31:e7:75:ae:84:37:90:00:e5:0b:6b:dc:23: + 98:69:d5:ef:ce:e2:0d:e7:19:f1:31:01:1f:2a:6c:23:a3:94: + 62:7a:bf:b3:b0:13:d0:62:fc:a5:a6:0d:52:bb:f4:31:ff:f3: + ce:3a:74:66:30:7f:29:04:8d:34:90:7a:9b:8f:da:82:2e:5c: + 81:dd:af:fa:3a:a1:4e:bb:0a:4c:62:01:40:39:67:9c:29:27: + 6e:2f:76:81:2d:33:68:ee:ee:ed:00:7f:12:7a:af:43:00:7b: + 2d:34:8a:26:9a:66:1c:e5:96:17:7c:f8:6d:1e:8c:17:39:ce: + 4f:0b:9e:40:72:e1:5e:33:3f:9e:84:b5:07:f5:ab:58:d7:37: + ed:d0:29:ad:ce:02:0d:fa:6f:96:a9:0e:6c:6e:32:d2:dc:11: + 23:a3:4a:60:54:b4:98:31:db:8f:4b:4c:58:64:39:4f:ff:27: + d0:02:e5:cc:b2:17:e8:46:dc:aa:cb:dc:3d:ed:14:52:ec:6d: + a6:cd:04:2f:fd:54:16:6c:7e:63:34:17:f1:1d:b8:37:dd:20: + 6c:f6:21:19:6f:bb:62:dd:bc:6c:41:34:ad:b1:90:eb:2a:e0: + 63:ea:70:60:6a:02:e8:fe:46:51:b1:9d:3c:54:54:73:25:b7: + 41:d1:4c:34:aa:88:48:b8:01:21:ae:d8:d3:06:38:05:65:78: + e7:38:f0:f6:e6:2e:61:c0:42:5e:3b:09:59:eb:09:48:4d:55: + 7c:af:f4:de:c1:09:a0:b4:60:f7:9e:a2:d5:46:fc:05:61:69: + e0:c1:2d:26:dc:42 +-----BEGIN CERTIFICATE----- +MIIC9TCCAV0CCGuzGDze9SACMA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAlVB +MRgwFgYDVQQIDA9LaGFya2l2IE9ibGFzdCcxEDAOBgNVBAcMB0toYXJraXYxJDAi +BgNVBAoMG0ludGVybmV0IFN5c3RlbXMgQ29uc29ydGl1bTEcMBoGA1UEAwwTY2Eu +dGVzdC5leGFtcGxlLmNvbTAgFw0yMjAyMDgxNzIxNDNaGA8yMDUyMDIwMTE3MjE0 +M1owKTEnMCUGA1UEAwwec3J2MDEuY3J0MDItbm8tc2FuLmV4YW1wbGUuY29tMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEoy0z/ZKQ3APvNvmkqJDxR2m+6I5lCNrls4Jj +HK+aN7R1fM5G+xkXvJByT3S2RTn3lrNEhRytatukdobujic992F43+EEiuuRiwFn +tmkyVFAcVobaL+/kPZS691sCFLUTMA0GCSqGSIb3DQEBCwUAA4IBgQAHICqmelJS +uh63ec/mEZzKP0Mr89cudHRXgaGq5mjJ/dGoplui/+r38LdG3KBaZF/O5w92YxRt +wlFLMOpRfkob07L4wj0/wb+t2034KDHnda6EN5AA5Qtr3COYadXvzuIN5xnxMQEf +Kmwjo5Rier+zsBPQYvylpg1Su/Qx//POOnRmMH8pBI00kHqbj9qCLlyB3a/6OqFO +uwpMYgFAOWecKSduL3aBLTNo7u7tAH8Seq9DAHstNIommmYc5ZYXfPhtHowXOc5P +C55AcuFeMz+ehLUH9atY1zft0CmtzgIN+m+WqQ5sbjLS3BEjo0pgVLSYMduPS0xY +ZDlP/yfQAuXMshfoRtyqy9w97RRS7G2mzQQv/VQWbH5jNBfxHbg33SBs9iEZb7ti +3bxsQTStsZDrKuBj6nBgagLo/kZRsZ08VFRzJbdB0Uw0qohIuAEhrtjTBjgFZXjn +OPD25i5hwEJeOwlZ6wlITVV8r/TewQmgtGD3nqLVRvwFYWngwS0m3EI= +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.key 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAtAQNSdzyxR3sm6gyx +2Ob3SNCsYvdsE6+gobSUJWYbdus0CCFBIN6Qpms9oc0hAgqhZANiAAQf1Xurc7Jw +Ff0zJgJcdhaADHB9V4N1rDy3SgJGNcEbwXq9vvIEmn9pg39UmhsQYtdwve8mkFFQ +EHdWtxovRF6RRjbhLqRMZy5iqH8aFRBEaIsY6s+4lgm/tTrR7xCPn7s= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv01.crt03-expired.example.com.pem 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207430 (0x6bb3183cdef52006) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Aug 15 08:00:00 2012 GMT + Not After : Aug 15 09:00:00 2012 GMT + Subject: CN=srv01.crt03-expired.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:1f:d5:7b:ab:73:b2:70:15:fd:33:26:02:5c:76: + 16:80:0c:70:7d:57:83:75:ac:3c:b7:4a:02:46:35: + c1:1b:c1:7a:bd:be:f2:04:9a:7f:69:83:7f:54:9a: + 1b:10:62:d7:70:bd:ef:26:90:51:50:10:77:56:b7: + 1a:2f:44:5e:91:46:36:e1:2e:a4:4c:67:2e:62:a8: + 7f:1a:15:10:44:68:8b:18:ea:cf:b8:96:09:bf:b5: + 3a:d1:ef:10:8f:9f:bb + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.crt03-expired.example.com, IP Address:10.53.0.1, IP Address:FD92:7065:B8E:FFFF:0:0:0:1 + Signature Algorithm: sha256WithRSAEncryption + 25:35:08:f6:e7:f0:83:81:be:65:31:1b:78:a8:04:84:fe:6a: + 2a:1a:5d:c1:73:20:88:08:11:d8:27:be:a5:8e:3c:df:e2:a6: + 19:c5:41:40:ea:01:91:85:99:8d:17:4e:4d:9a:3c:03:f9:78: + 4c:8a:20:41:5e:96:d6:64:83:2f:b2:fe:e7:77:09:f9:91:bd: + 22:1a:57:8b:f6:24:bc:7b:48:2b:2e:14:b7:32:bd:46:91:99: + 5e:21:9a:d3:15:a7:27:e1:c0:3a:c7:f5:f9:94:3f:6d:14:7e: + 0b:02:bf:05:d9:ac:10:8a:7e:b0:37:36:cd:cb:4a:b4:e1:01: + c7:04:8d:83:f3:c6:79:ff:ff:6c:f0:a4:bf:3c:12:61:ea:15: + ac:30:62:26:e3:c3:4e:7d:5c:68:d8:88:de:35:8d:44:75:8c: + a8:c1:0d:07:67:b5:d0:42:43:41:1f:39:a0:47:35:46:d7:0f: + 89:aa:e8:d3:86:45:9a:fb:33:01:06:23:64:53:24:48:5b:69: + fa:cf:d9:81:fb:5e:7e:7b:82:65:56:c6:46:65:5c:e1:4f:f2: + 3c:09:3c:28:5f:c9:e3:a5:24:e3:7b:aa:b5:b1:8a:6a:b2:02: + 32:5f:24:05:f1:67:c8:54:17:0c:cd:ca:3d:e4:44:3e:23:3a: + 7c:63:b6:f9:61:3a:21:e7:8f:27:ad:c3:26:86:39:49:6c:41: + 40:7f:1d:48:69:8d:db:6f:42:e4:09:fe:24:62:bd:8e:2e:54: + 25:f0:14:c2:d8:43:95:09:2e:5f:72:4f:43:b5:9a:8b:bb:8c: + 44:c6:77:c9:05:fb:1a:9f:d7:b6:a6:42:d9:5c:3d:a5:09:0f: + 9e:e0:c7:06:32:f1:ff:c9:53:5e:42:d4:2a:33:ad:06:ea:ec: + b0:26:d3:3c:ef:65:af:15:8e:7b:20:49:ad:f1:56:ef:17:6b: + fc:f4:d8:7c:82:9f:30:19:d0:bc:9c:79:e2:dc:9d:a7:f9:6b: + 6f:65:ae:21:a0:94 +-----BEGIN CERTIFICATE----- +MIIDQTCCAamgAwIBAgIIa7MYPN71IAYwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMB4XDTEyMDgxNTA4MDAwMFoXDTEyMDgxNTA5 +MDAwMFowKjEoMCYGA1UEAwwfc3J2MDEuY3J0MDMtZXhwaXJlZC5leGFtcGxlLmNv +bTB2MBAGByqGSM49AgEGBSuBBAAiA2IABB/Ve6tzsnAV/TMmAlx2FoAMcH1Xg3Ws +PLdKAkY1wRvBer2+8gSaf2mDf1SaGxBi13C97yaQUVAQd1a3Gi9EXpFGNuEupExn +LmKofxoVEERoixjqz7iWCb+1OtHvEI+fu6NGMEQwQgYDVR0RBDswOYIfc3J2MDEu +Y3J0MDMtZXhwaXJlZC5leGFtcGxlLmNvbYcECjUAAYcQ/ZJwZQuO//8AAAAAAAAA +ATANBgkqhkiG9w0BAQsFAAOCAYEAJTUI9ufwg4G+ZTEbeKgEhP5qKhpdwXMgiAgR +2Ce+pY483+KmGcVBQOoBkYWZjRdOTZo8A/l4TIogQV6W1mSDL7L+53cJ+ZG9IhpX +i/YkvHtIKy4UtzK9RpGZXiGa0xWnJ+HAOsf1+ZQ/bRR+CwK/BdmsEIp+sDc2zctK +tOEBxwSNg/PGef//bPCkvzwSYeoVrDBiJuPDTn1caNiI3jWNRHWMqMENB2e10EJD +QR85oEc1RtcPiaro04ZFmvszAQYjZFMkSFtp+s/ZgftefnuCZVbGRmVc4U/yPAk8 +KF/J46Uk43uqtbGKarICMl8kBfFnyFQXDM3KPeREPiM6fGO2+WE6IeePJ63DJoY5 +SWxBQH8dSGmN229C5An+JGK9ji5UJfAUwthDlQkuX3JPQ7Wai7uMRMZ3yQX7Gp/X +tqZC2Vw9pQkPnuDHBjLx/8lTXkLUKjOtBurssCbTPO9lrxWOeyBJrfFW7xdr/PTY +fIKfMBnQvJx54tydp/lrb2WuIaCU +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.key 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC/rdGBnhOuZ8hc7fUO +6v0LO2xd2LMjTS0TCb0pVwsccYN/f6OxWJtu0uGSt0DaN6ihZANiAARD1PvMuIhg +lRaqKtAxlss+qFzkdqzBv807ZYW7LMv6w0g8g8gI7txZFZciuEIXjHUJ+T62nPLF +2122impDSAqi3RPCNuRzs2RUebv41H5I9AW+DHdjAf5PMLCqYrzy7fk= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv02.crt01.example.com.pem 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207427 (0x6bb3183cdef52003) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:57:59 2022 GMT + Not After : Feb 1 17:57:59 2052 GMT + Subject: CN=srv02.crt01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:43:d4:fb:cc:b8:88:60:95:16:aa:2a:d0:31:96: + cb:3e:a8:5c:e4:76:ac:c1:bf:cd:3b:65:85:bb:2c: + cb:fa:c3:48:3c:83:c8:08:ee:dc:59:15:97:22:b8: + 42:17:8c:75:09:f9:3e:b6:9c:f2:c5:db:5d:b6:8a: + 6a:43:48:0a:a2:dd:13:c2:36:e4:73:b3:64:54:79: + bb:f8:d4:7e:48:f4:05:be:0c:77:63:01:fe:4f:30: + b0:aa:62:bc:f2:ed:f9 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv02.crt01.example.com, IP Address:10.53.0.2, IP Address:FD92:7065:B8E:FFFF:0:0:0:2 + Signature Algorithm: sha256WithRSAEncryption + 89:ba:ae:4f:f8:3e:da:48:1f:5c:8f:ff:ee:d8:42:b0:0b:9b: + f1:b5:e2:90:c9:76:40:09:77:a3:31:d5:73:8f:eb:7d:69:94: + 1c:2b:10:31:da:d4:0c:29:e7:80:4e:61:53:ba:15:9d:e1:e8: + 0c:0d:19:77:2b:a8:74:46:e3:03:ae:ab:96:ea:af:80:c3:18: + e0:93:8e:e9:58:0e:79:47:98:a4:06:95:6b:8f:2c:d1:f7:29: + b1:98:85:e8:a4:9c:45:52:ad:c8:60:20:dc:3a:6a:40:78:15: + d1:b4:d0:c3:c5:f3:ac:fe:ec:d3:94:ef:66:0b:d7:8c:46:f3: + 62:30:c4:c2:78:65:de:40:4e:d8:26:84:8e:18:a7:71:f2:b7: + 65:d8:d0:c2:c8:e6:a0:fb:ea:01:de:2f:03:8a:50:3d:f6:6c: + 0b:ef:ce:f5:25:1f:80:54:3e:c2:6d:2c:d3:2b:bd:23:b7:3b: + 82:6b:91:7f:ea:ff:e6:11:37:d3:f0:d4:db:9f:32:ac:12:cc: + ec:25:25:81:58:16:18:90:73:c3:ad:7c:09:a7:08:99:16:ce: + e8:6c:4b:9a:e6:09:96:11:c2:f1:cf:19:43:a6:a6:81:f2:57: + 21:fa:b1:91:58:39:76:17:89:32:4c:4b:df:fa:59:03:b2:32: + b4:b3:95:89:af:f4:5e:94:b1:df:e9:bf:21:73:14:06:5d:08: + 1e:0f:d2:84:14:44:20:91:19:72:b9:38:0b:3c:2e:4f:ea:3a: + 9b:ef:93:61:e7:36:82:df:49:e2:d7:45:ea:87:45:1d:74:36: + 18:f4:aa:30:d5:65:da:1f:c7:98:61:ab:64:2a:49:98:64:a1: + 8c:33:3a:a5:97:4a:69:a6:9d:6f:00:b9:6b:81:8d:09:0f:98: + 63:0f:85:ae:e4:21:70:a3:da:5a:27:eb:df:6d:82:ac:bb:48: + 6b:01:4e:36:95:5a:d3:f0:b9:30:43:72:87:af:41:7a:30:13: + f2:92:15:f1:69:e7 +-----BEGIN CERTIFICATE----- +MIIDMzCCAZugAwIBAgIIa7MYPN71IAMwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIwODE3NTc1OVoYDzIwNTIwMjAx +MTc1NzU5WjAiMSAwHgYDVQQDDBdzcnYwMi5jcnQwMS5leGFtcGxlLmNvbTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEPU+8y4iGCVFqoq0DGWyz6oXOR2rMG/zTtlhbss +y/rDSDyDyAju3FkVlyK4QheMdQn5Prac8sXbXbaKakNICqLdE8I25HOzZFR5u/jU +fkj0Bb4Md2MB/k8wsKpivPLt+aM+MDwwOgYDVR0RBDMwMYIXc3J2MDIuY3J0MDEu +ZXhhbXBsZS5jb22HBAo1AAKHEP2ScGULjv//AAAAAAAAAAIwDQYJKoZIhvcNAQEL +BQADggGBAIm6rk/4PtpIH1yP/+7YQrALm/G14pDJdkAJd6Mx1XOP631plBwrEDHa +1Awp54BOYVO6FZ3h6AwNGXcrqHRG4wOuq5bqr4DDGOCTjulYDnlHmKQGlWuPLNH3 +KbGYheiknEVSrchgINw6akB4FdG00MPF86z+7NOU72YL14xG82IwxMJ4Zd5ATtgm +hI4Yp3Hyt2XY0MLI5qD76gHeLwOKUD32bAvvzvUlH4BUPsJtLNMrvSO3O4JrkX/q +/+YRN9Pw1NufMqwSzOwlJYFYFhiQc8OtfAmnCJkWzuhsS5rmCZYRwvHPGUOmpoHy +VyH6sZFYOXYXiTJMS9/6WQOyMrSzlYmv9F6Usd/pvyFzFAZdCB4P0oQURCCRGXK5 +OAs8Lk/qOpvvk2HnNoLfSeLXReqHRR10Nhj0qjDVZdofx5hhq2QqSZhkoYwzOqWX +SmmmnW8AuWuBjQkPmGMPha7kIXCj2lon699tgqy7SGsBTjaVWtPwuTBDcoevQXow +E/KSFfFp5w== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.key 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBMJxQaJB76ywjBuhZI +LUz05LQuwmDBAFeZFqe10HG+r0cZvVw4Cr5M7jr2RVLqKRChZANiAARF27kbN2W/ +saGKWjkAjUoVO0OauC//qH2Zg6ic3LbCqp/4UaEOLpcPkBMiTIvx/zxr65EpfUzf +fAXdrepKTK0K1m+OUbCIWEKILBbURx24j7NODRLfTBT2JyA/lJojgUg= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv03.crt01.example.com.pem 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207428 (0x6bb3183cdef52004) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:58:15 2022 GMT + Not After : Feb 1 17:58:15 2052 GMT + Subject: CN=srv03.crt01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:45:db:b9:1b:37:65:bf:b1:a1:8a:5a:39:00:8d: + 4a:15:3b:43:9a:b8:2f:ff:a8:7d:99:83:a8:9c:dc: + b6:c2:aa:9f:f8:51:a1:0e:2e:97:0f:90:13:22:4c: + 8b:f1:ff:3c:6b:eb:91:29:7d:4c:df:7c:05:dd:ad: + ea:4a:4c:ad:0a:d6:6f:8e:51:b0:88:58:42:88:2c: + 16:d4:47:1d:b8:8f:b3:4e:0d:12:df:4c:14:f6:27: + 20:3f:94:9a:23:81:48 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv03.crt01.example.com, IP Address:10.53.0.3, IP Address:FD92:7065:B8E:FFFF:0:0:0:3 + Signature Algorithm: sha256WithRSAEncryption + 8f:96:88:82:94:76:8e:97:b6:75:8b:e9:2b:4f:f3:8f:14:5c: + 50:00:ca:67:96:9e:2e:bd:53:25:25:40:6d:c5:56:e6:1a:f6: + cb:fb:58:fc:b3:56:9d:fc:0b:e2:8e:99:7e:e8:e6:ad:b6:e7: + e6:3e:8a:59:ef:3e:76:a4:ed:7b:58:fd:a3:4b:aa:4e:11:e1: + 57:bf:b1:23:a5:a1:00:f8:95:07:c8:7d:ee:ac:a7:c8:24:ee: + cf:e8:c5:a4:9f:96:27:c9:47:c1:7d:11:de:66:d0:6d:d1:8d: + e7:8f:a0:0f:46:d9:2e:70:f3:9f:ac:6a:b0:3f:5a:dc:70:d4: + b9:a5:f3:ff:5c:21:50:5d:c2:a2:46:26:25:2a:2f:8a:aa:7a: + fd:76:31:5f:e0:25:a3:ee:df:36:f0:ab:05:a1:5d:0d:3c:6b: + 2c:1d:d5:c5:73:9c:a0:57:1f:c4:26:e6:dc:a1:7c:25:08:21: + 61:28:e2:b3:f5:51:83:20:73:14:19:8f:47:79:69:bc:2b:22: + f2:17:62:1d:83:f7:4f:a9:c4:51:68:e0:a9:d7:9f:17:6a:d2: + fd:f7:04:ce:a4:f5:8e:eb:31:b4:bf:c6:2d:da:0c:70:6e:0c: + a5:75:21:54:3c:f6:3d:36:b8:8a:d8:b6:7b:77:7e:54:1d:9f: + 91:8f:02:a6:d1:2c:a7:30:d1:cc:e6:d9:6b:76:80:15:4b:ba: + fd:55:20:cc:b2:99:85:57:60:11:97:c5:e7:28:50:a6:17:af: + d2:bd:1b:7e:06:48:7f:63:dc:70:f8:3f:22:9f:41:a1:66:f5: + a7:81:99:cb:07:0e:8a:9a:bb:12:f6:c0:fe:59:0c:00:37:15: + b2:9d:f0:f9:93:d1:1a:b6:f8:0a:6b:bd:9e:92:32:45:f5:a2: + 44:f0:45:8d:1a:d0:10:b2:db:98:c4:c7:5e:c1:e8:f3:94:33: + 6c:06:f5:1a:cc:51:23:72:ae:37:2f:57:d4:f8:ac:1f:25:b4: + d3:bf:99:9b:ac:fc +-----BEGIN CERTIFICATE----- +MIIDMzCCAZugAwIBAgIIa7MYPN71IAQwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIwODE3NTgxNVoYDzIwNTIwMjAx +MTc1ODE1WjAiMSAwHgYDVQQDDBdzcnYwMy5jcnQwMS5leGFtcGxlLmNvbTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEXbuRs3Zb+xoYpaOQCNShU7Q5q4L/+ofZmDqJzc +tsKqn/hRoQ4ulw+QEyJMi/H/PGvrkSl9TN98Bd2t6kpMrQrWb45RsIhYQogsFtRH +HbiPs04NEt9MFPYnID+UmiOBSKM+MDwwOgYDVR0RBDMwMYIXc3J2MDMuY3J0MDEu +ZXhhbXBsZS5jb22HBAo1AAOHEP2ScGULjv//AAAAAAAAAAMwDQYJKoZIhvcNAQEL +BQADggGBAI+WiIKUdo6XtnWL6StP848UXFAAymeWni69UyUlQG3FVuYa9sv7WPyz +Vp38C+KOmX7o5q225+Y+ilnvPnak7XtY/aNLqk4R4Ve/sSOloQD4lQfIfe6sp8gk +7s/oxaSflifJR8F9Ed5m0G3RjeePoA9G2S5w85+sarA/Wtxw1Lml8/9cIVBdwqJG +JiUqL4qqev12MV/gJaPu3zbwqwWhXQ08aywd1cVznKBXH8Qm5tyhfCUIIWEo4rP1 +UYMgcxQZj0d5abwrIvIXYh2D90+pxFFo4KnXnxdq0v33BM6k9Y7rMbS/xi3aDHBu +DKV1IVQ89j02uIrYtnt3flQdn5GPAqbRLKcw0czm2Wt2gBVLuv1VIMyymYVXYBGX +xecoUKYXr9K9G34GSH9j3HD4PyKfQaFm9aeBmcsHDoqauxL2wP5ZDAA3FbKd8PmT +0Rq2+AprvZ6SMkX1okTwRY0a0BCy25jEx17B6POUM2wG9RrMUSNyrjcvV9T4rB8l +tNO/mZus/A== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.key bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.key --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.key 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDq5a0oiMxJiOdwaSmk +U2NPPJXOWPZVWpIGxB0kczGcCS6Xq0VinNqLe5YI9M1YwXehZANiAASeQ9fMKeGO +SzWhj7ePMA9Ws1t/wGKbIyFwsSvnc/nqOAFmS1JDMc8QaRW/awjzaQc/mbu4cNA7 +iSId8iVCWj5VkcP8tL7HLYZRFMSr/nxUNGfHXtuGhMxm61SvnX3czhg= +-----END PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.pem bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/certs/srv04.crt01.example.com.pem 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207429 (0x6bb3183cdef52005) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:59:14 2022 GMT + Not After : Feb 1 17:59:14 2052 GMT + Subject: CN=srv04.crt01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:9e:43:d7:cc:29:e1:8e:4b:35:a1:8f:b7:8f:30: + 0f:56:b3:5b:7f:c0:62:9b:23:21:70:b1:2b:e7:73: + f9:ea:38:01:66:4b:52:43:31:cf:10:69:15:bf:6b: + 08:f3:69:07:3f:99:bb:b8:70:d0:3b:89:22:1d:f2: + 25:42:5a:3e:55:91:c3:fc:b4:be:c7:2d:86:51:14: + c4:ab:fe:7c:54:34:67:c7:5e:db:86:84:cc:66:eb: + 54:af:9d:7d:dc:ce:18 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv04.crt01.example.com, IP Address:10.53.0.4, IP Address:FD92:7065:B8E:FFFF:0:0:0:4 + Signature Algorithm: sha256WithRSAEncryption + 48:b5:38:59:79:e6:51:a6:ea:80:d7:d1:3c:29:03:70:31:e4: + 43:b4:e3:09:e7:e1:37:8c:d0:0f:2a:19:7a:f2:5a:6d:76:cd: + 17:7a:66:1c:3e:74:56:24:b8:29:06:55:b2:1c:af:9a:42:05: + 93:a4:70:cb:a5:68:85:ab:71:53:da:d9:29:a3:f4:2a:1e:df: + 0c:ec:7d:52:55:fa:9b:e6:a0:18:d5:4c:da:e6:d2:60:da:bc: + 09:5b:13:53:6d:c7:d2:30:b9:a8:a5:02:7f:a3:66:28:34:93: + de:55:a0:de:b5:c8:dc:43:7b:b9:03:06:1f:ce:8c:5f:82:d8: + af:40:56:ce:f8:b9:d4:73:1c:ae:c9:cb:1d:0f:a2:52:71:9b: + 8b:05:f4:d6:0b:1e:a8:db:0f:29:a0:43:b5:2f:56:09:d8:68: + 58:9c:e5:6a:df:38:91:56:9d:44:e5:d2:ca:9a:b1:41:a1:01: + 0c:68:a0:f5:0a:f7:98:4f:d5:a0:6f:99:59:a0:e0:cb:49:57: + 26:20:09:5a:fa:c2:75:40:f6:1b:6a:ac:55:47:50:8d:38:81: + 61:79:44:e7:d5:d1:b3:c7:3b:db:ec:44:59:ef:e1:82:31:a3: + 38:4c:de:40:11:31:52:8b:bb:1c:af:be:ce:c5:2b:f5:0d:c0: + 60:13:fb:7e:da:22:41:d4:85:5e:4d:ba:db:f8:f7:26:61:32: + 26:fe:fe:9e:37:a3:cc:25:3b:3c:c8:b5:a7:a5:5c:d9:4d:8f: + a8:f2:86:98:79:b3:00:08:0f:f2:c9:1f:c6:3f:07:ad:e4:a7: + 8d:86:3d:15:fa:5b:1a:0f:96:67:b6:0a:78:0a:bb:6e:05:a6: + 54:29:48:b4:f9:48:0d:7f:f0:13:65:32:2f:c5:ee:ab:b8:e8: + 0d:b2:f9:c9:96:d2:cf:51:a2:64:3c:58:0f:65:6f:c6:99:93: + 76:2c:42:08:d9:f3:f3:13:cd:41:b6:67:8f:1d:9a:2f:da:93: + 3d:26:4c:9a:11:c1 +-----BEGIN CERTIFICATE----- +MIIDMzCCAZugAwIBAgIIa7MYPN71IAUwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIwODE3NTkxNFoYDzIwNTIwMjAx +MTc1OTE0WjAiMSAwHgYDVQQDDBdzcnYwNC5jcnQwMS5leGFtcGxlLmNvbTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABJ5D18wp4Y5LNaGPt48wD1azW3/AYpsjIXCxK+dz ++eo4AWZLUkMxzxBpFb9rCPNpBz+Zu7hw0DuJIh3yJUJaPlWRw/y0vscthlEUxKv+ +fFQ0Z8de24aEzGbrVK+dfdzOGKM+MDwwOgYDVR0RBDMwMYIXc3J2MDQuY3J0MDEu +ZXhhbXBsZS5jb22HBAo1AASHEP2ScGULjv//AAAAAAAAAAQwDQYJKoZIhvcNAQEL +BQADggGBAEi1OFl55lGm6oDX0TwpA3Ax5EO04wnn4TeM0A8qGXryWm12zRd6Zhw+ +dFYkuCkGVbIcr5pCBZOkcMulaIWrcVPa2Smj9Coe3wzsfVJV+pvmoBjVTNrm0mDa +vAlbE1Ntx9IwuailAn+jZig0k95VoN61yNxDe7kDBh/OjF+C2K9AVs74udRzHK7J +yx0PolJxm4sF9NYLHqjbDymgQ7UvVgnYaFic5WrfOJFWnUTl0sqasUGhAQxooPUK +95hP1aBvmVmg4MtJVyYgCVr6wnVA9htqrFVHUI04gWF5ROfV0bPHO9vsRFnv4YIx +ozhM3kARMVKLuxyvvs7FK/UNwGAT+37aIkHUhV5Nutv49yZhMib+/p43o8wlOzzI +taelXNlNj6jyhph5swAID/LJH8Y/B63kp42GPRX6WxoPlme2CngKu24FplQpSLT5 +SA1/8BNlMi/F7qu46A2y+cmW0s9RomQ8WA9lb8aZk3YsQgjZ8/MTzUG2Z48dmi/a +kz0mTJoRwQ== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/index.txt bind9-9.20.29/bin/tests/system/checkds/CA/index.txt --- bind9-9.20.26/bin/tests/system/checkds/CA/index.txt 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/index.txt 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,9 @@ +V 20520201171852Z 6BB3183CDEF52001 unknown /CN=srv01.crt01.example.com +V 20520201172143Z 6BB3183CDEF52002 unknown /CN=srv01.crt02-no-san.example.com +V 20520201175759Z 6BB3183CDEF52003 unknown /CN=srv02.crt01.example.com +V 20520201175815Z 6BB3183CDEF52004 unknown /CN=srv03.crt01.example.com +V 20520201175914Z 6BB3183CDEF52005 unknown /CN=srv04.crt01.example.com +V 120815090000Z 6BB3183CDEF52006 unknown /CN=srv01.crt03-expired.example.com +V 20520203174420Z 6BB3183CDEF52007 unknown /CN=srv01.client01.example.com +V 20520204132112Z 6BB3183CDEF52008 unknown /CN=srv01.client02-ns2.example.com +V 120814060000Z 6BB3183CDEF52009 unknown /CN=srv01.client03-ns2-expired.example.com diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/index.txt.attr bind9-9.20.29/bin/tests/system/checkds/CA/index.txt.attr --- bind9-9.20.26/bin/tests/system/checkds/CA/index.txt.attr 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/index.txt.attr 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1 @@ +unique_subject = yes diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52001.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52001.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52001.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52001.pem 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207425 (0x6bb3183cdef52001) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:18:52 2022 GMT + Not After : Feb 1 17:18:52 2052 GMT + Subject: CN=srv01.crt01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:12:a1:7b:0f:79:f2:29:f5:8f:6a:06:d0:28:83: + 14:43:8f:19:4c:29:91:36:30:0f:06:a6:56:e7:57: + 9b:58:2c:9e:fc:9c:a3:4e:f6:e3:6f:90:40:d5:09: + fd:94:96:8e:14:68:74:6f:e8:a7:a7:ab:8c:35:96: + f2:d6:8f:5d:97:5d:d1:b9:22:5b:ef:31:15:a1:e1: + eb:6d:6f:af:b1:2f:80:e5:a5:a9:38:f2:6f:f9:65: + 14:70:a7:a5:ac:e1:1a + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.crt01.example.com, IP Address:10.53.0.1, IP Address:FD92:7065:B8E:FFFF:0:0:0:1 + Signature Algorithm: sha256WithRSAEncryption + 79:0f:08:ab:18:cc:f9:7a:bd:47:21:99:a1:a3:76:04:7f:d7: + 08:33:91:49:3d:2d:fc:8d:ff:c5:c1:8d:b8:70:05:65:32:cd: + e2:26:21:49:19:66:a2:94:4f:42:7d:83:3c:4f:ed:c1:87:89: + 5b:73:2c:64:64:67:29:f5:73:83:23:72:b7:a8:2e:d6:9a:de: + 13:0c:ba:35:d3:38:b1:c4:51:7d:81:fc:25:ca:a6:d9:d2:fa: + bb:6d:1f:a4:61:90:50:2d:8a:ed:70:1a:eb:56:2f:fc:7b:f3: + 76:df:68:8d:e8:a4:7d:82:b9:5c:c6:cb:d8:06:f7:78:dc:a7: + 94:35:d4:83:98:28:51:36:1c:73:47:e4:5b:32:d2:cd:de:1c: + 44:f6:de:37:8a:46:d0:14:8d:71:e5:10:22:b1:f9:73:f7:1b: + 4f:82:e1:a1:00:73:18:17:71:a2:bf:a2:0c:59:aa:43:58:46: + 82:f8:38:c4:5a:5a:9f:13:d7:a9:54:1f:58:9b:5d:52:16:d3: + a0:ba:6b:aa:cf:68:3a:d1:12:9c:94:ac:78:6b:7e:bc:69:6c: + 75:07:5d:fb:68:cd:e8:8d:bb:8c:b0:7c:6c:9e:f6:a5:7c:32: + 74:ef:c5:b1:1f:1d:ec:7b:2f:79:c0:3b:52:60:9b:48:89:09: + b4:46:34:69:d3:7b:1b:15:ef:0c:dd:64:1d:58:fe:a7:0b:b1: + 9d:28:1f:1e:9e:3c:c0:b1:a6:38:ab:9d:54:24:0e:75:6c:9e: + 90:13:b9:39:dc:43:fe:37:e3:14:0f:78:7e:2b:56:a2:d2:60: + 51:57:88:3b:4c:cf:24:67:36:77:21:bb:c8:07:eb:48:f7:b0: + 1e:e4:99:61:84:15:bb:61:3a:21:55:df:31:43:67:73:8f:6b: + e9:04:83:be:2d:8b:94:39:89:cf:40:d5:04:f7:6b:c9:c6:8c: + 6e:36:0f:5d:7a:9b:57:86:36:76:2c:75:35:47:50:ed:9a:84: + 7e:37:83:b5:21:a2 +-----BEGIN CERTIFICATE----- +MIIDMzCCAZugAwIBAgIIa7MYPN71IAEwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIwODE3MTg1MloYDzIwNTIwMjAx +MTcxODUyWjAiMSAwHgYDVQQDDBdzcnYwMS5jcnQwMS5leGFtcGxlLmNvbTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABBKhew958in1j2oG0CiDFEOPGUwpkTYwDwamVudX +m1gsnvyco07242+QQNUJ/ZSWjhRodG/op6erjDWW8taPXZdd0bkiW+8xFaHh621v +r7EvgOWlqTjyb/llFHCnpazhGqM+MDwwOgYDVR0RBDMwMYIXc3J2MDEuY3J0MDEu +ZXhhbXBsZS5jb22HBAo1AAGHEP2ScGULjv//AAAAAAAAAAEwDQYJKoZIhvcNAQEL +BQADggGBAHkPCKsYzPl6vUchmaGjdgR/1wgzkUk9LfyN/8XBjbhwBWUyzeImIUkZ +ZqKUT0J9gzxP7cGHiVtzLGRkZyn1c4MjcreoLtaa3hMMujXTOLHEUX2B/CXKptnS ++rttH6RhkFAtiu1wGutWL/x783bfaI3opH2CuVzGy9gG93jcp5Q11IOYKFE2HHNH +5Fsy0s3eHET23jeKRtAUjXHlECKx+XP3G0+C4aEAcxgXcaK/ogxZqkNYRoL4OMRa +Wp8T16lUH1ibXVIW06C6a6rPaDrREpyUrHhrfrxpbHUHXftozeiNu4ywfGye9qV8 +MnTvxbEfHex7L3nAO1Jgm0iJCbRGNGnTexsV7wzdZB1Y/qcLsZ0oHx6ePMCxpjir +nVQkDnVsnpATuTncQ/434xQPeH4rVqLSYFFXiDtMzyRnNnchu8gH60j3sB7kmWGE +FbthOiFV3zFDZ3OPa+kEg74ti5Q5ic9A1QT3a8nGjG42D116m1eGNnYsdTVHUO2a +hH43g7Uhog== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52002.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52002.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52002.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52002.pem 2026-09-11 19:41:01.191323563 +0000 @@ -0,0 +1,64 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: 7760573232607207426 (0x6bb3183cdef52002) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:21:43 2022 GMT + Not After : Feb 1 17:21:43 2052 GMT + Subject: CN=srv01.crt02-no-san.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:a3:2d:33:fd:92:90:dc:03:ef:36:f9:a4:a8:90: + f1:47:69:be:e8:8e:65:08:da:e5:b3:82:63:1c:af: + 9a:37:b4:75:7c:ce:46:fb:19:17:bc:90:72:4f:74: + b6:45:39:f7:96:b3:44:85:1c:ad:6a:db:a4:76:86: + ee:8e:27:3d:f7:61:78:df:e1:04:8a:eb:91:8b:01: + 67:b6:69:32:54:50:1c:56:86:da:2f:ef:e4:3d:94: + ba:f7:5b:02:14:b5:13 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + Signature Algorithm: sha256WithRSAEncryption + 07:20:2a:a6:7a:52:52:ba:1e:b7:79:cf:e6:11:9c:ca:3f:43: + 2b:f3:d7:2e:74:74:57:81:a1:aa:e6:68:c9:fd:d1:a8:a6:5b: + a2:ff:ea:f7:f0:b7:46:dc:a0:5a:64:5f:ce:e7:0f:76:63:14: + 6d:c2:51:4b:30:ea:51:7e:4a:1b:d3:b2:f8:c2:3d:3f:c1:bf: + ad:db:4d:f8:28:31:e7:75:ae:84:37:90:00:e5:0b:6b:dc:23: + 98:69:d5:ef:ce:e2:0d:e7:19:f1:31:01:1f:2a:6c:23:a3:94: + 62:7a:bf:b3:b0:13:d0:62:fc:a5:a6:0d:52:bb:f4:31:ff:f3: + ce:3a:74:66:30:7f:29:04:8d:34:90:7a:9b:8f:da:82:2e:5c: + 81:dd:af:fa:3a:a1:4e:bb:0a:4c:62:01:40:39:67:9c:29:27: + 6e:2f:76:81:2d:33:68:ee:ee:ed:00:7f:12:7a:af:43:00:7b: + 2d:34:8a:26:9a:66:1c:e5:96:17:7c:f8:6d:1e:8c:17:39:ce: + 4f:0b:9e:40:72:e1:5e:33:3f:9e:84:b5:07:f5:ab:58:d7:37: + ed:d0:29:ad:ce:02:0d:fa:6f:96:a9:0e:6c:6e:32:d2:dc:11: + 23:a3:4a:60:54:b4:98:31:db:8f:4b:4c:58:64:39:4f:ff:27: + d0:02:e5:cc:b2:17:e8:46:dc:aa:cb:dc:3d:ed:14:52:ec:6d: + a6:cd:04:2f:fd:54:16:6c:7e:63:34:17:f1:1d:b8:37:dd:20: + 6c:f6:21:19:6f:bb:62:dd:bc:6c:41:34:ad:b1:90:eb:2a:e0: + 63:ea:70:60:6a:02:e8:fe:46:51:b1:9d:3c:54:54:73:25:b7: + 41:d1:4c:34:aa:88:48:b8:01:21:ae:d8:d3:06:38:05:65:78: + e7:38:f0:f6:e6:2e:61:c0:42:5e:3b:09:59:eb:09:48:4d:55: + 7c:af:f4:de:c1:09:a0:b4:60:f7:9e:a2:d5:46:fc:05:61:69: + e0:c1:2d:26:dc:42 +-----BEGIN CERTIFICATE----- +MIIC9TCCAV0CCGuzGDze9SACMA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAlVB +MRgwFgYDVQQIDA9LaGFya2l2IE9ibGFzdCcxEDAOBgNVBAcMB0toYXJraXYxJDAi +BgNVBAoMG0ludGVybmV0IFN5c3RlbXMgQ29uc29ydGl1bTEcMBoGA1UEAwwTY2Eu +dGVzdC5leGFtcGxlLmNvbTAgFw0yMjAyMDgxNzIxNDNaGA8yMDUyMDIwMTE3MjE0 +M1owKTEnMCUGA1UEAwwec3J2MDEuY3J0MDItbm8tc2FuLmV4YW1wbGUuY29tMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEoy0z/ZKQ3APvNvmkqJDxR2m+6I5lCNrls4Jj +HK+aN7R1fM5G+xkXvJByT3S2RTn3lrNEhRytatukdobujic992F43+EEiuuRiwFn +tmkyVFAcVobaL+/kPZS691sCFLUTMA0GCSqGSIb3DQEBCwUAA4IBgQAHICqmelJS +uh63ec/mEZzKP0Mr89cudHRXgaGq5mjJ/dGoplui/+r38LdG3KBaZF/O5w92YxRt +wlFLMOpRfkob07L4wj0/wb+t2034KDHnda6EN5AA5Qtr3COYadXvzuIN5xnxMQEf +Kmwjo5Rier+zsBPQYvylpg1Su/Qx//POOnRmMH8pBI00kHqbj9qCLlyB3a/6OqFO +uwpMYgFAOWecKSduL3aBLTNo7u7tAH8Seq9DAHstNIommmYc5ZYXfPhtHowXOc5P +C55AcuFeMz+ehLUH9atY1zft0CmtzgIN+m+WqQ5sbjLS3BEjo0pgVLSYMduPS0xY +ZDlP/yfQAuXMshfoRtyqy9w97RRS7G2mzQQv/VQWbH5jNBfxHbg33SBs9iEZb7ti +3bxsQTStsZDrKuBj6nBgagLo/kZRsZ08VFRzJbdB0Uw0qohIuAEhrtjTBjgFZXjn +OPD25i5hwEJeOwlZ6wlITVV8r/TewQmgtGD3nqLVRvwFYWngwS0m3EI= +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52003.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52003.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52003.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52003.pem 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207427 (0x6bb3183cdef52003) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:57:59 2022 GMT + Not After : Feb 1 17:57:59 2052 GMT + Subject: CN=srv02.crt01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:43:d4:fb:cc:b8:88:60:95:16:aa:2a:d0:31:96: + cb:3e:a8:5c:e4:76:ac:c1:bf:cd:3b:65:85:bb:2c: + cb:fa:c3:48:3c:83:c8:08:ee:dc:59:15:97:22:b8: + 42:17:8c:75:09:f9:3e:b6:9c:f2:c5:db:5d:b6:8a: + 6a:43:48:0a:a2:dd:13:c2:36:e4:73:b3:64:54:79: + bb:f8:d4:7e:48:f4:05:be:0c:77:63:01:fe:4f:30: + b0:aa:62:bc:f2:ed:f9 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv02.crt01.example.com, IP Address:10.53.0.2, IP Address:FD92:7065:B8E:FFFF:0:0:0:2 + Signature Algorithm: sha256WithRSAEncryption + 89:ba:ae:4f:f8:3e:da:48:1f:5c:8f:ff:ee:d8:42:b0:0b:9b: + f1:b5:e2:90:c9:76:40:09:77:a3:31:d5:73:8f:eb:7d:69:94: + 1c:2b:10:31:da:d4:0c:29:e7:80:4e:61:53:ba:15:9d:e1:e8: + 0c:0d:19:77:2b:a8:74:46:e3:03:ae:ab:96:ea:af:80:c3:18: + e0:93:8e:e9:58:0e:79:47:98:a4:06:95:6b:8f:2c:d1:f7:29: + b1:98:85:e8:a4:9c:45:52:ad:c8:60:20:dc:3a:6a:40:78:15: + d1:b4:d0:c3:c5:f3:ac:fe:ec:d3:94:ef:66:0b:d7:8c:46:f3: + 62:30:c4:c2:78:65:de:40:4e:d8:26:84:8e:18:a7:71:f2:b7: + 65:d8:d0:c2:c8:e6:a0:fb:ea:01:de:2f:03:8a:50:3d:f6:6c: + 0b:ef:ce:f5:25:1f:80:54:3e:c2:6d:2c:d3:2b:bd:23:b7:3b: + 82:6b:91:7f:ea:ff:e6:11:37:d3:f0:d4:db:9f:32:ac:12:cc: + ec:25:25:81:58:16:18:90:73:c3:ad:7c:09:a7:08:99:16:ce: + e8:6c:4b:9a:e6:09:96:11:c2:f1:cf:19:43:a6:a6:81:f2:57: + 21:fa:b1:91:58:39:76:17:89:32:4c:4b:df:fa:59:03:b2:32: + b4:b3:95:89:af:f4:5e:94:b1:df:e9:bf:21:73:14:06:5d:08: + 1e:0f:d2:84:14:44:20:91:19:72:b9:38:0b:3c:2e:4f:ea:3a: + 9b:ef:93:61:e7:36:82:df:49:e2:d7:45:ea:87:45:1d:74:36: + 18:f4:aa:30:d5:65:da:1f:c7:98:61:ab:64:2a:49:98:64:a1: + 8c:33:3a:a5:97:4a:69:a6:9d:6f:00:b9:6b:81:8d:09:0f:98: + 63:0f:85:ae:e4:21:70:a3:da:5a:27:eb:df:6d:82:ac:bb:48: + 6b:01:4e:36:95:5a:d3:f0:b9:30:43:72:87:af:41:7a:30:13: + f2:92:15:f1:69:e7 +-----BEGIN CERTIFICATE----- +MIIDMzCCAZugAwIBAgIIa7MYPN71IAMwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIwODE3NTc1OVoYDzIwNTIwMjAx +MTc1NzU5WjAiMSAwHgYDVQQDDBdzcnYwMi5jcnQwMS5leGFtcGxlLmNvbTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEPU+8y4iGCVFqoq0DGWyz6oXOR2rMG/zTtlhbss +y/rDSDyDyAju3FkVlyK4QheMdQn5Prac8sXbXbaKakNICqLdE8I25HOzZFR5u/jU +fkj0Bb4Md2MB/k8wsKpivPLt+aM+MDwwOgYDVR0RBDMwMYIXc3J2MDIuY3J0MDEu +ZXhhbXBsZS5jb22HBAo1AAKHEP2ScGULjv//AAAAAAAAAAIwDQYJKoZIhvcNAQEL +BQADggGBAIm6rk/4PtpIH1yP/+7YQrALm/G14pDJdkAJd6Mx1XOP631plBwrEDHa +1Awp54BOYVO6FZ3h6AwNGXcrqHRG4wOuq5bqr4DDGOCTjulYDnlHmKQGlWuPLNH3 +KbGYheiknEVSrchgINw6akB4FdG00MPF86z+7NOU72YL14xG82IwxMJ4Zd5ATtgm +hI4Yp3Hyt2XY0MLI5qD76gHeLwOKUD32bAvvzvUlH4BUPsJtLNMrvSO3O4JrkX/q +/+YRN9Pw1NufMqwSzOwlJYFYFhiQc8OtfAmnCJkWzuhsS5rmCZYRwvHPGUOmpoHy +VyH6sZFYOXYXiTJMS9/6WQOyMrSzlYmv9F6Usd/pvyFzFAZdCB4P0oQURCCRGXK5 +OAs8Lk/qOpvvk2HnNoLfSeLXReqHRR10Nhj0qjDVZdofx5hhq2QqSZhkoYwzOqWX +SmmmnW8AuWuBjQkPmGMPha7kIXCj2lon699tgqy7SGsBTjaVWtPwuTBDcoevQXow +E/KSFfFp5w== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52004.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52004.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52004.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52004.pem 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207428 (0x6bb3183cdef52004) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:58:15 2022 GMT + Not After : Feb 1 17:58:15 2052 GMT + Subject: CN=srv03.crt01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:45:db:b9:1b:37:65:bf:b1:a1:8a:5a:39:00:8d: + 4a:15:3b:43:9a:b8:2f:ff:a8:7d:99:83:a8:9c:dc: + b6:c2:aa:9f:f8:51:a1:0e:2e:97:0f:90:13:22:4c: + 8b:f1:ff:3c:6b:eb:91:29:7d:4c:df:7c:05:dd:ad: + ea:4a:4c:ad:0a:d6:6f:8e:51:b0:88:58:42:88:2c: + 16:d4:47:1d:b8:8f:b3:4e:0d:12:df:4c:14:f6:27: + 20:3f:94:9a:23:81:48 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv03.crt01.example.com, IP Address:10.53.0.3, IP Address:FD92:7065:B8E:FFFF:0:0:0:3 + Signature Algorithm: sha256WithRSAEncryption + 8f:96:88:82:94:76:8e:97:b6:75:8b:e9:2b:4f:f3:8f:14:5c: + 50:00:ca:67:96:9e:2e:bd:53:25:25:40:6d:c5:56:e6:1a:f6: + cb:fb:58:fc:b3:56:9d:fc:0b:e2:8e:99:7e:e8:e6:ad:b6:e7: + e6:3e:8a:59:ef:3e:76:a4:ed:7b:58:fd:a3:4b:aa:4e:11:e1: + 57:bf:b1:23:a5:a1:00:f8:95:07:c8:7d:ee:ac:a7:c8:24:ee: + cf:e8:c5:a4:9f:96:27:c9:47:c1:7d:11:de:66:d0:6d:d1:8d: + e7:8f:a0:0f:46:d9:2e:70:f3:9f:ac:6a:b0:3f:5a:dc:70:d4: + b9:a5:f3:ff:5c:21:50:5d:c2:a2:46:26:25:2a:2f:8a:aa:7a: + fd:76:31:5f:e0:25:a3:ee:df:36:f0:ab:05:a1:5d:0d:3c:6b: + 2c:1d:d5:c5:73:9c:a0:57:1f:c4:26:e6:dc:a1:7c:25:08:21: + 61:28:e2:b3:f5:51:83:20:73:14:19:8f:47:79:69:bc:2b:22: + f2:17:62:1d:83:f7:4f:a9:c4:51:68:e0:a9:d7:9f:17:6a:d2: + fd:f7:04:ce:a4:f5:8e:eb:31:b4:bf:c6:2d:da:0c:70:6e:0c: + a5:75:21:54:3c:f6:3d:36:b8:8a:d8:b6:7b:77:7e:54:1d:9f: + 91:8f:02:a6:d1:2c:a7:30:d1:cc:e6:d9:6b:76:80:15:4b:ba: + fd:55:20:cc:b2:99:85:57:60:11:97:c5:e7:28:50:a6:17:af: + d2:bd:1b:7e:06:48:7f:63:dc:70:f8:3f:22:9f:41:a1:66:f5: + a7:81:99:cb:07:0e:8a:9a:bb:12:f6:c0:fe:59:0c:00:37:15: + b2:9d:f0:f9:93:d1:1a:b6:f8:0a:6b:bd:9e:92:32:45:f5:a2: + 44:f0:45:8d:1a:d0:10:b2:db:98:c4:c7:5e:c1:e8:f3:94:33: + 6c:06:f5:1a:cc:51:23:72:ae:37:2f:57:d4:f8:ac:1f:25:b4: + d3:bf:99:9b:ac:fc +-----BEGIN CERTIFICATE----- +MIIDMzCCAZugAwIBAgIIa7MYPN71IAQwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIwODE3NTgxNVoYDzIwNTIwMjAx +MTc1ODE1WjAiMSAwHgYDVQQDDBdzcnYwMy5jcnQwMS5leGFtcGxlLmNvbTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEXbuRs3Zb+xoYpaOQCNShU7Q5q4L/+ofZmDqJzc +tsKqn/hRoQ4ulw+QEyJMi/H/PGvrkSl9TN98Bd2t6kpMrQrWb45RsIhYQogsFtRH +HbiPs04NEt9MFPYnID+UmiOBSKM+MDwwOgYDVR0RBDMwMYIXc3J2MDMuY3J0MDEu +ZXhhbXBsZS5jb22HBAo1AAOHEP2ScGULjv//AAAAAAAAAAMwDQYJKoZIhvcNAQEL +BQADggGBAI+WiIKUdo6XtnWL6StP848UXFAAymeWni69UyUlQG3FVuYa9sv7WPyz +Vp38C+KOmX7o5q225+Y+ilnvPnak7XtY/aNLqk4R4Ve/sSOloQD4lQfIfe6sp8gk +7s/oxaSflifJR8F9Ed5m0G3RjeePoA9G2S5w85+sarA/Wtxw1Lml8/9cIVBdwqJG +JiUqL4qqev12MV/gJaPu3zbwqwWhXQ08aywd1cVznKBXH8Qm5tyhfCUIIWEo4rP1 +UYMgcxQZj0d5abwrIvIXYh2D90+pxFFo4KnXnxdq0v33BM6k9Y7rMbS/xi3aDHBu +DKV1IVQ89j02uIrYtnt3flQdn5GPAqbRLKcw0czm2Wt2gBVLuv1VIMyymYVXYBGX +xecoUKYXr9K9G34GSH9j3HD4PyKfQaFm9aeBmcsHDoqauxL2wP5ZDAA3FbKd8PmT +0Rq2+AprvZ6SMkX1okTwRY0a0BCy25jEx17B6POUM2wG9RrMUSNyrjcvV9T4rB8l +tNO/mZus/A== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52005.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52005.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52005.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52005.pem 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207429 (0x6bb3183cdef52005) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 8 17:59:14 2022 GMT + Not After : Feb 1 17:59:14 2052 GMT + Subject: CN=srv04.crt01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:9e:43:d7:cc:29:e1:8e:4b:35:a1:8f:b7:8f:30: + 0f:56:b3:5b:7f:c0:62:9b:23:21:70:b1:2b:e7:73: + f9:ea:38:01:66:4b:52:43:31:cf:10:69:15:bf:6b: + 08:f3:69:07:3f:99:bb:b8:70:d0:3b:89:22:1d:f2: + 25:42:5a:3e:55:91:c3:fc:b4:be:c7:2d:86:51:14: + c4:ab:fe:7c:54:34:67:c7:5e:db:86:84:cc:66:eb: + 54:af:9d:7d:dc:ce:18 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv04.crt01.example.com, IP Address:10.53.0.4, IP Address:FD92:7065:B8E:FFFF:0:0:0:4 + Signature Algorithm: sha256WithRSAEncryption + 48:b5:38:59:79:e6:51:a6:ea:80:d7:d1:3c:29:03:70:31:e4: + 43:b4:e3:09:e7:e1:37:8c:d0:0f:2a:19:7a:f2:5a:6d:76:cd: + 17:7a:66:1c:3e:74:56:24:b8:29:06:55:b2:1c:af:9a:42:05: + 93:a4:70:cb:a5:68:85:ab:71:53:da:d9:29:a3:f4:2a:1e:df: + 0c:ec:7d:52:55:fa:9b:e6:a0:18:d5:4c:da:e6:d2:60:da:bc: + 09:5b:13:53:6d:c7:d2:30:b9:a8:a5:02:7f:a3:66:28:34:93: + de:55:a0:de:b5:c8:dc:43:7b:b9:03:06:1f:ce:8c:5f:82:d8: + af:40:56:ce:f8:b9:d4:73:1c:ae:c9:cb:1d:0f:a2:52:71:9b: + 8b:05:f4:d6:0b:1e:a8:db:0f:29:a0:43:b5:2f:56:09:d8:68: + 58:9c:e5:6a:df:38:91:56:9d:44:e5:d2:ca:9a:b1:41:a1:01: + 0c:68:a0:f5:0a:f7:98:4f:d5:a0:6f:99:59:a0:e0:cb:49:57: + 26:20:09:5a:fa:c2:75:40:f6:1b:6a:ac:55:47:50:8d:38:81: + 61:79:44:e7:d5:d1:b3:c7:3b:db:ec:44:59:ef:e1:82:31:a3: + 38:4c:de:40:11:31:52:8b:bb:1c:af:be:ce:c5:2b:f5:0d:c0: + 60:13:fb:7e:da:22:41:d4:85:5e:4d:ba:db:f8:f7:26:61:32: + 26:fe:fe:9e:37:a3:cc:25:3b:3c:c8:b5:a7:a5:5c:d9:4d:8f: + a8:f2:86:98:79:b3:00:08:0f:f2:c9:1f:c6:3f:07:ad:e4:a7: + 8d:86:3d:15:fa:5b:1a:0f:96:67:b6:0a:78:0a:bb:6e:05:a6: + 54:29:48:b4:f9:48:0d:7f:f0:13:65:32:2f:c5:ee:ab:b8:e8: + 0d:b2:f9:c9:96:d2:cf:51:a2:64:3c:58:0f:65:6f:c6:99:93: + 76:2c:42:08:d9:f3:f3:13:cd:41:b6:67:8f:1d:9a:2f:da:93: + 3d:26:4c:9a:11:c1 +-----BEGIN CERTIFICATE----- +MIIDMzCCAZugAwIBAgIIa7MYPN71IAUwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIwODE3NTkxNFoYDzIwNTIwMjAx +MTc1OTE0WjAiMSAwHgYDVQQDDBdzcnYwNC5jcnQwMS5leGFtcGxlLmNvbTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABJ5D18wp4Y5LNaGPt48wD1azW3/AYpsjIXCxK+dz ++eo4AWZLUkMxzxBpFb9rCPNpBz+Zu7hw0DuJIh3yJUJaPlWRw/y0vscthlEUxKv+ +fFQ0Z8de24aEzGbrVK+dfdzOGKM+MDwwOgYDVR0RBDMwMYIXc3J2MDQuY3J0MDEu +ZXhhbXBsZS5jb22HBAo1AASHEP2ScGULjv//AAAAAAAAAAQwDQYJKoZIhvcNAQEL +BQADggGBAEi1OFl55lGm6oDX0TwpA3Ax5EO04wnn4TeM0A8qGXryWm12zRd6Zhw+ +dFYkuCkGVbIcr5pCBZOkcMulaIWrcVPa2Smj9Coe3wzsfVJV+pvmoBjVTNrm0mDa +vAlbE1Ntx9IwuailAn+jZig0k95VoN61yNxDe7kDBh/OjF+C2K9AVs74udRzHK7J +yx0PolJxm4sF9NYLHqjbDymgQ7UvVgnYaFic5WrfOJFWnUTl0sqasUGhAQxooPUK +95hP1aBvmVmg4MtJVyYgCVr6wnVA9htqrFVHUI04gWF5ROfV0bPHO9vsRFnv4YIx +ozhM3kARMVKLuxyvvs7FK/UNwGAT+37aIkHUhV5Nutv49yZhMib+/p43o8wlOzzI +taelXNlNj6jyhph5swAID/LJH8Y/B63kp42GPRX6WxoPlme2CngKu24FplQpSLT5 +SA1/8BNlMi/F7qu46A2y+cmW0s9RomQ8WA9lb8aZk3YsQgjZ8/MTzUG2Z48dmi/a +kz0mTJoRwQ== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52006.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52006.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52006.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52006.pem 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207430 (0x6bb3183cdef52006) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Aug 15 08:00:00 2012 GMT + Not After : Aug 15 09:00:00 2012 GMT + Subject: CN=srv01.crt03-expired.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:1f:d5:7b:ab:73:b2:70:15:fd:33:26:02:5c:76: + 16:80:0c:70:7d:57:83:75:ac:3c:b7:4a:02:46:35: + c1:1b:c1:7a:bd:be:f2:04:9a:7f:69:83:7f:54:9a: + 1b:10:62:d7:70:bd:ef:26:90:51:50:10:77:56:b7: + 1a:2f:44:5e:91:46:36:e1:2e:a4:4c:67:2e:62:a8: + 7f:1a:15:10:44:68:8b:18:ea:cf:b8:96:09:bf:b5: + 3a:d1:ef:10:8f:9f:bb + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.crt03-expired.example.com, IP Address:10.53.0.1, IP Address:FD92:7065:B8E:FFFF:0:0:0:1 + Signature Algorithm: sha256WithRSAEncryption + 25:35:08:f6:e7:f0:83:81:be:65:31:1b:78:a8:04:84:fe:6a: + 2a:1a:5d:c1:73:20:88:08:11:d8:27:be:a5:8e:3c:df:e2:a6: + 19:c5:41:40:ea:01:91:85:99:8d:17:4e:4d:9a:3c:03:f9:78: + 4c:8a:20:41:5e:96:d6:64:83:2f:b2:fe:e7:77:09:f9:91:bd: + 22:1a:57:8b:f6:24:bc:7b:48:2b:2e:14:b7:32:bd:46:91:99: + 5e:21:9a:d3:15:a7:27:e1:c0:3a:c7:f5:f9:94:3f:6d:14:7e: + 0b:02:bf:05:d9:ac:10:8a:7e:b0:37:36:cd:cb:4a:b4:e1:01: + c7:04:8d:83:f3:c6:79:ff:ff:6c:f0:a4:bf:3c:12:61:ea:15: + ac:30:62:26:e3:c3:4e:7d:5c:68:d8:88:de:35:8d:44:75:8c: + a8:c1:0d:07:67:b5:d0:42:43:41:1f:39:a0:47:35:46:d7:0f: + 89:aa:e8:d3:86:45:9a:fb:33:01:06:23:64:53:24:48:5b:69: + fa:cf:d9:81:fb:5e:7e:7b:82:65:56:c6:46:65:5c:e1:4f:f2: + 3c:09:3c:28:5f:c9:e3:a5:24:e3:7b:aa:b5:b1:8a:6a:b2:02: + 32:5f:24:05:f1:67:c8:54:17:0c:cd:ca:3d:e4:44:3e:23:3a: + 7c:63:b6:f9:61:3a:21:e7:8f:27:ad:c3:26:86:39:49:6c:41: + 40:7f:1d:48:69:8d:db:6f:42:e4:09:fe:24:62:bd:8e:2e:54: + 25:f0:14:c2:d8:43:95:09:2e:5f:72:4f:43:b5:9a:8b:bb:8c: + 44:c6:77:c9:05:fb:1a:9f:d7:b6:a6:42:d9:5c:3d:a5:09:0f: + 9e:e0:c7:06:32:f1:ff:c9:53:5e:42:d4:2a:33:ad:06:ea:ec: + b0:26:d3:3c:ef:65:af:15:8e:7b:20:49:ad:f1:56:ef:17:6b: + fc:f4:d8:7c:82:9f:30:19:d0:bc:9c:79:e2:dc:9d:a7:f9:6b: + 6f:65:ae:21:a0:94 +-----BEGIN CERTIFICATE----- +MIIDQTCCAamgAwIBAgIIa7MYPN71IAYwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMB4XDTEyMDgxNTA4MDAwMFoXDTEyMDgxNTA5 +MDAwMFowKjEoMCYGA1UEAwwfc3J2MDEuY3J0MDMtZXhwaXJlZC5leGFtcGxlLmNv +bTB2MBAGByqGSM49AgEGBSuBBAAiA2IABB/Ve6tzsnAV/TMmAlx2FoAMcH1Xg3Ws +PLdKAkY1wRvBer2+8gSaf2mDf1SaGxBi13C97yaQUVAQd1a3Gi9EXpFGNuEupExn +LmKofxoVEERoixjqz7iWCb+1OtHvEI+fu6NGMEQwQgYDVR0RBDswOYIfc3J2MDEu +Y3J0MDMtZXhwaXJlZC5leGFtcGxlLmNvbYcECjUAAYcQ/ZJwZQuO//8AAAAAAAAA +ATANBgkqhkiG9w0BAQsFAAOCAYEAJTUI9ufwg4G+ZTEbeKgEhP5qKhpdwXMgiAgR +2Ce+pY483+KmGcVBQOoBkYWZjRdOTZo8A/l4TIogQV6W1mSDL7L+53cJ+ZG9IhpX +i/YkvHtIKy4UtzK9RpGZXiGa0xWnJ+HAOsf1+ZQ/bRR+CwK/BdmsEIp+sDc2zctK +tOEBxwSNg/PGef//bPCkvzwSYeoVrDBiJuPDTn1caNiI3jWNRHWMqMENB2e10EJD +QR85oEc1RtcPiaro04ZFmvszAQYjZFMkSFtp+s/ZgftefnuCZVbGRmVc4U/yPAk8 +KF/J46Uk43uqtbGKarICMl8kBfFnyFQXDM3KPeREPiM6fGO2+WE6IeePJ63DJoY5 +SWxBQH8dSGmN229C5An+JGK9ji5UJfAUwthDlQkuX3JPQ7Wai7uMRMZ3yQX7Gp/X +tqZC2Vw9pQkPnuDHBjLx/8lTXkLUKjOtBurssCbTPO9lrxWOeyBJrfFW7xdr/PTY +fIKfMBnQvJx54tydp/lrb2WuIaCU +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52007.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52007.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52007.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52007.pem 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1,68 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207431 (0x6bb3183cdef52007) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 10 17:44:20 2022 GMT + Not After : Feb 3 17:44:20 2052 GMT + Subject: CN=srv01.client01.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:5e:93:6a:7a:da:75:cc:64:08:e4:f8:f9:2f:2b: + 85:36:ee:e1:df:fa:cd:4c:60:f1:44:b5:16:7b:f9: + 03:cf:a0:08:67:6f:ae:27:a3:95:8a:68:1e:63:ab: + cf:2e:20:62:52:e7:8c:3e:1e:ef:de:0d:69:64:65: + b6:e4:df:fe:1a:48:f8:68:75:84:83:11:fb:81:59: + 0e:c1:96:48:7f:24:da:11:dd:ac:cb:0a:c5:09:78: + 24:31:3a:df:37:e6:b3 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.client01.example.com + Signature Algorithm: sha256WithRSAEncryption + 82:bd:eb:8f:4e:a5:d2:46:c7:d8:70:3c:34:1d:58:43:1b:81: + 16:5d:c2:b0:76:4b:a9:f2:10:14:23:e4:ef:dc:59:03:b6:7f: + b0:40:34:e5:d0:82:4b:95:a6:07:9a:45:51:94:cf:08:c2:4e: + c9:44:d5:f3:b6:ed:f2:a0:01:94:ad:e0:0e:0f:ab:85:6f:35: + 4b:07:c8:97:25:fb:69:ff:a1:99:bc:ec:70:6c:51:b5:32:95: + e9:c9:45:cf:45:e2:c5:5e:b1:59:a2:e1:f2:83:c8:87:68:c4: + 60:e2:db:50:6c:18:64:1b:9a:9a:cc:7c:e7:fd:d9:f2:b7:d1: + de:1d:ec:29:c9:58:db:7b:9a:a1:06:9a:ce:36:a0:45:10:dc: + 7d:81:24:21:34:30:4c:71:f9:fc:96:37:d6:cf:0d:9d:11:12: + c7:62:bc:19:5b:79:e5:e0:37:e8:17:36:4b:13:af:fa:2c:2e: + 36:d9:be:53:e1:c3:f9:bc:94:a6:7a:97:14:99:36:f9:14:38: + 11:20:3a:2a:9d:fd:64:63:d0:a2:8f:f0:99:a9:02:ca:57:48: + d2:7d:65:44:b6:85:a0:38:ec:e8:19:7e:c2:48:e3:1d:22:53: + cf:3b:d4:0a:98:e1:72:62:ec:8b:01:3f:5a:ea:26:2c:8c:16: + c3:80:5a:c2:5d:40:c5:65:1c:e2:9a:e3:d6:65:16:ee:dc:17: + 30:d8:26:87:92:d0:ef:c7:72:07:99:86:05:9e:49:35:41:33: + b9:bb:cb:1b:25:50:70:85:e3:0f:c7:b9:b2:37:00:1b:87:a2: + 47:97:34:5b:cd:dc:66:22:e5:de:25:ec:57:fe:37:75:2c:03: + 10:f4:d4:a7:cc:f5:4b:0b:ff:eb:d3:a6:78:2e:cd:8f:65:51: + a7:8c:ef:83:67:ec:94:13:c2:1f:74:74:55:7c:a3:0b:b7:2f: + 80:5a:62:04:1d:a2:c0:c1:de:b2:7d:31:3b:a1:fa:f7:40:a7: + bd:12:25:95:5b:8b +-----BEGIN CERTIFICATE----- +MIIDITCCAYmgAwIBAgIIa7MYPN71IAcwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIxMDE3NDQyMFoYDzIwNTIwMjAz +MTc0NDIwWjAlMSMwIQYDVQQDDBpzcnYwMS5jbGllbnQwMS5leGFtcGxlLmNvbTB2 +MBAGByqGSM49AgEGBSuBBAAiA2IABF6TanradcxkCOT4+S8rhTbu4d/6zUxg8US1 +Fnv5A8+gCGdvriejlYpoHmOrzy4gYlLnjD4e794NaWRltuTf/hpI+Gh1hIMR+4FZ +DsGWSH8k2hHdrMsKxQl4JDE63zfms6MpMCcwJQYDVR0RBB4wHIIac3J2MDEuY2xp +ZW50MDEuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggGBAIK9649OpdJGx9hw +PDQdWEMbgRZdwrB2S6nyEBQj5O/cWQO2f7BANOXQgkuVpgeaRVGUzwjCTslE1fO2 +7fKgAZSt4A4Pq4VvNUsHyJcl+2n/oZm87HBsUbUylenJRc9F4sVesVmi4fKDyIdo +xGDi21BsGGQbmprMfOf92fK30d4d7CnJWNt7mqEGms42oEUQ3H2BJCE0MExx+fyW +N9bPDZ0REsdivBlbeeXgN+gXNksTr/osLjbZvlPhw/m8lKZ6lxSZNvkUOBEgOiqd +/WRj0KKP8JmpAspXSNJ9ZUS2haA47OgZfsJI4x0iU8871AqY4XJi7IsBP1rqJiyM +FsOAWsJdQMVlHOKa49ZlFu7cFzDYJoeS0O/HcgeZhgWeSTVBM7m7yxslUHCF4w/H +ubI3ABuHokeXNFvN3GYi5d4l7Ff+N3UsAxD01KfM9UsL/+vTpnguzY9lUaeM74Nn +7JQTwh90dFV8owu3L4BaYgQdosDB3rJ9MTuh+vdAp70SJZVbiw== +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52008.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52008.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52008.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52008.pem 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1,68 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207432 (0x6bb3183cdef52008) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Feb 11 13:21:12 2022 GMT + Not After : Feb 4 13:21:12 2052 GMT + Subject: CN=srv01.client02-ns2.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:e6:45:fa:57:12:6c:59:10:23:8b:7a:5c:76:33: + eb:3b:41:fa:b7:1c:90:b3:2f:33:2d:45:7b:e3:e5: + b6:a5:a2:a2:a4:14:f4:50:9d:b0:c6:38:ba:e9:45: + 65:a4:65:b9:10:32:2f:93:9b:d5:d8:cf:b4:29:5b: + dc:4e:c8:ec:a6:9f:58:76:24:f4:c5:d1:48:55:52: + eb:5d:b0:85:93:85:ee:3e:b8:c4:b1:cd:08:59:95: + 12:ff:7b:9b:ee:6a:b9 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.client02-ns2.example.com + Signature Algorithm: sha256WithRSAEncryption + 43:ec:0f:62:17:f6:f4:90:3b:7c:36:21:f2:18:94:a6:42:51: + 1e:1d:2a:43:8f:05:b7:8d:3c:ca:f0:20:2f:65:4b:be:48:ad: + 6a:0a:cc:2d:1f:d6:27:1d:af:4a:36:86:ed:0d:03:75:c5:71: + ec:58:9b:ec:f9:0f:e4:83:ef:6f:91:da:20:73:47:ac:e7:c7: + 8b:22:b2:d1:6e:a0:b0:d6:1c:4c:70:1e:74:08:1d:7f:61:06: + e5:be:f3:e8:c4:15:60:e2:b0:02:9b:f0:13:af:76:5b:a8:c7: + 91:2c:10:5f:0d:32:89:51:5a:7f:17:1b:7c:c6:46:97:ee:e7: + bb:8a:48:38:a2:52:d4:ff:3b:1c:ec:4a:a9:8c:a5:23:3a:04: + bb:d7:b8:ad:5b:69:7f:1d:be:ca:96:e0:eb:56:05:43:ee:c8: + ff:2c:48:03:00:c6:c2:ac:fc:4e:15:47:86:c5:33:ed:70:f6: + 98:bc:0b:07:b9:5b:1a:ec:fd:3c:bf:26:61:68:fc:db:02:55: + 07:ae:76:0e:be:ff:c5:b8:56:fb:52:54:a4:b1:2d:64:b4:1d: + 55:02:4f:da:06:bd:26:e4:22:d2:94:1f:7e:29:c4:97:10:d1: + 75:7d:41:53:be:46:52:70:b1:d9:ff:bb:9f:96:19:e3:a0:ba: + d0:4a:5a:8d:da:22:73:89:f0:4c:e6:18:80:53:be:bd:64:56: + 6a:c9:58:71:40:66:9e:4a:3e:31:3b:74:9e:6e:6a:f5:65:ca: + 93:06:52:00:74:65:a0:3a:eb:2e:56:56:d2:a5:4b:0e:85:17: + 25:78:cb:f3:f9:53:7b:85:f9:82:15:87:bc:36:70:b5:69:64: + 48:11:79:b9:2c:2e:cc:09:fd:0f:b0:b7:cd:97:3b:c7:0f:49: + 1a:fc:15:49:d6:1c:a9:dc:14:ff:44:d2:be:5a:36:00:66:0c: + d5:b8:bf:16:9e:60:27:79:c0:f5:b4:ff:2f:af:8c:b2:49:75: + 61:44:05:1a:e8:cd +-----BEGIN CERTIFICATE----- +MIIDKTCCAZGgAwIBAgIIa7MYPN71IAgwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMCAXDTIyMDIxMTEzMjExMloYDzIwNTIwMjA0 +MTMyMTEyWjApMScwJQYDVQQDDB5zcnYwMS5jbGllbnQwMi1uczIuZXhhbXBsZS5j +b20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATmRfpXEmxZECOLelx2M+s7Qfq3HJCz +LzMtRXvj5baloqKkFPRQnbDGOLrpRWWkZbkQMi+Tm9XYz7QpW9xOyOymn1h2JPTF +0UhVUutdsIWThe4+uMSxzQhZlRL/e5vuarmjLTArMCkGA1UdEQQiMCCCHnNydjAx +LmNsaWVudDAyLW5zMi5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAQ+wP +Yhf29JA7fDYh8hiUpkJRHh0qQ48Ft408yvAgL2VLvkitagrMLR/WJx2vSjaG7Q0D +dcVx7Fib7PkP5IPvb5HaIHNHrOfHiyKy0W6gsNYcTHAedAgdf2EG5b7z6MQVYOKw +ApvwE692W6jHkSwQXw0yiVFafxcbfMZGl+7nu4pIOKJS1P87HOxKqYylIzoEu9e4 +rVtpfx2+ypbg61YFQ+7I/yxIAwDGwqz8ThVHhsUz7XD2mLwLB7lbGuz9PL8mYWj8 +2wJVB652Dr7/xbhW+1JUpLEtZLQdVQJP2ga9JuQi0pQffinElxDRdX1BU75GUnCx +2f+7n5YZ46C60Epajdoic4nwTOYYgFO+vWRWaslYcUBmnko+MTt0nm5q9WXKkwZS +AHRloDrrLlZW0qVLDoUXJXjL8/lTe4X5ghWHvDZwtWlkSBF5uSwuzAn9D7C3zZc7 +xw9JGvwVSdYcqdwU/0TSvlo2AGYM1bi/Fp5gJ3nA9bT/L6+Mskl1YUQFGujN +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52009.pem bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52009.pem --- bind9-9.20.26/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52009.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/newcerts/6BB3183CDEF52009.pem 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7760573232607207433 (0x6bb3183cdef52009) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=UA, ST=Kharkiv Oblast', L=Kharkiv, O=Internet Systems Consortium, CN=ca.test.example.com + Validity + Not Before: Aug 14 05:00:00 2012 GMT + Not After : Aug 14 06:00:00 2012 GMT + Subject: CN=srv01.client03-ns2-expired.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:38:9a:9b:c2:6a:82:a6:d1:50:8a:78:7a:d1:be: + 61:be:d4:b6:d3:d6:a2:02:97:a4:48:50:c0:c5:1d: + d8:2d:23:19:25:6e:91:02:1d:69:c2:77:d6:f1:a8: + 4f:4a:9a:1d:3c:69:5a:89:41:0a:f2:e0:64:57:1b: + 0e:9e:df:9f:4c:7b:3c:42:dc:21:c8:2c:95:ab:b3: + 4c:5f:56:c4:70:ee:8a:a4:e4:46:c4:9e:98:f5:c8: + 7b:b2:73:d7:45:93:f0 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:srv01.client03-ns2-expired.example.com + Signature Algorithm: sha256WithRSAEncryption + 38:12:1f:5f:26:b6:8e:9b:3f:77:89:5a:b8:e8:46:78:c3:d6: + f0:0c:67:5f:d5:a3:9c:f6:f2:0a:ae:9c:87:74:9f:a3:5b:8a: + 27:58:47:e5:78:1a:e9:db:b5:cc:28:a7:f8:18:e3:e7:20:43: + cf:82:06:5d:a1:d0:82:ab:15:be:86:46:1e:e6:4d:ad:78:a4: + 16:6c:99:41:3d:29:21:c8:6b:9d:3d:4a:cd:93:37:1f:1c:88: + c7:ae:b6:7c:73:42:57:57:32:9d:e8:c6:e2:3e:da:12:57:3e: + c8:56:4a:bb:d4:01:fc:8e:30:8d:19:fe:61:3d:5e:02:64:65: + a2:46:b3:6e:ea:f9:cb:4e:f0:b9:f6:bc:6b:38:10:19:d0:93: + f8:f7:d9:4c:d2:87:2c:7f:dc:f5:00:c6:29:dd:00:5e:d2:f4: + df:52:fb:7a:5a:ad:98:36:77:72:1f:01:ed:48:91:48:16:2d: + 35:a5:15:21:98:ff:7e:5d:a1:45:c9:5f:9d:c2:3e:e5:98:e2: + ee:ce:4d:18:76:3d:8a:0a:64:9b:f1:19:9d:b6:82:af:1b:15: + d3:48:69:f1:9b:67:76:1b:41:8e:1d:69:d5:31:64:95:01:41: + 73:c1:a9:29:53:6b:f3:29:ad:e0:96:52:8e:3e:8d:c1:8e:d8: + b5:0c:94:5f:a2:6c:3c:0f:3e:5b:10:af:21:00:74:d0:b7:30: + 6c:44:fb:3d:09:46:8d:1d:e6:c2:e4:0a:5b:f4:eb:e1:71:c7: + d5:36:13:90:05:fe:65:16:61:24:b5:41:f2:10:bd:2c:c3:34: + 69:15:25:d1:32:f2:b3:d7:da:23:1b:e9:5b:33:63:43:c8:dc: + 68:f2:31:b5:93:0e:64:ea:9a:45:36:9f:96:44:38:1e:4e:d8: + 45:ba:37:68:06:4d:da:d4:16:d3:3e:77:86:4e:8d:58:d6:06: + a8:60:11:4d:d9:81:f3:85:2b:ee:58:50:6e:ea:2b:f7:84:00: + 9c:ec:a1:90:d4:94 +-----BEGIN CERTIFICATE----- +MIIDNzCCAZ+gAwIBAgIIa7MYPN71IAkwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE +BhMCVUExGDAWBgNVBAgMD0toYXJraXYgT2JsYXN0JzEQMA4GA1UEBwwHS2hhcmtp +djEkMCIGA1UECgwbSW50ZXJuZXQgU3lzdGVtcyBDb25zb3J0aXVtMRwwGgYDVQQD +DBNjYS50ZXN0LmV4YW1wbGUuY29tMB4XDTEyMDgxNDA1MDAwMFoXDTEyMDgxNDA2 +MDAwMFowMTEvMC0GA1UEAwwmc3J2MDEuY2xpZW50MDMtbnMyLWV4cGlyZWQuZXhh +bXBsZS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ4mpvCaoKm0VCKeHrRvmG+ +1LbT1qICl6RIUMDFHdgtIxklbpECHWnCd9bxqE9Kmh08aVqJQQry4GRXGw6e359M +ezxC3CHILJWrs0xfVsRw7oqk5EbEnpj1yHuyc9dFk/CjNTAzMDEGA1UdEQQqMCiC +JnNydjAxLmNsaWVudDAzLW5zMi1leHBpcmVkLmV4YW1wbGUuY29tMA0GCSqGSIb3 +DQEBCwUAA4IBgQA4Eh9fJraOmz93iVq46EZ4w9bwDGdf1aOc9vIKrpyHdJ+jW4on +WEfleBrp27XMKKf4GOPnIEPPggZdodCCqxW+hkYe5k2teKQWbJlBPSkhyGudPUrN +kzcfHIjHrrZ8c0JXVzKd6MbiPtoSVz7IVkq71AH8jjCNGf5hPV4CZGWiRrNu6vnL +TvC59rxrOBAZ0JP499lM0ocsf9z1AMYp3QBe0vTfUvt6Wq2YNndyHwHtSJFIFi01 +pRUhmP9+XaFFyV+dwj7lmOLuzk0Ydj2KCmSb8RmdtoKvGxXTSGnxm2d2G0GOHWnV +MWSVAUFzwakpU2vzKa3gllKOPo3Bjti1DJRfomw8Dz5bEK8hAHTQtzBsRPs9CUaN +HebC5Apb9OvhccfVNhOQBf5lFmEktUHyEL0swzRpFSXRMvKz19ojG+lbM2NDyNxo +8jG1kw5k6ppFNp+WRDgeTthFujdoBk3a1BbTPneGTo1Y1gaoYBFN2YHzhSvuWFBu +6iv3hACc7KGQ1JQ= +-----END CERTIFICATE----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/private/CA.key bind9-9.20.29/bin/tests/system/checkds/CA/private/CA.key --- bind9-9.20.26/bin/tests/system/checkds/CA/private/CA.key 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/private/CA.key 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG5AIBAAKCAYEAouoRHoAc6VCmxNTU6Ge7s+xDFGO0wXJJIsP+8nUyyjWvGCOC +aQYLhb1kLA2NHRhSSKFcMh8jcd7Hlvy6CAec1j2dsWzryy3HgPrdjWaW3PfBO41D +lUtdt8hA/p6pX2YwqvWbdK/3s8J0LY5xRZKNZnFOB/Sb4PGiIJ1NgMRO/M3IlPQm +PO/faRRTU4SI26KCPKFW342826Zi88YwOd6w5mQU4fskk5TGtlNqE+Fj40ZbWVpy +VXoEUS6RveRp020NX5CQG49SLtdF05AnnsATqmgNVCXptGuqW8uaHRONeGO3NBEy +nJmibWBDUMjtCCcGVgyrVXuTkyAJJWpImnshUwgMNYebRwmC2iVv2LtsJS5eUTUH +EWffnFl55XU2PkyNYgY35gA4y3SiWFJYV8+5FibU4ut0nb+lmHBF8WlqcU/kd3tp +Gkf0exjqOIHZFqV9bIhpUbXhxx9v9+gkkGQ9nrXE1KRlvigxxUeIK5xHy9a7fVIL +wo6WuCnLLJmbVkklAgMBAAECggGBAI5ZV3v/FUQIZK+4CBDKEwizeClotZgR9DWc +bDgOj8KABe5hmKGL1qWVRuH3NUYm6j7sP1LMQnxM3LjhOuupOzE3xYIyWhW+eoQI +r23OJiQNl5ohZNweblUXdTMGD5h8AipfUOY0m4tGbZ0gyXixBTxt5HCvG0UB3VgC +GqZY4Wujo5ADhSXZsqxuRiDDvZGr/YBcuTu87Tg/ulam5ZyrKIcnC9gpSVxqsva9 +DAMy/cSoxUjd7ukhJISK3G3AF3fV4GSslQcJTlyJ2D3+LnqPuHJKYTI4hc46lN3x +E2g24GdSCPYf6SoEPwACXtbavV8TXwQPJrHN+f+0/ePCI4jkYe5NoA3gwVgMb/WB +wFchxzVh3V4e8tPGiG+ofKl81DSAW8VZCJLUIbTEce9oxafPT78WJxdC0wWbh5S8 +V/qN6sW/yWnK3oY9SilWhJGRwKOZ+8xtStaDeCzyCaOqEcWi8ZR0QfC33UozlhdC +SrMKnOXmn/rUuXGrVR56IzIl0M7YAQKBwQDM3GJDdlFuHn6L0syKYdHDS8gXD9ke +s+ochIP6jvkEPcayaEoZGl8s7RT3iztqXod7wLaZdotktxfDAZnJfeuOcVrCu+Bx +HLytnBvV6czMfp3REGgQAJQeusSgtlBCTHHVOsDzIjdnkY3WBa7IiFYWO5wnYrGx +r3ucnwnHaUVDMj1r4YI7mYIpCuYQl6eGyW7mhWewyhVwoQXKbifdrXxjvOigL0Cp +tgsoU9pql3hpphOaYMX6hLOincTfaMxfnCECgcEAy5UXp3dA0OwK+4iDGKr+cUpk +AtGTheiE+8zEVh2KYFLt921mW/QZiB1+xtnkknp3c7u07Ugk8jAEXzCkwMnN5ZCx +LrJ72fC+cLIAbRm6/vMMP8iz83wyttao4qNMeoOBBfE9rEiP+lrugpv282V3ZHYa +IUZWTeugJbckUHTbD3RZQExmQcRVG3m/TzonBfoZ8HoRj/n3d7V2T911cHUhi8Xn +RQIi2m63VofOIep86LgartlKneMWnL0oOPq4RKyFAoHAZUzpDkD4nUJZAx025Yrf +ZfoYNEcy7vq6XmWsuX5vZoiBs4DcezNOMvH9NzdTJxMdXbV61cIHxcK/7j7hZABv +NZ2Z6sdqgaRbLGIQZaPaEJjfwxygyKDwnY1vY6UjZNVWSMFn3hJiYUVZZKakuiao +ow/Q9KzZ/2ot7tG5zTCh/ktekfUOKBiNg2wPPc8wGPeMblMzZflXxrzpFyOHdRev +dcZZJbSX/hO1yrhEPgculNd5xBHsdCegiF4JlwvEW9bhAoHAZQQiy5bx03j8bhkr +q6bVQFPAUmG5iL16lxLg7TYVPnyH1bk0DDaQIKk6CeN+dmxML2IZgY/FvWK0GKOj +bIH2J43nTRuFNvwtEvBQI9KbpfvlvRSSriOXaoATJvoObdAoylEM4BrVTk2mgapw +HA/h8Thk+NPU6S8ctPouC7ogJIf/7Va7erC35j0//0kEqgOSsW9wnXdUItMo1LI3 +nsiQD7Hwcp5/utErKcWTM+MNfdA0dUQesT9ILhfyCGvn2TOdAoHBAKldZkDyRcu9 +r9uDF1bhUEnpV2k4hgvTuCvQ3rzyx3WrVT8ChEmePC8Ke5A54ffu/YdbpDLbdf2c +j4n5CQhHbMIZs3P2hB3WqDCImApCfMbXaltfBbaT0j7uLJPMp+2+f/wWYpc3R+bn +HVnaRI2PoXXmG9OjQSQdVZ5gNpkEuemAo3dJOSS6BMqQaSxUynGy7o/a/d4izBjd +B58Fwq3sZI/Xv90Se9+b6ICST3YJ3p0vn8RKzmlCQjLg/xynpCByiw== +-----END RSA PRIVATE KEY----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/CA/serial bind9-9.20.29/bin/tests/system/checkds/CA/serial --- bind9-9.20.26/bin/tests/system/checkds/CA/serial 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/CA/serial 2026-09-11 19:41:01.192323587 +0000 @@ -0,0 +1 @@ +6BB3183CDEF5200A diff -Nru bind9-9.20.26/bin/tests/system/checkds/dhparam3072.pem bind9-9.20.29/bin/tests/system/checkds/dhparam3072.pem --- bind9-9.20.26/bin/tests/system/checkds/dhparam3072.pem 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/dhparam3072.pem 2026-09-11 19:41:01.193323611 +0000 @@ -0,0 +1,11 @@ +-----BEGIN DH PARAMETERS----- +MIIBiAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3 +7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32 +nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu +N///////////AgEC +-----END DH PARAMETERS----- diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns1/named.conf.j2 2026-07-20 14:47:53.645842643 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns1/named.conf.j2 2026-09-11 19:41:01.131322113 +0000 @@ -14,18 +14,13 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns10/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns10/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns10/named.conf.j2 2026-07-20 14:47:53.645842643 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns10/named.conf.j2 2026-09-11 19:41:01.131322113 +0000 @@ -14,77 +14,64 @@ // NS10 options { - query-source address 10.53.0.10; - notify-source 10.53.0.10; - transfer-source 10.53.0.10; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.10; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.10 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "ns2" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2.db"; }; zone "ns2-4" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2-4.db"; }; zone "ns2-4-5" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2-4-5.db"; }; zone "ns2-4-6" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2-4-6.db"; }; zone "ns2-5-7" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2-5-7.db"; }; zone "ns5" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns5.db"; }; zone "ns5-6-7" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns5-6-7.db"; }; zone "ns5-7" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns5-7.db"; }; zone "ns6" { type secondary; - primaries source 10.53.0.10 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns6.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns2/named.conf.j2 2026-07-20 14:47:53.646842668 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns2/named.conf.j2 2026-09-11 19:41:01.132322138 +0000 @@ -14,36 +14,20 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "ns2" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns2.db"; @@ -52,7 +36,7 @@ zone "ns2-4" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns2-4.db"; @@ -61,7 +45,7 @@ zone "ns2-4-5" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns2-4-5.db"; @@ -70,7 +54,7 @@ zone "ns2-4-6" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns2-4-6.db"; @@ -79,7 +63,7 @@ zone "ns2-5-7" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns2-5-7.db"; @@ -88,7 +72,7 @@ zone "ns5" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns5.db"; @@ -97,7 +81,7 @@ zone "ns5-6-7" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns5-6-7.db"; @@ -106,7 +90,7 @@ zone "ns5-7" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns5-7.db"; @@ -115,7 +99,7 @@ zone "ns6" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.2; 10.53.0.4; 10.53.0.8; }; + allow-transfer { @ns.ip@; 10.53.0.4; 10.53.0.8; }; also-notify { 10.53.0.4; 10.53.0.8; }; dnssec-policy default; file "ns6.db"; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns2/ns2.db.in bind9-9.20.29/bin/tests/system/checkds/ns2/ns2.db.in --- bind9-9.20.26/bin/tests/system/checkds/ns2/ns2.db.in 2026-07-20 14:47:53.646842668 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns2/ns2.db.in 2026-09-11 19:41:01.132322138 +0000 @@ -27,9 +27,11 @@ $ORIGIN explicit.dspublish.ns2. good NS ns9.good reference NS ns9.reference +tls-reference NS ns9.tls-reference resolver NS ns9.resolver ns9.good A 10.53.0.9 ns9.reference A 10.53.0.9 +ns9.tls-reference A 10.53.0.9 ns9.resolver A 10.53.0.9 $ORIGIN yes.dspublish.ns2. diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns3/named.conf.j2 2026-07-20 14:47:53.647842693 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns3/named.conf.j2 2026-09-11 19:41:01.132322138 +0000 @@ -14,28 +14,13 @@ // NS3 options { - query-source address 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; session-keyfile "session.key"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns4/named.conf.j2 2026-07-20 14:47:53.647842693 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns4/named.conf.j2 2026-09-11 19:41:01.133322162 +0000 @@ -14,77 +14,64 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "ns2" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2.db"; }; zone "ns2-4" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2-4.db"; }; zone "ns2-4-5" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2-4-5.db"; }; zone "ns2-4-6" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2-4-6.db"; }; zone "ns2-5-7" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2-5-7.db"; }; zone "ns5" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns5.db"; }; zone "ns5-6-7" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns5-6-7.db"; }; zone "ns5-7" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns5-7.db"; }; zone "ns6" { type secondary; - primaries source 10.53.0.4 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns6.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns5/named.conf.j2 2026-07-20 14:47:53.647842693 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns5/named.conf.j2 2026-09-11 19:41:01.133322162 +0000 @@ -14,36 +14,20 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "ns2" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns2.db"; @@ -52,7 +36,7 @@ zone "ns2-4" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns2-4.db"; @@ -61,7 +45,7 @@ zone "ns2-4-5" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns2-4-5.db"; @@ -70,7 +54,7 @@ zone "ns2-4-6" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns2-4-6.db"; @@ -79,7 +63,7 @@ zone "ns2-5-7" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns2-5-7.db"; @@ -88,7 +72,7 @@ zone "ns5" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns5.db"; @@ -97,7 +81,7 @@ zone "ns5-6-7" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns5-6-7.db"; @@ -106,7 +90,7 @@ zone "ns5-7" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns5-7.db"; @@ -115,7 +99,7 @@ zone "ns6" { type primary; allow-update { any; }; - allow-transfer { 10.53.0.5; 10.53.0.7; 10.53.0.10; }; + allow-transfer { @ns.ip@; 10.53.0.7; 10.53.0.10; }; also-notify { 10.53.0.7; 10.53.0.10; }; dnssec-policy default; file "ns6.db"; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns5/ns2.db.in bind9-9.20.29/bin/tests/system/checkds/ns5/ns2.db.in --- bind9-9.20.26/bin/tests/system/checkds/ns5/ns2.db.in 2026-07-20 14:47:53.647842693 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns5/ns2.db.in 2026-09-11 19:41:01.133322162 +0000 @@ -27,9 +27,11 @@ $ORIGIN explicit.dspublish.ns2. good NS ns9.good reference NS ns9.reference +tls-reference NS ns9.tls-reference resolver NS ns9.resolver ns9.good A 10.53.0.9 ns9.reference A 10.53.0.9 +ns9.tls-reference A 10.53.0.9 ns9.resolver A 10.53.0.9 $ORIGIN yes.dspublish.ns2. diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns6/named.conf.j2 2026-07-20 14:47:53.648842718 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns6/named.conf.j2 2026-09-11 19:41:01.134322186 +0000 @@ -14,31 +14,15 @@ // NS2 options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "foo" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns7/named.conf.j2 2026-07-20 14:47:53.648842718 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns7/named.conf.j2 2026-09-11 19:41:01.134322186 +0000 @@ -14,77 +14,64 @@ // NS7 options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "ns2" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2.db"; }; zone "ns2-4" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2-4.db"; }; zone "ns2-4-5" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2-4-5.db"; }; zone "ns2-4-6" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2-4-6.db"; }; zone "ns2-5-7" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns2-5-7.db"; }; zone "ns5" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns5.db"; }; zone "ns5-6-7" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns5-6-7.db"; }; zone "ns5-7" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns5-7.db"; }; zone "ns6" { type secondary; - primaries source 10.53.0.7 { 10.53.0.5 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.5 port @PORT@; }; file "ns6.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns8/named.conf.j2 2026-07-20 14:47:53.648842718 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns8/named.conf.j2 2026-09-11 19:41:01.134322186 +0000 @@ -13,78 +13,81 @@ // NS8 +{% if FEATURE_FIPS_DH == "1" %} +tls tls-forward-secrecy { + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv01.crt01.example.com.key"; + cert-file "../CA/certs/srv01.crt01.example.com.pem"; + dhparam-file "../dhparam3072.pem"; +}; +{% endif %} + options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; -}; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; +{% if FEATURE_FIPS_DH == "1" %} + tls-port @TLSPORT@; + listen-on tls tls-forward-secrecy { 10.53.0.8; }; +{% endif %} }; -controls { - inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "ns2" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2.db"; }; zone "ns2-4" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2-4.db"; }; zone "ns2-4-5" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2-4-5.db"; }; zone "ns2-4-6" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2-4-6.db"; }; zone "ns2-5-7" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns2-5-7.db"; }; zone "ns5" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns5.db"; }; zone "ns5-6-7" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns5-6-7.db"; }; zone "ns5-7" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns5-7.db"; }; zone "ns6" { type secondary; - primaries source 10.53.0.8 { 10.53.0.2 port @PORT@; }; + primaries source @ns.ip@ { 10.53.0.2 port @PORT@; }; file "ns6.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/checkds/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checkds/ns9/named.conf.j2 2026-07-20 14:47:53.648842718 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns9/named.conf.j2 2026-09-11 19:41:01.134322186 +0000 @@ -16,35 +16,29 @@ include "trusted.conf"; options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation yes; -}; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; +{% if FEATURE_FIPS_DH == "1" %} + tls-port @TLSPORT@; + listen-on tls ephemeral { 10.53.0.9; }; +{% endif %} }; -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +{% include "_common/controls.conf.j2" %} + +tls tls-checkds { + remote-hostname "srv01.crt01.example.com"; // enable Strict TLS + ca-file "../CA/CA.pem"; }; remote-servers "ns8" port @PORT@ { 10.53.0.8; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} /* * 1. Enabling DNSSEC @@ -66,6 +60,16 @@ parental-agents { "ns8"; }; }; +{% if FEATURE_FIPS_DH == "1" %} +/* Same as above, but now with a TLS reference to parental-agents. */ +zone "tls-reference.explicit.dspublish.ns2" { + type primary; + file "tls-reference.explicit.dspublish.ns2.db"; + dnssec-policy "default"; + parental-agents { 10.53.0.8 tls tls-checkds; }; +}; +{% endif %} + /* Same as above, but now with resolver parental agent configured. */ zone "resolver.explicit.dspublish.ns2" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/checkds/ns9/setup.sh bind9-9.20.29/bin/tests/system/checkds/ns9/setup.sh --- bind9-9.20.26/bin/tests/system/checkds/ns9/setup.sh 2026-07-20 14:47:53.648842718 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/ns9/setup.sh 2026-09-11 19:41:01.134322186 +0000 @@ -61,6 +61,7 @@ for zn in \ good.${checkds}.dspublish.ns2 \ reference.${checkds}.dspublish.ns2 \ + tls-reference.${checkds}.dspublish.ns2 \ resolver.${checkds}.dspublish.ns2 \ not-yet.${checkds}.dspublish.ns5 \ bad.${checkds}.dspublish.ns6 \ diff -Nru bind9-9.20.26/bin/tests/system/checkds/tests_checkds.py bind9-9.20.29/bin/tests/system/checkds/tests_checkds.py --- bind9-9.20.26/bin/tests/system/checkds/tests_checkds.py 2026-07-20 14:47:53.648842718 +0000 +++ bind9-9.20.29/bin/tests/system/checkds/tests_checkds.py 2026-09-11 19:41:01.134322186 +0000 @@ -24,8 +24,11 @@ import pytest import isctest +import isctest.mark pytestmark = [ + isctest.mark.with_libnghttp2, + isctest.mark.with_fips_dh, pytest.mark.extra_artifacts( [ "*.out", @@ -194,6 +197,12 @@ logs_to_wait_for=("DS response from 10.53.0.8",), expected_parent_state="DSPublish", ), + # Using a TLS reference to parental-agents. + CheckDSTest( + zone="tls-reference.explicit.dspublish.ns2", + logs_to_wait_for=("DS response from 10.53.0.8",), + expected_parent_state="DSPublish", + ), # Using a resolver as parental-agent (ns3). CheckDSTest( zone="resolver.explicit.dspublish.ns2", diff -Nru bind9-9.20.26/bin/tests/system/checknames/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/checknames/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checknames/ns1/named.conf.j2 2026-07-20 14:47:53.649842743 +0000 +++ bind9-9.20.29/bin/tests/system/checknames/ns1/named.conf.j2 2026-09-11 19:41:01.135322210 +0000 @@ -12,19 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; check-integrity no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/checknames/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/checknames/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checknames/ns2/named.conf.j2 2026-07-20 14:47:53.649842743 +0000 +++ bind9-9.20.29/bin/tests/system/checknames/ns2/named.conf.j2 2026-09-11 19:41:01.135322210 +0000 @@ -12,19 +12,12 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; check-names response warn; - notify yes; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/checknames/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/checknames/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checknames/ns3/named.conf.j2 2026-07-20 14:47:53.649842743 +0000 +++ bind9-9.20.29/bin/tests/system/checknames/ns3/named.conf.j2 2026-09-11 19:41:01.135322210 +0000 @@ -12,19 +12,12 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; check-names response fail; - notify yes; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/checknames/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/checknames/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checknames/ns4/named.conf.j2 2026-07-20 14:47:53.650842768 +0000 +++ bind9-9.20.29/bin/tests/system/checknames/ns4/named.conf.j2 2026-09-11 19:41:01.136322234 +0000 @@ -12,21 +12,14 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; dnssec-validation no; check-names primary ignore; check-names secondary ignore; - notify yes; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/checknames/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/checknames/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/checknames/ns5/named.conf.j2 2026-07-20 14:47:53.650842768 +0000 +++ bind9-9.20.29/bin/tests/system/checknames/ns5/named.conf.j2 2026-09-11 19:41:01.136322234 +0000 @@ -12,21 +12,14 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; dnssec-validation no; check-names master ignore; check-names slave ignore; - notify yes; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/checkzone/tests.sh bind9-9.20.29/bin/tests/system/checkzone/tests.sh --- bind9-9.20.26/bin/tests/system/checkzone/tests.sh 2026-07-20 14:47:53.650842768 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/tests.sh 2026-09-11 19:41:01.136322234 +0000 @@ -41,15 +41,126 @@ echo_i "checking $db ($n)" ret=0 v=0 case $db in - zones/bad-dns-sd-reverse.db | zones/bad-svcb-servername.db) - $CHECKZONE -k fail -i local 0.0.0.0.in-addr.arpa $db >test.out.$n 2>&1 || v=$? + zones/bad-_dns-svcb*.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "SVCB record not valid:" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-caa-rr.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "dns_rdata_fromtext: zones/bad-caa-rr\.db:15: near .*: syntax error" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-cdnskey.db | zones/bad-cds.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "CDS/CDNSKEY consistency checks failed" test.out.$n >/dev/null || ret=1 ;; - bad-cname-and*.db) + zones/bad-cname-and*.db) $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? grep "CNAME and other data" test.out.$n >/dev/null || ret=1 ;; - *) + zones/bad-dhcid.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "zones/bad-dhcid\.db:12: near eol: unexpected end of input" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-dns-sd-reverse.db) + $CHECKZONE -k fail -i local 0.0.0.0.in-addr.arpa $db >test.out.$n 2>&1 || v=$? + grep "${db}:19: near '!@#3.': bad name (check-names)" test.out.$n >/dev/null || ret=1 + grep "${db}:20: near '!@#3.': bad name (check-names)" test.out.$n >/dev/null || ret=1 + grep "${db}:21: near '!@#3.': bad name (check-names)" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-ds.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "DS record at top of zone (example)" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-ds-2.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "DS not at delegation point" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-eid.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "zones/bad-eid.db:12: near eol: unexpected end of input" test.out.$n >/dev/null || ret=1 + grep "zones/bad-eid.db:13: near eol: unexpected end of input" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-eui48-*.db | zones/bad-eui64-*.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "bad EUI" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-generate-garbage.db | zones/bad-generate-missing-brace.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "\$GENERATE: ${db}:17: syntax error" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-generate-range.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "\$GENERATE: ${db}:18: out of range" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-generate-tkey.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "\$GENERATE: ${db}:17: meta RR type 'TKEY'" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-include-directory.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "dns_master_load: .:1: isc_lex_gettoken() failed: not a file" test.out.$n >/dev/null || ret=1 + grep "dns_master_load: ..:1: isc_lex_gettoken() failed: not a file" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-nsap-empty.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "near '0x': unexpected end of input" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-nsap-odd-nibble.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "near '0x47000580005a0000000001e133ffffff000161000': unexpected end of input" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-nsec3-length.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "zones/bad-nsec3-length.db:17: near 'IMQ912BREQP1POLAH3RMONG': out of range" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-nsec3-padded.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "zones/bad-nsec3-padded.db:19: near 'CPNMU===': bad base32 encoding" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-nsec3owner-padded.db) + $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "zones/bad-nsec3owner-padded.db:18: CPNMU===.example: bad owner name (check-names)" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-svcb-alpn[123456].db) + $CHECKZONE -i local db $db >test.out.$n 2>&1 || v=$? + grep "${db}:17: near 'alpn=.*': syntax error" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-svcb-mandatory.db) + $CHECKZONE -i local db $db >test.out.$n 2>&1 || v=$? + grep "zones/bad-svcb-mandatory.db:17: near eol: disallowed (by application policy)" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-svcb-servername.db) + $CHECKZONE -k fail -i local 0.0.0.0.in-addr.arpa $db >test.out.$n 2>&1 || v=$? + grep "${db}:17: near '_underscore.example.': bad name (check-names)" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-svcb.db) + $CHECKZONE -i local db $db >test.out.$n 2>&1 || v=$? + grep "zones/bad-svcb.db:17: near 'unknown=wha': syntax error" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-tkey.db | zones/bad-tsig.db) + $CHECKZONE -i local db $db >test.out.$n 2>&1 || v=$? + grep "type '[A-Z]*': invalid use of a meta type" test.out.$n >/dev/null || ret=1 + ;; + zones/bad-unspec.db) + $CHECKZONE -i local db $db >test.out.$n 2>&1 || v=$? + grep "zones/bad-unspec.db:16: near '^#': unknown class/type" test.out.$n >/dev/null || ret=1 + ;; + zones/bad1.db) + $CHECKZONE -i local db $db >test.out.$n 2>&1 || v=$? + grep "zones/bad1.db:15: extra input text" test.out.$n >/dev/null || ret=1 + ;; + zones/bad[234].db) + $CHECKZONE -i local db $db >test.out.$n 2>&1 || v=$? + grep "\$GENERATE: ${db}:19: invalid range" test.out.$n >/dev/null || ret=1 + ;; + zones/badttl.db) $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$? + grep "zones/badttl.db:12: unexpected end of line" test.out.$n >/dev/null || ret=1 + ;; + *) + ret=1 + echo "add case entry for $db" + $CHECKZONE -i local example $db || v=$? ;; esac test $v = 1 || ret=1 diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-afsdb.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-afsdb.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-afsdb.db 2026-07-20 14:47:53.652842818 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-afsdb.db 2026-09-11 19:41:01.138322283 +0000 @@ -13,5 +13,5 @@ @ SOA ns hostmaster 2011012708 3600 1200 604800 1200 NS ns ns A 192.0.2.1 -bad BAD 65535 . +bad AFSDB 65535 . bad CNAME @ diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-brid.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-brid.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-brid.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-brid.db 2026-09-11 19:41:01.138322283 +0000 @@ -0,0 +1,17 @@ +; 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. + +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad BRID abcd +bad CNAME @ diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-dsync.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-dsync.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-dsync.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-dsync.db 2026-09-11 19:41:01.139322307 +0000 @@ -0,0 +1,6 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad DSYNC CDS NOTIFY 1000 scanner1 +bad CNAME @ diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-hhit.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-hhit.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-hhit.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-hhit.db 2026-09-11 19:41:01.139322307 +0000 @@ -0,0 +1,6 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad HHIT abcd +bad CNAME @ diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-opengpgkey.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-opengpgkey.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-opengpgkey.db 2026-07-20 14:47:53.655842893 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-opengpgkey.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -; 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. - -$TTL 600 -@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 - NS ns -ns A 192.0.2.1 -bad OPENGPGKEY ( AQMFD5raczCJHViKtLYhWGz8hMY - 9UGRuniJDBzC7w0aRyzWZriO6i2odGWWQVucZqKV - sENW91IOW4vqudngPZsY3GvQ/xVA8/7pyFj6b7Esg - a60zyGW6LFe9r8n6paHrlG5ojqf0BaqHT+8= ) -bad CNAME @ diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-openpgpkey.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-openpgpkey.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-openpgpkey.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-openpgpkey.db 2026-09-11 19:41:01.141322355 +0000 @@ -0,0 +1,20 @@ +; 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. + +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad OPENPGPKEY ( AQMFD5raczCJHViKtLYhWGz8hMY + 9UGRuniJDBzC7w0aRyzWZriO6i2odGWWQVucZqKV + sENW91IOW4vqudngPZsY3GvQ/xVA8/7pyFj6b7Esg + a60zyGW6LFe9r8n6paHrlG5ojqf0BaqHT+8= ) +bad CNAME @ diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-smimea.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-smimea.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-smimea.db 2026-07-20 14:47:53.655842893 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-smimea.db 2026-09-11 19:41:01.142322379 +0000 @@ -13,7 +13,7 @@ @ SOA ns hostmaster 2011012708 3600 1200 604800 1200 NS ns ns A 192.0.2.1 -bad SMIMES ( 1 1 2 92003ba34942dc74152e2f2c408d29ec +bad SMIMEA ( 1 1 2 92003ba34942dc74152e2f2c408d29ec a5a520e7f2e06bb944f4dca346baf63c 1b177615d466f6c4b71c216a50292bd5 8c9ebdd2f74e38fe51ffd48c43326cbc ) diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-type66.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-type66.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-type66.db 2026-07-20 14:47:53.656842918 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-type66.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -; 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. - -$TTL 600 -@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 - NS ns -ns A 192.0.2.1 -bad TYPE66 \# 1 00 -bad CNAME @ diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-type69.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-type69.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-cname-and-type69.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-cname-and-type69.db 2026-09-11 19:41:01.142322379 +0000 @@ -0,0 +1,6 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad TYPE69 \# 1 00 +bad CNAME @ diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui48-no-leading-zero.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-no-leading-zero.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui48-no-leading-zero.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-no-leading-zero.db 2026-09-11 19:41:01.143322403 +0000 @@ -0,0 +1,5 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad EUI48 1-23-45-67-89-ab diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui48-three-digits.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-three-digits.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui48-three-digits.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-three-digits.db 2026-09-11 19:41:01.143322403 +0000 @@ -0,0 +1,5 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad EUI48 01-23-45-567-89-ab diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui48-too-short.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-too-short.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui48-too-short.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-too-short.db 2026-09-11 19:41:01.143322403 +0000 @@ -0,0 +1,5 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad EUI48 01-23-45-67-89 diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui48-trailing-garbage.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-trailing-garbage.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui48-trailing-garbage.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui48-trailing-garbage.db 2026-09-11 19:41:01.144322428 +0000 @@ -0,0 +1,5 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad EUI48 01-23-45-67-89-abgarbage diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui64-no-leading-zero.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-no-leading-zero.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui64-no-leading-zero.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-no-leading-zero.db 2026-09-11 19:41:01.144322428 +0000 @@ -0,0 +1,5 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad EUI64 1-23-45-67-89-ab-cd-ef diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui64-three-digits.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-three-digits.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui64-three-digits.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-three-digits.db 2026-09-11 19:41:01.144322428 +0000 @@ -0,0 +1,5 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad EUI64 01-23-45-567-89-ab-cd-ef diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui64-too-short.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-too-short.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui64-too-short.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-too-short.db 2026-09-11 19:41:01.144322428 +0000 @@ -0,0 +1,5 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad EUI64 01-23-45-67-89-ab-cd diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui64-trailing-garbage.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-trailing-garbage.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-eui64-trailing-garbage.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-eui64-trailing-garbage.db 2026-09-11 19:41:01.144322428 +0000 @@ -0,0 +1,5 @@ +$TTL 600 +@ SOA ns hostmaster 2011012708 3600 1200 604800 1200 + NS ns +ns A 192.0.2.1 +bad EUI64 01-23-45-67-89-ab-cd-efgarbage diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-nimloc.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nimloc.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-nimloc.db 2026-07-20 14:47:53.657842943 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nimloc.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -; 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. \ No newline at end of file diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-nsap-empty.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsap-empty.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-nsap-empty.db 2026-07-20 14:47:53.657842943 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsap-empty.db 2026-09-11 19:41:01.144322428 +0000 @@ -14,5 +14,5 @@ NS ns ns A 192.0.2.1 -; NSAP with an odd number of hex digits -example NSAP 0x47000580005a0000000001e133ffffff000161000 +; empty NSAP address +example NSAP 0x diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-nsap-odd-nibble.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsap-odd-nibble.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-nsap-odd-nibble.db 2026-07-20 14:47:53.657842943 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsap-odd-nibble.db 2026-09-11 19:41:01.144322428 +0000 @@ -14,5 +14,5 @@ NS ns ns A 192.0.2.1 -; empty NSAP address -example NSAP 0x +; NSAP with an odd number of hex digits +example NSAP 0x47000580005a0000000001e133ffffff000161000 diff -Nru bind9-9.20.26/bin/tests/system/checkzone/zones/bad-nsec3-length.db bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsec3-length.db --- bind9-9.20.26/bin/tests/system/checkzone/zones/bad-nsec3-length.db 2026-07-20 14:47:53.658842968 +0000 +++ bind9-9.20.29/bin/tests/system/checkzone/zones/bad-nsec3-length.db 2026-09-11 19:41:01.144322428 +0000 @@ -14,4 +14,4 @@ NS ns ns A 192.0.2.1 -I7A7A184GGMI35K1E3IR650LKO7NOB5R.dyn.example.net. 7200 IN NSEC3 1 0 10 76931F IMQ912BREQP1POLAH3RMONG;UED541AS A RRSIG +I7A7A184GGMI35K1E3IR650LKO7NOB5R 7200 IN NSEC3 1 0 10 76931F IMQ912BREQP1POLAH3RMONG;UED541AS A RRSIG diff -Nru bind9-9.20.26/bin/tests/system/cipher_suites/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/cipher_suites/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cipher_suites/ns1/named.conf.j2 2026-07-20 14:47:53.662843068 +0000 +++ bind9-9.20.29/bin/tests/system/cipher_suites/ns1/named.conf.j2 2026-09-11 19:41:01.149322548 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls tls-perfect-forward-secrecy { protocols { TLSv1.3; }; @@ -50,15 +46,12 @@ }; options { - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on-v6 { none; }; - listen-on { 10.53.0.1; }; - listen-on tls tls-perfect-forward-secrecy { 10.53.0.1; }; - listen-on port @EXTRAPORT1@ tls tls-pfs-aes128 { 10.53.0.1; }; - listen-on port @EXTRAPORT2@ tls tls-pfs-aes256 { 10.53.0.1; }; - listen-on port @EXTRAPORT3@ tls tls-pfs-chacha20 { 10.53.0.1; }; + listen-on tls tls-perfect-forward-secrecy { @ns.ip@; }; + listen-on port @EXTRAPORT1@ tls tls-pfs-aes128 { @ns.ip@; }; + listen-on port @EXTRAPORT2@ tls tls-pfs-aes256 { @ns.ip@; }; + listen-on port @EXTRAPORT3@ tls tls-pfs-chacha20 { @ns.ip@; }; recursion no; notify explicit; also-notify { 10.53.0.2 port @PORT@; }; @@ -69,7 +62,6 @@ transfers-out 100; }; - zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/cipher_suites/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/cipher_suites/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cipher_suites/ns2/named.conf.j2 2026-07-20 14:47:53.662843068 +0000 +++ bind9-9.20.29/bin/tests/system/cipher_suites/ns2/named.conf.j2 2026-09-11 19:41:01.149322548 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls local { key-file "../self-signed-key.pem"; @@ -23,15 +19,9 @@ }; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on tls local { 10.53.0.2; }; // DoT - listen-on-v6 { none; }; + listen-on tls local { @ns.ip@; }; // DoT recursion no; notify no; ixfr-from-differences yes; @@ -39,11 +29,7 @@ dnssec-validation no; }; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} tls tls-v1.3 { protocols { TLSv1.3; }; diff -Nru bind9-9.20.26/bin/tests/system/cipher_suites/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/cipher_suites/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cipher_suites/ns3/named.conf.j2 2026-07-20 14:47:53.663843093 +0000 +++ bind9-9.20.29/bin/tests/system/cipher_suites/ns3/named.conf.j2 2026-09-11 19:41:01.149322548 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls local { key-file "../self-signed-key.pem"; @@ -23,15 +19,9 @@ }; options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on tls local { 10.53.0.3; }; // DoT - listen-on-v6 { none; }; + listen-on tls local { @ns.ip@; }; // DoT recursion no; notify no; ixfr-from-differences yes; @@ -39,11 +29,7 @@ dnssec-validation no; }; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} tls tls-v1.3 { protocols { TLSv1.3; }; diff -Nru bind9-9.20.26/bin/tests/system/cipher_suites/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/cipher_suites/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cipher_suites/ns4/named.conf.j2 2026-07-20 14:47:53.663843093 +0000 +++ bind9-9.20.29/bin/tests/system/cipher_suites/ns4/named.conf.j2 2026-09-11 19:41:01.149322548 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls local { key-file "../self-signed-key.pem"; @@ -23,15 +19,9 @@ }; options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on tls local { 10.53.0.4; }; // DoT - listen-on-v6 { none; }; + listen-on tls local { @ns.ip@; }; // DoT recursion no; notify no; ixfr-from-differences yes; @@ -39,11 +29,7 @@ dnssec-validation no; }; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} tls tls-v1.3 { protocols { TLSv1.3; }; diff -Nru bind9-9.20.26/bin/tests/system/cipher_suites/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/cipher_suites/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cipher_suites/ns5/named.conf.j2 2026-07-20 14:47:53.663843093 +0000 +++ bind9-9.20.29/bin/tests/system/cipher_suites/ns5/named.conf.j2 2026-09-11 19:41:01.149322548 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls local { key-file "../self-signed-key.pem"; @@ -23,15 +19,9 @@ }; options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on tls local { 10.53.0.5; }; // DoT - listen-on-v6 { none; }; + listen-on tls local { @ns.ip@; }; // DoT recursion no; notify no; ixfr-from-differences yes; @@ -39,11 +29,7 @@ dnssec-validation no; }; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} tls tls-v1.2 { protocols { TLSv1.2; }; diff -Nru bind9-9.20.26/bin/tests/system/cipher_suites/prereq.sh bind9-9.20.29/bin/tests/system/cipher_suites/prereq.sh --- bind9-9.20.26/bin/tests/system/cipher_suites/prereq.sh 2026-07-20 14:47:53.663843093 +0000 +++ bind9-9.20.29/bin/tests/system/cipher_suites/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -$FEATURETEST --have-openssl-cipher-suites || { - echo_i "SSL_CTX_set_ciphersuites() is required for the test." - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/cipher_suites/tests_cipher_suites.py bind9-9.20.29/bin/tests/system/cipher_suites/tests_cipher_suites.py --- bind9-9.20.26/bin/tests/system/cipher_suites/tests_cipher_suites.py 2026-07-20 14:47:53.663843093 +0000 +++ bind9-9.20.29/bin/tests/system/cipher_suites/tests_cipher_suites.py 2026-09-11 19:41:01.150322572 +0000 @@ -15,12 +15,17 @@ import isctest import isctest.mark -pytestmark = pytest.mark.extra_artifacts( +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "ns*/example*.db", ] ) +pytestmark = [ + isctest.mark.with_openssl_cipher_suites, + EXTRA_ARTIFACTS, +] + @pytest.fixture(scope="module") def transfers_complete(servers): diff -Nru bind9-9.20.26/bin/tests/system/class/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/class/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/class/ns1/named.conf.j2 2026-07-20 14:47:53.663843093 +0000 +++ bind9-9.20.29/bin/tests/system/class/ns1/named.conf.j2 2026-09-11 19:41:01.150322572 +0000 @@ -1,21 +1,8 @@ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view chaos ch { match-clients { any; }; diff -Nru bind9-9.20.26/bin/tests/system/class/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/class/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/class/ns2/named.conf.j2 2026-07-20 14:47:53.664843118 +0000 +++ bind9-9.20.29/bin/tests/system/class/ns2/named.conf.j2 2026-09-11 19:41:01.150322572 +0000 @@ -1,27 +1,13 @@ options { - directory "."; - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view default { match-clients { any; }; recursion no; - dnssec-validation no; + dnssec-validation no; zone "1.0.0.127.in-addr.arpa." { type primary; file "localhost.db"; diff -Nru bind9-9.20.26/bin/tests/system/class/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/class/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/class/ns3/named.conf.j2 2026-07-20 14:47:53.664843118 +0000 +++ bind9-9.20.29/bin/tests/system/class/ns3/named.conf.j2 2026-09-11 19:41:01.150322572 +0000 @@ -1,28 +1,14 @@ options { - directory "."; - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view chaos ch { match-clients { any; }; recursion yes; - dnssec-validation no; - forward only; - forwarders port @PORT@ { 10.53.0.2; }; - deny-answer-addresses { 0.0.0.0/0; ::/0; }; + dnssec-validation no; + forward only; + forwarders port @PORT@ { 10.53.0.2; }; + deny-answer-addresses { 0.0.0.0/0; ::/0; }; }; diff -Nru bind9-9.20.26/bin/tests/system/cname_dname_negcache/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/cname_dname_negcache/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cname_dname_negcache/ns1/named.conf.j2 2026-07-20 14:47:53.664843118 +0000 +++ bind9-9.20.29/bin/tests/system/cname_dname_negcache/ns1/named.conf.j2 2026-09-11 19:41:01.151322597 +0000 @@ -1,13 +1,11 @@ options { - query-source address @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; - recursion no; - dnssec-validation no; + {% include_indented "_common/options.conf.j2" %} + recursion no; + dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/cname_dname_negcache/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/cname_dname_negcache/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cname_dname_negcache/ns3/named.conf.j2 2026-07-20 14:47:53.665843143 +0000 +++ bind9-9.20.29/bin/tests/system/cname_dname_negcache/ns3/named.conf.j2 2026-09-11 19:41:01.151322597 +0000 @@ -1,11 +1,8 @@ options { - query-source address @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; - recursion yes; - dnssec-validation no; + {% include_indented "_common/options.conf.j2" %} + dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + {% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/ns1/catalog.db bind9-9.20.29/bin/tests/system/cname_recursion/ns1/catalog.db --- bind9-9.20.26/bin/tests/system/cname_recursion/ns1/catalog.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/ns1/catalog.db 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,16 @@ +; 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. + +$TTL 300 +@ IN SOA . . 1 86400 3600 86400 3600 +@ IN NS invalid. +version IN TXT "2" +mbr1.zones IN PTR member. diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/ns1/external.db bind9-9.20.29/bin/tests/system/cname_recursion/ns1/external.db --- bind9-9.20.26/bin/tests/system/cname_recursion/ns1/external.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/ns1/external.db 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,18 @@ +; 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. + +$TTL 300 +external. IN SOA ns1.external. hostmaster.external. 1 600 600 1200 600 +external. NS ns1.external. +ns1.external. A 10.53.0.1 +target.external. A 10.0.0.99 +target2.external. A 10.0.0.98 +target3.external. A 10.0.0.97 diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/ns1/member.db bind9-9.20.29/bin/tests/system/cname_recursion/ns1/member.db --- bind9-9.20.26/bin/tests/system/cname_recursion/ns1/member.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/ns1/member.db 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,16 @@ +; 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. + +$TTL 300 +member. IN SOA ns1.member. hostmaster.member. 1 600 600 1200 600 +member. NS ns1.member. +ns1.member. A 10.53.0.1 +alias.member. CNAME target3.external. diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/cname_recursion/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cname_recursion/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/ns1/named.conf.j2 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// NS1: root server, authoritative for the CNAME target zone, and +// primary for the catalog zone and its member zone + +options { + {% include_indented "_common/options.conf.j2" %} + recursion no; + dnssec-validation no; + allow-transfer { any; }; +}; + +{% include "_common/controls.conf.j2" %} + +zone "." { + type primary; + file "root.db"; +}; + +zone "external" { + type primary; + file "external.db"; +}; + +zone "catalog" { + type primary; + file "catalog.db"; +}; + +zone "member" { + type primary; + file "member.db"; +}; diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/ns1/root.db bind9-9.20.29/bin/tests/system/cname_recursion/ns1/root.db --- bind9-9.20.26/bin/tests/system/cname_recursion/ns1/root.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/ns1/root.db 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,18 @@ +; 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. + +$TTL 300 +. IN SOA a.root-servers.nil. hostmaster.nil. 1 600 600 1200 600 +. NS a.root-servers.nil. +a.root-servers.nil. A 10.53.0.1 + +external. NS ns1.external. +ns1.external. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/ns2/added.db bind9-9.20.29/bin/tests/system/cname_recursion/ns2/added.db --- bind9-9.20.26/bin/tests/system/cname_recursion/ns2/added.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/ns2/added.db 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,16 @@ +; 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. + +$TTL 300 +added. IN SOA ns2.added. hostmaster.added. 1 600 600 1200 600 +added. NS ns2.added. +ns2.added. A 10.53.0.2 +alias.added. CNAME target2.external. diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/ns2/internal.db bind9-9.20.29/bin/tests/system/cname_recursion/ns2/internal.db --- bind9-9.20.26/bin/tests/system/cname_recursion/ns2/internal.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/ns2/internal.db 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,16 @@ +; 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. + +$TTL 300 +internal. IN SOA ns2.internal. hostmaster.internal. 1 600 600 1200 600 +internal. NS ns2.internal. +ns2.internal. A 10.53.0.2 +alias.internal. CNAME target.external. diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/cname_recursion/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cname_recursion/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/ns2/named.conf.j2 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,45 @@ +/* + * 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. + */ + +// NS2: recursive resolver, also authoritative for zones with a CNAME +// pointing to a name outside of the zone: one static, one added at +// runtime with "rndc addzone", one added at runtime as a catalog zone +// member + +options { + {% include_indented "_common/options.conf.j2" %} + dnssec-validation no; + allow-query { any; }; + allow-new-zones yes; + catalog-zones { + zone "catalog" + default-primaries { 10.53.0.1; } + min-update-interval 1s + in-memory yes; + }; +}; + +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} + +zone "internal" { + type primary; + file "internal.db"; +}; + +zone "catalog" { + type secondary; + file "catalog.db"; + primaries { 10.53.0.1; }; +}; diff -Nru bind9-9.20.26/bin/tests/system/cname_recursion/tests_cname_recursion.py bind9-9.20.29/bin/tests/system/cname_recursion/tests_cname_recursion.py --- bind9-9.20.26/bin/tests/system/cname_recursion/tests_cname_recursion.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/cname_recursion/tests_cname_recursion.py 2026-09-11 19:41:01.152322621 +0000 @@ -0,0 +1,87 @@ +# 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. + +""" +An RD=1 query to a server which is authoritative for the queried zone, +where the answer is a CNAME pointing to a name outside of that zone, must +recurse to resolve the CNAME target and return the complete chain. + +Regression test: when a zone shares the view's "allow-query" ACL object +(zones added at runtime via "rndc addzone" or as catalog zone members do; +zones configured in named.conf get their own copy), evaluating the ACL +during the zone lookup used to clear all other client query attributes +(NS_QUERYATTR_RECURSIONOK and NS_QUERYATTR_CACHEOK among them), so the +restarted query for the CNAME target could not recurse and the response +contained only the CNAME record without the target's address record. +""" + +import dns.name +import dns.rdataclass +import dns.rdatatype +import pytest + +import isctest + +pytestmark = pytest.mark.extra_artifacts( + [ + "ns2/_default.nz*", + "ns2/catalog.db*", + ] +) + + +def assert_full_chain(res, alias, target, address): + isctest.check.noerror(res) + + cname = res.get_rrset( + res.answer, + dns.name.from_text(alias), + dns.rdataclass.IN, + dns.rdatatype.CNAME, + ) + assert cname is not None, "CNAME missing from the answer section" + + answer = res.get_rrset( + res.answer, + dns.name.from_text(target), + dns.rdataclass.IN, + dns.rdatatype.A, + ) + assert answer is not None, "CNAME target not resolved (partial response)" + assert str(answer[0]) == address + + +@pytest.mark.requires_zones_loaded("ns1", "ns2") +def test_cname_recursion_static_zone(ns2): + msg = isctest.query.create("alias.internal.", "A") + res = isctest.query.udp(msg, ns2.ip) + assert_full_chain(res, "alias.internal.", "target.external.", "10.0.0.99") + + +@pytest.mark.requires_zones_loaded("ns1", "ns2") +def test_cname_recursion_added_zone(ns2): + with ns2.watch_log_from_here() as watcher: + ns2.rndc('addzone added { type primary; file "added.db"; };') + watcher.wait_for_line("zone added/IN: loaded serial 1") + + msg = isctest.query.create("alias.added.", "A") + res = isctest.query.udp(msg, ns2.ip) + assert_full_chain(res, "alias.added.", "target2.external.", "10.0.0.98") + + +@pytest.mark.requires_zones_loaded("ns1", "ns2") +def test_cname_recursion_catz_member_zone(ns2): + with ns2.watch_log_from_start() as watcher: + watcher.wait_for_line("zone member/IN: transferred serial 1") + + msg = isctest.query.create("alias.member.", "A") + res = isctest.query.udp(msg, ns2.ip) + assert_full_chain(res, "alias.member.", "target3.external.", "10.0.0.97") diff -Nru bind9-9.20.26/bin/tests/system/conf.sh bind9-9.20.29/bin/tests/system/conf.sh --- bind9-9.20.26/bin/tests/system/conf.sh 2026-07-20 14:47:53.665843143 +0000 +++ bind9-9.20.29/bin/tests/system/conf.sh 2026-09-11 19:41:01.153322645 +0000 @@ -95,10 +95,6 @@ $PERL "$TOP_SRCDIR/bin/tests/system/stop.pl" "$SYSTESTDIR" "$@" } -send() { - $PERL "$TOP_SRCDIR/bin/tests/system/send.pl" "$@" -} - # # Useful functions in test scripts # diff -Nru bind9-9.20.26/bin/tests/system/conftest.py bind9-9.20.29/bin/tests/system/conftest.py --- bind9-9.20.26/bin/tests/system/conftest.py 2026-07-20 14:47:53.665843143 +0000 +++ bind9-9.20.29/bin/tests/system/conftest.py 2026-09-11 19:41:01.153322645 +0000 @@ -296,6 +296,31 @@ watcher.wait_for_line("all zones loaded") +@pytest.fixture(autouse=True) +def named_log_test_markers(request, servers): + """Send `rndc null` message with a test ID to each named instance.""" + + def mark(event): + for server in servers.values(): + if not isinstance(server, isctest.instance.NamedInstance): + continue + try: + with server.rndc_client(timeout=2) as c: + c.call(f"null ------ {event} {request.node.nodeid} ------") + except ( + OSError, + isctest.rndc.RNDCException, + isctest.rndc.RNDCProtocolError, + ): + # best-effort: the instance may be stopped or use a + # non-standard control channel + pass + + mark("BEGIN") + yield + mark("END") + + @pytest.fixture(scope="module", autouse=True) def configure_algorithm_set(request): """Configure the algorithm set to use in tests.""" @@ -546,14 +571,6 @@ isctest.log.error("testsock.pl: exited with code %d", exc.returncode) pytest.skip("Network interface aliases not set up.") - def check_prerequisites(): - try: - isctest.run.shell(f"{system_test_dir}/prereq.sh") - except FileNotFoundError: - pass # prereq.sh is optional - except subprocess.CalledProcessError: - pytest.skip("Prerequisites missing.") - def setup_test(): template_data = None bootstrap_fn = getattr(request.module, "bootstrap", None) @@ -613,7 +630,6 @@ # Perform checks which may skip this test. check_net_interfaces() - check_prerequisites() # Store the fact that this fixture hasn't successfully finished yet. # This is checked before temporary directory teardown to decide whether diff -Nru bind9-9.20.26/bin/tests/system/cookie/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/cookie/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cookie/ns1/named.conf.j2 2026-07-20 14:47:53.666843168 +0000 +++ bind9-9.20.29/bin/tests/system/cookie/ns1/named.conf.j2 2026-09-11 19:41:01.154322669 +0000 @@ -11,11 +11,6 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - key foo { secret "aaaaaaaaaaaa"; algorithm @DEFAULT_HMAC@; @@ -25,31 +20,23 @@ keys foo; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; } - except-from { "example.org"; }; + except-from { "example.org"; }; deny-answer-aliases { "example.org"; } - except-from { "goodcname.example.net"; - "gooddname.example.net"; }; + except-from { + "goodcname.example.net"; + "gooddname.example.net"; + }; allow-query {!10.53.0.8; any; }; send-cookie yes; nocookie-udp-size 512; }; - zone "." { type hint; file "root.hint"; diff -Nru bind9-9.20.26/bin/tests/system/cookie/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/cookie/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cookie/ns2/named.conf.j2 2026-07-20 14:47:53.666843168 +0000 +++ bind9-9.20.29/bin/tests/system/cookie/ns2/named.conf.j2 2026-09-11 19:41:01.154322669 +0000 @@ -12,19 +12,15 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; send-cookie yes; nocookie-udp-size 512; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/cookie/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/cookie/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cookie/ns3/named.conf.j2 2026-07-20 14:47:53.667843193 +0000 +++ bind9-9.20.29/bin/tests/system/cookie/ns3/named.conf.j2 2026-09-11 19:41:01.154322669 +0000 @@ -11,37 +11,24 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; } - except-from { "example.org"; }; + except-from { "example.org"; }; deny-answer-aliases { "example.org"; } - except-from { "goodcname.example.net"; - "gooddname.example.net"; }; + except-from { + "goodcname.example.net"; + "gooddname.example.net"; + }; allow-query {!10.53.0.8; any; }; send-cookie yes; nocookie-udp-size 512; require-server-cookie yes; }; - zone "." { type hint; file "root.hint"; diff -Nru bind9-9.20.26/bin/tests/system/cookie/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/cookie/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cookie/ns4/named.conf.j2 2026-07-20 14:47:53.667843193 +0000 +++ bind9-9.20.29/bin/tests/system/cookie/ns4/named.conf.j2 2026-09-11 19:41:01.154322669 +0000 @@ -11,31 +11,16 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; cookie-algorithm siphash24; cookie-secret "569d36a6cc27d6bf55502183302ba352"; require-server-cookie yes; }; - zone "." { type hint; file "root.hint"; diff -Nru bind9-9.20.26/bin/tests/system/cookie/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/cookie/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cookie/ns5/named.conf.j2 2026-07-20 14:47:53.667843193 +0000 +++ bind9-9.20.29/bin/tests/system/cookie/ns5/named.conf.j2 2026-09-11 19:41:01.155322693 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; cookie-algorithm siphash24; cookie-secret "569d36a6cc27d6bf55502183302ba352"; @@ -36,7 +22,6 @@ require-server-cookie yes; }; - zone "." { type hint; file "root.hint"; diff -Nru bind9-9.20.26/bin/tests/system/cookie/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/cookie/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cookie/ns6/named.conf.j2 2026-07-20 14:47:53.667843193 +0000 +++ bind9-9.20.29/bin/tests/system/cookie/ns6/named.conf.j2 2026-09-11 19:41:01.155322693 +0000 @@ -11,31 +11,16 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; cookie-algorithm siphash24; cookie-secret "6b300e27a0db46d4b046e4189790fa7d"; require-server-cookie yes; }; - zone "." { type hint; file "root.hint"; diff -Nru bind9-9.20.26/bin/tests/system/cookie/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/cookie/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cookie/ns7/named.conf.j2 2026-07-20 14:47:53.667843193 +0000 +++ bind9-9.20.29/bin/tests/system/cookie/ns7/named.conf.j2 2026-09-11 19:41:01.155322693 +0000 @@ -12,13 +12,7 @@ */ options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; answer-cookie no; send-cookie yes; @@ -26,6 +20,8 @@ dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/cookie/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/cookie/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cookie/ns8/named.conf.j2 2026-07-20 14:47:53.668843218 +0000 +++ bind9-9.20.29/bin/tests/system/cookie/ns8/named.conf.j2 2026-09-11 19:41:01.155322693 +0000 @@ -11,29 +11,15 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; rate-limit {}; require-server-cookie yes; }; - server 10.53.0.7 { require-cookie yes; }; zone "example" { diff -Nru bind9-9.20.26/bin/tests/system/cpu/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/cpu/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/cpu/ns1/named.conf.j2 2026-07-20 14:47:53.668843218 +0000 +++ bind9-9.20.29/bin/tests/system/cpu/ns1/named.conf.j2 2026-09-11 19:41:01.156322717 +0000 @@ -12,9 +12,7 @@ */ options { - query-source address 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} }; + +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/cpu/prereq.sh bind9-9.20.29/bin/tests/system/cpu/prereq.sh --- bind9-9.20.26/bin/tests/system/cpu/prereq.sh 2026-07-20 14:47:53.668843218 +0000 +++ bind9-9.20.29/bin/tests/system/cpu/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -command -v cpuset >/dev/null || command -v numactl >/dev/null || command -v taskset >/dev/null || { - echo_i "This test requires cpuset, numactl, or taskset." >&2 - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/cpu/tests_sh_cpu.py bind9-9.20.29/bin/tests/system/cpu/tests_sh_cpu.py --- bind9-9.20.26/bin/tests/system/cpu/tests_sh_cpu.py 2026-07-20 14:47:53.668843218 +0000 +++ bind9-9.20.29/bin/tests/system/cpu/tests_sh_cpu.py 2026-09-11 19:41:01.156322717 +0000 @@ -11,13 +11,20 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "named.run.*", "ns1/managed-keys.*", ] ) +pytestmark = [ + isctest.mark.with_cpu_affinity, + EXTRA_ARTIFACTS, +] + def test_cpu(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/database/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/database/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/database/ns1/named.conf.j2 2026-07-20 14:47:53.669843243 +0000 +++ bind9-9.20.29/bin/tests/system/database/ns1/named.conf.j2 2026-09-11 19:41:01.156322717 +0000 @@ -13,25 +13,11 @@ // NS1 -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/dialup/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dialup/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dialup/ns1/named.conf.j2 2026-07-20 14:47:53.669843243 +0000 +++ bind9-9.20.29/bin/tests/system/dialup/ns1/named.conf.j2 2026-09-11 19:41:01.156322717 +0000 @@ -11,16 +11,10 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; heartbeat-interval 1; recursion no; diff -Nru bind9-9.20.26/bin/tests/system/dialup/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dialup/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dialup/ns2/named.conf.j2 2026-07-20 14:47:53.669843243 +0000 +++ bind9-9.20.29/bin/tests/system/dialup/ns2/named.conf.j2 2026-09-11 19:41:01.157322742 +0000 @@ -11,16 +11,10 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; heartbeat-interval 1; recursion no; diff -Nru bind9-9.20.26/bin/tests/system/dialup/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/dialup/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dialup/ns3/named.conf.j2 2026-07-20 14:47:53.669843243 +0000 +++ bind9-9.20.29/bin/tests/system/dialup/ns3/named.conf.j2 2026-09-11 19:41:01.157322742 +0000 @@ -11,16 +11,10 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} heartbeat-interval 1; recursion no; dnssec-validation no; diff -Nru bind9-9.20.26/bin/tests/system/digdelv/common.py bind9-9.20.29/bin/tests/system/digdelv/common.py --- bind9-9.20.26/bin/tests/system/digdelv/common.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/common.py 2026-09-11 19:41:01.158322766 +0000 @@ -0,0 +1,56 @@ +# 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. + +""" +Helpers shared by the digdelv test modules. +""" + +import yaml + +ARTIFACTS = [ + "ans*/ans.run", + "ns*/anchor.*", + "ns*/dsset-*", + "ns*/keydata", + "ns*/keyid", + "ns*/K*.key", + "ns*/K*.private", + "ns1/root.db", + "ns2/example.db", + "ns2/example.tld.db", +] + + +def parse_yaml(text): + """Parse the tools' +yaml output.""" + return yaml.safe_load(text) + + +def check_ttl_range(text, rrtype, max_ttl): + """Check that a record of the given RR type and class IN (or its + unknown-format spelling CLASS1) is present with a TTL not exceeding + max_ttl. A leading ";" token is ignored so that delv's commented + records ("; name ttl class type ...") are checked too.""" + for line in text.splitlines(): + fields = line.split() + if fields and fields[0] == ";": + fields = fields[1:] + if len(fields) < 4: + continue + if fields[2] not in ("IN", "CLASS1") or fields[3] != rrtype: + continue + try: + ttl = int(fields[1]) + except ValueError: + continue + if ttl <= max_ttl: + return True + return False diff -Nru bind9-9.20.26/bin/tests/system/digdelv/conftest.py bind9-9.20.29/bin/tests/system/digdelv/conftest.py --- bind9-9.20.26/bin/tests/system/digdelv/conftest.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/conftest.py 2026-09-11 19:41:01.158322766 +0000 @@ -0,0 +1,41 @@ +# 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. + +""" +Fixtures shared by the digdelv test modules. +""" + +from dataclasses import dataclass + +import os + +import pytest + + +@dataclass +class Zsk: + keyid: str + keydata: str + rrcomment: str + + +@pytest.fixture(name="zsk") +def zsk_fixture(): + """Key id and rdata of the ZSK generated for the example zone.""" + with open("ns2/keyid", encoding="utf-8") as keyid_file: + keyid = keyid_file.read().strip() + with open("ns2/keydata", encoding="utf-8") as keydata_file: + keydata = keydata_file.read().strip() + return Zsk( + keyid=keyid, + keydata=keydata, + rrcomment=f"; ZSK; alg = {os.environ['DEFAULT_ALGORITHM']} ; key id = {keyid}", + ) diff -Nru bind9-9.20.26/bin/tests/system/digdelv/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/digdelv/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/digdelv/ns1/named.conf.j2 2026-07-20 14:47:53.670843268 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/ns1/named.conf.j2 2026-09-11 19:41:01.158322766 +0000 @@ -14,16 +14,13 @@ // NS1 options { - query-source address 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { fd92:7065:b8e:ffff::1; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/digdelv/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/digdelv/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/digdelv/ns2/named.conf.j2 2026-07-20 14:47:53.671843293 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/ns2/named.conf.j2 2026-09-11 19:41:01.158322766 +0000 @@ -14,19 +14,14 @@ // NS2 options { - query-source address 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/digdelv/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/digdelv/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/digdelv/ns3/named.conf.j2 2026-07-20 14:47:53.671843293 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/ns3/named.conf.j2 2026-09-11 19:41:01.159322790 +0000 @@ -12,17 +12,11 @@ */ options { - query-source address 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { fd92:7065:b8e:ffff::3; }; - recursion yes; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation no; server-id "ns3"; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/digdelv/prereq.sh bind9-9.20.29/bin/tests/system/digdelv/prereq.sh --- bind9-9.20.26/bin/tests/system/digdelv/prereq.sh 2026-07-20 14:47:53.671843293 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/digdelv/tests.sh bind9-9.20.29/bin/tests/system/digdelv/tests.sh --- bind9-9.20.26/bin/tests/system/digdelv/tests.sh 2026-07-20 14:47:53.671843293 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/tests.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,1822 +0,0 @@ -#!/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 - -# shellcheck source=conf.sh -. ../conf.sh - -status=0 -n=0 - -dig_with_opts() { - "$DIG" -p "$PORT" "$@" -} - -mdig_with_opts() { - "$MDIG" -p "$PORT" "$@" -} - -set_response_sequence() { - SEQUENCE="${1}" - LOGID="${2}" - dig_with_opts @10.53.0.5 "${SEQUENCE}.response-sequence._control" TXT >dig.out.control${LOGID} 2>&1 || ret=1 -} - -# Check if response in file $1 has the correct TTL range. -# The response record must have RRtype $2 and class IN (CLASS1). -# Maximum TTL is given by $3. This works in most cases where TTL is -# the second word on the line. TTL position can be adjusted with -# setting the position $4, but that requires updating this function. -check_ttl_range() { - file=$1 - pos=$4 - - case "$pos" in - "3") - { - awk -v rrtype="$2" -v ttl="$3" '($4 == "IN" || $4 == "CLASS1" ) && $5 == rrtype { if ($3 <= ttl) { ok=1 } } END { exit(ok?0:1) }' <$file - result=$? - } || true - ;; - *) - { - awk -v rrtype="$2" -v ttl="$3" '($3 == "IN" || $3 == "CLASS1" ) && $4 == rrtype { if ($2 <= ttl) { ok=1 } } END { exit(ok?0:1) }' <$file - result=$? - } || true - ;; - esac - - [ $result -eq 0 ] || echo_i "ttl check failed" - return $result -} - -# use delv insecure mode by default, as we're mostly not testing dnssec -delv_with_opts() { - "$DELV" +noroot -p "$PORT" "$@" -} - -KEYID="$(cat ns2/keyid)" -KEYDATA="$(sed /dev/null && HAS_PYYAML=1 - -n=$((n + 1)) -echo_i "check nslookup handles UPDATE response ($n)" -ret=0 -"$NSLOOKUP" -q=CNAME -timeout=1 "-port=$PORT" foo.bar 10.53.0.6 >nslookup.out.test$n 2>&1 && ret=1 -grep "Opcode mismatch" nslookup.out.test$n >/dev/null || ret=1 -if [ $ret -ne 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -n=$((n + 1)) -echo_i "check host handles UPDATE response ($n)" -ret=0 -"$HOST" -W 1 -t CNAME -p $PORT foo.bar 10.53.0.6 >host.out.test$n 2>&1 && ret=1 -grep "Opcode mismatch" host.out.test$n >/dev/null || ret=1 -if [ $ret -ne 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -n=$((n + 1)) -echo_i "check nsupdate handles UPDATE response to QUERY ($n)" -ret=0 -res=0 -$NSUPDATE <nsupdate.out.test$n 2>&1 || res=$? -server 10.53.0.6 ${PORT} -add x.example.com 300 in a 1.2.3.4 -send -EOF -test $res -eq 1 || ret=1 -grep "invalid OPCODE in response to SOA query" nsupdate.out.test$n >/dev/null || ret=1 -if [ $ret -ne 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -if [ -x "$DIG" ]; then - n=$((n + 1)) - echo_i "check dig handles UPDATE response ($n)" - ret=0 - dig_with_opts @10.53.0.6 +tries=1 +timeout=1 cname foo.bar >dig.out.test$n 2>&1 && ret=1 - grep "Opcode mismatch" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig short form works ($n)" - ret=0 - dig_with_opts @10.53.0.3 +short a a.example >dig.out.test$n || ret=1 - test "$(wc -l dig.out.test$n || ret=1 - grep " 9ABC DEF6 7890 " /dev/null || ret=1 - check_ttl_range dig.out.test$n "SSHFP" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +unknownformat works ($n)" - ret=0 - dig_with_opts @10.53.0.3 +unknownformat a a.example >dig.out.test$n || ret=1 - grep "CLASS1[ ][ ]*TYPE1[ ][ ]*\\\\# 4 0A000001" /dev/null || ret=1 - check_ttl_range dig.out.test$n "TYPE1" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig with reverse lookup works ($n)" - ret=0 - dig_with_opts @10.53.0.3 -x 127.0.0.1 >dig.out.test$n 2>&1 || ret=1 - # doesn't matter if has answer - grep -i "127\\.in-addr\\.arpa\\." /dev/null || ret=1 - check_ttl_range dig.out.test$n "SOA" 86400 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig over TCP works ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 a a.example >dig.out.test$n || ret=1 - grep "10\\.0\\.0\\.1$" /dev/null || ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +multi +norrcomments works for DNSKEY (when default is rrcomments)($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +multi +norrcomments -t DNSKEY example >dig.out.test$n || ret=1 - grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" dig.out.test$n >/dev/null && ret=1 - check_ttl_range dig.out.test$n "DNSKEY" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +multi +norrcomments works for SOA (when default is rrcomments)($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +multi +norrcomments -t SOA example >dig.out.test$n || ret=1 - grep "; serial" dig.out.test$n >/dev/null && ret=1 - check_ttl_range dig.out.test$n "SOA" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +rrcomments works for DNSKEY($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +rrcomments DNSKEY example >dig.out.test$n || ret=1 - grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" /dev/null || ret=1 - check_ttl_range dig.out.test$n "DNSKEY" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +short +rrcomments works for DNSKEY ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example >dig.out.test$n || ret=1 - grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +short +nosplit works($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +short +nosplit DNSKEY example >dig.out.test$n || ret=1 - grep "$NOSPLIT" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +short +rrcomments works($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example >dig.out.test$n || ret=1 - grep -q "$KEYDATA ; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID\$" dig.out.nn.$n || ret=1 - dig_with_opts +tcp @10.53.0.3 -t DNSKEY example +multi example +nomulti >dig.out.mn.$n || ret=1 - dig_with_opts +tcp @10.53.0.3 -t DNSKEY example +nomulti example +multi >dig.out.nm.$n || ret=1 - dig_with_opts +tcp @10.53.0.3 -t DNSKEY example +multi example +multi >dig.out.mm.$n || ret=1 - lcnn=$(wc -l dig.out.test$n || ret=1 - grep "Got answer:" /dev/null || ret=1 - check_ttl_range dig.out.test$n "SOA" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +short +rrcomments works($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example >dig.out.test$n || ret=1 - grep -q "$KEYDATA ; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID\$" dig.out.test$n || ret=1 - grep "^;; flags: qr rd; QUERY: 0, ANSWER: 0," /dev/null || ret=1 - grep "^;; QUESTION SECTION:" /dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +coflag works ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +coflag +qr example >dig.out.test$n || ret=1 - grep "^; EDNS: version: 0, flags: co;" /dev/null || ret=1 - check_ttl_range dig.out.test$n "SOA" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "checking dig +coflag +yaml works ($n)" - ret=0 - dig_with_opts +yaml +tcp @10.53.0.3 +coflag +qr example >dig.out.test$n || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS flags >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n || ret=1 - grep "^;; flags: rd ra ad; QUERY: 1, ANSWER: 0," /dev/null || ret=1 - grep "^;; flags: qr rd ra; QUERY: 1, ANSWER: 0," /dev/null || ret=1 - check_ttl_range dig.out.test$n "SOA" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +tcflag works ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +tcflag +qr example >dig.out.test$n || ret=1 - grep "^;; flags: tc rd ad; QUERY: 1, ANSWER: 0" /dev/null || ret=1 - grep "^;; flags: qr rd ra; QUERY: 1, ANSWER: 0," /dev/null || ret=1 - check_ttl_range dig.out.test$n "SOA" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +header-only works (with class and type set) ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +header-only -c IN -t A example >dig.out.test$n || ret=1 - grep "^;; flags: qr rd; QUERY: 0, ANSWER: 0," /dev/null || ret=1 - grep "^;; QUESTION SECTION:" /dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +zflag works, and that BIND properly ignores it ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.3 +zflag +qr A example >dig.out.test$n || ret=1 - sed -n '/Sending:/,/Got answer:/p' dig.out.test$n | grep "^;; flags: rd ad; MBZ: 0x4;" >/dev/null || ret=1 - sed -n '/Got answer:/,/AUTHORITY SECTION:/p' dig.out.test$n | grep "^;; flags: qr rd ra; QUERY: 1" >/dev/null || ret=1 - check_ttl_range dig.out.test$n "SOA" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +qr +ednsopt=08 does not cause an INSIST failure ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=08 +qr a a.example >dig.out.test$n || ret=1 - grep "INSIST" /dev/null && ret=1 - grep "FORMERR" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +ttlunits works ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.2 +ttlunits A weeks.example >dig.out.test$n || ret=1 - grep "^weeks.example. 3w" /dev/null || ret=1 - dig_with_opts +tcp @10.53.0.2 +ttlunits A days.example >dig.out.test$n || ret=1 - grep "^days.example. 3d" /dev/null || ret=1 - dig_with_opts +tcp @10.53.0.2 +ttlunits A hours.example >dig.out.test$n || ret=1 - grep "^hours.example. 3h" /dev/null || ret=1 - dig_with_opts +tcp @10.53.0.2 +ttlunits A minutes.example >dig.out.test$n || ret=1 - grep "^minutes.example. 45m" /dev/null || ret=1 - dig_with_opts +tcp @10.53.0.2 +ttlunits A seconds.example >dig.out.test$n || ret=1 - grep "^seconds.example. 45s" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig respects precedence of options with +ttlunits ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.2 +ttlunits +nottlid A weeks.example >dig.out.test$n || ret=1 - grep "^weeks.example. IN" /dev/null || ret=1 - dig_with_opts +tcp @10.53.0.2 +nottlid +ttlunits A weeks.example >dig.out.test$n || ret=1 - grep "^weeks.example. 3w" /dev/null || ret=1 - dig_with_opts +tcp @10.53.0.2 +nottlid +nottlunits A weeks.example >dig.out.test$n || ret=1 - grep "^weeks.example. 1814400" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig preserves origin on TCP retries ($n)" - ret=0 - dig_with_opts -d +tcp @10.53.0.4 +retry=1 +time=1 +domain=bar foo >dig.out.test$n 2>&1 && ret=1 - test "$(grep -c "trying origin bar" dig.out.test$n)" -eq 2 || ret=1 - grep "using root origin" /dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig -6 -4 ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.2 -4 -6 A a.example >dig.out.test$n 2>&1 && ret=1 - grep "only one of -4 and -6 allowed" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig @IPv6addr -4 A a.example ($n)" - if testsock6 fd92:7065:b8e:ffff::2 2>/dev/null; then - ret=0 - dig_with_opts +tcp @fd92:7065:b8e:ffff::2 -4 A a.example >dig.out.test$n 2>&1 && ret=1 - grep "address family not supported" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - else - echo_i "IPv6 unavailable; skipping" - fi - - n=$((n + 1)) - echo_i "checking dig +tcp @IPv4addr -6 A a.example ($n)" - if testsock6 fd92:7065:b8e:ffff::2 2>/dev/null; then - ret=0 - dig_with_opts +tcp @10.53.0.2 -6 A a.example >dig.out.test$n 2>&1 || ret=1 - grep "SERVER: ::ffff:10.53.0.2#$PORT" /dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - else - echo_i "IPv6 unavailable; skipping" - fi - n=$((n + 1)) - - echo_i "checking dig +notcp @IPv4addr -6 A a.example ($n)" - if testsock6 fd92:7065:b8e:ffff::2 2>/dev/null; then - ret=0 - dig_with_opts +notcp @10.53.0.2 -6 A a.example >dig.out.test$n 2>&1 || ret=1 - grep "SERVER: ::ffff:10.53.0.2#$PORT" /dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - else - echo_i "IPv6 unavailable; skipping" - fi - - n=$((n + 1)) - echo_i "checking dig +subnet ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.2 +subnet=127.0.0.1 A a.example >dig.out.test$n 2>&1 || ret=1 - grep "CLIENT-SUBNET: 127.0.0.1/32/0" /dev/null || ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +subnet +subnet ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.2 +subnet=127.0.0.0 +subnet=127.0.0.1 A a.example >dig.out.test$n 2>&1 || ret=1 - grep "CLIENT-SUBNET: 127.0.0.1/32/0" /dev/null || ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +subnet with various prefix lengths ($n)" - ret=0 - for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24; do - dig_with_opts +tcp @10.53.0.2 +subnet=255.255.255.255/$i A a.example >dig.out.$i.test$n 2>&1 || ret=1 - case $i in - 1 | 9 | 17) octet=128 ;; - 2 | 10 | 18) octet=192 ;; - 3 | 11 | 19) octet=224 ;; - 4 | 12 | 20) octet=240 ;; - 5 | 13 | 21) octet=248 ;; - 6 | 14 | 22) octet=252 ;; - 7 | 15 | 23) octet=254 ;; - 8 | 16 | 24) octet=255 ;; - esac - case $i in - 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8) addr="${octet}.0.0.0" ;; - 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16) addr="255.${octet}.0.0" ;; - 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24) addr="255.255.${octet}.0" ;; - esac - grep "FORMERR" /dev/null && ret=1 - grep "CLIENT-SUBNET: $addr/$i/0" /dev/null || ret=1 - check_ttl_range dig.out.$i.test$n "A" 300 || ret=1 - done - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +subnet=0/0 ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.2 +subnet=0/0 A a.example >dig.out.test$n 2>&1 || ret=1 - grep "status: NOERROR" /dev/null || ret=1 - grep "CLIENT-SUBNET: 0.0.0.0/0/0" /dev/null || ret=1 - grep "10.0.0.1" /dev/null || ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +subnet=0 ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.2 +subnet=0 A a.example >dig.out.test$n 2>&1 || ret=1 - grep "status: NOERROR" /dev/null || ret=1 - grep "CLIENT-SUBNET: 0.0.0.0/0/0" /dev/null || ret=1 - grep "10.0.0.1" /dev/null || ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "checking dig +subnet=0 +yaml ($n)" - ret=0 - dig_with_opts +yaml +tcp @10.53.0.2 +subnet=0 A a.example >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message response_message_data OPT_PSEUDOSECTION EDNS CLIENT-SUBNET >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - grep "status: NOERROR" /dev/null || ret=1 - grep "CLIENT-SUBNET: ::/0/0" /dev/null || ret=1 - grep "10.0.0.1" /dev/null || ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "checking dig +subnet=::/0 +yaml ($n)" - ret=0 - dig_with_opts +yaml +tcp @10.53.0.2 +subnet=::/0 A a.example >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message response_message_data OPT_PSEUDOSECTION EDNS CLIENT-SUBNET >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS CLIENT-SUBNET >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - grep "status: FORMERR" /dev/null || ret=1 - grep "CLIENT-SUBNET" /dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +ednsopt=8:00030000 (family=3, source=0, scope=0) ($n)" - ret=0 - dig_with_opts +qr +tcp @10.53.0.2 +ednsopt=8:00030000 A a.example >dig.out.test$n 2>&1 || ret=1 - grep "status: FORMERR" /dev/null || ret=1 - grep "CLIENT-SUBNET: 00 03 00 00" /dev/null || ret=1 - test "$(grep -c "CLIENT-SUBNET: 00 03 00 00" dig.out.test$n)" -eq 1 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +subnet with prefix lengths between byte boundaries ($n)" - ret=0 - for p in 9 10 11 12 13 14 15; do - dig_with_opts +tcp @10.53.0.2 +subnet=10.53/$p A a.example >dig.out.test.$p.$n 2>&1 || ret=1 - grep "FORMERR" /dev/null && ret=1 - grep "CLIENT-SUBNET.*/$p/0" /dev/null || ret=1 - check_ttl_range dig.out.test.$p.$n "A" 300 || ret=1 - done - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +sp works as an abbreviated form of split ($n)" - ret=0 - dig_with_opts @10.53.0.3 +sp=4 -t sshfp foo.example >dig.out.test$n || ret=1 - grep " 9ABC DEF6 7890 " /dev/null || ret=1 - check_ttl_range dig.out.test$n "SSHFP" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig -c works ($n)" - ret=0 - dig_with_opts @10.53.0.3 -c CHAOS -t txt version.bind >dig.out.test$n || ret=1 - grep "version.bind. 0 CH TXT" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +ednsopt with option number ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=3 a.example >dig.out.test$n 2>&1 || ret=1 - grep 'NSID: .* ("ns3")' dig.out.test$n >/dev/null || ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking dig +ednsopt with option name ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=nsid a.example >dig.out.test$n 2>&1 || ret=1 - grep 'NSID: .* ("ns3")' dig.out.test$n >/dev/null || ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking ednsopt UPDATE-LEASE prints as expected (single lease) ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=UPDATE-LEASE:00000e10 +qr a.example >dig.out.test$n 2>&1 || ret=1 - pat='UPDATE-LEASE: 3600 (1 hour)' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - n=$((n + 1)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "checking ednsopt UPDATE-LEASE prints as expected (single lease) +yaml ($n)" - ret=0 - dig_with_opts @10.53.0.3 +yaml +ednsopt=UPDATE-LEASE:00000e10 +qr a.example >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS UPDATE-LEASE LEASE >yamlget.out.test$n 2>&1 || ret=1 - read -r value /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - fi - - n=$((n + 1)) - echo_i "checking ednsopt UPDATE-LEASE prints as expected (split lease) ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=UPDATE-LEASE:00000e1000127500 +qr a.example >dig.out.test$n 2>&1 || ret=1 - pat='UPDATE-LEASE: 3600/1209600 (1 hour/2 weeks)' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "checking ednsopt UPDATE-LEASE prints as expected (split lease) +yaml ($n)" - ret=0 - dig_with_opts @10.53.0.3 +yaml +ednsopt=UPDATE-LEASE:00000e1000127500 +qr a.example >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS UPDATE-LEASE LEASE >yamlget.out.test$n 2>&1 || ret=1 - read -r value /dev/null || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS UPDATE-LEASE KEY-LEASE >yamlget.out.test$n 2>&1 || ret=1 - read -r value /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - fi - - echo_i "checking ednsopt LLQ prints as expected ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=llq:0001000200001234567812345678fefefefe +qr a.example >dig.out.test$n 2>&1 || ret=1 - pat='LLQ: Version: 1, Opcode: 2, Error: 0, Identifier: 1311768465173141112, Lifetime: 4278124286$' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "checking ednsopt LLQ prints as expected +yaml ($n)" - ret=0 - dig_with_opts @10.53.0.3 +yaml +ednsopt=llq:0001000200001234567812345678fefefefe +qr a.example >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS LLQ LLQ-VERSION >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - grep ";; WARNING: .local is reserved for Multicast DNS" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig processes +ednsopt=key-tag and FORMERR is returned ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=key-tag a.example +qr >dig.out.test$n 2>&1 || ret=1 - grep "; KEY-TAG: *$" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig processes +ednsopt=key-tag: ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=key-tag:00010002 a.example +qr >dig.out.test$n 2>&1 || ret=1 - grep "; KEY-TAG: 1, 2$" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null && ret=1 - check_ttl_range dig.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - ret=0 - echo_i "check that dig processes +ednsopt=key-tag: +yaml ($n)" - dig_with_opts @10.53.0.3 +yaml +ednsopt=key-tag:00010002 a.example +qr >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS KEY-TAG >yamlget.out.test$n 2>&1 || ret=1 - read -r value and FORMERR is returned ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=key-tag:0001000201 a.example +qr >dig.out.test$n 2>&1 || ret=1 - grep "; KEY-TAG: 00 01 00 02 01" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig processes +ednsopt=client-tag:value ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=client-tag:0001 a.example +qr >dig.out.test$n 2>&1 || ret=1 - grep "; CLIENT-TAG: 1$" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check that dig processes +ednsopt=client-tag:value +yaml ($n)" - ret=0 - dig_with_opts @10.53.0.3 +yaml +ednsopt=client-tag:0001 a.example +qr >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS CLIENT-TAG >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - grep "; CLIENT-TAG" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that FORMERR is returned for a too long client-tag ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=client-tag:000001 a.example +qr >dig.out.test$n 2>&1 || ret=1 - grep "; CLIENT-TAG" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig processes +ednsopt=server-tag:value ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=server-tag:0001 a.example +qr >dig.out.test$n 2>&1 || ret=1 - grep "; SERVER-TAG: 1$" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check that dig processes +ednsopt=server-tag:value +yaml ($n)" - ret=0 - dig_with_opts @10.53.0.3 +yaml +ednsopt=server-tag:0001 a.example +qr >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS SERVER-TAG >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - grep "; SERVER-TAG" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that FORMERR is returned for a too long server-tag ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=server-tag:000001 a.example +qr >dig.out.test$n 2>&1 || ret=1 - grep "; SERVER-TAG" dig.out.test$n >/dev/null || ret=1 - grep "status: FORMERR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig processes +ednsopt=chain:02002200 ($n)" - ret=0 - dig_with_opts @10.53.0.3 +ednsopt=chain:02002200 'a.\000"' +qr >dig.out.test$n 2>&1 || ret=1 - grep '; CHAIN: "\\000\\""' dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check that dig processes +ednsopt=chain:02002200 +yaml ($n)" - ret=0 - dig_with_opts @10.53.0.3 +yaml +ednsopt=chain:02002200 'a.\000"' +qr >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS CHAIN >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - grep '; EXPIRE: 1200 (20 minutes)' dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check that dig processes +expire +yaml ($n)" - ret=0 - dig_with_opts @10.53.0.1 +yaml +expire . soa >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message response_message_data OPT_PSEUDOSECTION EDNS EXPIRE >yamlget.out.test$n 2>&1 || ret=1 - read -r value /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - fi - - n=$((n + 1)) - echo_i "check that dig processes +keepalive ($n)" - ret=0 - dig_with_opts @10.53.0.1 +keepalive . soa +tcp >dig.out.test$n 2>&1 || ret=1 - grep '; TCP-KEEPALIVE: 30.0 secs' dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check that dig processes +keepalive +yaml ($n)" - ret=0 - dig_with_opts @10.53.0.1 +yaml +keepalive . soa +tcp >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message response_message_data OPT_PSEUDOSECTION EDNS TCP-KEEPALIVE >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - pat='^; EDE: 0 (Other): (foo)$' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check that Extended DNS Error 0 is printed correctly +yaml ($n)" - ret=0 - # add specials '"' and '\' - dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0000666f6f225c a.example +qr >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE EXTRA-TEXT >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - pat='^; EDE: 24 (Invalid Data)$' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that Extended DNS Error 25 is printed correctly ($n)" - ret=0 - # First undefined EDE code, additional text "foo". - dig_with_opts @10.53.0.3 +ednsopt=ede:0019666f6f a.example +qr >dig.out.test$n 2>&1 || ret=1 - pat='^; EDE: 25: (foo)$' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that invalid Extended DNS Error (length 0) is printed ($n)" - ret=0 - # EDE payload is too short - dig_with_opts @10.53.0.3 +ednsopt=ede a.example +qr >dig.out.test$n 2>&1 || ret=1 - pat='^; EDE:$' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that invalid Extended DNS Error (length 1) is printed ($n)" - ret=0 - # EDE payload is too short - dig_with_opts @10.53.0.3 +ednsopt=ede:00 a.example +qr >dig.out.test$n 2>&1 || ret=1 - pat='^; EDE: 00 (".")$' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check that +yaml Extended DNS Error 0 is printed correctly ($n)" - ret=0 - # First defined EDE code, additional text "foo". - dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0000666f6f a.example +qr >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that +yaml Extended DNS Error 25 is printed correctly ($n)" - ret=0 - # First undefined EDE code, additional text "foo". - dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0019666f6f a.example +qr >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 && ret=1 - grep "ednsopt no code point specified" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig gracefully handles bad escape in domain name ($n)" - ret=0 - digstatus=0 - dig_with_opts @10.53.0.3 '\0.' >dig.out.test$n 2>&1 || digstatus=$? - echo digstatus=$digstatus >>dig.out.test$n - test $digstatus -eq 10 || ret=1 - grep REQUIRE dig.out.test$n >/dev/null && ret=1 - grep "is not a legal name (bad escape)" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig -q -m works ($n)" - ret=0 - dig_with_opts @10.53.0.3 -q -m >dig.out.test$n 2>&1 - pat='^;-m\..*IN.*A$' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - grep "Dump of all outstanding memory allocations" dig.out.test$n >/dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking exit code for a retry upon TCP EOF (immediate -> immediate) ($n)" - ret=0 - set_response_sequence no-response $n - dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 && ret=1 - # Sanity check: ensure ans5 behaves as expected. - [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> partial AXFR) ($n)" - ret=0 - set_response_sequence partial-axfr $n - dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 && ret=1 - # Sanity check: ensure ans5 behaves as expected. - [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking exit code for a retry upon TCP EOF (immediate -> partial AXFR) ($n)" - ret=0 - set_response_sequence no-response.partial-axfr $n - dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 && ret=1 - # Sanity check: ensure ans5 behaves as expected. - [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> immediate) ($n)" - ret=0 - set_response_sequence partial-axfr.no-response $n - dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 && ret=1 - # Sanity check: ensure ans5 behaves as expected. - [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking exit code for a retry upon TCP EOF (immediate -> complete AXFR) ($n)" - ret=0 - set_response_sequence no-response.complete-axfr $n - dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 || ret=1 - # Sanity check: ensure ans5 behaves as expected. - [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> complete AXFR) ($n)" - ret=0 - set_response_sequence partial-axfr.complete-axfr $n - dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 || ret=1 - # Sanity check: ensure ans5 behaves as expected. - [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking +tries=1 won't retry twice upon TCP EOF ($n)" - ret=0 - set_response_sequence no-response $n - dig_with_opts @10.53.0.5 example AXFR +tries=1 >dig.out.test$n 2>&1 && ret=1 - # Sanity check: ensure ans5 behaves as expected. - [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking +retry=0 won't retry twice upon TCP EOF ($n)" - ret=0 - dig_with_opts @10.53.0.5 example AXFR +retry=0 >dig.out.test$n 2>&1 && ret=1 - # Sanity check: ensure ans5 behaves as expected. - [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig +expandaaaa works ($n)" - ret=0 - dig_with_opts @10.53.0.3 +expandaaaa AAAA ns2.example >dig.out.test$n 2>&1 || ret=1 - grep "ns2.example.*fd92:7065:0b8e:ffff:0000:0000:0000:0002" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig +noexpandaaaa works ($n)" - ret=0 - dig_with_opts @10.53.0.3 +noexpandaaaa AAAA ns2.example >dig.out.test$n 2>&1 || ret=1 - grep "ns2.example.*fd92:7065:b8e:ffff::2" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig default for +[no]expandaaa (+noexpandaaaa) works ($n)" - ret=0 - dig_with_opts @10.53.0.3 AAAA ns2.example >dig.out.test$n 2>&1 || ret=1 - grep "ns2.example.*fd92:7065:b8e:ffff::2" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - - echo_i "check that dig +short +expandaaaa works ($n)" - ret=0 - dig_with_opts @10.53.0.3 +short +expandaaaa AAAA ns2.example >dig.out.test$n 2>&1 || ret=1 - pat='^fd92:7065:0b8e:ffff:0000:0000:0000:0002$' - grep "$pat" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check dig +yaml ANY output ($n)" - ret=0 - dig_with_opts +qr +yaml @10.53.0.3 any ns2.example >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data status >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 1 message response_message_data ANSWER_SECTION 0 >yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - grep "EDNS:" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig +bufsize restores default bufsize ($n)" - ret=0 - dig_with_opts @10.53.0.3 a.example +bufsize=0 +bufsize +qr >dig.out.test$n 2>&1 || ret=1 - lines=$(grep "EDNS:.* udp:" dig.out.test$n | wc -l) - lines1232=$(grep "EDNS:.* udp: 1232" dig.out.test$n | wc -l) - test $lines -eq 2 || ret=1 - test $lines1232 -eq 2 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig without -u displays 'Query time' in millseconds ($n)" - ret=0 - dig_with_opts @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - grep ';; Query time: [0-9][0-9]* msec' dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig -u displays 'Query time' in microseconds ($n)" - ret=0 - dig_with_opts -u @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - grep ';; Query time: [0-9][0-9]* usec' dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig +yaml without -u displays timestamps in milliseconds ($n)" - ret=0 - dig_with_opts +yaml @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - grep 'query_time: !!timestamp ....-..-..T..:..:..\....Z' dig.out.test$n >/dev/null || ret=1 - grep 'response_time: !!timestamp ....-..-..T..:..:..\....Z' dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig -u +yaml displays timestamps in microseconds ($n)" - ret=0 - dig_with_opts -u +yaml @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - grep 'query_time: !!timestamp ....-..-..T..:..:..\.......Z' dig.out.test$n >/dev/null || ret=1 - grep 'response_time: !!timestamp ....-..-..T..:..:..\.......Z' dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - # See [GL #3020] for more information - n=$((n + 1)) - echo_i "check that dig handles UDP timeout followed by a SERVFAIL correctly ($n)" - ret=0 - dig_with_opts +timeout=1 +nofail @10.53.0.7 silent-then-servfail.example >dig.out.test$n 2>&1 || ret=1 - grep -F "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig handles TCP timeout followed by a SERVFAIL correctly ($n)" - ret=0 - dig_with_opts +timeout=1 +nofail +tcp @10.53.0.7 silent-then-servfail.example >dig.out.test$n 2>&1 || ret=1 - grep -F "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig tries the next server after a UDP socket network unreachable error ($n)" - ret=0 - dig_with_opts @192.0.2.128 @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - test $(grep -F -e "connection refused" -e "timed out" -e "network unreachable" -e "host unreachable" dig.out.test$n | wc -l) -eq 3 || ret=1 - grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig tries the next server after a TCP socket network unreachable error ($n)" - ret=0 - dig_with_opts +tcp @192.0.2.128 @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - test $(grep -F -e "connection refused" -e "timed out" -e "network unreachable" -e "host unreachable" dig.out.test$n | wc -l) -eq 3 || ret=1 - grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig tries the next server after a UDP socket read error ($n)" - ret=0 - dig_with_opts @10.53.0.99 @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig tries the next server after a TCP socket read error ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.7 @10.53.0.3 close.example >dig.out.test$n 2>&1 || ret=1 - grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - # Note that we combine TCP socket "connection error" and "timeout" cases in - # one, because it is not trivial to simulate the timeout case in a system test - # in Linux without a firewall, but the code which handles error cases during - # the connection establishment time does not differentiate between timeout and - # other types of errors (unlike during reading), so this one check should be - # sufficient for both cases. - n=$((n + 1)) - echo_i "check that dig tries the next server after a TCP socket connection error/timeout ($n)" - ret=0 - dig_with_opts +tcp @10.53.0.99 @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - test $(grep -F -e "connection refused" -e "timed out" -e "network unreachable" -e "host unreachable" dig.out.test$n | wc -l) -eq 3 || ret=1 - grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig tries the next server after UDP socket read timeouts ($n)" - ret=0 - dig_with_opts +timeout=1 @10.53.0.7 @10.53.0.3 silent.example >dig.out.test$n 2>&1 || ret=1 - grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig tries the next server after TCP socket read timeouts ($n)" - ret=0 - dig_with_opts +timeout=1 +tcp @10.53.0.7 @10.53.0.3 silent.example >dig.out.test$n 2>&1 || ret=1 - grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - # See [GL #3248] for more information - n=$((n + 1)) - echo_i "check that dig correctly refuses to use a server with a IPv4 mapped IPv6 address after failing with a regular IP address ($n)" - ret=0 - dig_with_opts @10.53.0.7 @::ffff:10.53.0.7 silent.example >dig.out.test$n 2>&1 || ret=1 - grep -F ";; Skipping mapped address" dig.out.test$n >/dev/null || ret=1 - grep -F ";; No acceptable nameservers" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - # See [GL #3244] for more information - n=$((n + 1)) - echo_i "check that dig handles printing query information with +qr and +y when multiple queries are involved (including a failed query) ($n)" - ret=0 - dig_with_opts +timeout=1 +qr +y @127.0.0.1 @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1 - grep -F "IN A 10.0.0.1" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig +noedns +ednsflags= re-enables EDNS ($n)" - dig_with_opts @10.53.0.3 +qr +noedns +ednsflags=0x70 a.example >dig.out.test$n 2>&1 || ret=1 - grep "; EDNS: version: 0, flags:; MBZ: 0x0070, udp: 1232" dig.out.test$n >/dev/null || ret=1 - grep "; EDNS: version: 0, flags:; udp: 1232" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that dig +showbadvers works ($n)" - dig_with_opts @10.53.0.3 +edns=1 +qr +showbadvers a.example >dig.out.test$n 2>&1 || ret=1 - grep "; EDNS: version: 1, flags:; udp: 1232" dig.out.test$n >/dev/null || ret=1 - grep "; EDNS: version: 0, flags:; udp: 1232" dig.out.test$n >/dev/null || ret=1 - grep -F "status: BADVERS" dig.out.test$n >/dev/null || ret=1 - grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - # See GL#5609 - n=$((n + 1)) - echo_i "check dig with a IPv4 source address and a server with both IPv4 and IPv6 addresses doesn't crash ($n)" - ret=0 - dig_with_opts @localhost example -b 10.53.0.1 >dig.out.test$n 2>&1 || ret=1 - # We only care about an assertion failure, otherwise reset 'ret' to 0, because - # @localhost is't really expected to have an answer for our query. - grep -F "core dumped" dig.out.test$n >/dev/null || ret=0 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) -else - echo_i "$DIG is needed, so skipping these dig tests" -fi - -if [ -x "$MDIG" ]; then - n=$((n + 1)) - echo_i "checking mdig +tcp works with a source address and port ($n)" - ret=0 - # When running more than once in quick succession with a source address#port, - # we can get a "response failed with address not available" error because - # the address#port is still busy, but we are not interested in that error, - # as we are only looking for the unexpected error case, that's why we ignore - # the return code from mdig, but we check for the unexpected error message - # using grep. See GitLab #4969. - mdig_with_opts -b "10.53.0.3#${EXTRAPORT8}" +tcp @10.53.0.3 example >dig.out.test$n 2>&1 || true - grep -F "unexpected error" dig.out.test$n >/dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that mdig handles malformed option '+ednsopt=:' gracefully ($n)" - ret=0 - mdig_with_opts @10.53.0.3 +ednsopt=: a.example >dig.out.test$n 2>&1 && ret=1 - grep "ednsopt no code point specified" dig.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking mdig +multi +norrcomments works for DNSKEY (when default is rrcomments)($n)" - ret=0 - mdig_with_opts +tcp @10.53.0.3 +multi +norrcomments -t DNSKEY example >dig.out.test$n || ret=1 - grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" dig.out.test$n && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking mdig +multi +norrcomments works for SOA (when default is rrcomments)($n)" - ret=0 - mdig_with_opts +tcp @10.53.0.3 +multi +norrcomments -t SOA example >dig.out.test$n || ret=1 - grep "; serial" /dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check mdig +yaml output ($n)" - ret=0 - mdig_with_opts +yaml @10.53.0.3 -t any ns2.example >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message response_message_data status >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value delv.out.test$n || ret=1 - test "$(wc -l delv.out.test$n || ret=1 - grep " 9ABC DEF6 7890 " /dev/null || ret=1 - check_ttl_range delv.out.test$n "SSHFP" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +unknownformat works ($n)" - ret=0 - delv_with_opts @10.53.0.3 +unknownformat a a.example >delv.out.test$n || ret=1 - grep "CLASS1[ ][ ]*TYPE1[ ][ ]*\\\\# 4 0A000001" /dev/null || ret=1 - check_ttl_range delv.out.test$n "TYPE1" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv -4 -6 ($n)" - ret=0 - delv_with_opts @10.53.0.3 -4 -6 A a.example >delv.out.test$n 2>&1 && ret=1 - grep "only one of -4 and -6 allowed" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv exits cleanly on malformed query name ($n)" - ret=0 - longlabel="$(printf 'a%.0s' $(seq 1 64))" - delv_with_opts @10.53.0.3 -t a "$longlabel.example.com" >delv.out.test$n 2>&1 - rc=$? - # Pre-fix: SIGABRT (exit 134) from dns_client_detach(NULL) in run_resolve cleanup. - [ $rc -eq 134 ] && ret=1 - grep "label too long" delv.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv with IPv6 on IPv4 does not work ($n)" - if testsock6 fd92:7065:b8e:ffff::3 2>/dev/null; then - ret=0 - # following should fail because @IPv4 overrides earlier @IPv6 above - # and -6 forces IPv6 so this should fail, with a message - # "Use of IPv4 disabled by -6" - delv_with_opts @fd92:7065:b8e:ffff::3 @10.53.0.3 -6 -t txt foo.example >delv.out.test$n 2>&1 && ret=1 - # it should have no results but error output - grep "testing" /dev/null && ret=1 - grep "Use of IPv4 disabled by -6" delv.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - else - echo_i "IPv6 unavailable; skipping" - fi - - n=$((n + 1)) - echo_i "checking delv with IPv4 on IPv6 does not work ($n)" - if testsock6 fd92:7065:b8e:ffff::3 2>/dev/null; then - ret=0 - # following should fail because @IPv6 overrides earlier @IPv4 above - # and -4 forces IPv4 so this should fail, with a message - # "Use of IPv6 disabled by -4" - delv_with_opts @10.53.0.3 @fd92:7065:b8e:ffff::3 -4 -t txt foo.example >delv.out.test$n 2>&1 && ret=1 - # it should have no results but error output - grep "testing" delv.out.test$n >/dev/null && ret=1 - grep "Use of IPv6 disabled by -4" delv.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - else - echo_i "IPv6 unavailable; skipping" - fi - - n=$((n + 1)) - echo_i "checking delv with reverse lookup works ($n)" - ret=0 - delv_with_opts @10.53.0.3 -x 127.0.0.1 >delv.out.test$n 2>&1 || ret=1 - # doesn't matter if has answer - grep -i "127\\.in-addr\\.arpa\\." /dev/null || ret=1 - check_ttl_range delv.out.test$n '\\-ANY' 10800 3 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv over TCP works ($n)" - ret=0 - delv_with_opts +tcp @10.53.0.3 a a.example >delv.out.test$n || ret=1 - grep "10\\.0\\.0\\.1$" /dev/null || ret=1 - check_ttl_range delv.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +multi +norrcomments works for DNSKEY (when default is rrcomments)($n)" - ret=0 - delv_with_opts +tcp @10.53.0.3 +multi +norrcomments DNSKEY example >delv.out.test$n || ret=1 - grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" /dev/null && ret=1 - check_ttl_range delv.out.test$n "DNSKEY" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +multi +norrcomments works for SOA (when default is rrcomments)($n)" - ret=0 - delv_with_opts +tcp @10.53.0.3 +multi +norrcomments SOA example >delv.out.test$n || ret=1 - grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" /dev/null && ret=1 - check_ttl_range delv.out.test$n "SOA" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +rrcomments works for DNSKEY($n)" - ret=0 - delv_with_opts +tcp @10.53.0.3 +rrcomments DNSKEY example >delv.out.test$n || ret=1 - grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" /dev/null || ret=1 - check_ttl_range delv.out.test$n "DNSKEY" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +short +rrcomments works for DNSKEY ($n)" - ret=0 - delv_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example >delv.out.test$n || ret=1 - grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" /dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +short +rrcomments works ($n)" - ret=0 - delv_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example >delv.out.test$n || ret=1 - grep -q "$KEYDATA ; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" delv.out.test$n || ret=1 - grep -q "$NOSPLIT" delv.out.test$n || ret=1 - grep -q "$NOSPLIT\$" delv.out.test$n || ret=1 - grep " 9ABC DEF6 7890 " /dev/null || ret=1 - check_ttl_range delv.out.test$n "SSHFP" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +sh works as an abbriviated form of short ($n)" - ret=0 - delv_with_opts @10.53.0.3 +sh a a.example >delv.out.test$n || ret=1 - test "$(wc -l delv.out.test$n || ret=1 - grep "a.example." /dev/null || ret=1 - check_ttl_range delv.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv -c CH is ignored, and treated like IN ($n)" - ret=0 - delv_with_opts @10.53.0.3 -c CH -t a a.example >delv.out.test$n || ret=1 - grep "a.example." /dev/null || ret=1 - check_ttl_range delv.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv -c CH is ignored, and treated like IN ($n)" - ret=0 - delv_with_opts @10.53.0.3 -c CH -t a a.example >delv.out.test$n || ret=1 - grep "a.example." /dev/null || ret=1 - check_ttl_range delv.out.test$n "A" 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that delv -q -m works ($n)" - ret=0 - delv_with_opts @10.53.0.3 -q -m >delv.out.test$n 2>&1 || ret=1 - grep '^; -m\..*[0-9]*.*IN.*ANY.*;' delv.out.test$n >/dev/null || ret=1 - grep "^add " delv.out.test$n >/dev/null && ret=1 - grep "^del " delv.out.test$n >/dev/null && ret=1 - check_ttl_range delv.out.test$n '\\-ANY' 300 3 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that delv -t ANY works ($n)" - ret=0 - delv_with_opts @10.53.0.3 -t ANY example >delv.out.test$n 2>&1 || ret=1 - grep "^example." /dev/null || ret=1 - check_ttl_range delv.out.test$n NS 300 || ret=1 - check_ttl_range delv.out.test$n SOA 300 || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that delv loads key-style trust anchors ($n)" - ret=0 - delv_with_opts -a ns3/anchor.dnskey +root=example @10.53.0.3 -t DNSKEY example >delv.out.test$n 2>&1 || ret=1 - grep "fully validated" delv.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check that delv loads DS-style trust anchors ($n)" - ret=0 - delv_with_opts -a ns3/anchor.ds +root=example @10.53.0.3 -t DNSKEY example >delv.out.test$n 2>&1 || ret=1 - grep "fully validated" delv.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if [ $HAS_PYYAML -ne 0 ]; then - n=$((n + 1)) - echo_i "check delv +yaml ANY output ($n)" - ret=0 - delv_with_opts +yaml @10.53.0.3 any ns2.example >delv.out.test$n || ret=1 - $PYTHON yamlget.py delv.out.test$n status >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value delv.out.test$n || ret=1 - $PYTHON yamlget.py delv.out.test$n status >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value delv.out.test$n || ret=1 - $PYTHON yamlget.py delv.out.test$n status >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value delv.out.test$n 2>&1 || ret=1 - grep ";; resolution failed: broken trust chain" delv.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "check NS output from delv +ns ($n)" - ret=0 - delv_with_opts -i +ns +nortrace +nostrace +nomtrace +novtrace +hint=root.hint ns example >delv.out.test$n || ret=1 - lines=$(awk '$1 == "example." && $4 == "NS" {print}' delv.out.test$n | wc -l) - [ $lines -eq 2 ] || ret=1 - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +ns (no validation) ($n)" - ret=0 - delv_with_opts -i +ns +hint=root.hint a a.example >delv.out.test$n || ret=1 - grep -q '; authoritative' delv.out.test$n || ret=1 - grep -q '_.example' delv.out.test$n && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +ns +qmin (no validation) ($n)" - ret=0 - delv_with_opts -i +ns +qmin +hint=root.hint a a.example >delv.out.test$n || ret=1 - grep -q '; authoritative' delv.out.test$n || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +ns (with validation) ($n)" - ret=0 - delv_with_opts -a ns1/anchor.dnskey +root +ns +hint=root.hint a a.example >delv.out.test$n || ret=1 - grep -q '; fully validated' delv.out.test$n || ret=1 - grep -q '_.example' delv.out.test$n && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv +ns +qmin (with validation) ($n)" - ret=0 - delv_with_opts -a ns1/anchor.dnskey +root +ns +qmin +hint=root.hint a a.example >delv.out.test$n || ret=1 - grep -q '; fully validated' delv.out.test$n || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - if testsock6 fd92:7065:b8e:ffff::2 2>/dev/null; then - n=$((n + 1)) - echo_i "checking delv -4 +ns uses only IPv4 ($n)" - ret=0 - delv_with_opts -a ns1/anchor.dnskey +root -4 +ns +hint=root.hint a a.example >delv.out.test$n || ret=1 - grep -qF 'sending packet to 10.53' delv.out.test$n >/dev/null || ret=1 - grep -qF 'sending packet to fd92:7065' delv.out.test$n >/dev/null && ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - - n=$((n + 1)) - echo_i "checking delv -6 +ns uses only IPv6 ($n)" - ret=0 - delv_with_opts -a ns1/anchor.dnskey +root -6 +ns +hint=root.hint a a.example >delv.out.test$n || ret=1 - grep -qF 'sending packet to 10.53' delv.out.test$n >/dev/null && ret=1 - grep -qF 'sending packet to fd92:7065' delv.out.test$n >/dev/null || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) - fi - -else - echo_i "$DELV is needed, so skipping these delv tests" -fi - -if [ $HAS_PYYAML -ne 0 ]; then - for qname in "yaml" "'.yaml" "[.yaml" "{.yaml" "&.yaml" "#.yaml"; do - n=$((n + 1)) - echo_i "check yaml special '${yaml}.example' ($n)" - ret=0 - dig_with_opts @10.53.0.3 +yaml "${qname}.example" TXT +qr >dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 0 message query_message_data QUESTION_SECTION 0 >yamlget.out.test$n 2>&1 || ret=1 - read -r value yamlget.out.test$n 2>&1 || ret=1 - read -r value dig.out.test$n 2>&1 || ret=1 - $PYTHON yamlget.py dig.out.test$n 1 message response_message_data ANSWER_SECTION 0 >yamlget.out.test$n 2>&1 || ret=1 - read -r value " "?" "@" "A" "B" "C" "D" "E" "F" "G" "H"' - expected="$expected "'"I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V"' - expected="$expected "'"W" "X" "Y" "Z" "[" "\\" "]" "^" "_" "`" "a" "b" "c" "d"' - expected="$expected "'"e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r"' - expected="$expected "'"s" "t" "u" "v" "w" "x" "y" "z" "{" "|" "}" "~" "\127"' - expected="$expected "'"\128" "\129" "\130" "\131" "\132" "\133" "\134" "\135"' - expected="$expected "'"\136" "\137" "\138" "\139" "\140" "\141" "\142" "\143"' - expected="$expected "'"\144" "\145" "\146" "\147" "\148" "\149" "\150" "\151"' - expected="$expected "'"\152" "\153" "\154" "\155" "\156" "\157" "\158" "\159"' - expected="$expected "'"\160" "\161" "\162" "\163" "\164" "\165" "\166" "\167"' - expected="$expected "'"\168" "\169" "\170" "\171" "\172" "\173" "\174" "\175"' - expected="$expected "'"\176" "\177" "\178" "\179" "\180" "\181" "\182" "\183"' - expected="$expected "'"\184" "\185" "\186" "\187" "\188" "\189" "\190" "\191"' - expected="$expected "'"\192" "\193" "\194" "\195" "\196" "\197" "\198" "\199"' - expected="$expected "'"\200" "\201" "\202" "\203" "\204" "\205" "\206" "\207"' - expected="$expected "'"\208" "\209" "\210" "\211" "\212" "\213" "\214" "\215"' - expected="$expected "'"\216" "\217" "\218" "\219" "\220" "\221" "\222" "\223"' - expected="$expected "'"\224" "\225" "\226" "\227" "\228" "\229" "\230" "\231"' - expected="$expected "'"\232" "\233" "\234" "\235" "\236" "\237" "\238" "\239"' - expected="$expected "'"\240" "\241" "\242" "\243" "\244" "\245" "\246" "\247"' - expected="$expected "'"\248" "\249" "\250" "\251" "\252" "\253" "\254" "\255"' - [ "$value" = "$expected" ] || ret=1 - if [ $ret -ne 0 ]; then echo_i "failed"; fi - status=$((status + ret)) -fi - -echo_i "exit status: $status" -[ $status -eq 0 ] || exit 1 diff -Nru bind9-9.20.26/bin/tests/system/digdelv/tests_dig.py bind9-9.20.29/bin/tests/system/digdelv/tests_dig.py --- bind9-9.20.26/bin/tests/system/digdelv/tests_dig.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/tests_dig.py 2026-09-11 19:41:01.159322790 +0000 @@ -0,0 +1,983 @@ +# 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. + +""" +Tests for the dig tool. +""" + +from re import compile as Re + +import ipaddress +import os +import re + +import pytest + +from digdelv.common import ARTIFACTS, check_ttl_range, parse_yaml +from isctest.util import param + +import isctest +import isctest.mark + +pytestmark = [ + pytest.mark.extra_artifacts(ARTIFACTS), +] + + +@pytest.fixture(name="dig") +def dig_fixture(named_port): + return isctest.run.EnvCmd("DIG", f"-p {named_port}") + + +def edns_yaml(text, direction="query"): + """Get the EDNS OPT pseudosection mapping of the first message in + dig +yaml output.""" + message = parse_yaml(text)[0]["message"] + return message[f"{direction}_message_data"]["OPT_PSEUDOSECTION"]["EDNS"] + + +def test_update_response(dig, ans6): + """Check that dig rejects a response with the UPDATE opcode.""" + result = dig( + f"@{ans6.ip} +tries=1 +timeout=1 cname foo.bar", raise_on_exception=False + ) + assert result.rc != 0 + assert "Opcode mismatch" in result.out + + +def test_short(dig, ns3): + """Check that dig +short returns a single-line answer.""" + result = dig(f"@{ns3.ip} +short a a.example") + assert len(result.out.splitlines()) == 1 + + +@pytest.mark.parametrize("option", ["+split=4", "+sp=4"]) +def test_split_width(dig, ns3, option): + """Check that dig +split (and its +sp abbreviation) splits hex data + into fields of the requested width.""" + result = dig(f"@{ns3.ip} {option} -t sshfp foo.example") + assert " 9ABC DEF6 7890 " in result.out + assert check_ttl_range(result.out, "SSHFP", 300) + + +def test_unknownformat(dig, ns3): + """Check that dig +unknownformat prints RFC 3597 format.""" + result = dig(f"@{ns3.ip} +unknownformat a a.example") + assert Re(r"CLASS1\s+TYPE1\s+\\# 4 0A000001") in result.out + assert check_ttl_range(result.out, "TYPE1", 300) + + +def test_reverse_lookup(dig, ns3): + """Check that dig -x works.""" + result = dig(f"@{ns3.ip} -x 127.0.0.1") + # doesn't matter if has answer + assert Re(r"127\.in-addr\.arpa\.", re.IGNORECASE) in result.out + assert check_ttl_range(result.out, "SOA", 86400) + + +def test_tcp(dig, ns3): + """Check that dig over TCP works.""" + result = dig(f"+tcp @{ns3.ip} a a.example") + assert Re(r"10\.0\.0\.1$") in result.out + assert check_ttl_range(result.out, "A", 300) + + +@pytest.mark.parametrize( + "args,expect_rrcomment", + [ + param("+multi +norrcomments -t DNSKEY example", False, id="multi-norrcomments"), + param("+rrcomments DNSKEY example", True, id="rrcomments"), + param("+short +rrcomments DNSKEY example", True, id="short-rrcomments"), + ], +) +def test_dnskey_rrcomments(dig, ns3, zsk, args, expect_rrcomment): + """Check that +[no]rrcomments controls the DNSKEY comment + (the default is rrcomments, even with +multi).""" + result = dig(f"+tcp @{ns3.ip} {args}") + assert (zsk.rrcomment in result.out) == expect_rrcomment + if "+short" not in args: + assert check_ttl_range(result.out, "DNSKEY", 300) + + +def test_soa_norrcomments(dig, ns3): + """Check that +multi +norrcomments suppresses the SOA field comments.""" + result = dig(f"+tcp @{ns3.ip} +multi +norrcomments -t SOA example") + assert "; serial" not in result.out + assert check_ttl_range(result.out, "SOA", 300) + + +def test_short_nosplit(dig, ns3, zsk): + """Check that dig +short +nosplit does not split the key data.""" + result = dig(f"+tcp @{ns3.ip} +short +nosplit DNSKEY example") + assert zsk.keydata.replace(" ", "") in result.out + + +def test_short_rrcomments_line(dig, ns3, zsk): + """Check the exact dig +short +rrcomments output line.""" + result = dig(f"+tcp @{ns3.ip} +short +rrcomments DNSKEY example") + expected = re.escape(f"{zsk.keydata} {zsk.rrcomment}") + assert Re(expected + "$") in result.out + + +def test_multi_flag_is_local(dig, ns3): + """Check that +[no]multi applies to a single lookup only.""" + lines = {} + for flags in [ + ("nomulti", "nomulti"), + ("multi", "nomulti"), + ("nomulti", "multi"), + ("multi", "multi"), + ]: + first, second = flags + result = dig(f"+tcp @{ns3.ip} -t DNSKEY example +{first} example +{second}") + assert check_ttl_range(result.out, "DNSKEY", 300) + lines[flags] = len(result.out.splitlines()) + assert lines[("multi", "multi")] >= lines[("nomulti", "multi")] + assert lines[("multi", "multi")] >= lines[("multi", "nomulti")] + assert lines[("nomulti", "multi")] >= lines[("nomulti", "nomulti")] + assert lines[("multi", "nomulti")] >= lines[("nomulti", "nomulti")] + + +def test_noheader_only(dig, ns3): + """Check that dig +noheader-only sends a full query.""" + result = dig(f"+tcp @{ns3.ip} +noheader-only A example") + assert "Got answer:" in result.out + assert check_ttl_range(result.out, "SOA", 300) + + +@pytest.mark.parametrize( + "class_type", + [ + param("", id="default"), + param("-c IN -t A", id="with-class-and-type"), + ], +) +def test_header_only(dig, ns3, class_type): + """Check that dig +header-only sends a query without a question.""" + result = dig(f"+tcp @{ns3.ip} +header-only {class_type} example") + assert Re(r"^;; flags: qr rd; QUERY: 0, ANSWER: 0,") in result.out + assert Re(r"^;; QUESTION SECTION:") not in result.out + + +@pytest.mark.parametrize( + "qname,ttl", + [ + param("weeks", "3w"), + param("days", "3d"), + param("hours", "3h"), + param("minutes", "45m"), + param("seconds", "45s"), + ], +) +def test_ttl_units(dig, ns2, qname, ttl): + """Check that dig +ttlunits prints TTLs in time units.""" + result = dig(f"+tcp @{ns2.ip} +ttlunits A {qname}.example") + assert Re(rf"^{qname}\.example\.\s+{ttl}\s") in result.out + + +@pytest.mark.parametrize( + "options,field", + [ + param("+ttlunits +nottlid", "IN", id="nottlid-wins"), + param("+nottlid +ttlunits", "3w", id="ttlunits-wins"), + param("+nottlid +nottlunits", "1814400", id="plain-seconds"), + ], +) +def test_ttl_units_precedence(dig, ns2, options, field): + """Check that the last of the +ttlid/+ttlunits options wins.""" + result = dig(f"+tcp @{ns2.ip} {options} A weeks.example") + assert Re(rf"^weeks\.example\.\s+{re.escape(field)}\s") in result.out + + +def test_class_chaos(dig, ns3): + """Check that dig -c CHAOS works.""" + result = dig(f"@{ns3.ip} -c CHAOS -t txt version.bind") + assert "version.bind.\t\t0\tCH\tTXT" in result.out + + +def test_bad_escape(dig, ns3): + """Check that dig gracefully rejects a bad escape in the domain name.""" + result = dig(rf"@{ns3.ip} \0.", raise_on_exception=False) + assert result.rc == 10 + assert "REQUIRE" not in result.err + assert "is not a legal name (bad escape)" in result.err + + +def test_q_m(dig, ns3): + """Check that -q -m treats -m as a query name, not as the memory + debugging flag.""" + result = dig(f"@{ns3.ip} -q -m", raise_on_exception=False) + assert Re(r"^;-m\..*IN.*A$") in result.out + assert "Dump of all outstanding memory allocations" not in result.out + + +@pytest.mark.parametrize( + "options,pattern", + [ + param( + "+expandaaaa", + r"ns2\.example.*fd92:7065:0b8e:ffff:0000:0000:0000:0002", + id="expandaaaa", + ), + param( + "+noexpandaaaa", r"ns2\.example.*fd92:7065:b8e:ffff::2", id="noexpandaaaa" + ), + param("", r"ns2\.example.*fd92:7065:b8e:ffff::2", id="default"), + param( + "+short +expandaaaa", + r"^fd92:7065:0b8e:ffff:0000:0000:0000:0002$", + id="short-expandaaaa", + ), + ], +) +def test_expandaaaa(dig, ns3, options, pattern): + """Check that +[no]expandaaaa controls AAAA address formatting + (the default is +noexpandaaaa).""" + result = dig(f"@{ns3.ip} {options} AAAA ns2.example") + assert Re(pattern) in result.out + + +def test_bufsize_zero(dig, ns3): + """Check that +bufsize=0 just sets the advertised buffer size to 0 + instead of disabling EDNS.""" + result = dig(f"@{ns3.ip} a.example +bufsize=0 +qr") + assert "EDNS:" in result.out + + +def test_bufsize_restores_default(dig, ns3): + """Check that a later +bufsize restores the default buffer size.""" + result = dig(f"@{ns3.ip} a.example +bufsize=0 +bufsize +qr") + assert len(result.out.grep(Re(r"EDNS:.* udp:"))) == 2 + assert len(result.out.grep(Re(r"EDNS:.* udp: 1232"))) == 2 + + +@pytest.mark.parametrize( + "options,unit", + [ + param("", "msec", id="msec"), + param("-u", "usec", id="usec"), + ], +) +def test_query_time_units(dig, ns3, options, unit): + """Check that Query time is in milliseconds, or in microseconds + with -u.""" + result = dig(f"{options} @{ns3.ip} a.example") + assert Re(rf";; Query time: \d+ {unit}") in result.out + + +@pytest.mark.parametrize( + "options,digits", + [ + param("+yaml", 3, id="msec"), + param("-u +yaml", 6, id="usec"), + ], +) +def test_yaml_timestamp_precision(dig, ns3, options, digits): + """Check that +yaml timestamps have millisecond precision, or + microsecond precision with -u.""" + result = dig(f"{options} @{ns3.ip} a.example") + for field in ("query_time", "response_time"): + pattern = ( + rf"{field}: !!timestamp \d{{4}}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{{{digits}}}Z" + ) + assert Re(pattern) in result.out + + +def test_local_reserved_warning(dig, ns3): + """Check that dig warns about .local queries.""" + result = dig(f"@{ns3.ip} local soa") + assert ";; WARNING: .local is reserved for Multicast DNS" in result.out + + +def test_nocrypto(dig, ns1): + """Check that +nocrypto omits the key and signature data.""" + alg_num = os.environ["DEFAULT_ALGORITHM_NUMBER"] + result = dig(f"+dnssec +norec +nocrypto DNSKEY . @{ns1.ip}") + assert Re(rf"256 \d+ {alg_num} \[key id = [1-9]\d*]") in result.out + assert Re(r"RRSIG.* \[omitted]") in result.out + result = dig(f"+norec +nocrypto DS example @{ns1.ip}") + assert Re(r"DS.* \d+ [12] \[omitted]") in result.out + + +def test_coflag(dig, ns3): + """Check that dig +coflag sets the EDNS CO flag in the sent query.""" + result = dig(f"+tcp @{ns3.ip} +coflag +qr example") + assert Re(r"^; EDNS: version: 0, flags: co;") in result.out + assert check_ttl_range(result.out, "SOA", 300) + + +def test_coflag_yaml(dig, ns3): + """Check that dig +coflag +yaml shows the CO flag in the sent query.""" + result = dig(f"+yaml +tcp @{ns3.ip} +coflag +qr example") + assert edns_yaml(result.out)["flags"] == "co" + + +@pytest.mark.parametrize( + "option,sent_flags", + [ + param("+raflag", "rd ra ad"), + param("+tcflag", "tc rd ad"), + ], +) +def test_header_flag_options(dig, ns3, option, sent_flags): + """Check that +raflag/+tcflag set the flag in the sent query and that + the response is unaffected.""" + result = dig(f"+tcp @{ns3.ip} {option} +qr example") + assert Re(rf"^;; flags: {sent_flags}; QUERY: 1, ANSWER: 0") in result.out + assert Re(r"^;; flags: qr rd ra; QUERY: 1, ANSWER: 0,") in result.out + assert check_ttl_range(result.out, "SOA", 300) + + +def test_zflag(dig, ns3): + """Check that dig +zflag sets the MBZ bit and that named ignores it.""" + result = dig(f"+tcp @{ns3.ip} +zflag +qr A example") + assert Re(r"^;; flags: rd ad; MBZ: 0x4;") in result.out + assert Re(r"^;; flags: qr rd ra; QUERY: 1") in result.out + assert check_ttl_range(result.out, "SOA", 300) + + +def test_ednsopt_08_no_insist(dig, ns3): + """Check that +qr +ednsopt=08 does not cause an INSIST failure.""" + result = dig(f"@{ns3.ip} +ednsopt=08 +qr a a.example") + assert "INSIST" not in result.out + assert "FORMERR" in result.out + + +@pytest.mark.parametrize( + "option", + [ + param("3", id="number"), + param("nsid", id="name"), + ], +) +def test_ednsopt_nsid(dig, ns3, option): + """Check that +ednsopt accepts an option number as well as a name.""" + result = dig(f"@{ns3.ip} +ednsopt={option} a.example") + assert Re(r'NSID: .* \("ns3"\)') in result.out + assert check_ttl_range(result.out, "A", 300) + + +def test_ednsopt_update_lease(dig, ns3): + """Check that a single-lease UPDATE-LEASE option prints as expected.""" + result = dig(f"@{ns3.ip} +ednsopt=UPDATE-LEASE:00000e10 +qr a.example") + assert "UPDATE-LEASE: 3600 (1 hour)" in result.out + + +def test_ednsopt_update_lease_yaml(dig, ns3): + """Check that a single-lease UPDATE-LEASE option prints as expected + with +yaml.""" + result = dig(f"@{ns3.ip} +yaml +ednsopt=UPDATE-LEASE:00000e10 +qr a.example") + assert edns_yaml(result.out)["UPDATE-LEASE"]["LEASE"] == 3600 + assert "LEASE: 3600 # 1 hour" in result.out + + +def test_ednsopt_update_lease_split(dig, ns3): + """Check that a split-lease UPDATE-LEASE option prints as expected.""" + result = dig(f"@{ns3.ip} +ednsopt=UPDATE-LEASE:00000e1000127500 +qr a.example") + assert "UPDATE-LEASE: 3600/1209600 (1 hour/2 weeks)" in result.out + + +def test_ednsopt_update_lease_split_yaml(dig, ns3): + """Check that a split-lease UPDATE-LEASE option prints as expected + with +yaml.""" + result = dig( + f"@{ns3.ip} +yaml +ednsopt=UPDATE-LEASE:00000e1000127500 +qr a.example" + ) + update_lease = edns_yaml(result.out)["UPDATE-LEASE"] + assert update_lease["LEASE"] == 3600 + assert update_lease["KEY-LEASE"] == 1209600 + assert "LEASE: 3600 # 1 hour" in result.out + assert "KEY-LEASE: 1209600 # 2 weeks" in result.out + + +def test_ednsopt_llq(dig, ns3): + """Check that the LLQ option prints as expected.""" + result = dig( + f"@{ns3.ip} +ednsopt=llq:0001000200001234567812345678fefefefe +qr a.example" + ) + pattern = ( + r"LLQ: Version: 1, Opcode: 2, Error: 0, " + r"Identifier: 1311768465173141112, Lifetime: 4278124286$" + ) + assert Re(pattern) in result.out + + +def test_ednsopt_llq_yaml(dig, ns3): + """Check that the LLQ option prints as expected with +yaml.""" + result = dig( + f"@{ns3.ip} +yaml +ednsopt=llq:0001000200001234567812345678fefefefe " + "+qr a.example" + ) + llq = edns_yaml(result.out)["LLQ"] + assert llq["LLQ-VERSION"] == 1 + assert llq["LLQ-OPCODE"] == 2 + assert llq["LLQ-ERROR"] == 0 + assert llq["LLQ-ID"] == 1311768465173141112 + assert llq["LLQ-LEASE"] == 4278124286 + + +def test_ednsopt_key_tag_empty(dig, ns3): + """Check that an empty key-tag option is sent and FORMERR is returned.""" + result = dig(f"@{ns3.ip} +ednsopt=key-tag a.example +qr") + assert Re(r"; KEY-TAG: *$") in result.out + assert "status: FORMERR" in result.out + + +def test_ednsopt_key_tag(dig, ns3): + """Check that a key-tag value list is sent and accepted.""" + result = dig(f"@{ns3.ip} +ednsopt=key-tag:00010002 a.example +qr") + assert Re(r"; KEY-TAG: 1, 2$") in result.out + assert "status: FORMERR" not in result.out + assert check_ttl_range(result.out, "A", 300) + + +def test_ednsopt_key_tag_yaml(dig, ns3): + """Check that a key-tag value list prints as a list with +yaml.""" + result = dig(f"@{ns3.ip} +yaml +ednsopt=key-tag:00010002 a.example +qr") + assert edns_yaml(result.out)["KEY-TAG"] == [1, 2] + + +def test_ednsopt_key_tag_malformed(dig, ns3): + """Check that a malformed key-tag value list is sent as raw data and + FORMERR is returned.""" + result = dig(f"@{ns3.ip} +ednsopt=key-tag:0001000201 a.example +qr") + assert "; KEY-TAG: 00 01 00 02 01" in result.out + assert "status: FORMERR" in result.out + + +@pytest.mark.parametrize("tag", ["client-tag", "server-tag"]) +def test_ednsopt_tag(dig, ns3, tag): + """Check that a valid client/server-tag value is sent and accepted.""" + result = dig(f"@{ns3.ip} +ednsopt={tag}:0001 a.example +qr") + assert Re(rf"; {tag.upper()}: 1$") in result.out + assert "status: FORMERR" not in result.out + + +@pytest.mark.parametrize("tag", ["client-tag", "server-tag"]) +def test_ednsopt_tag_yaml(dig, ns3, tag): + """Check that a client/server-tag value prints as expected with +yaml.""" + result = dig(f"@{ns3.ip} +yaml +ednsopt={tag}:0001 a.example +qr") + assert edns_yaml(result.out)[tag.upper()] == 1 + + +@pytest.mark.parametrize( + "value", + [ + param("01", id="too-short"), + param("000001", id="too-long"), + ], +) +@pytest.mark.parametrize("tag", ["client-tag", "server-tag"]) +def test_ednsopt_tag_bad_length(dig, ns3, tag, value): + """Check that FORMERR is returned for a client/server-tag value of the + wrong length.""" + result = dig(f"@{ns3.ip} +ednsopt={tag}:{value} a.example +qr") + assert f"; {tag.upper()}" in result.out + assert "status: FORMERR" in result.out + + +def test_ednsopt_chain(dig, ns3): + """Check that the CHAIN option prints special characters escaped.""" + result = dig(rf'@{ns3.ip} +ednsopt=chain:02002200 a.\000" +qr') + assert r'; CHAIN: "\000\""' in result.out + + +def test_ednsopt_chain_yaml(dig, ns3): + """Check that the CHAIN option prints special characters escaped + with +yaml.""" + result = dig(rf'@{ns3.ip} +yaml +ednsopt=chain:02002200 a.\000" +qr') + assert edns_yaml(result.out)["CHAIN"] == r"\000\"" + + +def test_expire(dig, ns1): + """Check that dig processes +expire.""" + result = dig(f"@{ns1.ip} +expire . soa") + assert "; EXPIRE: 1200 (20 minutes)" in result.out + + +def test_expire_yaml(dig, ns1): + """Check that dig processes +expire with +yaml.""" + result = dig(f"@{ns1.ip} +yaml +expire . soa") + assert edns_yaml(result.out, "response")["EXPIRE"] == 1200 + assert "EXPIRE: 1200 # 20 minutes" in result.out + + +def test_keepalive(dig, ns1): + """Check that dig processes +keepalive.""" + result = dig(f"@{ns1.ip} +keepalive . soa +tcp") + assert "; TCP-KEEPALIVE: 30.0 secs" in result.out + + +def test_keepalive_yaml(dig, ns1): + """Check that dig processes +keepalive with +yaml.""" + result = dig(f"@{ns1.ip} +yaml +keepalive . soa +tcp") + assert edns_yaml(result.out, "response")["TCP-KEEPALIVE"] == "30.0 secs" + + +@pytest.mark.parametrize( + "payload,expected", + [ + param("ede:0000666f6f", "; EDE: 0 (Other): (foo)", id="first-defined-code"), + param("ede:0018", "; EDE: 24 (Invalid Data)", id="last-defined-code"), + param("ede:0019666f6f", "; EDE: 25: (foo)", id="undefined-code"), + param("ede", "; EDE:", id="empty"), + param("ede:00", '; EDE: 00 (".")', id="too-short"), + ], +) +def test_ednsopt_ede(dig, ns3, payload, expected): + """Check that Extended DNS Error options, including invalid ones with + a too short payload, are printed correctly.""" + result = dig(f"@{ns3.ip} +ednsopt={payload} a.example +qr") + assert Re("^" + re.escape(expected) + "$") in result.out + + +@pytest.mark.parametrize( + "payload,info_code,extra_text", + [ + param("ede:0000666f6f", "0 (Other)", "foo", id="first-defined-code"), + param("ede:0018", "24 (Invalid Data)", None, id="last-defined-code"), + param("ede:0019666f6f", 25, "foo", id="undefined-code"), + ], +) +def test_ednsopt_ede_yaml(dig, ns3, payload, info_code, extra_text): + """Check that Extended DNS Error options are printed correctly + with +yaml.""" + result = dig(f"@{ns3.ip} +yaml +ednsopt={payload} a.example +qr") + ede = edns_yaml(result.out)["EDE"] + assert ede["INFO-CODE"] == info_code + if extra_text is None: + assert "EXTRA-TEXT" not in ede + else: + assert ede["EXTRA-TEXT"] == extra_text + + +def test_ednsopt_ede_yaml_specials(dig, ns3): + """Check that EDE extra text with '"' and '\\' specials survives YAML + quoting.""" + result = dig(f"@{ns3.ip} +yaml +ednsopt=ede:0000666f6f225c a.example +qr") + assert edns_yaml(result.out)["EDE"]["EXTRA-TEXT"] == 'foo"\\' + + +@pytest.mark.parametrize( + "payload,expected", + [ + param("ede", None, id="empty"), + param("ede:00", '00 (".")', id="too-short"), + ], +) +def test_ednsopt_ede_yaml_invalid(dig, ns3, payload, expected): + """Check that invalid Extended DNS Error options with a too short + payload are printed correctly with +yaml.""" + result = dig(f"@{ns3.ip} +yaml +ednsopt={payload} a.example +qr") + assert edns_yaml(result.out)["EDE"] == expected + + +def test_ednsopt_malformed(dig, ns3): + """Check that dig handles the malformed option '+ednsopt=:' + gracefully.""" + result = dig(f"@{ns3.ip} +ednsopt=: a.example", raise_on_exception=False) + assert result.rc != 0 + assert "ednsopt no code point specified" in result.err + + +def test_ednsflags_reenables_edns(dig, ns3): + """Check that +noedns +ednsflags= re-enables EDNS.""" + result = dig(f"@{ns3.ip} +qr +noedns +ednsflags=0x70 a.example") + assert "; EDNS: version: 0, flags:; MBZ: 0x0070, udp: 1232" in result.out + assert "; EDNS: version: 0, flags:; udp: 1232" in result.out + + +def test_showbadvers(dig, ns3): + """Check that +showbadvers displays the BADVERS response as well as + the retry without EDNS version 1.""" + result = dig(f"@{ns3.ip} +edns=1 +qr +showbadvers a.example") + assert "; EDNS: version: 1, flags:; udp: 1232" in result.out + assert "; EDNS: version: 0, flags:; udp: 1232" in result.out + assert "status: BADVERS" in result.out + assert "status: NOERROR" in result.out + + +def test_subnet(dig, ns2): + """Check that dig +subnet sends the client subnet.""" + result = dig(f"+tcp @{ns2.ip} +subnet=127.0.0.1 A a.example") + assert "CLIENT-SUBNET: 127.0.0.1/32/0" in result.out + assert check_ttl_range(result.out, "A", 300) + + +def test_subnet_last_wins(dig, ns2): + """Check that the last of multiple +subnet options wins.""" + result = dig(f"+tcp @{ns2.ip} +subnet=127.0.0.0 +subnet=127.0.0.1 A a.example") + assert "CLIENT-SUBNET: 127.0.0.1/32/0" in result.out + assert check_ttl_range(result.out, "A", 300) + + +@pytest.mark.parametrize("plen", range(1, 25)) +def test_subnet_prefix_lengths(dig, ns2, plen): + """Check that dig +subnet masks the address to various prefix + lengths.""" + result = dig(f"+tcp @{ns2.ip} +subnet=255.255.255.255/{plen} A a.example") + addr = ipaddress.ip_address((0xFFFFFFFF << (32 - plen)) & 0xFFFFFFFF) + assert "FORMERR" not in result.out + assert f"CLIENT-SUBNET: {addr}/{plen}/0" in result.out + assert check_ttl_range(result.out, "A", 300) + + +@pytest.mark.parametrize("plen", range(9, 16)) +def test_subnet_prefix_between_byte_boundaries(dig, ns2, plen): + """Check dig +subnet with prefix lengths between byte boundaries.""" + result = dig(f"+tcp @{ns2.ip} +subnet=10.53/{plen} A a.example") + assert "FORMERR" not in result.out + assert Re(rf"CLIENT-SUBNET.*/{plen}/0") in result.out + assert check_ttl_range(result.out, "A", 300) + + +ZERO_SUBNETS = [ + param("+subnet=0/0", "0.0.0.0/0/0"), + param("+subnet=0", "0.0.0.0/0/0"), + param("+subnet=::/0", "::/0/0"), +] + + +@pytest.mark.parametrize("option,subnet", ZERO_SUBNETS) +def test_subnet_zero(dig, ns2, option, subnet): + """Check that a zero-length client subnet is sent and answered.""" + result = dig(f"+tcp @{ns2.ip} {option} A a.example") + assert "status: NOERROR" in result.out + assert f"CLIENT-SUBNET: {subnet}" in result.out + assert "10.0.0.1" in result.out + assert check_ttl_range(result.out, "A", 300) + + +@pytest.mark.parametrize("option,subnet", ZERO_SUBNETS) +def test_subnet_zero_yaml(dig, ns2, option, subnet): + """Check that a zero-length client subnet is echoed in the +yaml + response.""" + result = dig(f"+yaml +tcp @{ns2.ip} {option} A a.example") + assert edns_yaml(result.out, "response")["CLIENT-SUBNET"] == subnet + + +def test_subnet_yaml(dig, ns2): + """Check that +subnet=dead::/16 is shown in the +yaml query.""" + result = dig(f"+yaml +tcp @{ns2.ip} +qr +subnet=dead::/16 A a.example") + assert edns_yaml(result.out)["CLIENT-SUBNET"] == "dead::/16/0" + + +def test_subnet_raw_zero(dig, ns2): + """Check that a raw zero-length ECS option (family 0, source 0, + scope 0) is rejected by the server with FORMERR.""" + result = dig(f"+tcp @{ns2.ip} +ednsopt=8:00000000 A a.example") + assert "status: FORMERR" in result.out + assert "CLIENT-SUBNET" not in result.out + + +def test_subnet_raw_unknown_family(dig, ns2): + """Check that a raw ECS option with an unknown family (3) is sent + as-is and rejected by the server with FORMERR.""" + result = dig(f"+qr +tcp @{ns2.ip} +ednsopt=8:00030000 A a.example") + assert "status: FORMERR" in result.out + assert len(result.out.grep("CLIENT-SUBNET: 00 03 00 00")) == 1 + + +def test_origin_preserved_on_tcp_retries(dig, ans4): + """Check that dig preserves the search origin when retrying over + TCP.""" + result = dig( + f"-d +tcp @{ans4.ip} +retry=1 +time=1 +domain=bar foo", + raise_on_exception=False, + ) + assert result.rc != 0 + assert len(result.err.grep("trying origin bar")) == 2 + assert "using root origin" not in result.err + + +def test_4_and_6_mutually_exclusive(dig, ns2): + """Check that dig rejects -4 combined with -6.""" + result = dig(f"+tcp @{ns2.ip} -4 -6 A a.example", raise_on_exception=False) + assert result.rc != 0 + assert "only one of -4 and -6 allowed" in result.err + + +@isctest.mark.with_ipv6 +def test_ipv6_server_with_ipv4_only(dig): + """Check that dig -4 rejects an IPv6 server address.""" + result = dig("+tcp @fd92:7065:b8e:ffff::2 -4 A a.example", raise_on_exception=False) + assert result.rc != 0 + assert "address family not supported" in result.err + + +@isctest.mark.with_ipv6 +@pytest.mark.parametrize("option", ["+tcp", "+notcp"]) +def test_ipv4_server_with_ipv6_only(dig, ns2, option): + """Check that dig -6 does not use a mapped form of an IPv4 server + address.""" + result = dig(f"{option} @{ns2.ip} -6 A a.example") + assert f"SERVER: ::ffff:{ns2.ip}#" not in result.out + + +@pytest.fixture(name="set_response_sequence") +def set_response_sequence_fixture(dig, ans5): + """Arm the sequence of AXFR responses served by ans5.""" + + def _set(sequence): + dig(f"@{ans5.ip} {sequence}.response-sequence._control TXT") + + return _set + + +@pytest.mark.parametrize( + "sequence,tries,expect_failure,eof_errors", + [ + param("no-response", 2, True, 2, id="immediate-immediate"), + param("partial-axfr", 2, True, 2, id="partial-partial"), + param("no-response.partial-axfr", 2, True, 2, id="immediate-partial"), + param("partial-axfr.no-response", 2, True, 2, id="partial-immediate"), + param("no-response.complete-axfr", 2, False, 1, id="immediate-complete"), + param("partial-axfr.complete-axfr", 2, False, 1, id="partial-complete"), + param("no-response", 1, True, 1, id="tries-1-no-second-retry"), + ], +) +def test_axfr_retry_upon_tcp_eof( + dig, ans5, set_response_sequence, sequence, tries, expect_failure, eof_errors +): + """Check the exit code and the number of retries for an AXFR retried + upon TCP EOF.""" + set_response_sequence(sequence) + result = dig(f"@{ans5.ip} example AXFR +tries={tries}", raise_on_exception=False) + assert (result.rc != 0) == expect_failure + # Sanity check: ensure ans5 behaves as expected. + eof_pattern = Re("communications error.*end of file") + assert len(result.out.grep(eof_pattern)) == eof_errors + + +def test_axfr_no_retry_with_retry_0(dig, ans5, set_response_sequence): + """Check that +retry=0 does not retry upon TCP EOF.""" + set_response_sequence("no-response") + result = dig(f"@{ans5.ip} example AXFR +retry=0", raise_on_exception=False) + assert result.rc != 0 + # Sanity check: ensure ans5 behaves as expected. + eof_pattern = Re("communications error.*end of file") + assert len(result.out.grep(eof_pattern)) == 1 + + +@pytest.mark.parametrize( + "option", + [ + param("", id="udp"), + param("+tcp", id="tcp"), + ], +) +def test_timeout_then_servfail(dig, ans7, option): + """Check that dig handles a timeout followed by a SERVFAIL + correctly. See GL #3020 for more information.""" + result = dig(f"+timeout=1 +nofail {option} @{ans7.ip} silent-then-servfail.example") + assert "status: SERVFAIL" in result.out + + +def test_comments_retry_comment(dig, ans7): + """Check that dig +comments emits the retry comment.""" + result = dig( + f"+timeout=1 +nofail +comments @{ans7.ip} silent-then-servfail.example" + ) + assert ";; Got SERVFAIL reply from" in result.out + + +def test_short_comments_suppresses_retry_comment(dig, ans7): + """Check that dig +short +comments does not leak the ";; " comments + into the short-form output. +short normally turns comments off, but + "+short +comments" re-enables them while short form is still in + effect; the comment output then belongs to the verbose form and + would corrupt the short output.""" + result = dig( + f"+timeout=1 +nofail +short +comments @{ans7.ip} silent-then-servfail.example" + ) + assert ";; Got SERVFAIL reply from" not in result.out + + +ERROR_PATTERN = Re("connection refused|timed out|network unreachable|host unreachable") + + +@pytest.mark.parametrize( + "option", + [ + param("", id="udp"), + param("+tcp", id="tcp"), + ], +) +def test_next_server_after_network_unreachable(dig, ns3, option): + """Check that dig tries the next server after a socket network + unreachable error.""" + result = dig(f"{option} @192.0.2.128 @{ns3.ip} a.example") + assert len(result.out.grep(ERROR_PATTERN)) == 3 + assert "status: NOERROR" in result.out + + +def test_next_server_after_udp_read_error(dig, ns3): + """Check that dig tries the next server after a UDP socket read + error.""" + result = dig(f"@10.53.0.99 @{ns3.ip} a.example") + assert "status: NOERROR" in result.out + + +def test_next_server_after_tcp_read_error(dig, ans7, ns3): + """Check that dig tries the next server after a TCP socket read + error.""" + result = dig(f"+tcp @{ans7.ip} @{ns3.ip} close.example") + assert "status: NOERROR" in result.out + + +def test_next_server_after_tcp_connection_error(dig, ns3): + """Check that dig tries the next server after a TCP socket connection + error/timeout. The connection error and timeout cases are combined, + because it is not trivial to simulate the timeout case in a system + test in Linux without a firewall, but the code which handles error + cases during connection establishment does not differentiate between + timeout and other types of errors (unlike during reading), so this + one check should be sufficient for both cases.""" + result = dig(f"+tcp @10.53.0.99 @{ns3.ip} a.example") + assert len(result.out.grep(ERROR_PATTERN)) == 3 + assert "status: NOERROR" in result.out + + +@pytest.mark.parametrize( + "option", + [ + param("", id="udp"), + param("+tcp", id="tcp"), + ], +) +def test_next_server_after_read_timeout(dig, ans7, ns3, option): + """Check that dig tries the next server after socket read timeouts.""" + result = dig(f"+timeout=1 {option} @{ans7.ip} @{ns3.ip} silent.example") + assert "status: NOERROR" in result.out + + +def test_mapped_ipv6_server_refused(dig, ans7): + """Check that dig refuses to use a server with an IPv4-mapped IPv6 + address after failing with the regular IP address. See GL #3248 + for more information.""" + result = dig(f"@{ans7.ip} @::ffff:{ans7.ip} silent.example") + assert ";; Skipping mapped address" in result.out + assert ";; No acceptable nameservers" in result.out + + +def test_qr_and_y_with_failed_query(dig, ns3): + """Check that dig handles printing query information with +qr and +y + when multiple queries are involved, including a failed one. See + GL #3244 for more information.""" + result = dig(f"+timeout=1 +qr +y @127.0.0.1 @{ns3.ip} a.example") + assert "IN A 10.0.0.1" in result.out + + +def test_startup_banner_default(dig, ans7): + """Check that dig prints the startup banner by default, including on + the error path. This makes the absence check with +nocmd + meaningful.""" + result = dig( + f"silent.example @{ans7.ip} +notcp +timeout=1 +tries=1", + raise_on_exception=False, + ) + assert result.rc != 0 + assert "<<>> DiG" in result.out + assert "no servers could be reached" in result.out + + +def test_nocmd_after_query_name(dig, ans7): + """Check that +nocmd placed after the query name suppresses the + startup banner, including on the error path. This regressed because + the banner was built as soon as the query name was seen, before + +nocmd had been parsed.""" + result = dig( + f"silent.example @{ans7.ip} +notcp +timeout=1 +tries=1 +nocmd", + raise_on_exception=False, + ) + assert result.rc != 0 + assert "<<>> DiG" not in result.out + assert "no servers could be reached" in result.out + + +def test_yaml_valid_when_no_server_reached(dig, ans7): + """Check that dig +yaml produces valid YAML when no servers could be + reached; the ";"-prefixed startup banner must not precede the + DIG_ERROR block. The query name is deliberately placed before +yaml + on the command line: that is what makes dig build the banner (while + +cmd is still in effect) before switching to YAML output, which is + the ordering that regressed.""" + result = dig( + f"silent.example @{ans7.ip} +notcp +timeout=1 +tries=1 +yaml", + raise_on_exception=False, + ) + assert result.rc != 0 + assert parse_yaml(result.out)[0]["type"] == "DIG_ERROR" + + +@isctest.mark.with_ipv6 +def test_source_address_both_families_no_crash(dig, ns1): + """Check that dig with an IPv4 source address and a server with both + IPv4 and IPv6 addresses does not crash. @localhost is not really + expected to have an answer for the query; only a crash (termination + by a signal) is an error. Without IPv6, @localhost resolves to the + IPv4 address only and the address-family mismatch under test never + happens. See GL #5609 for more information.""" + result = dig(f"@localhost example -b {ns1.ip}", raise_on_exception=False) + assert result.rc >= 0 + + +def test_yaml_any_output(dig, ns3): + """Check the structure of dig +yaml output for an ANY query.""" + result = dig(f"+qr +yaml @{ns3.ip} any ns2.example") + messages = parse_yaml(result.out) + query = messages[0]["message"]["query_message_data"] + assert query["status"] == "NOERROR" + response = messages[1]["message"]["response_message_data"] + assert response["status"] == "NOERROR" + assert response["QUESTION_SECTION"][0] == "ns2.example. IN ANY" + + +def test_yaml_ipv6_trailing_zeroes(dig, ns3): + """Check dig +yaml output of an IPv6 address ending in zeroes.""" + result = dig(f"+qr +yaml @{ns3.ip} aaaa d.example") + response = parse_yaml(result.out)[1]["message"]["response_message_data"] + answer = response["ANSWER_SECTION"][0] + assert answer == "d.example. 300 IN AAAA fd92:7065:b8e:ffff::0" + + +@pytest.mark.parametrize( + "qname", ["yaml", "'.yaml", "[.yaml", "{.yaml", "&.yaml", "#.yaml"] +) +def test_yaml_special_characters_in_qname(dig, ns3, qname): + """Check that qnames containing characters special to YAML are quoted + correctly in dig +yaml output.""" + result = dig(f"@{ns3.ip} +yaml {qname}.example TXT +qr") + query = parse_yaml(result.out)[0]["message"]["query_message_data"] + question = query["QUESTION_SECTION"][0] + assert question == f"{qname}.example. IN TXT" + response = parse_yaml(result.out)[1]["message"]["response_message_data"] + answer = response["ANSWER_SECTION"][0] + assert answer == f'{qname}.example. 300 IN TXT "a: b"' + + +def test_yaml_character_values(dig, ns3): + """Check the quoting of all 256 character values in dig +yaml TXT + output.""" + + def quoted(i): + char = chr(i) + if char in ('"', "\\"): + return f'"\\{char}"' + if 32 <= i <= 126: + return f'"{char}"' + return f'"\\{i:03d}"' + + result = dig(f"@{ns3.ip} +yaml all.yaml.example TXT +qr") + response = parse_yaml(result.out)[1]["message"]["response_message_data"] + answer = response["ANSWER_SECTION"][0] + strings = " ".join(quoted(i) for i in range(256)) + assert answer == f"all.yaml.example. 300 IN TXT {strings}" diff -Nru bind9-9.20.26/bin/tests/system/digdelv/tests_digdelv_delv.py bind9-9.20.29/bin/tests/system/digdelv/tests_digdelv_delv.py --- bind9-9.20.26/bin/tests/system/digdelv/tests_digdelv_delv.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/tests_digdelv_delv.py 2026-09-11 19:41:01.159322790 +0000 @@ -0,0 +1,321 @@ +# 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. + +""" +Tests for the delv tool. +""" + +from re import compile as Re + +import re + +import pytest + +from digdelv.common import ARTIFACTS, check_ttl_range, parse_yaml +from isctest.util import param + +import isctest +import isctest.mark + +pytestmark = [ + pytest.mark.extra_artifacts(ARTIFACTS), +] + + +@pytest.fixture(name="delv") +def delv_fixture(named_port): + # use delv insecure mode by default, as we're mostly not testing dnssec + return isctest.run.EnvCmd("DELV", f"+noroot -p {named_port}") + + +@pytest.mark.parametrize("option", ["+short", "+sh"]) +def test_short(delv, ns3, option): + """Check that delv +short (and its +sh abbreviation) returns a + single-line answer.""" + result = delv(f"@{ns3.ip} {option} a a.example") + assert len(result.out.splitlines()) == 1 + + +@pytest.mark.parametrize("option", ["+split=4", "+sp=4"]) +def test_split_width(delv, ns3, option): + """Check that delv +split (and its +sp abbreviation) splits hex data + into fields of the requested width.""" + result = delv(f"@{ns3.ip} {option} -t sshfp foo.example") + assert " 9ABC DEF6 7890 " in result.out + assert check_ttl_range(result.out, "SSHFP", 300) + + +def test_unknownformat(delv, ns3): + """Check that delv +unknownformat prints RFC 3597 format.""" + result = delv(f"@{ns3.ip} +unknownformat a a.example") + assert Re(r"CLASS1\s+TYPE1\s+\\# 4 0A000001") in result.out + assert check_ttl_range(result.out, "TYPE1", 300) + + +def test_4_and_6_mutually_exclusive(delv, ns3): + """Check that delv rejects -4 combined with -6.""" + result = delv(f"@{ns3.ip} -4 -6 A a.example", raise_on_exception=False) + assert result.rc != 0 + assert "only one of -4 and -6 allowed" in result.err + + +def test_malformed_query_name(delv, ns3): + """Check that delv exits cleanly on a malformed query name instead of + aborting in the dns_client_detach(NULL) cleanup path.""" + longlabel = "a" * 64 + result = delv(f"@{ns3.ip} -t a {longlabel}.example.com", raise_on_exception=False) + assert result.rc >= 0 + assert "label too long" in result.err + + +@isctest.mark.with_ipv6 +@pytest.mark.parametrize( + "server_args,message", + [ + param( + "@fd92:7065:b8e:ffff::3 @{ns3} -6", + "Use of IPv4 disabled by -6", + id="ipv4-server-with-6", + ), + param( + "@{ns3} @fd92:7065:b8e:ffff::3 -4", + "Use of IPv6 disabled by -4", + id="ipv6-server-with-4", + ), + ], +) +def test_address_family_mismatch(delv, ns3, server_args, message): + """Check that the last @server option overrides earlier ones and that + the forced address family makes such a lookup fail.""" + result = delv( + server_args.format(ns3=ns3.ip) + " -t txt foo.example", + raise_on_exception=False, + ) + assert result.rc != 0 + # it should have no results but error output + assert "testing" not in result.out + assert message in result.err + + +def test_reverse_lookup(delv, ns3): + """Check that delv -x works.""" + result = delv(f"@{ns3.ip} -x 127.0.0.1") + # doesn't matter if has answer + assert Re(r"127\.in-addr\.arpa\.", re.IGNORECASE) in result.out + assert check_ttl_range(result.out, r"\-ANY", 10800) + + +def test_tcp(delv, ns3): + """Check that delv over TCP works.""" + result = delv(f"+tcp @{ns3.ip} a a.example") + assert Re(r"10\.0\.0\.1$") in result.out + assert check_ttl_range(result.out, "A", 300) + + +@pytest.mark.parametrize( + "args,expect_rrcomment,ttl_rrtype", + [ + param( + "+multi +norrcomments DNSKEY example", + False, + "DNSKEY", + id="multi-norrcomments-dnskey", + ), + param( + "+multi +norrcomments SOA example", + False, + "SOA", + id="multi-norrcomments-soa", + ), + param("+rrcomments DNSKEY example", True, "DNSKEY", id="rrcomments"), + param("+short +rrcomments DNSKEY example", True, None, id="short-rrcomments"), + ], +) +def test_rrcomments(delv, ns3, zsk, args, expect_rrcomment, ttl_rrtype): + """Check that +[no]rrcomments controls the DNSKEY comment + (the default is rrcomments, even with +multi).""" + result = delv(f"+tcp @{ns3.ip} {args}") + assert (zsk.rrcomment in result.out) == expect_rrcomment + if ttl_rrtype: + assert check_ttl_range(result.out, ttl_rrtype, 300) + + +def test_short_rrcomments_line(delv, ns3, zsk): + """Check the exact delv +short +rrcomments output line.""" + result = delv(f"+tcp @{ns3.ip} +short +rrcomments DNSKEY example") + assert f"{zsk.keydata} {zsk.rrcomment}" in result.out + + +def test_short_nosplit(delv, ns3, zsk): + """Check that delv +short +nosplit does not split the key data.""" + result = delv(f"+tcp @{ns3.ip} +short +nosplit DNSKEY example") + assert zsk.keydata.replace(" ", "") in result.out + assert len(result.out.splitlines()) == 1 + assert len(result.out.split()) == 14 + + +def test_short_nosplit_norrcomments(delv, ns3, zsk): + """Check that delv +short +nosplit +norrcomments prints the bare + unsplit rdata.""" + result = delv(f"+tcp @{ns3.ip} +short +nosplit +norrcomments DNSKEY example") + nosplit = zsk.keydata.replace(" ", "") + assert Re(re.escape(nosplit) + "$") in result.out + assert len(result.out.splitlines()) == 1 + assert len(result.out.split()) == 4 + + +@pytest.mark.parametrize( + "qclass", + [ + param("IN", id="in"), + param("CH", id="ch-ignored"), + ], +) +def test_class_option(delv, ns3, qclass): + """Check that delv -c IN works and that -c CH is ignored and treated + like IN.""" + result = delv(f"@{ns3.ip} -c {qclass} -t a a.example") + assert "a.example." in result.out + assert check_ttl_range(result.out, "A", 300) + + +def test_q_m(delv, ns3): + """Check that -q -m treats -m as a query name, not as the memory + debugging flag.""" + result = delv(f"@{ns3.ip} -q -m") + assert Re(r"^; -m\..*\d*.*IN.*ANY.*;") in result.out + for stream in (result.out, result.err): + assert Re(r"^add ") not in stream + assert Re(r"^del ") not in stream + assert check_ttl_range(result.out, r"\-ANY", 300) + + +def test_any_query(delv, ns3): + """Check that delv -t ANY works.""" + result = delv(f"@{ns3.ip} -t ANY example") + assert Re(r"^example\.") in result.out + assert check_ttl_range(result.out, "NS", 300) + assert check_ttl_range(result.out, "SOA", 300) + + +@pytest.mark.parametrize( + "anchor", + [ + param("anchor.dnskey", id="key-style"), + param("anchor.ds", id="ds-style"), + ], +) +def test_trust_anchors(delv, ns3, anchor): + """Check that delv loads key-style and DS-style trust anchors and + validates with them.""" + result = delv(f"-a ns3/{anchor} +root=example @{ns3.ip} -t DNSKEY example") + assert "fully validated" in result.out + + +def test_refused_chasing_ds(delv, ns2): + """Check that delv handles REFUSED when chasing DS records.""" + result = delv(f"@{ns2.ip} +root xxx.example.tld A") + assert ";; resolution failed: broken trust chain" in result.err + + +def test_yaml_any(delv, ns3): + """Check the structure of delv +yaml output.""" + result = delv(f"+yaml @{ns3.ip} any ns2.example") + data = parse_yaml(result.out) + assert data["status"] == "success" + assert data["query_name"] == "ns2.example" + answer = data["records"][0]["answer_not_validated"][0] + assert len(str(answer).split()) == 5 + + +@pytest.mark.parametrize( + "qtype,qname,status", + [ + param("type500", "ns2.example", "ncache nxrrset", id="nodata"), + param("a", "this-does-not-exist.ns2.example", "ncache nxdomain", id="nxdomain"), + ], +) +def test_yaml_negative(delv, ns3, qtype, qname, status): + """Check the structure of delv +yaml output for negative responses.""" + result = delv(f"+yaml @{ns3.ip} {qtype} {qname}") + data = parse_yaml(result.out) + assert data["status"] == status + assert data["query_name"] == qname + answer = data["records"][0]["negative_response_answer_not_validated"][0] + assert len(str(answer).split()) == 5 + + +@pytest.mark.usefixtures("ns1") +def test_ns_output(delv): + """Check the NS records in delv +ns output.""" + result = delv( + "-i +ns +nortrace +nostrace +nomtrace +novtrace +hint=root.hint ns example" + ) + ns_lines = [ + fields + for fields in (line.split() for line in result.out.splitlines()) + if len(fields) >= 4 and fields[0] == "example." and fields[3] == "NS" + ] + assert len(ns_lines) == 2 + + +@pytest.mark.parametrize( + "args,marker,expect_no_qmin_labels", + [ + param( + "-i +ns +hint=root.hint", + "; authoritative", + True, + id="no-validation", + ), + param( + "-i +ns +qmin +hint=root.hint", + "; authoritative", + False, + id="no-validation-qmin", + ), + param( + "-a ns1/anchor.dnskey +root +ns +hint=root.hint", + "; fully validated", + True, + id="validation", + ), + param( + "-a ns1/anchor.dnskey +root +ns +qmin +hint=root.hint", + "; fully validated", + False, + id="validation-qmin", + ), + ], +) +@pytest.mark.usefixtures("ns1") +def test_ns_lookup(delv, args, marker, expect_no_qmin_labels): + """Check delv +ns lookups with and without validation and query name + minimization.""" + result = delv(f"{args} a a.example") + assert marker in result.out + if expect_no_qmin_labels: + assert "_.example" not in result.out + + +@isctest.mark.with_ipv6 +@pytest.mark.parametrize("family", ["-4", "-6"]) +@pytest.mark.usefixtures("ns1") +def test_ns_address_family(delv, family): + """Check that delv +ns with -4/-6 uses only the selected address + family.""" + ipv4_packet = "sending packet to 10.53" + ipv6_packet = "sending packet to fd92:7065" + result = delv( + f"-a ns1/anchor.dnskey +root {family} +ns +hint=root.hint a a.example" + ) + assert (ipv4_packet in result.out) == (family == "-4") + assert (ipv6_packet in result.out) == (family == "-6") diff -Nru bind9-9.20.26/bin/tests/system/digdelv/tests_mdig.py bind9-9.20.29/bin/tests/system/digdelv/tests_mdig.py --- bind9-9.20.26/bin/tests/system/digdelv/tests_mdig.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/tests_mdig.py 2026-09-11 19:41:01.159322790 +0000 @@ -0,0 +1,82 @@ +# 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. + +""" +Tests for the mdig tool. +""" + +import os + +import pytest + +from digdelv.common import ARTIFACTS, parse_yaml + +import isctest + +pytestmark = [ + pytest.mark.extra_artifacts(ARTIFACTS), +] + + +@pytest.fixture(name="mdig") +def mdig_fixture(named_port): + return isctest.run.EnvCmd("MDIG", f"-p {named_port}") + + +def test_tcp_with_source_address_and_port(mdig, ns3): + """Check that mdig +tcp works with a source address and port. When + running more than once in quick succession with a source + address#port, the query can fail with "response failed with address + not available" because the address#port is still busy; that error is + not interesting, only the unexpected error case is. See GL #4969 + for more information.""" + extraport8 = os.environ["EXTRAPORT8"] + result = mdig( + f"-b {ns3.ip}#{extraport8} +tcp @{ns3.ip} example", raise_on_exception=False + ) + assert "unexpected error" not in result.out + assert "unexpected error" not in result.err + + +def test_ednsopt_malformed(mdig, ns3): + """Check that mdig handles the malformed option '+ednsopt=:' + gracefully.""" + result = mdig(f"@{ns3.ip} +ednsopt=: a.example", raise_on_exception=False) + assert result.rc != 0 + assert "ednsopt no code point specified" in result.err + + +def test_ednsopt_ednsopts(mdig, ns3): + """Check that mdig handles multiple queries with ednsopts.""" + result = mdig(f"@{ns3.ip} +ednsopt=100:00 a.example b.example") + assert result.rc == 0 + + +def test_dnskey_norrcomments(mdig, ns3, zsk): + """Check that +multi +norrcomments suppresses the DNSKEY comment + (the default is rrcomments).""" + result = mdig(f"+tcp @{ns3.ip} +multi +norrcomments -t DNSKEY example") + assert zsk.rrcomment not in result.out + + +def test_soa_norrcomments(mdig, ns3): + """Check that +multi +norrcomments suppresses the SOA field + comments.""" + result = mdig(f"+tcp @{ns3.ip} +multi +norrcomments -t SOA example") + assert "; serial" not in result.out + + +def test_yaml_output(mdig, ns3): + """Check the structure of mdig +yaml output.""" + result = mdig(f"+yaml @{ns3.ip} -t any ns2.example") + response = parse_yaml(result.out)[0]["message"]["response_message_data"] + assert response["status"] == "NOERROR" + assert response["QUESTION_SECTION"][0] == "ns2.example. IN ANY" diff -Nru bind9-9.20.26/bin/tests/system/digdelv/tests_others.py bind9-9.20.29/bin/tests/system/digdelv/tests_others.py --- bind9-9.20.26/bin/tests/system/digdelv/tests_others.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/tests_others.py 2026-09-11 19:41:01.159322790 +0000 @@ -0,0 +1,59 @@ +# 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. + +""" +Tests for the look-up tools other than dig, delv and mdig: nslookup, +host and nsupdate. +""" + +from textwrap import dedent + +import pytest + +from digdelv.common import ARTIFACTS + +import isctest + +pytestmark = pytest.mark.extra_artifacts(ARTIFACTS) + + +def test_nslookup_update_response(named_port, ans6): + """Check that nslookup rejects a response with the UPDATE opcode.""" + nslookup = isctest.run.EnvCmd("NSLOOKUP") + result = nslookup( + f"-port={named_port} -q=CNAME -timeout=1 foo.bar {ans6.ip}", + raise_on_exception=False, + ) + assert result.rc != 0 + assert "Opcode mismatch" in result.out + + +def test_host_update_response(named_port, ans6): + """Check that host rejects a response with the UPDATE opcode.""" + host = isctest.run.EnvCmd("HOST") + result = host( + f"-p {named_port} -W 1 -t CNAME foo.bar {ans6.ip}", raise_on_exception=False + ) + assert result.rc != 0 + assert "Opcode mismatch" in result.out + + +def test_nsupdate_update_response(named_port, ans6): + """Check that nsupdate rejects an UPDATE response to its SOA query.""" + nsupdate = isctest.run.EnvCmd("NSUPDATE") + commands = dedent(f"""\ + server {ans6.ip} {named_port} + add x.example.com 300 in a 1.2.3.4 + send + """) + result = nsupdate("", input_text=commands.encode(), raise_on_exception=False) + assert result.rc == 1 + assert "invalid OPCODE in response to SOA query" in result.err diff -Nru bind9-9.20.26/bin/tests/system/digdelv/tests_sh_digdelv.py bind9-9.20.29/bin/tests/system/digdelv/tests_sh_digdelv.py --- bind9-9.20.26/bin/tests/system/digdelv/tests_sh_digdelv.py 2026-07-20 14:47:53.672843319 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/tests_sh_digdelv.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -# 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. - -import pytest - -pytestmark = pytest.mark.extra_artifacts( - [ - "delv.out.*", - "dig.out.*", - "host.out.*", - "nslookup.out.*", - "nsupdate.out.*", - "yamlget.out.*", - "ans*/ans.run", - "ns*/anchor.*", - "ns*/dsset-*", - "ns*/keydata", - "ns*/keyid", - "ns*/K*.key", - "ns*/K*.private", - "ns1/root.db", - "ns2/example.db", - "ns2/example.tld.db", - ] -) - - -def test_digdelv(run_tests_sh): - run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/digdelv/yamlget.py bind9-9.20.29/bin/tests/system/digdelv/yamlget.py --- bind9-9.20.26/bin/tests/system/digdelv/yamlget.py 2026-07-20 14:47:53.672843319 +0000 +++ bind9-9.20.29/bin/tests/system/digdelv/yamlget.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -# 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. - -import sys - -try: - import yaml -except ImportError: - print("No python yaml module, skipping") - sys.exit(1) - -with open(sys.argv[1], "r", encoding="utf-8") as f: - for item in yaml.safe_load_all(f): - for key in sys.argv[2:]: - try: - key = int(key) - except ValueError: - pass - - try: - item = item[key] - except KeyError: - print('Key "' + key + '" not found.') - sys.exit(1) - - print(item) diff -Nru bind9-9.20.26/bin/tests/system/dispatch/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dispatch/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dispatch/ns1/named.conf.j2 2026-07-20 14:47:53.672843319 +0000 +++ bind9-9.20.29/bin/tests/system/dispatch/ns1/named.conf.j2 2026-09-11 19:41:01.160322814 +0000 @@ -11,28 +11,12 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options-dual.conf.j2" %} - listen-on { 10.53.0.1; }; - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - listen-on-v6 { fd92:7065:b8e:ffff::1; }; - query-source-v6 address fd92:7065:b8e:ffff::1; - notify-source-v6 fd92:7065:b8e:ffff::1; - transfer-source-v6 fd92:7065:b8e:ffff::1; recursion no; servfail-ttl 0; diff -Nru bind9-9.20.26/bin/tests/system/dispatch/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dispatch/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dispatch/ns2/named.conf.j2 2026-07-20 14:47:53.672843319 +0000 +++ bind9-9.20.29/bin/tests/system/dispatch/ns2/named.conf.j2 2026-09-11 19:41:01.160322814 +0000 @@ -11,38 +11,18 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options-dual.conf.j2" %} + - listen-on { 10.53.0.2; }; - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - - listen-on-v6 { fd92:7065:b8e:ffff::2; }; - query-source-v6 address fd92:7065:b8e:ffff::2; - notify-source-v6 fd92:7065:b8e:ffff::2; - transfer-source-v6 fd92:7065:b8e:ffff::2; - recursion yes; servfail-ttl 0; dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/dlzexternal/driver/Makefile.in bind9-9.20.29/bin/tests/system/dlzexternal/driver/Makefile.in --- bind9-9.20.26/bin/tests/system/dlzexternal/driver/Makefile.in 2026-07-20 14:49:10.394577140 +0000 +++ bind9-9.20.29/bin/tests/system/dlzexternal/driver/Makefile.in 2026-09-11 19:42:18.366184075 +0000 @@ -271,6 +271,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/tests/system/dlzexternal/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dlzexternal/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dlzexternal/ns1/named.conf.j2 2026-07-20 14:47:53.673843344 +0000 +++ bind9-9.20.29/bin/tests/system/dlzexternal/ns1/named.conf.j2 2026-09-11 19:41:01.161322838 +0000 @@ -12,30 +12,19 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.1; 127.0.0.1; }; + listen-on { @ns.ip@; 127.0.0.1; }; listen-on-v6 { none; }; - allow-transfer { !10.53.0.1; any; }; + allow-transfer { !@ns.ip@; any; }; recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - include "ddns.key"; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dlz "example one" { database "dlopen ../driver/.libs/dlzexternal.so example.nil"; @@ -51,7 +40,7 @@ dlz "example four" { // Long zone name to trigger ISC_R_NOSPACE in dns_sdlz_putrr. - database "dlopen ../driver/.libs/dlzexternal.so 123456789.123456789.123456789.123456789.123456789.example.foo"; + database "dlopen ../driver/.libs/dlzexternal.so 123456789.123456789.123456789.123456789.123456789.example.foo"; }; dlz "unsearched1" { diff -Nru bind9-9.20.26/bin/tests/system/dlzexternal/prereq.sh bind9-9.20.29/bin/tests/system/dlzexternal/prereq.sh --- bind9-9.20.26/bin/tests/system/dlzexternal/prereq.sh 2026-07-20 14:47:53.673843344 +0000 +++ bind9-9.20.29/bin/tests/system/dlzexternal/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -$FEATURETEST --tsan && { - echo_i "TSAN - skipping dlzexternal test" - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/dlzexternal/tests_sh_dlzexternal.py bind9-9.20.29/bin/tests/system/dlzexternal/tests_sh_dlzexternal.py --- bind9-9.20.26/bin/tests/system/dlzexternal/tests_sh_dlzexternal.py 2026-07-20 14:47:53.674843369 +0000 +++ bind9-9.20.29/bin/tests/system/dlzexternal/tests_sh_dlzexternal.py 2026-09-11 19:41:01.161322838 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "ns1/ddns.key", @@ -19,6 +21,11 @@ ] ) +pytestmark = [ + isctest.mark.without_tsan, + EXTRA_ARTIFACTS, +] + def test_dlzexternal(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/dns64/ns1/example.db bind9-9.20.29/bin/tests/system/dns64/ns1/example.db --- bind9-9.20.26/bin/tests/system/dns64/ns1/example.db 2026-07-20 14:47:53.676843419 +0000 +++ bind9-9.20.29/bin/tests/system/dns64/ns1/example.db 2026-09-11 19:41:01.163322886 +0000 @@ -26,6 +26,9 @@ A 10.0.0.1 partially-excluded-only AAAA 2001:eeee::3 AAAA 2001::3 +; A wildcard match yields a signed answer carrying a NOQNAME proof. +*.wild-partially-excluded AAAA 2001:eeee::4 + AAAA 2001::4 a-only A 1.2.3.5 a-and-aaaa AAAA 2001::1 A 1.2.3.6 diff -Nru bind9-9.20.26/bin/tests/system/dns64/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dns64/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dns64/ns1/named.conf.j2 2026-07-20 14:47:53.676843419 +0000 +++ bind9-9.20.29/bin/tests/system/dns64/ns1/named.conf.j2 2026-09-11 19:41:01.163322886 +0000 @@ -13,24 +13,13 @@ // NS1 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - allow-recursion { 10.53.0.1; }; - notify yes; + {% include_indented "_common/options.conf.j2" %} + allow-recursion { @ns.ip@; }; dnssec-validation no; dns64 2001:bbbb::/96 { diff -Nru bind9-9.20.26/bin/tests/system/dns64/ns1/named2.conf.j2 bind9-9.20.29/bin/tests/system/dns64/ns1/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/dns64/ns1/named2.conf.j2 2026-07-20 14:47:53.676843419 +0000 +++ bind9-9.20.29/bin/tests/system/dns64/ns1/named2.conf.j2 2026-09-11 19:41:01.163322886 +0000 @@ -13,24 +13,13 @@ // NS1 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - allow-recursion { 10.53.0.1; }; - notify yes; + {% include_indented "_common/options.conf.j2" %} + allow-recursion { @ns.ip@; }; dnssec-validation no; dns64 2001:bbbb::/96 { diff -Nru bind9-9.20.26/bin/tests/system/dns64/ns1/named3.conf.j2 bind9-9.20.29/bin/tests/system/dns64/ns1/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/dns64/ns1/named3.conf.j2 2026-07-20 14:47:53.676843419 +0000 +++ bind9-9.20.29/bin/tests/system/dns64/ns1/named3.conf.j2 2026-09-11 19:41:01.164322911 +0000 @@ -13,24 +13,13 @@ // NS1 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - allow-recursion { 10.53.0.1; }; - notify yes; + {% include_indented "_common/options.conf.j2" %} + allow-recursion { @ns.ip@; }; dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/dns64/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dns64/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dns64/ns2/named.conf.j2 2026-07-20 14:47:53.676843419 +0000 +++ bind9-9.20.29/bin/tests/system/dns64/ns2/named.conf.j2 2026-09-11 19:41:01.164322911 +0000 @@ -16,19 +16,11 @@ acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; dns64 2001:aaaa::/96 { - clients { 10.53.0.2; }; + clients { @ns.ip@; }; mapped { !rfc1918; any; }; exclude { 2001:eeee::/32; 64:FF9B::/96; ::ffff:0000:0000/96; }; suffix ::; @@ -47,6 +39,14 @@ suffix ::; }; + dns64 2001:cccc::/96 { + clients { 10.53.0.8; }; + mapped { !rfc1918; any; }; + exclude { 2001:eeee::/32; 64:FF9B::/96; ::ffff:0000:0000/96; }; + suffix ::; + break-dnssec yes; + }; + dns64-server "dns64.example.net."; dns64-contact "hostmaster.example.net."; dns64 2001:32::/32 { clients { 10.53.0.6; }; }; @@ -60,11 +60,9 @@ response-policy { zone "rpz"; }; }; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "rpz" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/dns64/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/dns64/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dns64/ns3/named.conf.j2 2026-07-20 14:47:53.676843419 +0000 +++ bind9-9.20.29/bin/tests/system/dns64/ns3/named.conf.j2 2026-09-11 19:41:01.164322911 +0000 @@ -17,18 +17,11 @@ acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.3; - query-source-v6 address fd92:7065:b8e:ffff::3; - notify-source 10.53.0.3; - notify-source-v6 fd92:7065:b8e:ffff::3; - transfer-source 10.53.0.3; - transfer-source-v6 fd92:7065:b8e:ffff::3; + {% include_indented "_common/options/sources-dual.conf.j2" %} + {% include_indented "_common/options/listen-dual.conf.j2" %} port @EXTRAPORT1@; pid-file "named.pid"; - listen-on port @PORT@ { 10.53.0.3; }; // for start.pl - listen-on { 10.53.0.3; }; - listen-on-v6 { fd92:7065:b8e:ffff::3; }; - notify yes; + listen-on port @PORT@ { @ns.ip@; }; // for start.pl dnssec-validation no; allow-recursion { any; }; resolver-use-dns64 yes; @@ -40,6 +33,7 @@ }; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/dns64/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/dns64/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dns64/ns4/named.conf.j2 2026-07-20 14:47:53.677843444 +0000 +++ bind9-9.20.29/bin/tests/system/dns64/ns4/named.conf.j2 2026-09-11 19:41:01.164322911 +0000 @@ -15,21 +15,19 @@ // NS4 options { - query-source address 10.53.0.4; - query-source-v6 address fd92:7065:b8e:fffe::10.53.0.4; - notify-source 10.53.0.4; - notify-source-v6 fd92:7065:b8e:fffe::10.53.0.4; - transfer-source 10.53.0.4; - transfer-source-v6 fd92:7065:b8e:fffe::10.53.0.4; + {% include_indented "_common/options/sources.conf.j2" %} + query-source-v6 address fd92:7065:b8e:fffe::@ns.ip@; + notify-source-v6 fd92:7065:b8e:fffe::@ns.ip@; + transfer-source-v6 fd92:7065:b8e:fffe::@ns.ip@; port @EXTRAPORT1@; pid-file "named.pid"; - listen-on port @PORT@ { 10.53.0.4; }; // for start.pl - listen-on-v6 { fd92:7065:b8e:fffe::10.53.0.4; }; - notify yes; + listen-on port @PORT@ { @ns.ip@; }; // for start.pl + listen-on-v6 { fd92:7065:b8e:fffe::@ns.ip@; }; dnssec-validation no; recursion no; }; +{% include "_common/controls.conf.j2" %} zone "." { type master; diff -Nru bind9-9.20.26/bin/tests/system/dns64/tests.sh bind9-9.20.29/bin/tests/system/dns64/tests.sh --- bind9-9.20.26/bin/tests/system/dns64/tests.sh 2026-07-20 14:47:53.677843444 +0000 +++ bind9-9.20.29/bin/tests/system/dns64/tests.sh 2026-09-11 19:41:01.165322935 +0000 @@ -1276,6 +1276,29 @@ if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) +# The answer is wildcard-expanded, so it is cached with a NOQNAME proof, +# and it is partially excluded, so it is filtered rather than synthesized. +# 10.53.0.8 is the only client for which break-dnssec is in effect, which +# is what lets a +dnssec query reach the filtering path at all. +echo_i "checking partially-excluded wildcard AAAA lookup in signed zone works with +dnssec ($n)" +ret=0 +$DIG $DIGOPTS +dnssec a.wild-partially-excluded.signed. @10.53.0.2 -b 10.53.0.8 aaaa >dig.out.ns2.test$n || ret=1 +grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1 +grep "ANSWER: 1," dig.out.ns2.test$n >/dev/null || ret=1 +grep "2001::4" dig.out.ns2.test$n >/dev/null || ret=1 +grep "2001:eeee::4" dig.out.ns2.test$n >/dev/null && ret=1 +n=$((n + 1)) +if [ $ret != 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + +echo_i "checking ns2 survived the partially-excluded wildcard lookup ($n)" +ret=0 +$DIG $DIGOPTS aaaa-only.signed. @10.53.0.2 -b 10.53.0.2 aaaa >dig.out.ns2.test$n || ret=1 +grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1 +n=$((n + 1)) +if [ $ret != 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + echo_i "checking reverse mapping ($n)" ret=0 $DIG $DIGOPTS -x 2001:aaaa::10.0.0.1 @10.53.0.2 >dig.out.ns2.test$n || ret=1 diff -Nru bind9-9.20.26/bin/tests/system/dns64_dname/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dns64_dname/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dns64_dname/ns1/named.conf.j2 2026-07-20 14:47:53.678843469 +0000 +++ bind9-9.20.29/bin/tests/system/dns64_dname/ns1/named.conf.j2 2026-09-11 19:41:01.165322935 +0000 @@ -1,15 +1,13 @@ // NS1 options { - query-source address 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/dns64_dname/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dns64_dname/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dns64_dname/ns2/named.conf.j2 2026-07-20 14:47:53.678843469 +0000 +++ bind9-9.20.29/bin/tests/system/dns64_dname/ns2/named.conf.j2 2026-09-11 19:41:01.166322959 +0000 @@ -1,12 +1,7 @@ // NS2 options { - query-source address 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} allow-recursion { any; }; dnssec-validation no; qname-minimization off; @@ -14,7 +9,6 @@ dns64 64:ff9b::/96 { }; }; -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/dns64_dname/ns2/root.hint bind9-9.20.29/bin/tests/system/dns64_dname/ns2/root.hint --- bind9-9.20.26/bin/tests/system/dns64_dname/ns2/root.hint 2026-07-20 14:47:53.678843469 +0000 +++ bind9-9.20.29/bin/tests/system/dns64_dname/ns2/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/dnssec/conf/keystore-keydirectory.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/conf/keystore-keydirectory.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/conf/keystore-keydirectory.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/conf/keystore-keydirectory.conf.j2 2026-09-11 19:41:01.166322959 +0000 @@ -0,0 +1,10 @@ +# 'key-directory' is a reserved keyword +key-store "key-directory" { + directory "."; +}; + +dnssec-policy "csk" { + keys { + csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/kasp.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/kasp.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/kasp.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/kasp.conf.j2 2026-09-11 19:41:01.167322983 +0000 @@ -0,0 +1,8 @@ +dnssec-policy "tagged-keys" { + dnskey-ttl 3600; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 0 32767; + zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns1/named.conf.j2 2026-07-20 14:47:53.679843494 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns1/named.conf.j2 2026-09-11 19:41:01.167322983 +0000 @@ -14,20 +14,15 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; /* test that we can turn off trust-anchor-telemetry */ trust-anchor-telemetry no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns2/example.db.in bind9-9.20.29/bin/tests/system/dnssec/ns2/example.db.in --- bind9-9.20.26/bin/tests/system/dnssec/ns2/example.db.in 2026-07-20 14:47:53.680843519 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns2/example.db.in 2026-09-11 19:41:01.168323007 +0000 @@ -185,3 +185,21 @@ ns3.extrabadkey A 10.53.0.3 dname-at-apex-nsec3 NS ns3 + +; A secure subdomain whose DS RRset is flooded with many mismatched DS +; records, each with a unique key tag (GL #5349). The DS records are +; hand-built in sign.sh (dsset-keytrap.example.); none match the child's +; real DNSKEY, so validation must fail. +keytrap NS ns3.keytrap +ns3.keytrap A 10.53.0.3 + +; A companion to keytrap whose child has several DNSKEYs, so a smaller +; (still mismatched) DS RRset is enough to exceed the DS-by-DNSKEY +; combination cap (GL #5349). +keytrap2 NS ns3.keytrap2 +ns3.keytrap2 A 10.53.0.3 + +; A valid delegation with many additional unsupported DS algorithm and digest +; records. Only the generated supported DS requires DNSKEY matching. +keytrap3 NS ns3.keytrap3 +ns3.keytrap3 A 10.53.0.3 diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns2/named.conf.j2 2026-07-20 14:47:53.681843544 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns2/named.conf.j2 2026-09-11 19:41:01.169323031 +0000 @@ -14,29 +14,15 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation yes; notify-delay 1; minimal-responses no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "dnssec" { keys { @@ -67,10 +53,7 @@ signatures-validity 500d; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "trusted" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns2/sign.sh bind9-9.20.29/bin/tests/system/dnssec/ns2/sign.sh --- bind9-9.20.26/bin/tests/system/dnssec/ns2/sign.sh 2026-07-20 14:47:53.681843544 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns2/sign.sh 2026-09-11 19:41:01.169323031 +0000 @@ -64,10 +64,49 @@ dnskey-unknown dnskey-unsupported dnskey-unsupported-2 \ dnskey-nsec3-unknown managed-future future revkey \ dname-at-apex-nsec3 occluded rsasha1 rsasha1-1024 \ - extrabadkey; do + extrabadkey keytrap3; do cp "../ns3/dsset-$subdomain.example." . done +# Build a flooded DS RRset for the "keytrap.example." delegation: many +# DS records, each with a unique key tag, none matching the child's real +# DNSKEY (GL #5349). dnssec-signzone -g inserts these into the parent +# below; the resolver must reject the zone with bounded per-DS work. +: >"dsset-keytrap.example." +i=1 +while [ $i -le 25 ]; do + keytag=$((60000 + i)) + digest=$(printf '%064x' "$i") + echo "keytrap.example. IN DS $keytag $DEFAULT_ALGORITHM_NUMBER 2 $digest" >>"dsset-keytrap.example." + i=$((i + 1)) +done + +# Build a smaller mismatched DS RRset for the "keytrap2.example." +# delegation (GL #5349). Fewer DS records than the per-DS validation +# quota, but the child's multi-key DNSKEY RRset makes the DS-by-DNSKEY +# product exceed the up-front combination cap. +: >"dsset-keytrap2.example." +i=1 +while [ $i -le 12 ]; do + keytag=$((62000 + i)) + digest=$(printf '%064x' "$i") + echo "keytrap2.example. IN DS $keytag $DEFAULT_ALGORITHM_NUMBER 2 $digest" >>"dsset-keytrap2.example." + i=$((i + 1)) +done + +# Add enough ignored DS records to the valid "keytrap3.example." delegation +# to exceed the combination cap if the raw RRset size is used. Half use an +# unsupported DNSKEY algorithm and half use an unsupported digest type; the +# generated supported DS must still validate the child. +i=1 +while [ $i -le 16 ]; do + keytag=$((63000 + i)) + digest=$(printf '%064x' "$i") + echo "keytrap3.example. IN DS $keytag 255 2 $digest" >>"dsset-keytrap3.example." + echo "keytrap3.example. IN DS $keytag $DEFAULT_ALGORITHM_NUMBER 255 $digest" >>"dsset-keytrap3.example." + i=$((i + 1)) +done + # Sign the "example." zone. keyname1=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone -f KSK "$zone") keyname2=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone "$zone") diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns3/named.conf.j2 2026-07-20 14:47:53.683843594 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns3/named.conf.j2 2026-09-11 19:41:01.171323080 +0000 @@ -14,29 +14,15 @@ // NS3 options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation yes; session-keyfile "session.key"; minimal-responses no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "dnssec" { keys { @@ -74,10 +60,7 @@ nsec3param iterations 0 optout no salt-length 0; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type secondary; @@ -109,6 +92,21 @@ allow-update { any; }; }; +zone "keytrap.example" { + type primary; + file "keytrap.example.db.signed"; +}; + +zone "keytrap2.example" { + type primary; + file "keytrap2.example.db.signed"; +}; + +zone "keytrap3.example" { + type primary; + file "keytrap3.example.db.signed"; +}; + zone "badds.example" { type primary; file "badds.example.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns3/sign.sh bind9-9.20.29/bin/tests/system/dnssec/ns3/sign.sh --- bind9-9.20.26/bin/tests/system/dnssec/ns3/sign.sh 2026-07-20 14:47:53.685843644 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns3/sign.sh 2026-09-11 19:41:01.174323152 +0000 @@ -101,6 +101,50 @@ "$SIGNER" -z -o "$zone" "$zonefile" >/dev/null +# A normally-signed child zone whose parent DS RRset (built in ns2) is +# flooded with many mismatched DS records with unique key tags (GL #5349). +# A single key keeps the DNSKEY RRset small so the flood lives entirely on +# the DS side; none of the parent DS records match this key. +zone=keytrap.example. +infile=template.db.in +zonefile=keytrap.example.db + +keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone") + +cat "$infile" "$keyname.key" >"$zonefile" + +"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null + +# A companion to keytrap.example that exercises the up-front DS-by-DNSKEY +# combination cap instead of the per-DS quota (GL #5349). The child +# publishes several DNSKEYs, so even a DS RRset smaller than the per-DS +# quota (built in ns2) pushes the product of the two counts over the +# limit. None of the parent DS records match these keys. +zone=keytrap2.example. +infile=template.db.in +zonefile=keytrap2.example.db + +keyname1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone") +keyname2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone") +keyname3=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone") + +cat "$infile" "$keyname1.key" "$keyname2.key" "$keyname3.key" >"$zonefile" + +"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null + +# A valid child whose generated DS is accompanied by enough unsupported +# algorithm and digest records in the parent to exceed the raw DS-by-DNSKEY +# combination cap. Unsupported records must not count as matching work. +zone=keytrap3.example. +infile=template.db.in +zonefile=keytrap3.example.db + +keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone") + +cat "$infile" "$keyname.key" >"$zonefile" + +"$SIGNER" -z -o "$zone" "$zonefile" >/dev/null + # zone=secure.example. infile=secure.example.db.in diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns4/named.conf.j2 2026-07-20 14:47:53.686843669 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns4/named.conf.j2 2026-09-11 19:41:01.174323152 +0000 @@ -14,14 +14,7 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; dnssec-must-be-secure mustbesecure.example yes; minimal-responses no; @@ -45,19 +38,9 @@ bindkeys-file "../../../../../bind.keys"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "corp" { type static-stub; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns4/named2.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns4/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns4/named2.conf.j2 2026-07-20 14:47:53.686843669 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns4/named2.conf.j2 2026-09-11 19:41:01.175323176 +0000 @@ -14,14 +14,7 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation auto; bindkeys-file "managed.conf"; minimal-responses no; @@ -33,16 +26,6 @@ disable-algorithms "ent.secure.example." { ECDSAP256SHA256; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns4/named3.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns4/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns4/named3.conf.j2 2026-07-20 14:47:53.686843669 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns4/named3.conf.j2 2026-09-11 19:41:01.175323176 +0000 @@ -14,14 +14,7 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation auto; bindkeys-file "managed.conf"; dnssec-accept-expired yes; @@ -36,16 +29,6 @@ disable-algorithms "ent.secure.example." { ECDSAP256SHA256; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns4/named4.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns4/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns4/named4.conf.j2 2026-07-20 14:47:53.686843669 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns4/named4.conf.j2 2026-09-11 19:41:01.175323176 +0000 @@ -14,13 +14,7 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} disable-algorithms "digest-alg-unsupported.example." { ECDSAP384SHA384; }; disable-ds-digests "digest-alg-unsupported.example." { "SHA384"; "SHA-384"; }; disable-ds-digests "ds-unsupported.example." { "SHA256"; "SHA-256"; "SHA384"; "SHA-384"; }; @@ -29,14 +23,7 @@ disable-algorithms "ent.secure.example." { ECDSAP256SHA256; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key auth { secret "1234abcd8765"; @@ -52,10 +39,7 @@ dnssec-accept-expired yes; minimal-responses no; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone secure.example { type static-stub; @@ -72,10 +56,7 @@ recursion no; allow-recursion { none; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone secure.example { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns5/named.conf.j2 2026-07-20 14:47:53.687843694 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns5/named.conf.j2 2026-09-11 19:41:01.175323176 +0000 @@ -14,30 +14,13 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns5/named2.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns5/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns5/named2.conf.j2 2026-07-20 14:47:53.687843694 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns5/named2.conf.j2 2026-09-11 19:41:01.175323176 +0000 @@ -13,24 +13,13 @@ // NS5 -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; 127.0.0.1; }; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + listen-on { @ns.ip@; 127.0.0.1; }; listen-on-v6 { none; }; - recursion yes; dnssec-validation yes; }; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns6/named.conf.j2 2026-07-20 14:47:53.687843694 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns6/named.conf.j2 2026-09-11 19:41:01.175323176 +0000 @@ -14,23 +14,14 @@ // NS6 options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} disable-algorithms . { @ALTERNATIVE_ALGORITHM@; }; dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "optout-tld" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns7/named.conf.j2 2026-07-20 14:47:53.687843694 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns7/named.conf.j2 2026-09-11 19:41:01.175323176 +0000 @@ -14,23 +14,15 @@ // NS3 options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; minimal-responses yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "nsec3.example" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns8/named.conf.j2 2026-07-20 14:47:53.688843719 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns8/named.conf.j2 2026-09-11 19:41:01.176323200 +0000 @@ -14,33 +14,16 @@ // NS8 options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; minimal-responses no; disable-algorithms "disabled.managed." { @DISABLED_ALGORITHM@; }; disable-algorithms "disabled.trusted." { @DISABLED_ALGORITHM@; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "managed.conf"; include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec/ns9/named.conf.j2 2026-07-20 14:47:53.688843719 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/ns9/named.conf.j2 2026-09-11 19:41:01.176323200 +0000 @@ -14,27 +14,13 @@ // NS9 options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; forward only; forwarders { 10.53.0.4; }; servfail-ttl 0; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec/prereq.sh bind9-9.20.29/bin/tests/system/dnssec/prereq.sh --- bind9-9.20.26/bin/tests/system/dnssec/prereq.sh 2026-07-20 14:47:53.688843719 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/dnssec/tests.sh bind9-9.20.29/bin/tests/system/dnssec/tests.sh --- bind9-9.20.26/bin/tests/system/dnssec/tests.sh 2026-07-20 14:47:53.691843794 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/tests.sh 2026-09-11 19:41:01.179323273 +0000 @@ -3323,19 +3323,6 @@ test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) -echo_i "check dig's +nocrypto flag ($n)" -ret=0 -dig_with_opts +norec +nocrypto DNSKEY . \ - @10.53.0.1 >dig.out.dnskey.ns1.test$n || ret=1 -grep -E "256 [0-9]+ $DEFAULT_ALGORITHM_NUMBER \\[key id = [1-9][0-9]*]" dig.out.dnskey.ns1.test$n >/dev/null || ret=1 -grep -E "RRSIG.* \\[omitted]" dig.out.dnskey.ns1.test$n >/dev/null || ret=1 -dig_with_opts +norec +nocrypto DS example \ - @10.53.0.1 >dig.out.ds.ns1.test$n || ret=1 -grep -E "DS.* [0-9]+ [12] \[omitted]" dig.out.ds.ns1.test$n >/dev/null || ret=1 -n=$((n + 1)) -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - echo_i "check that increasing the signatures-validity resigning triggers re-signing ($n)" ret=0 before=$($DIG axfr siginterval.example -p "$PORT" @10.53.0.3 | grep RRSIG.SOA) @@ -4652,6 +4639,25 @@ kid=$(keyfile_to_key_id "$ksk") zid=$(keyfile_to_key_id "$zsk") [ $kid -ge 0 -a $kid -le 32767 ] || ret=1 +[ $zid -ge 32768 -a $zid -le 65535 ] || ret=1 +rksk=$($REVOKE -R $ksk) +rzsk=$($REVOKE -R $zsk) +krid=$(keyfile_to_key_id "$rksk") +zrid=$(keyfile_to_key_id "$rzsk") +[ $krid -ge 0 -a $krid -le 32767 ] || ret=1 +[ $zrid -ge 32768 -a $zrid -le 65535 ] || ret=1 +n=$((n + 1)) +if [ "$ret" -ne 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + +echo_i "check that dnssec-keygen honours key tag ranges from dnssec-policy ($n)" +ret=0 +zone=settagrangepolicy +ksk=$("$KEYGEN" -f KSK -k tagged-keys -l kasp.conf "$zone") +zsk=$("$KEYGEN" -f ZSK -k tagged-keys -l kasp.conf "$zone") +kid=$(keyfile_to_key_id "$ksk") +zid=$(keyfile_to_key_id "$zsk") +[ $kid -ge 0 -a $kid -le 32767 ] || ret=1 [ $zid -ge 32768 -a $zid -le 65535 ] || ret=1 rksk=$($REVOKE -R $ksk) rzsk=$($REVOKE -R $zsk) diff -Nru bind9-9.20.26/bin/tests/system/dnssec/tests_keygen.py bind9-9.20.29/bin/tests/system/dnssec/tests_keygen.py --- bind9-9.20.26/bin/tests/system/dnssec/tests_keygen.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/tests_keygen.py 2026-09-11 19:41:01.179323273 +0000 @@ -0,0 +1,73 @@ +# 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. + +import os + +import pytest + +import isctest +import isctest.mark + +pytestmark = pytest.mark.extra_artifacts( + [ + "*/K*", + "*/NSEC*", + "*/dsset-*", + "*/*.bk", + "*/*.conf", + "*/*.db", + "*/*.id", + "*/*.jnl", + "*/*.jbk", + "*/*.key", + "*/*.signed", + "*/settime.out.*", + "ans*/ans.run", + "*/trusted.keys", + "*/*.bad", + "*/*.next", + "*/*.stripped", + "*/*.tmp", + "*/*.stage?", + "*/*.patched", + "*/*.lower", + "*/*.upper", + "*/*.unsplit", + "kasp.conf", + ] +) + + +# run named-checkconf +def checkconf(cfgfile): + checkconf_cmd = [os.environ.get("CHECKCONF"), "-k", cfgfile] + return isctest.run.cmd(checkconf_cmd, raise_on_exception=False) + + +# run dnssec-keygen +def keygen(*args): + keygen_cmd = [os.environ.get("KEYGEN")] + keygen_cmd.extend(args) + return isctest.run.cmd(keygen_cmd, raise_on_exception=False) + + +def test_keygen_keystore_keydirectory(): + zone = "keystore-keydirectory.example." + conf = "conf/keystore-keydirectory.conf" + policy = "csk" + + # named-checkconf should complain about the key-store name. + result = checkconf(conf) + assert "name 'key-directory' not allowed" in result.out + + # dnssec-keygen should also complain about the key-store name. + result = keygen("-k", policy, "-l", conf, zone) + assert "key-store: duplicate key-store found 'key-directory'" in result.err diff -Nru bind9-9.20.26/bin/tests/system/dnssec/tests_sh_dnssec.py bind9-9.20.29/bin/tests/system/dnssec/tests_sh_dnssec.py --- bind9-9.20.26/bin/tests/system/dnssec/tests_sh_dnssec.py 2026-07-20 14:47:53.691843794 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/tests_sh_dnssec.py 2026-09-11 19:41:01.179323273 +0000 @@ -21,6 +21,7 @@ "dnssectools.out.*", "dsfromkey.out.*", "dsset-*", + "kasp.conf", "keygen*.err*", "named.secroots.*", "nsupdate.out.*", @@ -42,6 +43,7 @@ "*/*.mkeys*", "ans*/ans.run", "ans*/query.log", + "conf/*.conf", "ns1/managed.key.id", "ns1/root.db", "ns1/trusted.keys", @@ -108,6 +110,9 @@ "ns3/extrabadkey.example.db", "ns3/future.example.db", "ns3/keyless.example.db", + "ns3/keytrap.example.db", + "ns3/keytrap2.example.db", + "ns3/keytrap3.example.db", "ns3/kskonly.example.db", "ns3/lower.example.db", "ns3/managed-future.example.db", diff -Nru bind9-9.20.26/bin/tests/system/dnssec/tests_validation.py bind9-9.20.29/bin/tests/system/dnssec/tests_validation.py --- bind9-9.20.26/bin/tests/system/dnssec/tests_validation.py 2026-07-20 14:47:53.691843794 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec/tests_validation.py 2026-09-11 19:41:01.179323273 +0000 @@ -42,6 +42,7 @@ "*/*.lower", "*/*.upper", "*/*.unsplit", + "kasp.conf", ] ) @@ -57,3 +58,43 @@ answers = {(str(rr.name), rr.rdtype) for rr in res.answer} assert ("dname-at-apex-nsec3.example.", rdatatype.DNAME) in answers assert ("a.example.", rdatatype.A) in answers + + +def test_ds_keytag_flood(ns4): + # GL #5349: a securely-delegated zone whose parent DS RRset is flooded + # with many mismatched DS records (each a unique key tag) must be + # rejected without unbounded per-DS matching work. The per-fetch + # validation quota caps the DS x DNSKEY matching, so the DNSKEY fetch + # fails with ISC_R_QUOTA and the answer is SERVFAIL. An unbounded + # walk would grind through every DS and never hit the quota. + with ns4.watch_log_from_here() as watcher: + msg = isctest.query.create("keytrap.example", "SOA") + res = isctest.query.tcp(msg, "10.53.0.4") + isctest.check.servfail(res) + watcher.wait_for_line("quota reached resolving 'keytrap.example/DNSKEY/IN'") + + +def test_ds_keytag_flood_combinations(ns4): + # GL #5349: the parent DS RRset here is smaller than the per-fetch + # validation quota, but the child DNSKEY RRset has several keys, so the + # DS-by-DNSKEY combination count exceeds the up-front product cap. The + # DNSKEY fetch must fail terminally with the validation quota (SERVFAIL, + # no retry). Without the product cap the per-DS walk would finish below + # the quota and never reject the zone; returning ISC_R_RANGE instead of + # ISC_R_QUOTA would log "out of range" and retry rather than stop here. + with ns4.watch_log_from_here() as watcher: + msg = isctest.query.create("keytrap2.example", "SOA") + res = isctest.query.tcp(msg, "10.53.0.4") + isctest.check.servfail(res) + watcher.wait_for_line("quota reached resolving 'keytrap2.example/DNSKEY/IN'") + + +def test_ds_keytag_flood_ignores_unsupported_ds(): + # GL #5349: unsupported DS algorithms and digest types do not reach + # DNSKEY matching and therefore must not contribute to its combination + # cap. The raw DS-by-DNSKEY count exceeds the cap, but the delegation has + # one supported DS and must validate successfully. + msg = isctest.query.create("keytrap3.example", "SOA") + res = isctest.query.tcp(msg, "10.53.0.4") + isctest.check.noerror(res) + isctest.check.adflag(res) diff -Nru bind9-9.20.26/bin/tests/system/dnssec_bypass/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_bypass/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_bypass/ns1/named.conf.j2 2026-07-20 14:47:53.691843794 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_bypass/ns1/named.conf.j2 2026-09-11 19:41:01.180323297 +0000 @@ -12,14 +12,13 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "test." { type primary; file "test.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_bypass/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_bypass/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_bypass/ns2/named.conf.j2 2026-07-20 14:47:53.692843819 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_bypass/ns2/named.conf.j2 2026-09-11 19:41:01.180323297 +0000 @@ -12,14 +12,13 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "victim.test." { type primary; file "victim.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_bypass/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_bypass/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_bypass/ns3/named.conf.j2 2026-07-20 14:47:53.692843819 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_bypass/ns3/named.conf.j2 2026-09-11 19:41:01.180323297 +0000 @@ -12,14 +12,13 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "evil.test." { type primary; file "evil.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_bypass/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_bypass/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_bypass/ns4/named.conf.j2 2026-07-20 14:47:53.692843819 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_bypass/ns4/named.conf.j2 2026-09-11 19:41:01.180323297 +0000 @@ -12,24 +12,16 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; dnssec-validation yes; synth-from-dnssec yes; }; +{% include "_common/controls.conf.j2" %} + trust-anchors { @root.domain@ @root.type@ @root.contents@; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/dnssec_cname_response/ans2/ans.py bind9-9.20.29/bin/tests/system/dnssec_cname_response/ans2/ans.py --- bind9-9.20.26/bin/tests/system/dnssec_cname_response/ans2/ans.py 2026-07-20 14:47:53.692843819 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_cname_response/ans2/ans.py 2026-09-11 19:41:01.181323321 +0000 @@ -1,19 +1,22 @@ -# 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. +""" +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. +""" from collections.abc import AsyncGenerator -import dns.flags import dns.name import dns.rcode +import dns.rdataclass +import dns.rdataset import dns.rdatatype import dns.rrset import dns.zone @@ -23,6 +26,7 @@ DnsResponseSend, DomainHandler, QueryContext, + ResponseHandler, ) # 'example.' answers DNSKEY/NSEC/NSEC3/RRSIG queries with a CNAME (the @@ -40,197 +44,172 @@ STUFFED = dns.zone.from_file("stuffed.signed.zone", origin="stuffed.", relativize=False) -def _append_rrset_with_rrsig( +def a(owner: dns.name.Name, address: str) -> dns.rrset.RRset: + return dns.rrset.from_text(owner, 300, dns.rdataclass.IN, dns.rdatatype.A, address) + + +def cname(owner: dns.name.Name, target: str) -> dns.rrset.RRset: + return dns.rrset.from_text( + owner, 300, dns.rdataclass.IN, dns.rdatatype.CNAME, target + ) + + +def rrset_with_rrsig( zone: dns.zone.Zone, - section: list, name: dns.name.Name, - qclass: int, - rdtype: int, - rds, -) -> None: - rrset = dns.rrset.RRset(name, qclass, rdtype) - rrset.update(rds) - section.append(rrset) - - node = zone.get_node(name) - if node is None: - return - rrsig_rds = node.get_rdataset(qclass, dns.rdatatype.RRSIG, covers=rdtype) - if rrsig_rds is None: - return - rrsig_rrset = dns.rrset.RRset(name, qclass, dns.rdatatype.RRSIG, covers=rdtype) - rrsig_rrset.update(rrsig_rds) - section.append(rrsig_rrset) - - -class CnameZoneHandler(DomainHandler): - """Serve a signed zone faithfully, but answer queries for the configured - rdata types with a CNAME instead of the real records.""" - - def __init__(self, zone: dns.zone.Zone, cname_qtypes) -> None: - self.zone = zone - self.cname_qtypes = frozenset(cname_qtypes) - super().__init__() + rdtype: dns.rdatatype.RdataType, +) -> list[dns.rrset.RRset]: + covered = zone.get_rrset(name, rdtype) + assert covered is not None + rrsets = [covered] + rrsig = zone.get_rrset(name, dns.rdatatype.RRSIG, covers=rdtype) + if rrsig is not None: + rrsets.append(rrsig) + return rrsets - @property - def domains(self) -> list[str]: - return [self.zone.origin.to_text()] + +class LoneAHandler(DomainHandler): + """ + Answer any query with a single unrelated A record (no RRSIG and no + alias). An RRSIG query is handled by the resolver as a subset of ANY, + and such an answer used to be dropped entirely, leaving the fetch waiting + for a validator that was never started. + """ + + domains = ["lone-a.example."] async def get_responses( self, qctx: QueryContext ) -> AsyncGenerator[DnsResponseSend, None]: qctx.prepare_new_response(with_zone_data=False) - qctx.response.flags |= dns.flags.AA + qctx.response.answer.append(a(qctx.qname, "192.0.2.1")) + yield DnsResponseSend(qctx.response) - if qctx.qtype in self.cname_qtypes: - cname_target = f"cname-target.{qctx.qname.to_text()}" - cname_rrset = dns.rrset.from_text( - qctx.qname, - 300, - qctx.qclass, - dns.rdatatype.CNAME, - cname_target, - ) - qctx.response.answer.append(cname_rrset) - yield DnsResponseSend(qctx.response) - return - node = self.zone.get_node(qctx.qname) - soa_rds = self.zone.get_rdataset(self.zone.origin, dns.rdatatype.SOA) +class CnameHandler(ResponseHandler): + """ + Answer with a CNAME instead of the real records. + """ - if node is None: - qctx.response.set_rcode(dns.rcode.NXDOMAIN) - _append_rrset_with_rrsig( - self.zone, - qctx.response.authority, - self.zone.origin, - qctx.qclass, - dns.rdatatype.SOA, - soa_rds, - ) - yield DnsResponseSend(qctx.response) - return + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + qctx.prepare_new_response(with_zone_data=False) + target = f"cname-target.{qctx.qname.to_text()}" + qctx.response.answer.append(cname(qctx.qname, target)) + yield DnsResponseSend(qctx.response) - rds = node.get_rdataset(qctx.qclass, qctx.qtype) - if rds is None: - _append_rrset_with_rrsig( - self.zone, - qctx.response.authority, - self.zone.origin, - qctx.qclass, - dns.rdatatype.SOA, - soa_rds, - ) - yield DnsResponseSend(qctx.response) - return - _append_rrset_with_rrsig( - self.zone, - qctx.response.answer, - qctx.qname, - qctx.qclass, - qctx.qtype, - rds, - ) - yield DnsResponseSend(qctx.response) +class ExampleMetatypeCnameHandler(DomainHandler, CnameHandler): + domains = ["example."] + _qtypes = frozenset( + { + dns.rdatatype.DNSKEY, + dns.rdatatype.NSEC, + dns.rdatatype.NSEC3, + dns.rdatatype.RRSIG, + } + ) + def match(self, qctx: QueryContext) -> bool: + return qctx.qtype in self._qtypes and super().match(qctx) -class LoneRecordHandler(DomainHandler): - """Answer any query with a single unrelated A record (no RRSIG and no - alias). An RRSIG query is handled by the resolver as a subset of ANY, - and such an answer used to be dropped entirely, leaving the fetch - waiting for a validator that was never started.""" - domains = ["lone-a.example."] +class SecureDsCnameHandler(DomainHandler, CnameHandler): + domains = ["secure."] + + def match(self, qctx: QueryContext) -> bool: + return qctx.qtype == dns.rdatatype.DS and super().match(qctx) + + +class SignedZoneHandler(DomainHandler): + """ + Serve a signed zone faithfully. + """ + + def __init__(self, zone: dns.zone.Zone) -> None: + self._zone = zone + super().__init__() + + @property + def domains(self) -> list[str]: + return [self._zone.origin.to_text()] + + def _soa(self) -> list[dns.rrset.RRset]: + return rrset_with_rrsig(self._zone, self._zone.origin, dns.rdatatype.SOA) async def get_responses( self, qctx: QueryContext ) -> AsyncGenerator[DnsResponseSend, None]: qctx.prepare_new_response(with_zone_data=False) - qctx.response.flags |= dns.flags.AA - a_rrset = dns.rrset.from_text( - qctx.qname, 300, qctx.qclass, dns.rdatatype.A, "192.0.2.1" + + node = self._zone.get_node(qctx.qname) + if node is None: + qctx.response.set_rcode(dns.rcode.NXDOMAIN) + qctx.response.authority.extend(self._soa()) + yield DnsResponseSend(qctx.response) + return + + rds = node.get_rdataset(dns.rdataclass.IN, qctx.qtype) + if rds is None: + qctx.response.authority.extend(self._soa()) + yield DnsResponseSend(qctx.response) + return + + qctx.response.answer.extend( + rrset_with_rrsig(self._zone, qctx.qname, qctx.qtype) ) - qctx.response.answer.append(a_rrset) yield DnsResponseSend(qctx.response) -class StuffedNsec3Handler(DomainHandler): - """Answer NXDOMAIN with every NSEC3 RRset from a signed zone.""" +class StuffedNxdomainHandler(DomainHandler): + """ + Answer NXDOMAIN with every NSEC3 RRset from a signed zone. + """ def __init__(self, zone: dns.zone.Zone) -> None: - self.zone = zone - self.nsec3_authority = [] + self._zone = zone super().__init__() + self._nsec3_authority = self._build_authority() - soa_rds = self.zone.get_rdataset(self.zone.origin, dns.rdatatype.SOA) - _append_rrset_with_rrsig( - self.zone, - self.nsec3_authority, - self.zone.origin, - self.zone.rdclass, - dns.rdatatype.SOA, - soa_rds, - ) + @property + def domains(self) -> list[str]: + return [self._zone.origin.to_text()] - for name, node in self.zone.items(): - rdset = node.get_rdataset(self.zone.rdclass, dns.rdatatype.NSEC3) - if rdset is None: - continue - _append_rrset_with_rrsig( - self.zone, - self.nsec3_authority, - name, - self.zone.rdclass, - dns.rdatatype.NSEC3, - rdset, - ) + def _build_authority(self) -> list[dns.rrset.RRset]: + authority = rrset_with_rrsig(self._zone, self._zone.origin, dns.rdatatype.SOA) + for name, _ in self._zone.iterate_rdatasets(dns.rdatatype.NSEC3): + authority.extend(rrset_with_rrsig(self._zone, name, dns.rdatatype.NSEC3)) + return authority - @property - def domains(self) -> list: - return [self.zone.origin.to_text()] + def match(self, qctx: QueryContext) -> bool: + return super().match(qctx) and self._answer_rds(qctx) is None + + def _answer_rds(self, qctx: QueryContext) -> dns.rdataset.Rdataset | None: + node = self._zone.get_node(qctx.qname) + if node is None: + return None + return node.get_rdataset(dns.rdataclass.IN, qctx.qtype) async def get_responses( self, qctx: QueryContext ) -> AsyncGenerator[DnsResponseSend, None]: qctx.prepare_new_response(with_zone_data=False) - qctx.response.flags |= dns.flags.AA - - node = self.zone.get_node(qctx.qname) - if node is not None: - rds = node.get_rdataset(qctx.qclass, qctx.qtype) - if rds is not None: - _append_rrset_with_rrsig( - self.zone, - qctx.response.answer, - qctx.qname, - qctx.qclass, - qctx.qtype, - rds, - ) - yield DnsResponseSend(qctx.response) - return - qctx.response.set_rcode(dns.rcode.NXDOMAIN) - qctx.response.authority.extend(self.nsec3_authority) + qctx.response.authority.extend(self._nsec3_authority) yield DnsResponseSend(qctx.response) def main() -> None: server = AsyncDnsServer(default_rcode=dns.rcode.NOERROR, default_aa=True) server.install_response_handlers( - LoneRecordHandler(), - CnameZoneHandler( - EXAMPLE, - { - dns.rdatatype.DNSKEY, - dns.rdatatype.NSEC, - dns.rdatatype.NSEC3, - dns.rdatatype.RRSIG, - }, - ), - CnameZoneHandler(SECURE, {dns.rdatatype.DS}), - StuffedNsec3Handler(STUFFED), + LoneAHandler(), + ExampleMetatypeCnameHandler(), + SignedZoneHandler(EXAMPLE), + SecureDsCnameHandler(), + SignedZoneHandler(SECURE), + StuffedNxdomainHandler(STUFFED), + SignedZoneHandler(STUFFED), ) server.run() diff -Nru bind9-9.20.26/bin/tests/system/dnssec_cname_response/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_cname_response/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_cname_response/ns3/named.conf.j2 2026-07-20 14:47:53.693843844 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_cname_response/ns3/named.conf.j2 2026-09-11 19:41:01.181323321 +0000 @@ -1,16 +1,11 @@ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; dnssec-validation yes; - recursion yes; }; +{% include "_common/controls.conf.j2" %} + zone "example." { type static-stub; server-addresses { 10.53.0.2; }; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_nsec3/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_nsec3/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_nsec3/ns2/named.conf.j2 2026-07-20 14:47:53.693843844 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_nsec3/ns2/named.conf.j2 2026-09-11 19:41:01.182323345 +0000 @@ -1,29 +1,15 @@ // validating resolver options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; minimal-responses no; qname-minimization off; }; -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "f025.test" { type static-stub; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_parent_rrsig/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_parent_rrsig/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_parent_rrsig/ns2/named.conf.j2 2026-07-20 14:47:53.694843869 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_parent_rrsig/ns2/named.conf.j2 2026-09-11 19:41:01.182323345 +0000 @@ -1,14 +1,7 @@ // validating resolver options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; trust-anchor-telemetry no; resolver-query-timeout 5000; @@ -16,16 +9,9 @@ minimal-responses no; }; -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "f044.test" { type static-stub; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/ans4/ans.py bind9-9.20.29/bin/tests/system/dnssec_py/ans4/ans.py --- bind9-9.20.26/bin/tests/system/dnssec_py/ans4/ans.py 2026-07-20 14:47:53.694843869 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/ans4/ans.py 2026-09-11 19:41:01.183323370 +0000 @@ -17,7 +17,12 @@ file bounds its scope as the server accrues unrelated domains. """ -from dnssec_py.ans4 import noqname_mismatch, rrsig_labels_signer_ans, sibling_ds_ans +from dnssec_py.ans4 import ( + delegationtrap_ans, + noqname_mismatch, + rrsig_labels_signer_ans, + sibling_ds_ans, +) from isctest.asyncserver import AsyncDnsServer @@ -29,6 +34,8 @@ server.install_response_handlers(noqname_mismatch.RuntimeCheckHandler()) if rrsig_labels_signer_ans.PEM_PATH.exists(): server.install_response_handler(rrsig_labels_signer_ans.AttackerZoneHandler()) + if delegationtrap_ans.PEM_PATH.exists(): + server.install_response_handler(delegationtrap_ans.DelegationTrapHandler()) server.run() diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/ans4/delegationtrap_ans.py bind9-9.20.29/bin/tests/system/dnssec_py/ans4/delegationtrap_ans.py --- bind9-9.20.26/bin/tests/system/dnssec_py/ans4/delegationtrap_ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/ans4/delegationtrap_ans.py 2026-09-11 19:41:01.183323370 +0000 @@ -0,0 +1,153 @@ +# 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. + +"""Handler for the attack.delegationtrap. zone (DelegationTrap reproducer). + +This is a Python port of the DelegationTrap vector from the ReTrap PoC +(gitlab.isc.org/bind-team/nankai-cve-reproducers). It reproduces the +"deep delegation hierarchy" algorithmic-complexity attack described in +issue #5347 (part of the #5341 meta-issue). + +The server is authoritative for the whole attack.delegationtrap. subtree +and pretends that *every* label below the apex is its own secure zone, +all sharing a single reused key. For any name N under the apex it +answers: + + N/DNSKEY -> DNSKEY(K) signed by N (self-signed) + N/DS -> DS(K, owner=N) signed by parent(N) + N/A -> A 10.53.0.4 signed by parent(N) + +Because the A answer is returned directly (no referral) but its RRSIG +signer is the immediate parent, a validating resolver must build the +whole chain of trust label by label: for a query with a depth-D name it +fetches and validates DNSKEY + DS at each of the D levels. This is the +"chain-of-trust construction" cost the attack amplifies, and it is what +BIND's per-fetch validation quota (max-validations-per-fetch) is meant +to bound. + +Key material is written by bootstrap() in tests_delegationtrap.py to +attack_delegationtrap.pem in this directory before any server starts. +""" + +from collections.abc import AsyncGenerator +from pathlib import Path + +import time + +from cryptography.hazmat.primitives import serialization +from dns.rdtypes.dnskeybase import Flag + +import dns.dnssec +import dns.name +import dns.rcode +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset + +from isctest.asyncserver import ( + DnsResponseSend, + DomainHandler, + QueryContext, + ResponseAction, +) + +ZONE_NAME = "attack.delegationtrap." +SERVER_IP = "10.53.0.4" +TTL = 300 +PEM_PATH = Path("attack_delegationtrap.pem") + + +class DelegationTrapHandler(DomainHandler): + """Serve every label under attack.delegationtrap. as a secure zone cut.""" + + domains = [ZONE_NAME] + + def __init__(self) -> None: + super().__init__() + self._apex = dns.name.from_text(ZONE_NAME) + + self._priv = serialization.load_pem_private_key( + PEM_PATH.read_bytes(), password=None + ) + self._dnskey = dns.dnssec.make_dnskey( + self._priv.public_key(), + dns.dnssec.Algorithm.ECDSAP256SHA256, + flags=Flag.ZONE | Flag.SEP, + ) + + now = int(time.time()) + self._inception = now - 3600 + self._expiration = now + 14 * 86400 + + def _sign(self, rrset: dns.rrset.RRset, signer: dns.name.Name) -> dns.rrset.RRset: + """Return an RRSIG RRset covering `rrset`, signed as zone `signer`.""" + rrsig = dns.dnssec.sign( + rrset, + self._priv, + signer=signer, + dnskey=self._dnskey, + inception=self._inception, + expiration=self._expiration, + lifetime=None, + deterministic=False, # for OpenSSL<3.2.0 compat + ) + rrsig_rrset = dns.rrset.RRset( + rrset.name, rrset.rdclass, dns.rdatatype.RRSIG, rrset.rdtype + ) + rrsig_rrset.update_ttl(TTL) + rrsig_rrset.add(rrsig) + return rrsig_rrset + + def _dnskey_rrset(self, name: dns.name.Name) -> dns.rrset.RRset: + rrset = dns.rrset.RRset(name, dns.rdataclass.IN, dns.rdatatype.DNSKEY) + rrset.update_ttl(TTL) + rrset.add(self._dnskey) + return rrset + + def _ds_rrset(self, name: dns.name.Name) -> dns.rrset.RRset: + ds = dns.dnssec.make_ds(name, self._dnskey, dns.dnssec.DSDigest.SHA256) + rrset = dns.rrset.RRset(name, dns.rdataclass.IN, dns.rdatatype.DS) + rrset.update_ttl(TTL) + rrset.add(ds) + return rrset + + def _a_rrset(self, name: dns.name.Name) -> dns.rrset.RRset: + rrset = dns.rrset.RRset(name, dns.rdataclass.IN, dns.rdatatype.A) + rrset.update_ttl(TTL) + rrset.add(dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, SERVER_IP)) + return rrset + + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[ResponseAction, None]: + qname = qctx.qname + qtype = qctx.qtype + response = qctx.prepare_new_response(with_zone_data=False) + response.set_rcode(dns.rcode.NOERROR) + + parent = qname.parent() if qname != dns.name.root else qname + + if qtype == dns.rdatatype.DNSKEY: + # The DNSKEY RRset is signed by the zone itself (self-signed KSK). + rrset = self._dnskey_rrset(qname) + response.answer.extend([rrset, self._sign(rrset, qname)]) + elif qtype == dns.rdatatype.DS: + # A DS lives in the parent zone and is signed by the parent. + rrset = self._ds_rrset(qname) + response.answer.extend([rrset, self._sign(rrset, parent)]) + elif qtype == dns.rdatatype.A: + # The A answer is signed by the immediate parent, forcing the + # resolver to build the trust chain label by label. + rrset = self._a_rrset(qname) + response.answer.extend([rrset, self._sign(rrset, parent)]) + + yield DnsResponseSend(response, authoritative=True) diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/ans4/noqname_mismatch.py bind9-9.20.29/bin/tests/system/dnssec_py/ans4/noqname_mismatch.py --- bind9-9.20.26/bin/tests/system/dnssec_py/ans4/noqname_mismatch.py 2026-07-20 14:47:53.694843869 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/ans4/noqname_mismatch.py 2026-09-11 19:41:01.183323370 +0000 @@ -4,6 +4,13 @@ # # SPDX-License-Identifier: MPL-2.0 +""" +Forged wildcard answers whose NOQNAME proof owner carries both denial types +(NSEC and NSEC3), in the wire orders that made the resolver's +dns_rdataset_addnoqname() and dns_rdataset_getnoqname() disagree about +which proof to cache (#5985, #6369). +""" + from collections.abc import AsyncGenerator from dataclasses import dataclass from datetime import datetime, timedelta, timezone @@ -30,9 +37,26 @@ ZONE = "f217.test." PEM_PATH = Path(f"{ZONE}.pem") CHILD = f"evil.{ZONE}" + +# Signed NSEC followed by an unsigned NSEC3 at the proof owner (#5985). ATTACK = f"www.{CHILD}" +# Signed NSEC3 followed by an unsigned NSEC at the proof owner (#6369). +ATTACK_NSEC3 = f"nsec3.{CHILD}" +# Both denial types signed; only the NSEC3 (second in wire order) covers. +ATTACK_BOTH = f"both.{CHILD}" + +# The forged answers claim to be synthesized from *.evil.f217.test. +WILDCARD_LABELS = len(dns.name.from_text(CHILD).labels) - 1 + +# Not a valid NSEC3 hash label, so only the NSEC is usable at this owner. NSEC_OWNER = f"00000000.{CHILD}" NSEC_NEXT = f"zzz.{CHILD}" +# A valid (all zero) NSEC3 hash label; the NSEC3 covers every hashed name. +NSEC3_OWNER = f"{'0' * 32}.{CHILD}" +NSEC3_NEXT = "V" * 32 +# An NSEC at NSEC3_OWNER with this next name covers none of the qnames. +NSEC_NONCOVERING_NEXT = f"{'0' * 31}1.{CHILD}" + FORGED_A = "192.0.2.217" @@ -107,56 +131,104 @@ return dns.rrset.from_rdata(name(owner), TTL, rdata) +def owner_labels(owner: str) -> int: + """The RRSIG labels field of a non-wildcard record at 'owner'.""" + return len(name(owner).labels) - 1 + + def add_ds_denial(response: dns.message.Message, key: Key) -> None: add_signed(response.authority, soa_rrset(ZONE), key) nsec = rrset(CHILD, dns.rdatatype.NSEC, f"ns.{ZONE} NS RRSIG NSEC") add_signed(response.authority, nsec, key) +def add_forged_answer(response: dns.message.Message, qname: str) -> None: + """ + A forged A record at 'qname' with a garbage RRSIG whose labels field + is that of *.evil.f217.test., so the resolver treats the answer as a + wildcard expansion and looks for a NOQNAME proof (findnoqname()). + + 300 IN A 192.0.2.217 + 300 IN RRSIG A 13 3 300 12345 evil.f217.test. <64 x 0x00> + """ + response.answer.append(rrset(qname, dns.rdatatype.A, FORGED_A)) + response.answer.append( + garbage_rrsig(qname, dns.rdatatype.A, WILDCARD_LABELS, CHILD) + ) + + +def nsec_rrset(owner: str, next_name: str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.NSEC, f"{next_name} A RRSIG NSEC") + + +def nsec_rrsig(owner: str) -> dns.rrset.RRset: + return garbage_rrsig(owner, dns.rdatatype.NSEC, owner_labels(owner), CHILD) + + +def nsec3_rrset(owner: str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.NSEC3, f"1 0 0 - {NSEC3_NEXT} A RRSIG") + + +def nsec3_rrsig(owner: str) -> dns.rrset.RRset: + return garbage_rrsig(owner, dns.rdatatype.NSEC3, owner_labels(owner), CHILD) + + def add_attack_answer(response: dns.message.Message) -> None: """ - Crafted authoritative response to .evil.f217.hack./A + www.evil.f217.test./A (#5985): the proof owner carries a signed NSEC + followed by an unsigned NSEC3. The NSEC3 owner label is not a valid + hash, so findnoqname() selects the NSEC. + + ;; AUTHORITY (single owner, three rdatasets in this wire order) + 00000000.evil.f217.test. 300 IN NSEC zzz.evil.f217.test. A RRSIG NSEC + 00000000.evil.f217.test. 300 IN RRSIG NSEC 13 4 300 12345 evil.f217.test. <64 x 0x00> + 00000000.evil.f217.test. 300 IN NSEC3 1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG + """ + add_forged_answer(response, ATTACK) + response.authority.append(nsec_rrset(NSEC_OWNER, NSEC_NEXT)) + response.authority.append(nsec_rrsig(NSEC_OWNER)) + response.authority.append(nsec3_rrset(NSEC_OWNER)) - ;; ANSWER - .evil.f217.hack. 300 IN A 192.0.2.217 - .evil.f217.hack. 300 IN RRSIG A 13 1 300 12345 evil.f217.hack. - ^^^ Labels = 1, qname has 4 labels, wildcard heuristic fires + +def add_nsec3_attack_answer(response: dns.message.Message) -> None: + """ + nsec3.evil.f217.test./A (#6369): the proof owner carries a signed NSEC3 + covering the hashed qname, followed by an unsigned NSEC that does not + cover the qname, so findnoqname() selects the NSEC3. ;; AUTHORITY (single owner, three rdatasets in this wire order) - 00000000.evil.f217.hack. 300 IN NSEC zzz.evil.f217.hack. A RRSIG NSEC - 00000000.evil.f217.hack. 300 IN RRSIG NSEC 13 4 300 12345 evil.f217.hack. - 00000000.evil.f217.hack. 300 IN NSEC3 1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG - """ - # A + RRSIG - response.answer.append(rrset(ATTACK, dns.rdatatype.A, FORGED_A)) - response.answer.append(garbage_rrsig(ATTACK, dns.rdatatype.A, 1, CHILD)) - # NSEC - nsec = rrset( - NSEC_OWNER, - dns.rdatatype.NSEC, - f"{NSEC_NEXT} A RRSIG NSEC", - ) - response.authority.append(nsec) - # RRSIG(NSEC) - response.authority.append( - garbage_rrsig( - NSEC_OWNER, - dns.rdatatype.NSEC, - len(name(NSEC_OWNER).labels) - 1, - CHILD, - ) - ) - # NSEC3 - nsec3 = rrset( - NSEC_OWNER, - dns.rdatatype.NSEC3, - "1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG", - ) - response.authority.append(nsec3) + <32 x 0>.evil.f217.test. 300 IN NSEC3 1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG + <32 x 0>.evil.f217.test. 300 IN RRSIG NSEC3 13 4 300 12345 evil.f217.test. <64 x 0x00> + <32 x 0>.evil.f217.test. 300 IN NSEC <31 x 0>1.evil.f217.test. A RRSIG NSEC + """ + add_forged_answer(response, ATTACK_NSEC3) + response.authority.append(nsec3_rrset(NSEC3_OWNER)) + response.authority.append(nsec3_rrsig(NSEC3_OWNER)) + response.authority.append(nsec_rrset(NSEC3_OWNER, NSEC_NONCOVERING_NEXT)) + + +def add_both_attack_answer(response: dns.message.Message) -> None: + """ + both.evil.f217.test./A: both denial types are signed at the proof + owner. The NSEC comes first in wire order but does not cover the + qname; the NSEC3 does, so findnoqname() selects the NSEC3 and the + cache must keep that choice rather than the first signed pair. + + ;; AUTHORITY (single owner, four rdatasets in this wire order) + <32 x 0>.evil.f217.test. 300 IN NSEC <31 x 0>1.evil.f217.test. A RRSIG NSEC + <32 x 0>.evil.f217.test. 300 IN RRSIG NSEC 13 4 300 12345 evil.f217.test. <64 x 0x00> + <32 x 0>.evil.f217.test. 300 IN NSEC3 1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG + <32 x 0>.evil.f217.test. 300 IN RRSIG NSEC3 13 4 300 12345 evil.f217.test. <64 x 0x00> + """ + add_forged_answer(response, ATTACK_BOTH) + response.authority.append(nsec_rrset(NSEC3_OWNER, NSEC_NONCOVERING_NEXT)) + response.authority.append(nsec_rrsig(NSEC3_OWNER)) + response.authority.append(nsec3_rrset(NSEC3_OWNER)) + response.authority.append(nsec3_rrsig(NSEC3_OWNER)) class RuntimeCheckHandler(DomainHandler): - """Serve attacker.rrsig-labels-signer. with crafted wildcard RRSIG.""" + """Serve f217.test. and the forged wildcard answers below evil.f217.test.""" domains = [ZONE] @@ -165,7 +237,11 @@ self.key = load_key() self.zone = name(ZONE) self.child = name(CHILD) - self.attack = name(ATTACK) + self.attacks = { + name(ATTACK): add_attack_answer, + name(ATTACK_NSEC3): add_nsec3_attack_answer, + name(ATTACK_BOTH): add_both_attack_answer, + } def match(self, qctx: QueryContext) -> bool: return qctx.qname.is_subdomain(self.zone) @@ -189,8 +265,8 @@ add_ds_denial(qctx.response, self.key) elif qctx.qname == self.child and qctx.qtype == dns.rdatatype.DNSKEY: qctx.response.authority.append(soa_rrset(CHILD)) - elif qctx.qname == self.attack and qctx.qtype == dns.rdatatype.A: - add_attack_answer(qctx.response) + elif qctx.qname in self.attacks and qctx.qtype == dns.rdatatype.A: + self.attacks[qctx.qname](qctx.response) else: add_signed(qctx.response.authority, soa_rrset(ZONE), self.key) diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_py/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_py/ns1/named.conf.j2 2026-07-20 14:47:53.695843894 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/ns1/named.conf.j2 2026-09-11 19:41:01.183323370 +0000 @@ -1,13 +1,7 @@ // NS1 options { - query-source address @ns.ip@; - notify-source @ns.ip@; - transfer-source @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} key-directory "keys"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_py/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_py/ns2/named.conf.j2 2026-07-20 14:47:53.695843894 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/ns2/named.conf.j2 2026-09-11 19:41:01.183323370 +0000 @@ -1,13 +1,7 @@ // NS2 options { - query-source address @ns.ip@; - notify-source @ns.ip@; - transfer-source @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} key-directory "keys"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_py/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_py/ns3/named.conf.j2 2026-07-20 14:47:53.695843894 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/ns3/named.conf.j2 2026-09-11 19:41:01.184323393 +0000 @@ -1,13 +1,7 @@ // NS3 options { - query-source address @ns.ip@; - notify-source @ns.ip@; - transfer-source @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} key-directory "keys"; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_py/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_py/ns9/named.conf.j2 2026-07-20 14:47:53.695843894 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/ns9/named.conf.j2 2026-09-11 19:41:01.184323393 +0000 @@ -3,15 +3,8 @@ {% set max_validations_per_fetch = max_validations_per_fetch | default(16) %} options { - query-source address @ns.ip@; - notify-source @ns.ip@; - transfer-source @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} - recursion yes; dnssec-validation yes; diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/tests_delegationtrap.py bind9-9.20.29/bin/tests/system/dnssec_py/tests_delegationtrap.py --- bind9-9.20.26/bin/tests/system/dnssec_py/tests_delegationtrap.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/tests_delegationtrap.py 2026-09-11 19:41:01.184323393 +0000 @@ -0,0 +1,118 @@ +# 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. + +"""DelegationTrap characterization (issue #5347, part of the #5341 ReTrap set). + +An attacker who controls a DNSSEC-signed zone can hand out a deep chain of +secure delegations so that a single query forces the resolver to build a +very long chain of trust: to validate the leaf answer it must fetch and +validate a DNSKEY and a DS at every label. This is an algorithmic- +complexity attack -- a low query rate turns into a large amount of +signature-verification work. + +In the default configuration this is already bounded by the resolver's +layered work limits, with no extra validation quota required: + + * max-recursion-queries (default 50) caps the whole fetch tree. Every + label forces a DNSKEY *and* a DS fetch -- distinct names the validator + must resolve -- so the chain exhausts the recursion-query budget after + ~25 labels and the deep query is terminated with SERVFAIL. + * max-validations-per-fetch (default 16) independently caps the crypto + within any single RRset's validation (the KeyTrap unit). + +This test pins that default-config behaviour: a shallow name still validates +as secure, and a deep chain is stopped by the recursion-query budget +(SERVFAIL, logged as "exceeded max queries ... max-recursion-queries"). + +Zone hierarchy used by this module: + . (ns1) signed + delegationtrap. (ns2) signed, secure delegation to: + attack.delegationtrap. (ans4) custom auth; every label below the + apex is served as its own secure zone + (see ans4/delegationtrap_ans.py) + ns9: recursive validating resolver, default work limits +""" + +from dnssec_py.common import DNSSEC_PY_MARK +from isctest.algorithms import ECDSAP256SHA256 +from isctest.template import NS2, Nameserver, zones +from isctest.zone import PythonZoneKey, Zone, configure_root + +import isctest +import isctest.check +import isctest.query + +pytestmark = DNSSEC_PY_MARK + +ANS4 = Nameserver("ans4") + +MAX_VALIDATIONS = 16 + +# A depth whose chain of trust needs more DNSKEY/DS fetches than the default +# max-recursion-queries budget allows, so the recursion-query limit stops it. +DEEP = ".".join(["w"] * 32) + ".attack.delegationtrap" + + +def bootstrap(): + """Set up the delegationtrap hierarchy and the attacker key material. + + The attacker zone attack.delegationtrap. is served dynamically by ans4; + only its key needs to exist on disk. It is written both as a PEM (read + by the custom server) and, via a PythonZoneKey attached to the Zone, as + the DS that delegationtrap. (signed by dnssec-signzone) delegates to. + """ + attack = Zone("attack.delegationtrap", ANS4, signed=False) + attack_key = PythonZoneKey.generate(attack, alg=ECDSAP256SHA256) + attack_key.write_private_key_pem("ans4/attack_delegationtrap.pem") + attack.keys = [attack_key] + + parent = Zone("delegationtrap", NS2, signed=True) + parent.delegations = [attack] + parent.configure() + + root = configure_root([parent]) + + return { + "trust_anchors": root.trust_anchors(), + "zones": zones([root, parent]), + "max_validations_per_fetch": MAX_VALIDATIONS, + } + + +def test_delegationtrap_shallow_secure(ns9): + """A shallow name under the attacker zone still validates as secure. + + Its chain of trust is short (well under the query budget), so the + resolver answers NOERROR with the AD bit set. This guards against the + budget breaking ordinary validation. + """ + msg = isctest.query.create("leaf.attack.delegationtrap", "A") + res = isctest.query.udp(msg, ns9.ip) + isctest.check.noerror(res) + isctest.check.adflag(res) + + +def test_delegationtrap_bounded(ns9): + """A deep delegation chain is bounded by max-recursion-queries. + + Building the chain of trust for the 32-label name needs a DNSKEY and a DS + fetch at every label -- more outbound queries than the default + max-recursion-queries (50) budget allows. The resolver therefore exhausts + that budget mid-chain and terminates the query: SERVFAIL, logged as + "exceeded max queries ... max-recursion-queries". This is the + default-config bound that makes the attack a non-issue with no extra + validation quota. + """ + msg = isctest.query.create(DEEP, "A") + with ns9.watch_log_from_here() as watcher: + res = isctest.query.udp(msg, ns9.ip) + watcher.wait_for_line("exceeded max queries") + isctest.check.servfail(res) diff -Nru bind9-9.20.26/bin/tests/system/dnssec_py/tests_findnoqname_mismatch.py bind9-9.20.29/bin/tests/system/dnssec_py/tests_findnoqname_mismatch.py --- bind9-9.20.26/bin/tests/system/dnssec_py/tests_findnoqname_mismatch.py 2026-07-20 14:47:53.696843919 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_py/tests_findnoqname_mismatch.py 2026-09-11 19:41:01.184323393 +0000 @@ -4,6 +4,11 @@ # # SPDX-License-Identifier: MPL-2.0 +""" +The resolver must cache the NOQNAME proof that findnoqname() selected, and +serve it back, when the proof owner carries both NSEC and NSEC3 records in +any wire order (#5985, #6369). +""" from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec @@ -23,7 +28,11 @@ ZONE = "f217.test." CHILD = f"evil.{ZONE}" ATTACK = f"www.{CHILD}" +ATTACK_NSEC3 = f"nsec3.{CHILD}" +ATTACK_BOTH = f"both.{CHILD}" +WILDCARD_LABELS = 3 NSEC_OWNER = f"00000000.{CHILD}" +NSEC3_OWNER = f"{'0' * 32}.{CHILD}" FORGED_A = "192.0.2.217" AUTH = "10.53.0.4" RESOLVER = "10.53.0.9" @@ -98,31 +107,79 @@ assert rrsig[0].labels == labels, response.to_text() -def test_malicious_findnoqname_addnoqname_mismatch(): - response = _query(AUTH, ATTACK, "A") - isctest.check.noerror(response) - assert _has_a(response, response.answer, ATTACK, FORGED_A), response.to_text() - _check_rrsig(response, response.answer, ATTACK, dns.rdatatype.A, CHILD, labels=1) +def _check_proof(response, owner, rdtype, signed): + """Check the denial type 'rdtype' is present at 'owner', signed or not.""" + assert _rrset(response, response.authority, owner, rdtype), response.to_text() + rrsig = _rrset(response, response.authority, owner, dns.rdatatype.RRSIG, rdtype) + if signed: + _check_rrsig(response, response.authority, owner, rdtype, CHILD) + else: + assert rrsig is None, response.to_text() - # Has NSEC - assert _rrset(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC) - _check_rrsig(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC, CHILD) - # Has NSEC3 - assert _rrset(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC3) - assert ( - _rrset( - response, - response.authority, - NSEC_OWNER, - dns.rdatatype.RRSIG, - covers=dns.rdatatype.NSEC3, - ) - is None + +def _check_forged_answer(server, qname): + response = _query(server, qname, "A") + isctest.check.noerror(response) + assert _has_a(response, response.answer, qname, FORGED_A), response.to_text() + _check_rrsig( + response, response.answer, qname, dns.rdatatype.A, CHILD, WILDCARD_LABELS ) + return response -def test_resolver_findnoqname_addnoqname_mismatch(): - # Send one trigger query - _query(RESOLVER, ATTACK, "A") +def test_malicious_findnoqname_addnoqname_mismatch(): + # #5985: signed NSEC followed by unsigned NSEC3 + response = _check_forged_answer(AUTH, ATTACK) + _check_proof(response, NSEC_OWNER, dns.rdatatype.NSEC, signed=True) + _check_proof(response, NSEC_OWNER, dns.rdatatype.NSEC3, signed=False) + + +def test_malicious_nsec3_then_unsigned_nsec(): + # #6369: signed NSEC3 followed by unsigned NSEC + response = _check_forged_answer(AUTH, ATTACK_NSEC3) + _check_proof(response, NSEC3_OWNER, dns.rdatatype.NSEC3, signed=True) + _check_proof(response, NSEC3_OWNER, dns.rdatatype.NSEC, signed=False) + + +def test_malicious_both_signed(): + # both denial types signed, non-covering NSEC first + response = _check_forged_answer(AUTH, ATTACK_BOTH) + _check_proof(response, NSEC3_OWNER, dns.rdatatype.NSEC, signed=True) + _check_proof(response, NSEC3_OWNER, dns.rdatatype.NSEC3, signed=True) + + +def _check_cached_proof(qname, owner, selected, other): + # The trigger query caches the forged answer along with the NOQNAME + # proof that findnoqname() selected... + _check_forged_answer(RESOLVER, qname) + + # ...and the cached answer is served with that same proof. + response = _check_forged_answer(RESOLVER, qname) + _check_proof(response, owner, selected, signed=True) + assert ( + _rrset(response, response.authority, owner, other) is None + ), response.to_text() + + # named is still alive response = _query(RESOLVER, ZONE, "SOA") isctest.check.noerror(response) + + +def test_resolver_findnoqname_addnoqname_mismatch(): + # #5985: signed NSEC followed by unsigned NSEC3 + _check_cached_proof(ATTACK, NSEC_OWNER, dns.rdatatype.NSEC, dns.rdatatype.NSEC3) + + +def test_resolver_nsec3_then_unsigned_nsec(): + # #6369: signed NSEC3 followed by unsigned NSEC + _check_cached_proof( + ATTACK_NSEC3, NSEC3_OWNER, dns.rdatatype.NSEC3, dns.rdatatype.NSEC + ) + + +def test_resolver_keeps_selected_proof(): + # both denial types signed: the covering NSEC3 was selected, not the + # NSEC that comes first in wire order + _check_cached_proof( + ATTACK_BOTH, NSEC3_OWNER, dns.rdatatype.NSEC3, dns.rdatatype.NSEC + ) diff -Nru bind9-9.20.26/bin/tests/system/dnssec_wildcard/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dnssec_wildcard/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnssec_wildcard/ns2/named.conf.j2 2026-07-20 14:47:53.697843944 +0000 +++ bind9-9.20.29/bin/tests/system/dnssec_wildcard/ns2/named.conf.j2 2026-09-11 19:41:01.185323418 +0000 @@ -1,38 +1,24 @@ // validating resolver options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; minimal-responses no; }; -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} {% if PARENT_DNSKEY is defined and PARENT_DNSKEY|length %} zone "f045.test" { - type static-stub; - server-addresses { 10.53.0.1; }; + type static-stub; + server-addresses { 10.53.0.1; }; }; trust-anchors { - f045.test. static-key 257 3 13 "@PARENT_DNSKEY@"; + f045.test. static-key 257 3 13 "@PARENT_DNSKEY@"; }; {% else %} zone "f043.test" { diff -Nru bind9-9.20.26/bin/tests/system/dnstap/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dnstap/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnstap/ns1/named.conf.j2 2026-07-20 14:47:53.699843994 +0000 +++ bind9-9.20.29/bin/tests/system/dnstap/ns1/named.conf.j2 2026-09-11 19:41:01.188323490 +0000 @@ -12,15 +12,8 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; statistics-file "named.stats"; dnstap-identity "ns1"; dnstap-version "xxx"; @@ -33,14 +26,7 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/dnstap/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dnstap/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnstap/ns2/named.conf.j2 2026-07-20 14:47:53.700844019 +0000 +++ bind9-9.20.29/bin/tests/system/dnstap/ns2/named.conf.j2 2026-09-11 19:41:01.188323490 +0000 @@ -12,15 +12,7 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} statistics-file "named.stats"; dnstap-identity "ns2"; dnstap-version "xxx"; @@ -33,19 +25,9 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/dnstap/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/dnstap/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnstap/ns3/named.conf.j2 2026-07-20 14:47:53.700844019 +0000 +++ bind9-9.20.29/bin/tests/system/dnstap/ns3/named.conf.j2 2026-09-11 19:41:01.189323514 +0000 @@ -12,16 +12,7 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnstap-identity "ns3"; dnstap-version "xxx"; dnstap-output file "dnstap.out"; @@ -36,16 +27,6 @@ server 10.53.0.1 { tcp-only yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/dnstap/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/dnstap/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnstap/ns4/named.conf.j2 2026-07-20 14:47:53.700844019 +0000 +++ bind9-9.20.29/bin/tests/system/dnstap/ns4/named.conf.j2 2026-09-11 19:41:01.189323514 +0000 @@ -12,16 +12,7 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnstap-identity "ns4"; dnstap-version "xxx"; dnstap-output unix "dnstap.out"; @@ -35,16 +26,6 @@ server 10.53.0.1 { tcp-only yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/dnstap/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/dnstap/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dnstap/ns5/named.conf.j2 2026-07-20 14:47:53.700844019 +0000 +++ bind9-9.20.29/bin/tests/system/dnstap/ns5/named.conf.j2 2026-09-11 19:41:01.189323514 +0000 @@ -12,16 +12,7 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnstap-identity "ns5"; dnstap-version "xxx"; dnstap-output file "dnstap.out"; @@ -34,11 +25,4 @@ forward only; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/dnstap/tests_sh_dnstap.py bind9-9.20.29/bin/tests/system/dnstap/tests_sh_dnstap.py --- bind9-9.20.26/bin/tests/system/dnstap/tests_sh_dnstap.py 2026-07-20 14:47:53.700844019 +0000 +++ bind9-9.20.29/bin/tests/system/dnstap/tests_sh_dnstap.py 2026-09-11 19:41:01.189323514 +0000 @@ -31,6 +31,5 @@ ] -@pytest.mark.flaky(max_runs=2, rerun_filter=isctest.mark.is_host_freebsd_13) def test_dnstap(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/doth/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/doth/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/doth/ns1/named.conf.j2 2026-07-20 14:47:53.705844145 +0000 +++ bind9-9.20.29/bin/tests/system/doth/ns1/named.conf.j2 2026-09-11 19:41:01.194323635 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} http local { endpoints { "/dns-query"; "/alter"; }; @@ -69,27 +65,24 @@ }; options { - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; https-port @HTTPSPORT@; http-port @HTTPPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on tls tls-forward-secrecy { 10.53.0.1; }; // DoT - listen-on-v6 tls tls-forward-secrecy { fd92:7065:b8e:ffff::1;}; - listen-on tls ephemeral http local { 10.53.0.1; }; // DoH - listen-on-v6 tls ephemeral http local { fd92:7065:b8e:ffff::1; }; - listen-on tls none http local { 10.53.0.1; }; // unencrypted DoH - listen-on-v6 tls none http local { fd92:7065:b8e:ffff::1; }; - listen-on-v6 { none; }; - listen-on port @EXTRAPORT1@ tls tls-pfs-aes256 { 10.53.0.1; }; // DoT - listen-on-v6 port @EXTRAPORT1@ tls tls-pfs-aes256 { fd92:7065:b8e:ffff::1;}; - listen-on port @EXTRAPORT2@ tls tls-no-subject-alt-name { 10.53.0.1; }; // DoT - listen-on port @EXTRAPORT3@ tls tls-no-subject-alt-name http local { 10.53.0.1; }; // DoH - listen-on port @EXTRAPORT4@ tls tls-expired { 10.53.0.1; }; // DoT - listen-on port @EXTRAPORT5@ tls tls-forward-secrecy-mutual-tls { 10.53.0.1; }; // DoT - listen-on port @EXTRAPORT6@ tls tls-forward-secrecy-mutual-tls http local { 10.53.0.1; }; // DoH - listen-on port @EXTRAPORT7@ tls tls-forward-secrecy { 10.53.0.1; }; // DoT + listen-on tls tls-forward-secrecy { @ns.ip@; }; // DoT + listen-on-v6 tls tls-forward-secrecy { @ns.ip6@;}; + listen-on tls ephemeral http local { @ns.ip@; }; // DoH + listen-on-v6 tls ephemeral http local { @ns.ip6@; }; + listen-on tls none http local { @ns.ip@; }; // unencrypted DoH + listen-on-v6 tls none http local { @ns.ip6@; }; + listen-on port @EXTRAPORT1@ tls tls-pfs-aes256 { @ns.ip@; }; // DoT + listen-on-v6 port @EXTRAPORT1@ tls tls-pfs-aes256 { @ns.ip6@;}; + listen-on port @EXTRAPORT2@ tls tls-no-subject-alt-name { @ns.ip@; }; // DoT + listen-on port @EXTRAPORT3@ tls tls-no-subject-alt-name http local { @ns.ip@; }; // DoH + listen-on port @EXTRAPORT4@ tls tls-expired { @ns.ip@; }; // DoT + listen-on port @EXTRAPORT5@ tls tls-forward-secrecy-mutual-tls { @ns.ip@; }; // DoT + listen-on port @EXTRAPORT6@ tls tls-forward-secrecy-mutual-tls http local { @ns.ip@; }; // DoH + listen-on port @EXTRAPORT7@ tls tls-forward-secrecy { @ns.ip@; }; // DoT recursion no; notify explicit; also-notify { 10.53.0.2 port @PORT@; }; @@ -101,7 +94,6 @@ max-records-per-type 0; }; - zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/doth/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/doth/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/doth/ns2/named.conf.j2 2026-07-20 14:47:53.706844170 +0000 +++ bind9-9.20.29/bin/tests/system/doth/ns2/named.conf.j2 2026-09-11 19:41:01.195323659 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls local { key-file "../CA/certs/srv02.crt01.example.com.key"; @@ -28,26 +24,19 @@ }; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; https-port @HTTPSPORT@; http-port @HTTPPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on tls local { 10.53.0.2; }; // DoT - listen-on-v6 tls local { fd92:7065:b8e:ffff::2; }; - listen-on tls local http local { 10.53.0.2; }; // DoH - listen-on-v6 tls local http local { fd92:7065:b8e:ffff::2; }; - listen-on tls none http local { 10.53.0.2; }; // unencrypted DoH - listen-on-v6 tls none http local { fd92:7065:b8e:ffff::2; }; - listen-on-v6 { none; }; - recursion yes; + listen-on tls local { @ns.ip@; }; // DoT + listen-on-v6 tls local { @ns.ip6@; }; + listen-on tls local http local { @ns.ip@; }; // DoH + listen-on-v6 tls local http local { @ns.ip6@; }; + listen-on tls none http local { @ns.ip@; }; // unencrypted DoH + listen-on-v6 tls none http local { @ns.ip6@; }; allow-recursion { any; }; allow-query-cache { any; }; - allow-recursion-on { 10.53.0.2; }; # allow-query-cache-on inherits; + allow-recursion-on { @ns.ip@; }; # allow-query-cache-on inherits; notify no; ixfr-from-differences yes; check-integrity no; @@ -57,11 +46,7 @@ transfers-out 100; }; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} tls tls-example-primary-wrong-ca { remote-hostname "srv01.crt01.example.com"; // enable Strict TLS @@ -71,7 +56,7 @@ zone "test.example.com" { type forward; forward only; - forwarders port @TLSPORT@ { 10.53.0.2 tls tls-example-primary-wrong-ca; }; + forwarders port @TLSPORT@ { @ns.ip@ tls tls-example-primary-wrong-ca; }; }; tls tls-example-primary { @@ -173,7 +158,7 @@ }; tls tls-example-primary-mutual-tls { - remote-hostname "srv01.crt01.example.com"; + remote-hostname "srv01.crt01.example.com"; ca-file "../CA/CA.pem"; cert-file "../CA/certs/srv01.client02-ns2.example.com.pem"; key-file "../CA/certs/srv01.client02-ns2.example.com.key"; @@ -194,7 +179,7 @@ }; tls tls-example-primary-mutual-tls-expired { - remote-hostname "srv01.crt01.example.com"; + remote-hostname "srv01.crt01.example.com"; ca-file "../CA/CA.pem"; cert-file "../CA/certs/srv01.client03-ns2-expired.example.com.pem"; key-file "../CA/certs/srv01.client03-ns2-expired.example.com.key"; diff -Nru bind9-9.20.26/bin/tests/system/doth/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/doth/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/doth/ns3/named.conf.j2 2026-07-20 14:47:53.706844170 +0000 +++ bind9-9.20.29/bin/tests/system/doth/ns3/named.conf.j2 2026-09-11 19:41:01.195323659 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls local { key-file "../CA/certs/srv03.crt01.example.com.key"; @@ -28,17 +24,11 @@ }; options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; https-port @HTTPSPORT@; http-port @HTTPPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on tls local { 10.53.0.3; }; // DoT - listen-on-v6 { none; }; + listen-on tls local { @ns.ip@; }; // DoT recursion no; notify no; ixfr-from-differences yes; @@ -47,11 +37,7 @@ max-records-per-type 0; }; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} tls tls-v1.2-pfs { protocols { TLSv1.2; }; diff -Nru bind9-9.20.26/bin/tests/system/doth/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/doth/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/doth/ns4/named.conf.j2 2026-07-20 14:47:53.706844170 +0000 +++ bind9-9.20.29/bin/tests/system/doth/ns4/named.conf.j2 2026-09-11 19:41:01.195323659 +0000 @@ -18,11 +18,7 @@ # startup/reconfiguration was known to cause timeout issues in the CI # system, where many tests run in parallel. -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls local { key-file "../CA/certs/srv04.crt01.example.com.key"; @@ -35,18 +31,12 @@ }; options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; https-port @HTTPSPORT@; http-port @HTTPPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on tls local { 10.53.0.4; }; // DoT - listen-on tls local http local { 10.53.0.4; }; // DoH - listen-on-v6 { none; }; + listen-on tls local { @ns.ip@; }; // DoT + listen-on tls local http local { @ns.ip@; }; // DoH recursion no; notify no; ixfr-from-differences yes; @@ -56,10 +46,7 @@ }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} tls tls-v1.2-pfs { protocols { TLSv1.2; }; diff -Nru bind9-9.20.26/bin/tests/system/doth/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/doth/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/doth/ns5/named.conf.j2 2026-07-20 14:47:53.706844170 +0000 +++ bind9-9.20.29/bin/tests/system/doth/ns5/named.conf.j2 2026-09-11 19:41:01.195323659 +0000 @@ -18,23 +18,13 @@ # startup/reconfiguration was known to cause timeout issues in the CI # system, where many tests run in parallel. -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; https-port @HTTPSPORT@; http-port @HTTPPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; recursion no; notify no; ixfr-from-differences yes; @@ -44,10 +34,7 @@ }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} # Let's reuse the same entry multiple times to see if transfers will succeed diff -Nru bind9-9.20.26/bin/tests/system/doth/prereq.sh bind9-9.20.29/bin/tests/system/doth/prereq.sh --- bind9-9.20.26/bin/tests/system/doth/prereq.sh 2026-07-20 14:47:53.706844170 +0000 +++ bind9-9.20.29/bin/tests/system/doth/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -#!/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. - -. ../conf.sh - -$FEATURETEST --with-libnghttp2 || { - echo_i "This test requires libnghttp2 support." >&2 - exit 255 -} - -$FEATURETEST --have-fips-dh || { - echo_i "FIPS mode Diffie-Hellman not working - skipping doth test" - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/doth/tests_gnutls.py bind9-9.20.29/bin/tests/system/doth/tests_gnutls.py --- bind9-9.20.26/bin/tests/system/doth/tests_gnutls.py 2026-07-20 14:47:53.707844195 +0000 +++ bind9-9.20.29/bin/tests/system/doth/tests_gnutls.py 2026-09-11 19:41:01.196323683 +0000 @@ -24,14 +24,21 @@ import pytest import isctest +import isctest.mark -pytestmark = pytest.mark.extra_artifacts( +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "gnutls-cli.*", "ns*/example*.db", ] ) +pytestmark = [ + isctest.mark.with_libnghttp2, + isctest.mark.with_fips_dh, + EXTRA_ARTIFACTS, +] + def test_gnutls_cli_query(gnutls_cli_executable, named_tlsport): # Prepare the example/SOA query which will be sent over TLS. diff -Nru bind9-9.20.26/bin/tests/system/doth/tests_malicious.py bind9-9.20.29/bin/tests/system/doth/tests_malicious.py --- bind9-9.20.26/bin/tests/system/doth/tests_malicious.py 2026-07-20 14:47:53.707844195 +0000 +++ bind9-9.20.29/bin/tests/system/doth/tests_malicious.py 2026-09-11 19:41:01.196323683 +0000 @@ -18,6 +18,13 @@ import dns.message +import isctest.mark + +pytestmark = [ + isctest.mark.with_libnghttp2, + isctest.mark.with_fips_dh, +] + def test_settings_frame_flood(ns1, named_httpsport): msg = dns.message.make_query(".", "SOA") diff -Nru bind9-9.20.26/bin/tests/system/doth/tests_sh_doth.py bind9-9.20.29/bin/tests/system/doth/tests_sh_doth.py --- bind9-9.20.26/bin/tests/system/doth/tests_sh_doth.py 2026-07-20 14:47:53.707844195 +0000 +++ bind9-9.20.29/bin/tests/system/doth/tests_sh_doth.py 2026-09-11 19:41:01.196323683 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "headers.*", @@ -19,6 +21,12 @@ ] ) +pytestmark = [ + isctest.mark.with_libnghttp2, + isctest.mark.with_fips_dh, + EXTRA_ARTIFACTS, +] + def test_doth(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/doth/tests_sslyze.py bind9-9.20.29/bin/tests/system/doth/tests_sslyze.py --- bind9-9.20.26/bin/tests/system/doth/tests_sslyze.py 2026-07-20 14:47:53.707844195 +0000 +++ bind9-9.20.29/bin/tests/system/doth/tests_sslyze.py 2026-09-11 19:41:01.196323683 +0000 @@ -18,14 +18,21 @@ import pytest import isctest +import isctest.mark -pytestmark = pytest.mark.extra_artifacts( +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "sslyze.log.*", "ns*/example*.db", ] ) +pytestmark = [ + isctest.mark.with_libnghttp2, + isctest.mark.with_fips_dh, + EXTRA_ARTIFACTS, +] + def is_pid_alive(pid): try: diff -Nru bind9-9.20.26/bin/tests/system/dsdigest/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dsdigest/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dsdigest/ns1/named.conf.j2 2026-07-20 14:47:53.707844195 +0000 +++ bind9-9.20.29/bin/tests/system/dsdigest/ns1/named.conf.j2 2026-09-11 19:41:01.196323683 +0000 @@ -13,18 +13,11 @@ // NS1 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; diff -Nru bind9-9.20.26/bin/tests/system/dsdigest/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/dsdigest/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dsdigest/ns2/named.conf.j2 2026-07-20 14:47:53.707844195 +0000 +++ bind9-9.20.29/bin/tests/system/dsdigest/ns2/named.conf.j2 2026-09-11 19:41:01.196323683 +0000 @@ -13,25 +13,15 @@ // NS2 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "good" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/dsdigest/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/dsdigest/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dsdigest/ns3/named.conf.j2 2026-07-20 14:47:53.708844220 +0000 +++ bind9-9.20.29/bin/tests/system/dsdigest/ns3/named.conf.j2 2026-09-11 19:41:01.197323708 +0000 @@ -13,17 +13,10 @@ // NS3 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; dnssec-must-be-secure . yes; /* only SHA-256 is enabled */ @@ -31,9 +24,6 @@ }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/dsdigest/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/dsdigest/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dsdigest/ns4/named.conf.j2 2026-07-20 14:47:53.708844220 +0000 +++ bind9-9.20.29/bin/tests/system/dsdigest/ns4/named.conf.j2 2026-09-11 19:41:01.197323708 +0000 @@ -13,25 +13,15 @@ // NS3 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; /* only SHA-256 is enabled */ disable-ds-digests . { SHA-1; SHA-384; 5; 6; 7; 8; 9; }; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/dyndb/driver/Makefile.in bind9-9.20.29/bin/tests/system/dyndb/driver/Makefile.in --- bind9-9.20.26/bin/tests/system/dyndb/driver/Makefile.in 2026-07-20 14:49:10.419577714 +0000 +++ bind9-9.20.29/bin/tests/system/dyndb/driver/Makefile.in 2026-09-11 19:42:18.392184708 +0000 @@ -273,6 +273,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/tests/system/dyndb/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/dyndb/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/dyndb/ns1/named.conf.j2 2026-07-20 14:47:53.710844270 +0000 +++ bind9-9.20.29/bin/tests/system/dyndb/ns1/named.conf.j2 2026-09-11 19:41:01.199323756 +0000 @@ -11,30 +11,17 @@ * information regarding copyright ownership. */ -controls { }; - options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.1; 127.0.0.1; }; + listen-on { @ns.ip@; 127.0.0.1; }; listen-on-v6 { none; }; recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dyndb sample "../driver/.libs/sample.so" { ipv4.example.nil. in-addr.arpa. }; dyndb sample2 "../driver/.libs/sample.so" { ipv6.example.nil. 8.b.d.0.1.0.0.2.ip6.arpa. }; diff -Nru bind9-9.20.26/bin/tests/system/dyndb/prereq.sh bind9-9.20.29/bin/tests/system/dyndb/prereq.sh --- bind9-9.20.26/bin/tests/system/dyndb/prereq.sh 2026-07-20 14:47:53.710844270 +0000 +++ bind9-9.20.29/bin/tests/system/dyndb/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -$FEATURETEST --tsan && { - echo_i "TSAN - skipping dyndb test" - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/dyndb/tests_sh_dyndb.py bind9-9.20.29/bin/tests/system/dyndb/tests_sh_dyndb.py --- bind9-9.20.26/bin/tests/system/dyndb/tests_sh_dyndb.py 2026-07-20 14:47:53.710844270 +0000 +++ bind9-9.20.29/bin/tests/system/dyndb/tests_sh_dyndb.py 2026-09-11 19:41:01.199323756 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "added.*", "deleted.*", @@ -19,6 +21,11 @@ ] ) +pytestmark = [ + isctest.mark.without_tsan, + EXTRA_ARTIFACTS, +] + def test_dyndb(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/ecdsa/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/ecdsa/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ecdsa/ns1/named.conf.j2 2026-07-20 14:47:53.711844295 +0000 +++ bind9-9.20.29/bin/tests/system/ecdsa/ns1/named.conf.j2 2026-09-11 19:41:01.199323756 +0000 @@ -13,18 +13,11 @@ // NS1 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; diff -Nru bind9-9.20.26/bin/tests/system/ecdsa/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/ecdsa/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ecdsa/ns2/named.conf.j2 2026-07-20 14:47:53.711844295 +0000 +++ bind9-9.20.29/bin/tests/system/ecdsa/ns2/named.conf.j2 2026-09-11 19:41:01.199323756 +0000 @@ -13,24 +13,13 @@ // NS2 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/ecdsa/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/ecdsa/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ecdsa/ns3/named.conf.j2 2026-07-20 14:47:53.711844295 +0000 +++ bind9-9.20.29/bin/tests/system/ecdsa/ns3/named.conf.j2 2026-09-11 19:41:01.199323756 +0000 @@ -13,24 +13,13 @@ // NS2 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/eddsa/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/eddsa/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/eddsa/ns1/named.conf.j2 2026-07-20 14:47:53.712844320 +0000 +++ bind9-9.20.29/bin/tests/system/eddsa/ns1/named.conf.j2 2026-09-11 19:41:01.200323780 +0000 @@ -13,18 +13,11 @@ // NS1 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; diff -Nru bind9-9.20.26/bin/tests/system/eddsa/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/eddsa/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/eddsa/ns2/named.conf.j2 2026-07-20 14:47:53.712844320 +0000 +++ bind9-9.20.29/bin/tests/system/eddsa/ns2/named.conf.j2 2026-09-11 19:41:01.200323780 +0000 @@ -13,24 +13,13 @@ // NS2 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/eddsa/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/eddsa/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/eddsa/ns3/named.conf.j2 2026-07-20 14:47:53.713844345 +0000 +++ bind9-9.20.29/bin/tests/system/eddsa/ns3/named.conf.j2 2026-09-11 19:41:01.201323804 +0000 @@ -13,24 +13,13 @@ // NS2 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/eddsa/prereq.sh bind9-9.20.29/bin/tests/system/eddsa/prereq.sh --- bind9-9.20.26/bin/tests/system/eddsa/prereq.sh 2026-07-20 14:47:53.713844345 +0000 +++ bind9-9.20.29/bin/tests/system/eddsa/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -#!/bin/sh -e - -# 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 - -if [ $ED25519_SUPPORTED = 0 ] && [ $ED448_SUPPORTED = 0 ]; then - exit 1 -fi diff -Nru bind9-9.20.26/bin/tests/system/eddsa/tests_sh_eddsa.py bind9-9.20.29/bin/tests/system/eddsa/tests_sh_eddsa.py --- bind9-9.20.26/bin/tests/system/eddsa/tests_sh_eddsa.py 2026-07-20 14:47:53.713844345 +0000 +++ bind9-9.20.29/bin/tests/system/eddsa/tests_sh_eddsa.py 2026-09-11 19:41:01.201323804 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "ns*/*.signed", @@ -25,6 +27,11 @@ ] ) +pytestmark = [ + isctest.mark.with_eddsa, + EXTRA_ARTIFACTS, +] + def test_eddsa(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/ednscompliance/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/ednscompliance/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ednscompliance/ns1/named.conf.j2 2026-07-20 14:47:53.714844370 +0000 +++ bind9-9.20.29/bin/tests/system/ednscompliance/ns1/named.conf.j2 2026-09-11 19:41:01.201323804 +0000 @@ -12,18 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; server-id "ns1"; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/emptyzones/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/emptyzones/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/emptyzones/ns1/named.conf.j2 2026-07-20 14:47:53.714844370 +0000 +++ bind9-9.20.29/bin/tests/system/emptyzones/ns1/named.conf.j2 2026-09-11 19:41:01.202323828 +0000 @@ -11,30 +11,18 @@ * information regarding copyright ownership. */ -key rndc_key { - algorithm @DEFAULT_HMAC@; - secret "1234abcd8765"; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; } - except-from { "example.org"; }; + except-from { "example.org"; }; deny-answer-aliases { "example.org"; } - except-from { "goodcname.example.net"; - "gooddname.example.net"; }; + except-from { + "goodcname.example.net"; + "gooddname.example.net"; + }; allow-query {!10.53.0.8; any; }; allow-transfer { none; }; }; diff -Nru bind9-9.20.26/bin/tests/system/enginepkcs11/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/enginepkcs11/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/enginepkcs11/ns1/named.conf.j2 2026-07-20 14:47:53.715844395 +0000 +++ bind9-9.20.29/bin/tests/system/enginepkcs11/ns1/named.conf.j2 2026-09-11 19:41:01.202323828 +0000 @@ -11,29 +11,14 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; - options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key-store "hsm" { directory "."; diff -Nru bind9-9.20.26/bin/tests/system/enginepkcs11/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/enginepkcs11/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/enginepkcs11/ns2/named.conf.j2 2026-07-20 14:47:53.715844395 +0000 +++ bind9-9.20.29/bin/tests/system/enginepkcs11/ns2/named.conf.j2 2026-09-11 19:41:01.202323828 +0000 @@ -11,29 +11,23 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; }; key "keyforview1" { - algorithm @DEFAULT_HMAC@; - secret "YPfMoAk6h+3iN8MDRQC004iSNHY="; + algorithm @DEFAULT_HMAC@; + secret "YPfMoAk6h+3iN8MDRQC004iSNHY="; }; key "keyforview2" { - algorithm @DEFAULT_HMAC@; - secret "4xILSZQnuO1UKubXHkYUsvBRPu8="; + algorithm @DEFAULT_HMAC@; + secret "4xILSZQnuO1UKubXHkYUsvBRPu8="; }; key-store "hsm" { diff -Nru bind9-9.20.26/bin/tests/system/enginepkcs11/prereq.sh bind9-9.20.29/bin/tests/system/enginepkcs11/prereq.sh --- bind9-9.20.26/bin/tests/system/enginepkcs11/prereq.sh 2026-07-20 14:47:53.715844395 +0000 +++ bind9-9.20.29/bin/tests/system/enginepkcs11/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -#!/bin/sh -e -# -# 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. - -. ../conf.sh - -[ "prereq/var/tmp/etc/openssl-provider.cnf" = "prereq${OPENSSL_CONF}" ] || { - echo_i "skip: pkcs11-provider not enabled" - exit 255 -} - -[ -n "${SOFTHSM2_CONF}" ] || { - echo_i "skip: softhsm2 configuration not available" - exit 255 -} - -[ -f "$SOFTHSM2_MODULE" ] || { - echo_i "skip: softhsm2 module not available" - exit 1 -} - -for _bin in softhsm2-util pkcs11-tool; do - command -v "$_bin" >/dev/null || { - echo_i "skip: $_bin not available" - exit 1 - } -done diff -Nru bind9-9.20.26/bin/tests/system/enginepkcs11/tests_sh_enginepkcs11.py bind9-9.20.29/bin/tests/system/enginepkcs11/tests_sh_enginepkcs11.py --- bind9-9.20.26/bin/tests/system/enginepkcs11/tests_sh_enginepkcs11.py 2026-07-20 14:47:53.715844395 +0000 +++ bind9-9.20.29/bin/tests/system/enginepkcs11/tests_sh_enginepkcs11.py 2026-09-11 19:41:01.203323852 +0000 @@ -13,7 +13,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "dsset-*", @@ -52,6 +54,12 @@ ] ) +pytestmark = [ + isctest.mark.with_pkcs11_provider, + isctest.mark.softhsm2_environment, + EXTRA_ARTIFACTS, +] + def bootstrap(): return { diff -Nru bind9-9.20.26/bin/tests/system/expiredglue/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/expiredglue/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/expiredglue/ns1/named.conf.j2 2026-07-20 14:47:53.716844420 +0000 +++ bind9-9.20.29/bin/tests/system/expiredglue/ns1/named.conf.j2 2026-09-11 19:41:01.203323852 +0000 @@ -12,12 +12,7 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -29,11 +24,4 @@ }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/expiredglue/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/expiredglue/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/expiredglue/ns2/named.conf.j2 2026-07-20 14:47:53.716844420 +0000 +++ bind9-9.20.29/bin/tests/system/expiredglue/ns2/named.conf.j2 2026-09-11 19:41:01.203323852 +0000 @@ -12,12 +12,7 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -27,11 +22,4 @@ file "tld.db"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/expiredglue/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/expiredglue/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/expiredglue/ns3/named.conf.j2 2026-07-20 14:47:53.716844420 +0000 +++ bind9-9.20.29/bin/tests/system/expiredglue/ns3/named.conf.j2 2026-09-11 19:41:01.204323877 +0000 @@ -12,12 +12,7 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -32,11 +27,4 @@ file "example.tld.db"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/expiredglue/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/expiredglue/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/expiredglue/ns4/named.conf.j2 2026-07-20 14:47:53.716844420 +0000 +++ bind9-9.20.29/bin/tests/system/expiredglue/ns4/named.conf.j2 2026-09-11 19:41:01.204323877 +0000 @@ -12,26 +12,10 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; -zone "." { - type hint; - file "root.hint"; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/root.hint.conf" %} -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/expiredglue/ns4/root.hint bind9-9.20.29/bin/tests/system/expiredglue/ns4/root.hint --- bind9-9.20.26/bin/tests/system/expiredglue/ns4/root.hint 2026-07-20 14:47:53.716844420 +0000 +++ bind9-9.20.29/bin/tests/system/expiredglue/ns4/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/fetchlimit/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/fetchlimit/ns1/named.conf.j2 2026-07-20 14:47:53.717844445 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns1/named.conf.j2 2026-09-11 19:41:01.204323877 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/fetchlimit/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/fetchlimit/ns2/named.conf.j2 2026-07-20 14:47:53.717844445 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns2/named.conf.j2 2026-09-11 19:41:01.204323877 +0000 @@ -12,26 +12,12 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/fetchlimit/ns3/named.conf.j2 2026-07-20 14:47:53.717844445 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named.conf.j2 2026-09-11 19:41:01.205323901 +0000 @@ -11,38 +11,16 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; - options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; fetches-per-server 400; }; - server 10.53.0.4 { edns no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/fetchlimit/ns3/named2.conf.j2 2026-07-20 14:47:53.717844445 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named2.conf.j2 2026-09-11 19:41:01.205323901 +0000 @@ -12,17 +12,8 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; fetches-per-zone 40; }; @@ -31,16 +22,6 @@ edns no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns3/named3.conf.j2 bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/fetchlimit/ns3/named3.conf.j2 2026-07-20 14:47:53.717844445 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns3/named3.conf.j2 2026-09-11 19:41:01.205323901 +0000 @@ -12,17 +12,8 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; recursive-clients 400; }; @@ -31,16 +22,6 @@ edns no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns3/root.hint bind9-9.20.29/bin/tests/system/fetchlimit/ns3/root.hint --- bind9-9.20.26/bin/tests/system/fetchlimit/ns3/root.hint 2026-07-20 14:47:53.717844445 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns3/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/fetchlimit/ns5/named.conf.j2 2026-07-20 14:47:53.718844470 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named.conf.j2 2026-09-11 19:41:01.205323901 +0000 @@ -12,17 +12,8 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; clients-per-query 5; max-clients-per-query 10; }; @@ -32,16 +23,6 @@ edns no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns5/named2.conf.j2 bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/fetchlimit/ns5/named2.conf.j2 2026-07-20 14:47:53.718844470 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named2.conf.j2 2026-09-11 19:41:01.205323901 +0000 @@ -12,17 +12,8 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; stale-answer-enable yes; stale-cache-enable yes; stale-answer-client-timeout 0; @@ -35,16 +26,6 @@ edns no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns5/named3.conf.j2 bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/fetchlimit/ns5/named3.conf.j2 2026-07-20 14:47:53.718844470 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns5/named3.conf.j2 2026-09-11 19:41:01.205323901 +0000 @@ -12,17 +12,8 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; stale-answer-enable yes; stale-cache-enable yes; stale-answer-client-timeout 0; @@ -36,16 +27,6 @@ edns no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/ns5/root.hint bind9-9.20.29/bin/tests/system/fetchlimit/ns5/root.hint --- bind9-9.20.26/bin/tests/system/fetchlimit/ns5/root.hint 2026-07-20 14:47:53.718844470 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/ns5/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/prereq.sh bind9-9.20.29/bin/tests/system/fetchlimit/prereq.sh --- bind9-9.20.26/bin/tests/system/fetchlimit/prereq.sh 2026-07-20 14:47:53.718844470 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/tests.sh bind9-9.20.29/bin/tests/system/fetchlimit/tests.sh --- bind9-9.20.26/bin/tests/system/fetchlimit/tests.sh 2026-07-20 14:47:53.718844470 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/tests.sh 2026-09-11 19:41:01.205323901 +0000 @@ -134,14 +134,11 @@ n=$((n + 1)) echo_i "dumping ADB data ($n)" -ret=0 info=$(rndccmd 10.53.0.3 fetchlimit | grep 10.53.0.4 | sed 's/.*quota .*(\([0-9]*\).*atr \([.0-9]*\).*/\2 \1/') echo_i $info set -- $info -[ ${2:-${quota}} -lt $quota ] || ret=1 +# Record the quota at start of recovery quota=$2 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) n=$((n + 1)) echo_i "checking lame server recovery (continued) ($n)" diff -Nru bind9-9.20.26/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py bind9-9.20.29/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py --- bind9-9.20.26/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py 2026-07-20 14:47:53.718844470 +0000 +++ bind9-9.20.29/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py 2026-09-11 19:41:01.205323901 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "wait_for_message.*", @@ -22,6 +24,11 @@ ] ) +pytestmark = [ + isctest.mark.requires_net_dns, + EXTRA_ARTIFACTS, +] + @pytest.mark.flaky(max_runs=3) def test_fetchlimit(run_tests_sh): diff -Nru bind9-9.20.26/bin/tests/system/filters/ans6/ans.py bind9-9.20.29/bin/tests/system/filters/ans6/ans.py --- bind9-9.20.26/bin/tests/system/filters/ans6/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/filters/ans6/ans.py 2026-09-11 19:41:01.205323901 +0000 @@ -0,0 +1,97 @@ +""" +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. +""" + +import dns.rcode +import dns.rdataclass +import dns.rdatatype +import dns.rrset + +from isctest.asyncserver import ( + AsyncDnsServer, + QnameQtypeHandler, + QueryContext, + StaticResponseHandler, +) + +DNS64_TRIGGER = "nodata.test." + + +def rrset(name: str, rdtype: dns.rdatatype.RdataType, *rdata: str) -> dns.rrset.RRset: + return dns.rrset.from_text(name, 60, dns.rdataclass.IN, rdtype, *rdata) + + +def soa() -> dns.rrset.RRset: + return rrset("test.", dns.rdatatype.SOA, "ns.test. hostmaster.test. 1 2 3 4 5") + + +def a() -> dns.rrset.RRset: + return rrset(DNS64_TRIGGER, dns.rdatatype.A, "192.0.2.1") + + +def aaaa() -> dns.rrset.RRset: + return rrset(DNS64_TRIGGER, dns.rdatatype.AAAA, "2001:db8::1") + + +class NodataOnceHandler(QnameQtypeHandler, StaticResponseHandler): + """ + Answer only the first AAAA query, with NODATA, so the DNS64 resolver looks + up an A record; the delayed A lookup lets filter-a re-enter and re-query + AAAA (answered by AaaaHandler), triggering the bug. + """ + + qnames = [DNS64_TRIGGER] + qtypes = [dns.rdatatype.AAAA] + authority = [soa()] + + def __init__(self) -> None: + super().__init__() + self._answered = False + + def match(self, qctx: QueryContext) -> bool: + if self._answered: + return False + self._answered = True + return super().match(qctx) + + +class AaaaHandler(QnameQtypeHandler, StaticResponseHandler): + qnames = [DNS64_TRIGGER] + qtypes = [dns.rdatatype.AAAA] + answer = [aaaa()] + + +class DelayedAHandler(QnameQtypeHandler, StaticResponseHandler): + qnames = [DNS64_TRIGGER] + qtypes = [dns.rdatatype.A] + answer = [a()] + delay = 2.0 + + +class FallbackHandler(StaticResponseHandler): + rcode = dns.rcode.NXDOMAIN + authority = [soa()] + + +def main() -> None: + server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR) + server.install_response_handlers( + NodataOnceHandler(), + AaaaHandler(), + DelayedAHandler(), + FallbackHandler(), + ) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/filters/common.py bind9-9.20.29/bin/tests/system/filters/common.py --- bind9-9.20.26/bin/tests/system/filters/common.py 2026-07-20 14:47:53.718844470 +0000 +++ bind9-9.20.29/bin/tests/system/filters/common.py 2026-09-11 19:41:01.206323925 +0000 @@ -22,6 +22,7 @@ "ns*/K*", "ns*/dsset-*", "ns*/signer.err", + "ans*/ans.run", ] diff -Nru bind9-9.20.26/bin/tests/system/filters/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/filters/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/filters/ns1/named.conf.j2 2026-07-20 14:47:53.719844495 +0000 +++ bind9-9.20.29/bin/tests/system/filters/ns1/named.conf.j2 2026-09-11 19:41:01.206323925 +0000 @@ -15,41 +15,27 @@ {% set family = family | default("v4") %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { fd92:7065:b8e:ffff::1; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; - notify yes; minimal-responses no; }; {% if family == "v6" %} - plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { - filter-@filtertype@-on-v6 yes; - filter-@filtertype@ { fd92:7065:b8e:ffff::1; }; - }; +plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v6 yes; + filter-@filtertype@ { @ns.ip6@; }; +}; {% else %} - acl filterees { 10.53.0.1; }; - - plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { - filter-@filtertype@-on-v4 yes; - filter-@filtertype@ { filterees; }; - }; -{% endif %} +acl filterees { @ns.ip@; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; +plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v4 yes; + filter-@filtertype@ { filterees; }; }; +{% endif %} -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; file "root.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/filters/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/filters/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/filters/ns2/named.conf.j2 2026-07-20 14:47:53.720844520 +0000 +++ bind9-9.20.29/bin/tests/system/filters/ns2/named.conf.j2 2026-09-11 19:41:01.207323949 +0000 @@ -15,40 +15,24 @@ {% set family = family | default("v4") %} options { - query-source address 10.53.0.2; - query-source-v6 address fd92:7065:b8e:ffff::2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; - recursion yes; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation yes; - notify yes; minimal-responses no; }; {% if family == "v6" %} - plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { - filter-@filtertype@-on-v6 yes; - filter-@filtertype@ { fd92:7065:b8e:ffff::2; }; - }; +plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v6 yes; + filter-@filtertype@ { @ns.ip6@; }; +}; {% else %} - plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { - filter-@filtertype@-on-v4 yes; - filter-@filtertype@{ 10.53.0.2; }; - }; -{% endif %} - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; +plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v4 yes; + filter-@filtertype@{ @ns.ip@; }; }; +{% endif %} -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/filters/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/filters/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/filters/ns3/named.conf.j2 2026-07-20 14:47:53.720844520 +0000 +++ bind9-9.20.29/bin/tests/system/filters/ns3/named.conf.j2 2026-09-11 19:41:01.207323949 +0000 @@ -15,40 +15,24 @@ {% set family = family | default("v4") %} options { - query-source address 10.53.0.3; - query-source-v6 address fd92:7065:b8e:ffff::3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { fd92:7065:b8e:ffff::3; }; - recursion yes; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation yes; - notify yes; minimal-responses no; }; {% if family == "v6" %} - plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { - filter-@filtertype@-on-v6 break-dnssec; - filter-@filtertype@ { fd92:7065:b8e:ffff::3; }; - }; +plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v6 break-dnssec; + filter-@filtertype@ { @ns.ip6@; }; +}; {% else %} - plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { - filter-@filtertype@-on-v4 break-dnssec; - filter-@filtertype@ { 10.53.0.3; }; - }; -{% endif %} - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; +plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v4 break-dnssec; + filter-@filtertype@ { @ns.ip@; }; }; +{% endif %} -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/filters/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/filters/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/filters/ns4/named.conf.j2 2026-07-20 14:47:53.720844520 +0000 +++ bind9-9.20.29/bin/tests/system/filters/ns4/named.conf.j2 2026-09-11 19:41:01.207323949 +0000 @@ -15,39 +15,25 @@ {% set family = family | default("v4") %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { fd92:7065:b8e:ffff::4; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; - notify yes; minimal-responses no; }; {% if family == "v6" %} - plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { - filter-@filtertype@-on-v6 break-dnssec; - filter-@filtertype@ { fd92:7065:b8e:ffff::4; }; - }; +plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v6 break-dnssec; + filter-@filtertype@ { @ns.ip6@; }; +}; {% else %} - plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { - filter-@filtertype@-on-v4 break-dnssec; - filter-@filtertype@ { 10.53.0.4; }; - }; -{% endif %} - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; +plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v4 break-dnssec; + filter-@filtertype@ { @ns.ip@; }; }; +{% endif %} -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; file "root.db"; }; zone "signed" { type primary; file "signed.db.signed"; }; diff -Nru bind9-9.20.26/bin/tests/system/filters/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/filters/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/filters/ns5/named.conf.j2 2026-07-20 14:47:53.721844545 +0000 +++ bind9-9.20.29/bin/tests/system/filters/ns5/named.conf.j2 2026-09-11 19:41:01.208323973 +0000 @@ -1,27 +1,9 @@ -/* - * 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 filtertype = filtertype | default("aaaa") %} +{% set family = family | default("v4") %} options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { fd92:7065:b8e:ffff::5; }; - recursion yes; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation no; - notify yes; dns64 64:ff9b::/96 { clients { any; }; exclude { ::1/128; }; @@ -30,20 +12,22 @@ minimal-responses no; }; -plugin query "../../../../plugins/.libs/filter-aaaa.so" { - filter-aaaa-on-v4 break-dnssec; - filter-aaaa { any; }; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% if family == "v6" %} + plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v6 break-dnssec; + filter-@filtertype@ { any; }; + }; +{% else %} + plugin query "../../../../plugins/.libs/filter-@filtertype@.so" { + filter-@filtertype@-on-v4 break-dnssec; + filter-@filtertype@ { any; }; + }; +{% endif %} -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints"; }; +zone "test" { type forward; forward only; forwarders { 10.53.0.6; }; }; + include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/filters/tests_filter_a_dns64.py bind9-9.20.29/bin/tests/system/filters/tests_filter_a_dns64.py --- bind9-9.20.26/bin/tests/system/filters/tests_filter_a_dns64.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/filters/tests_filter_a_dns64.py 2026-09-11 19:41:01.208323973 +0000 @@ -0,0 +1,34 @@ +# 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. + +import pytest + +from filters.common import ARTIFACTS + +import isctest + +pytestmark = pytest.mark.extra_artifacts(ARTIFACTS) + + +def bootstrap(): + return { + "family": "v4", + "filtertype": "a", + } + + +def test_dns64_filter_a_reentry(): + msg = isctest.query.create("nodata.test.", "aaaa", dnssec=False) + res = isctest.query.tcp(msg, "10.53.0.5", attempts=1) + isctest.check.noerror(res) + answer = res.get_rrset(res.answer, "nodata.test.", "in", "aaaa") + assert answer is not None, res + assert answer[0].address == "64:ff9b::c000:201" diff -Nru bind9-9.20.26/bin/tests/system/filters/tests_filter_aaaa_dns64.py bind9-9.20.29/bin/tests/system/filters/tests_filter_aaaa_dns64.py --- bind9-9.20.26/bin/tests/system/filters/tests_filter_aaaa_dns64.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/filters/tests_filter_aaaa_dns64.py 2026-09-11 19:41:01.208323973 +0000 @@ -0,0 +1,38 @@ +# 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. + +import pytest + +from filters.common import ARTIFACTS + +import isctest + +pytestmark = pytest.mark.extra_artifacts(ARTIFACTS) + + +def bootstrap(): + return { + "family": "v4", + "filtertype": "aaaa", + } + + +def test_filter_dns64(): + # This configuration doesn't make sense. The AAAA is wanted by + # filter-aaaa, but discarded by the dns64 configuration. We just + # need to ensure that the server keeps running. + msg = isctest.query.create("aaaa-only.unsigned", "aaaa") + res = isctest.query.tcp(msg, "10.53.0.5") + isctest.check.noerror(res) + + msg = isctest.query.create("excludeone.unsigned", "aaaa") + res = isctest.query.tcp(msg, "10.53.0.5") + isctest.check.noerror(res) diff -Nru bind9-9.20.26/bin/tests/system/filters/tests_filter_dns64.py bind9-9.20.29/bin/tests/system/filters/tests_filter_dns64.py --- bind9-9.20.26/bin/tests/system/filters/tests_filter_dns64.py 2026-07-20 14:47:53.721844545 +0000 +++ bind9-9.20.29/bin/tests/system/filters/tests_filter_dns64.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# 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. - -import pytest - -from filters.common import ARTIFACTS - -import isctest - -pytestmark = pytest.mark.extra_artifacts(ARTIFACTS) - - -def test_filter_dns64(): - # This configuration doesn't make sense. The AAAA is wanted by - # filter-aaaa, but discarded by the dns64 configuration. We just - # need to ensure that the server keeps running. - msg = isctest.query.create("aaaa-only.unsigned", "aaaa") - res = isctest.query.tcp(msg, "10.53.0.5") - isctest.check.noerror(res) - - msg = isctest.query.create("excludeone.unsigned", "aaaa") - res = isctest.query.tcp(msg, "10.53.0.5") - isctest.check.noerror(res) diff -Nru bind9-9.20.26/bin/tests/system/formerr/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/formerr/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/formerr/ns1/named.conf.j2 2026-07-20 14:47:53.721844545 +0000 +++ bind9-9.20.29/bin/tests/system/formerr/ns1/named.conf.j2 2026-09-11 19:41:01.209323997 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/forward/ans6/ans.py bind9-9.20.29/bin/tests/system/forward/ans6/ans.py --- bind9-9.20.26/bin/tests/system/forward/ans6/ans.py 2026-07-20 14:47:53.723844595 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ans6/ans.py 2026-09-11 19:41:01.211324046 +0000 @@ -15,61 +15,88 @@ import dns.name import dns.rcode +import dns.rdataclass import dns.rdatatype import dns.rrset from isctest.asyncserver import ( ControllableAsyncDnsServer, DnsResponseSend, + DomainHandler, + QnameQtypeHandler, QueryContext, - ResponseAction, ResponseHandler, + StaticResponseHandler, ToggleResponsesCommand, ) +SLD = "sld.tld." +NS1 = f"ns1.{SLD}" -class ChaseDsHandler(ResponseHandler): + +def rrset( + owner: dns.name.Name | str, rdtype: dns.rdatatype.RdataType, rdata: str +) -> dns.rrset.RRset: + return dns.rrset.from_text(owner, 300, dns.rdataclass.IN, rdtype, rdata) + + +def a(owner: dns.name.Name | str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.A, "10.53.0.2") + + +def aaaa(owner: dns.name.Name | str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.AAAA, "fd92:7065:b8e:ffff::2") + + +def ns(owner: dns.name.Name | str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.NS, NS1) + + +def soa(owner: dns.name.Name | str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.SOA, ". . 0 0 0 0 0") + + +class Ns1AHandler(QnameQtypeHandler, StaticResponseHandler): + qnames = [NS1] + qtypes = [dns.rdatatype.A] + answer = [a(NS1)] + edns = None + + +class Ns1AaaaHandler(QnameQtypeHandler, StaticResponseHandler): + qnames = [NS1] + qtypes = [dns.rdatatype.AAAA] + answer = [aaaa(NS1)] + edns = None + + +class SldDelegationHandler(DomainHandler): """ - Yield responses triggering DS chasing logic in `named`. These responses - cannot be served from a static zone file because most of them need to be - generated dynamically so that the owner name of the returned RRset is - copied from the QNAME sent by the client: - - - A/AAAA queries for `ns1.sld.tld.` elicit responses with IP addresses, - - all NS queries below `sld.tld.` elicit a delegation to `ns1.sld.tld.`, - - all other queries elicit a negative response with a common SOA record. + Delegate every NS query at or below sld.tld. to ns1.sld.tld., copying the + owner name from the QNAME. Together with Ns1AHandler / Ns1AaaaHandler + (which resolve the delegated nameserver) and NegativeSoaHandler (the + negative catch-all), this drives named's DS-chasing logic. """ + domains = [SLD] + + def match(self, qctx: QueryContext) -> bool: + return qctx.qtype == dns.rdatatype.NS and super().match(qctx) + async def get_responses( self, qctx: QueryContext - ) -> AsyncGenerator[ResponseAction, None]: - ns1_sld_tld = dns.name.from_text("ns1.sld.tld.") - sld_tld = dns.name.from_text("sld.tld.") - - if qctx.qname == ns1_sld_tld and qctx.qtype == dns.rdatatype.A: - response_type = dns.rdatatype.A - response_rdata = "10.53.0.2" - response_section = qctx.response.answer - elif qctx.qname == ns1_sld_tld and qctx.qtype == dns.rdatatype.AAAA: - response_type = dns.rdatatype.AAAA - response_rdata = "fd92:7065:b8e:ffff::2" - response_section = qctx.response.answer - elif qctx.qname.is_subdomain(sld_tld) and qctx.qtype == dns.rdatatype.NS: - response_type = dns.rdatatype.NS - response_rdata = "ns1.sld.tld." - response_section = qctx.response.answer - else: - response_type = dns.rdatatype.SOA - response_rdata = ". . 0 0 0 0 0" - response_section = qctx.response.authority - + ) -> AsyncGenerator[DnsResponseSend, None]: qctx.response.use_edns(None) + qctx.response.answer.append(ns(qctx.qname)) + yield DnsResponseSend(qctx.response) - response_rrset = dns.rrset.from_text( - qctx.qname, 300, qctx.qclass, response_type, response_rdata - ) - response_section.append(response_rrset) +class NegativeSoaHandler(ResponseHandler): + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + qctx.response.use_edns(None) + qctx.response.authority.append(soa(qctx.qname)) yield DnsResponseSend(qctx.response) @@ -78,7 +105,12 @@ default_rcode=dns.rcode.NOERROR, default_aa=True ) server.install_control_command(ToggleResponsesCommand()) - server.install_response_handler(ChaseDsHandler()) + server.install_response_handlers( + Ns1AHandler(), + Ns1AaaaHandler(), + SldDelegationHandler(), + NegativeSoaHandler(), + ) server.run() diff -Nru bind9-9.20.26/bin/tests/system/forward/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns1/named.conf.j2 2026-07-20 14:47:53.724844620 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns1/named.conf.j2 2026-09-11 19:41:01.211324046 +0000 @@ -12,20 +12,13 @@ */ options { - query-source address 10.53.0.1; - query-source-v6 address fd92:7065:b8e:ffff::1; - notify-source 10.53.0.1; - notify-source-v6 fd92:7065:b8e:ffff::1; - transfer-source 10.53.0.1; - transfer-source-v6 fd92:7065:b8e:ffff::1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { fd92:7065:b8e:ffff::1; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns10/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns10/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns10/named.conf.j2 2026-07-20 14:47:53.725844645 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns10/named.conf.j2 2026-09-11 19:41:01.212324070 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.10; - notify-source 10.53.0.10; - transfer-source 10.53.0.10; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.10; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} minimal-responses no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "net." { type master; file "fakenet.zone"; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns2/named-tls.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns2/named-tls.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns2/named-tls.conf.j2 2026-07-20 14:47:53.725844645 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns2/named-tls.conf.j2 2026-09-11 19:41:01.213324094 +0000 @@ -12,29 +12,29 @@ */ tls tls-forward-secrecy { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv02.crt01.example.nil.key"; - cert-file "../CA/certs/srv02.crt01.example.nil.pem"; - dhparam-file "../dhparam3072.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv02.crt01.example.nil.key"; + cert-file "../CA/certs/srv02.crt01.example.nil.pem"; + dhparam-file "../dhparam3072.pem"; }; tls tls-forward-secrecy-mutual-tls { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv02.crt01.example.nil.key"; - cert-file "../CA/certs/srv02.crt01.example.nil.pem"; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv02.crt01.example.nil.key"; + cert-file "../CA/certs/srv02.crt01.example.nil.pem"; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; tls tls-expired { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv02.crt02-expired.example.nil.key"; - cert-file "../CA/certs/srv02.crt02-expired.example.nil.pem"; - dhparam-file "../dhparam3072.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv02.crt02-expired.example.nil.key"; + cert-file "../CA/certs/srv02.crt02-expired.example.nil.pem"; + dhparam-file "../dhparam3072.pem"; }; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns2/named.conf.j2 2026-07-20 14:47:53.725844645 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns2/named.conf.j2 2026-09-11 19:41:01.213324094 +0000 @@ -16,29 +16,22 @@ {% endif %} options { - query-source address 10.53.0.2; - query-source-v6 address fd92:7065:b8e:ffff::2; - notify-source 10.53.0.2; - notify-source-v6 fd92:7065:b8e:ffff::2; - transfer-source 10.53.0.2; - transfer-source-v6 fd92:7065:b8e:ffff::2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; {% if FEATURE_FIPS_DH == "1" %} tls-port @TLSPORT@; - listen-on tls ephemeral { 10.53.0.2; }; - listen-on port @EXTRAPORT1@ tls tls-forward-secrecy { 10.53.0.2; }; - listen-on port @EXTRAPORT2@ tls tls-forward-secrecy-mutual-tls { 10.53.0.2; }; - listen-on port @EXTRAPORT3@ tls tls-expired { 10.53.0.2; }; + listen-on tls ephemeral { @ns.ip@; }; + listen-on port @EXTRAPORT1@ tls tls-forward-secrecy { @ns.ip@; }; + listen-on port @EXTRAPORT2@ tls tls-forward-secrecy-mutual-tls { @ns.ip@; }; + listen-on port @EXTRAPORT3@ tls tls-expired { @ns.ip@; }; {% endif %} }; +{% include "_common/controls.conf.j2" %} + zone "." { type hint; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns3/named.conf.j2 2026-07-20 14:47:53.725844645 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns3/named.conf.j2 2026-09-11 19:41:01.213324094 +0000 @@ -12,30 +12,14 @@ */ options { - query-source address 10.53.0.3; - query-source-v6 address fd92:7065:b8e:ffff::3; - notify-source 10.53.0.3; - notify-source-v6 fd92:7065:b8e:ffff::3; - transfer-source 10.53.0.3; - transfer-source-v6 fd92:7065:b8e:ffff::3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { fd92:7065:b8e:ffff::3; }; + {% include_indented "_common/options-dual.conf.j2" %} forwarders { fd92:7065:b8e:ffff::2; }; forward first; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns3/named2.conf.j2 2026-07-20 14:47:53.726844670 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns3/named2.conf.j2 2026-09-11 19:41:01.213324094 +0000 @@ -12,30 +12,14 @@ */ options { - query-source address 10.53.0.3; - query-source-v6 address fd92:7065:b8e:ffff::3; - notify-source 10.53.0.3; - notify-source-v6 fd92:7065:b8e:ffff::3; - transfer-source 10.53.0.3; - transfer-source-v6 fd92:7065:b8e:ffff::3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { fd92:7065:b8e:ffff::3; }; + {% include_indented "_common/options-dual.conf.j2" %} forwarders { 10.53.0.6; }; dnssec-validation yes; }; include "trusted.conf"; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns4/named-tls.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns4/named-tls.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns4/named-tls.conf.j2 2026-07-20 14:47:53.726844670 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns4/named-tls.conf.j2 2026-09-11 19:41:01.213324094 +0000 @@ -12,39 +12,39 @@ */ tls tls-forward-secrecy { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; tls tls-forward-secrecy-remote-hostname { - protocols { TLSv1.2; }; - ca-file "../CA/CA.pem"; - remote-hostname "srv02.crt01.example.nil"; + protocols { TLSv1.2; }; + ca-file "../CA/CA.pem"; + remote-hostname "srv02.crt01.example.nil"; }; tls tls-forward-secrecy-bad-remote-hostname { - protocols { TLSv1.2; }; - ca-file "../CA/CA.pem"; - remote-hostname "srv02-bad.crt01.example.nil"; + protocols { TLSv1.2; }; + ca-file "../CA/CA.pem"; + remote-hostname "srv02-bad.crt01.example.nil"; }; tls tls-forward-secrecy-mutual-tls { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - key-file "../CA/certs/srv04.crt01.example.nil.key"; - cert-file "../CA/certs/srv04.crt01.example.nil.pem"; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + key-file "../CA/certs/srv04.crt01.example.nil.key"; + cert-file "../CA/certs/srv04.crt01.example.nil.pem"; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; tls tls-expired { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; zone "example1." { diff -Nru bind9-9.20.26/bin/tests/system/forward/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns4/named.conf.j2 2026-07-20 14:47:53.726844670 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns4/named.conf.j2 2026-09-11 19:41:01.213324094 +0000 @@ -16,14 +16,7 @@ {% endif %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; minimal-responses yes; @@ -33,7 +26,9 @@ }; -statistics-channels { inet 10.53.0.4 port @EXTRAPORT1@ allow { localhost; }; }; +{% include "_common/controls.conf.j2" %} + +statistics-channels { inet @ns.ip@ port @EXTRAPORT1@ allow { localhost; }; }; zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns5/named.conf.j2 2026-07-20 14:47:53.726844670 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns5/named.conf.j2 2026-09-11 19:41:01.214324118 +0000 @@ -12,19 +12,14 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} forward only; forwarders { 10.53.0.4; }; deny-answer-aliases { "rebind"; }; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns7/named.conf.j2 2026-07-20 14:47:53.726844670 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns7/named.conf.j2 2026-09-11 19:41:01.214324118 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} forwarders { 10.53.0.4; }; forward first; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns8/named.conf.j2 2026-07-20 14:47:53.727844695 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns8/named.conf.j2 2026-09-11 19:41:01.214324118 +0000 @@ -12,23 +12,15 @@ */ options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} forwarders { 10.53.0.2; }; // returns referrals forward first; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "root.db"; -}; +{% include "_common/root.hint.conf" %} zone "sub.local.tld" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns8/root.db bind9-9.20.29/bin/tests/system/forward/ns8/root.db --- bind9-9.20.26/bin/tests/system/forward/ns8/root.db 2026-07-20 14:47:53.727844695 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns8/root.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -; 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. - -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/forward/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns9/named.conf.j2 2026-07-20 14:47:53.727844695 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns9/named.conf.j2 2026-09-11 19:41:01.214324118 +0000 @@ -12,25 +12,12 @@ */ options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; edns-udp-size 1232; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} server 10.53.0.10 { edns no; @@ -40,10 +27,7 @@ edns no; }; -zone "." { - type hint; - file "root.db"; -}; +{% include "_common/root.hint.conf" %} zone "attacksecuredomain.net." { type forward; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns9/named2.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns9/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns9/named2.conf.j2 2026-07-20 14:47:53.727844695 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns9/named2.conf.j2 2026-09-11 19:41:01.215324142 +0000 @@ -12,25 +12,12 @@ */ options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; edns-udp-size 1232; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} server 10.53.0.10 { edns no; @@ -40,10 +27,7 @@ edns no; }; -zone "." { - type hint; - file "root.db"; -}; +{% include "_common/root.hint.conf" %} zone "attacksecuredomain.net." { type forward; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns9/named3.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns9/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns9/named3.conf.j2 2026-07-20 14:47:53.727844695 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns9/named3.conf.j2 2026-09-11 19:41:01.215324142 +0000 @@ -12,36 +12,20 @@ */ options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; edns-udp-size 1232; forward only; forwarders { 10.53.0.10; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} server 10.53.0.10 { edns no; }; -zone "." { - type hint; - file "root.db"; -}; +{% include "_common/root.hint.conf" %} zone "local.net." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns9/named4.conf.j2 bind9-9.20.29/bin/tests/system/forward/ns9/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/forward/ns9/named4.conf.j2 2026-07-20 14:47:53.727844695 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns9/named4.conf.j2 2026-09-11 19:41:01.215324142 +0000 @@ -12,34 +12,18 @@ */ options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; edns-udp-size 1232; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} server 10.53.0.10 { edns no; }; -zone "." { - type hint; - file "root.db"; -}; +{% include "_common/root.hint.conf" %} zone "local.tld." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/forward/ns9/root.db bind9-9.20.29/bin/tests/system/forward/ns9/root.db --- bind9-9.20.26/bin/tests/system/forward/ns9/root.db 2026-07-20 14:47:53.727844695 +0000 +++ bind9-9.20.29/bin/tests/system/forward/ns9/root.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -; 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. - -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/forward/prereq.sh bind9-9.20.29/bin/tests/system/forward/prereq.sh --- bind9-9.20.26/bin/tests/system/forward/prereq.sh 2026-07-20 14:47:53.727844695 +0000 +++ bind9-9.20.29/bin/tests/system/forward/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/fwdfirst/ans3/ans.py bind9-9.20.29/bin/tests/system/fwdfirst/ans3/ans.py --- bind9-9.20.26/bin/tests/system/fwdfirst/ans3/ans.py 2026-07-20 14:47:53.729844745 +0000 +++ bind9-9.20.29/bin/tests/system/fwdfirst/ans3/ans.py 2026-09-11 19:41:01.216324166 +0000 @@ -11,38 +11,32 @@ information regarding copyright ownership. """ -from collections.abc import AsyncGenerator - import dns.rcode +import dns.rdataclass import dns.rdatatype import dns.rrset -from isctest.asyncserver import ( - AsyncDnsServer, - DnsResponseSend, - QueryContext, - ResponseAction, - ResponseHandler, -) - - -class AttackerAuthority(ResponseHandler): - async def get_responses( - self, qctx: QueryContext - ) -> AsyncGenerator[ResponseAction, None]: - if qctx.qtype == dns.rdatatype.A: - qctx.response.answer.append( - dns.rrset.from_text( - qctx.qname, 300, qctx.qclass, dns.rdatatype.A, "6.6.6.6" - ) - ) +from isctest.asyncserver import AsyncDnsServer, QnameQtypeHandler, StaticResponseHandler + +VICTIM = "victim.sibling.hack." +POISON_ADDRESS = "6.6.6.6" + + +def a(name: str) -> dns.rrset.RRset: + return dns.rrset.from_text( + name, 300, dns.rdataclass.IN, dns.rdatatype.A, POISON_ADDRESS + ) + - yield DnsResponseSend(qctx.response) +class PoisonedAHandler(QnameQtypeHandler, StaticResponseHandler): + qnames = [VICTIM] + qtypes = [dns.rdatatype.A] + answer = [a(VICTIM)] def main() -> None: server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR) - server.install_response_handler(AttackerAuthority()) + server.install_response_handler(PoisonedAHandler()) server.run() diff -Nru bind9-9.20.26/bin/tests/system/fwdfirst/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/fwdfirst/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/fwdfirst/ns4/named.conf.j2 2026-07-20 14:47:53.729844745 +0000 +++ bind9-9.20.29/bin/tests/system/fwdfirst/ns4/named.conf.j2 2026-09-11 19:41:01.216324166 +0000 @@ -1,28 +1,14 @@ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} allow-query { any; }; allow-recursion { any; }; dnssec-validation no; qname-minimization off; }; -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "fwd.hack" { type forward; diff -Nru bind9-9.20.26/bin/tests/system/fwdfirst/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/fwdfirst/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/fwdfirst/ns5/named.conf.j2 2026-07-20 14:47:53.729844745 +0000 +++ bind9-9.20.29/bin/tests/system/fwdfirst/ns5/named.conf.j2 2026-09-11 19:41:01.216324166 +0000 @@ -1,12 +1,5 @@ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} allow-query { any; }; allow-recursion { any; }; dnssec-validation no; @@ -15,13 +8,6 @@ forwarders { 10.53.0.2 port @PORT@; }; }; -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/geoip2/conf/bad-asnum.conf bind9-9.20.29/bin/tests/system/geoip2/conf/bad-asnum.conf --- bind9-9.20.26/bin/tests/system/geoip2/conf/bad-asnum.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/conf/bad-asnum.conf 2026-09-11 19:41:01.217324190 +0000 @@ -0,0 +1,17 @@ +// NS2 + +options { + query-source address 10.53.0.2; + notify-source 10.53.0.2; + transfer-source 10.53.0.2; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; +}; + +view one { + match-clients { geoip asnum "AS1234JUNK"; }; + zone "example" { + type primary; + file "example1.db"; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/conf/good-options.conf bind9-9.20.29/bin/tests/system/geoip2/conf/good-options.conf --- bind9-9.20.26/bin/tests/system/geoip2/conf/good-options.conf 2026-07-20 14:47:53.730844770 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/conf/good-options.conf 2026-09-11 19:41:01.217324190 +0000 @@ -32,5 +32,6 @@ geoip timezone "America/Los_Angeles"; geoip postal 95060; geoip postalcode 95060; + geoip asnum "AS12345"; }; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named.conf.j2 2026-07-20 14:47:53.731844795 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named.conf.j2 2026-09-11 19:41:01.218324215 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip db country country AU; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named10.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named10.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named10.conf.j2 2026-07-20 14:47:53.731844795 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named10.conf.j2 2026-09-11 19:41:01.218324215 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip asnum 100001; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named11.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named11.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named11.conf.j2 2026-07-20 14:47:53.731844795 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named11.conf.j2 2026-09-11 19:41:01.218324215 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip domain one.de; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named12.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named12.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named12.conf.j2 2026-07-20 14:47:53.731844795 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named12.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -18,24 +18,11 @@ }; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; blackhole { blocking; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named13.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named13.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named13.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named13.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// NS2 + +options { + {% include_indented "_common/options-dual.conf.j2" %} + recursion no; + dnssec-validation no; + geoip-directory "../data"; + sortlist { { geoip db country country US; }; }; +}; + +{% include "_common/controls.conf.j2" %} + +zone "example" { + type primary; + file "example2.db"; +}; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named2.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named2.conf.j2 2026-07-20 14:47:53.731844795 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named2.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -14,26 +14,16 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 127.0.0.1; 10.53.0.2; }; - listen-on-v6 { ::1; fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + listen-on { 127.0.0.1; @ns.ip@; }; + listen-on-v6 { ::1; @ns.ip6@; }; recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} acl gAU { geoip db country country AU; }; acl gUS { geoip db country country US; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named3.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named3.conf.j2 2026-07-20 14:47:53.731844795 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named3.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip db country country Australia; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named4.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named4.conf.j2 2026-07-20 14:47:53.731844795 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named4.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip db country continent OC; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named5.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named5.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named5.conf.j2 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named5.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip region CA; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named6.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named6.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named6.conf.j2 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named6.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip city "Redwood City"; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named7.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named7.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named7.conf.j2 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named7.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip isp "One Systems, Inc."; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named8.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named8.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named8.conf.j2 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named8.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip org "One Systems, Inc."; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/ns2/named9.conf.j2 bind9-9.20.29/bin/tests/system/geoip2/ns2/named9.conf.j2 --- bind9-9.20.26/bin/tests/system/geoip2/ns2/named9.conf.j2 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/ns2/named9.conf.j2 2026-09-11 19:41:01.219324239 +0000 @@ -14,26 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; geoip-directory "../data"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view one { match-clients { geoip asnum "AS100001"; }; diff -Nru bind9-9.20.26/bin/tests/system/geoip2/prereq.sh bind9-9.20.29/bin/tests/system/geoip2/prereq.sh --- bind9-9.20.26/bin/tests/system/geoip2/prereq.sh 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -#!/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. - -. ../conf.sh - -$FEATURETEST --have-geoip2 || { - echo_i "This test requires GeoIP support." >&2 - exit 255 -} -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/geoip2/tests.sh bind9-9.20.29/bin/tests/system/geoip2/tests.sh --- bind9-9.20.26/bin/tests/system/geoip2/tests.sh 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/tests.sh 2026-09-11 19:41:01.219324239 +0000 @@ -473,5 +473,19 @@ [ $ret -eq 0 ] || echo_i "failed" status=$((status + ret)) +echo_i "reloading server" +cp ns2/named13.conf ns2/named.conf +$CHECKCONF ns2/named.conf | grep -v "'sortlist' is deprecated" | cat_i +rndc_reload ns2 10.53.0.2 +sleep 3 + +n=$((n + 1)) +echo_i "checking geoip single-element sortlist ($n)" +ret=0 +$DIG $DIGOPTS -b 10.53.0.2 txt example >dig.out.ns2.test$n || ret=1 +$RNDCCMD 10.53.0.2 status 2>&1 >rndc.out.ns2.test$n || ret=1 +[ $ret -eq 0 ] || echo_i "failed" +status=$((status + ret)) + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff -Nru bind9-9.20.26/bin/tests/system/geoip2/tests_sh_geoip2.py bind9-9.20.29/bin/tests/system/geoip2/tests_sh_geoip2.py --- bind9-9.20.26/bin/tests/system/geoip2/tests_sh_geoip2.py 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/geoip2/tests_sh_geoip2.py 2026-09-11 19:41:01.220324263 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "rndc.out.*", @@ -19,6 +21,11 @@ ] ) +pytestmark = [ + isctest.mark.with_geoip2, + EXTRA_ARTIFACTS, +] + def test_geoip2(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/glue/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/glue/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/glue/ns1/named.conf.j2 2026-07-20 14:47:53.732844811 +0000 +++ bind9-9.20.29/bin/tests/system/glue/ns1/named.conf.j2 2026-09-11 19:41:01.220324263 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/hooks/driver/Makefile.in bind9-9.20.29/bin/tests/system/hooks/driver/Makefile.in --- bind9-9.20.26/bin/tests/system/hooks/driver/Makefile.in 2026-07-20 14:49:10.445578311 +0000 +++ bind9-9.20.29/bin/tests/system/hooks/driver/Makefile.in 2026-09-11 19:42:18.417185317 +0000 @@ -270,6 +270,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/tests/system/hooks/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/hooks/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/hooks/ns1/named.conf.j2 2026-07-20 14:47:53.734844842 +0000 +++ bind9-9.20.29/bin/tests/system/hooks/ns1/named.conf.j2 2026-09-11 19:41:01.221324287 +0000 @@ -12,29 +12,16 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; minimal-responses no; }; plugin query "../driver/.libs/test-async.so"; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example.com" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/host/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/host/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/host/ns1/named.conf.j2 2026-07-20 14:47:53.734844842 +0000 +++ bind9-9.20.29/bin/tests/system/host/ns1/named.conf.j2 2026-09-11 19:41:01.221324287 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/idna/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/idna/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/idna/ns1/named.conf.j2 2026-07-20 14:47:53.734844842 +0000 +++ bind9-9.20.29/bin/tests/system/idna/ns1/named.conf.j2 2026-09-11 19:41:01.222324311 +0000 @@ -14,16 +14,13 @@ // NS1 options { - query-source address 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { fd92:7065:b8e:ffff::1; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/include_multiplecfg/ns2/mars.conf bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/mars.conf --- bind9-9.20.26/bin/tests/system/include_multiplecfg/ns2/mars.conf 2026-07-20 14:47:53.735844857 +0000 +++ bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/mars.conf 2026-09-11 19:41:01.222324311 +0000 @@ -12,7 +12,7 @@ */ zone "mars.com" { - type primary; - file "mars.com.db"; + type primary; + file "mars.com.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/include_multiplecfg/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/include_multiplecfg/ns2/named.conf.j2 2026-07-20 14:47:53.735844857 +0000 +++ bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/named.conf.j2 2026-09-11 19:41:01.222324311 +0000 @@ -12,18 +12,16 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + # Should include all files matching pattern. include "zone*.conf"; # Shouldn't break standard file pattern. include "mars.conf"; - diff -Nru bind9-9.20.26/bin/tests/system/include_multiplecfg/ns2/zone1.conf bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/zone1.conf --- bind9-9.20.26/bin/tests/system/include_multiplecfg/ns2/zone1.conf 2026-07-20 14:47:53.735844857 +0000 +++ bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/zone1.conf 2026-09-11 19:41:01.223324335 +0000 @@ -12,7 +12,7 @@ */ zone "zone1.com" { - type primary; - file "zone1.com.db"; + type primary; + file "zone1.com.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/include_multiplecfg/ns2/zone2.conf bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/zone2.conf --- bind9-9.20.26/bin/tests/system/include_multiplecfg/ns2/zone2.conf 2026-07-20 14:47:53.736844873 +0000 +++ bind9-9.20.29/bin/tests/system/include_multiplecfg/ns2/zone2.conf 2026-09-11 19:41:01.223324335 +0000 @@ -12,7 +12,7 @@ */ zone "zone2.com" { - type primary; - file "zone2.com.db"; + type primary; + file "zone2.com.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns1/named.conf.j2 2026-07-20 14:47:53.736844873 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns1/named.conf.j2 2026-09-11 19:41:01.223324335 +0000 @@ -13,19 +13,12 @@ // NS1 -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation yes; }; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns2/named.conf.j2 2026-07-20 14:47:53.736844873 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns2/named.conf.j2 2026-09-11 19:41:01.224324359 +0000 @@ -13,23 +13,12 @@ // NS2 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; notify-delay 0; allow-new-zones yes; dnssec-validation no; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns3/named.conf.j2 2026-07-20 14:47:53.737844889 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns3/named.conf.j2 2026-09-11 19:41:01.224324359 +0000 @@ -13,23 +13,12 @@ // NS3 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; allow-transfer { any; }; - notify yes; try-tcp-refresh no; notify-delay 0; allow-new-zones yes; @@ -71,12 +60,12 @@ }; zone "incremental-updates" { - type primary; - file "incremental-updates.db"; - inline-signing yes; - dnssec-policy inline; - sig-signing-signatures 1; // force incremental processing - allow-update { any; }; + type primary; + file "incremental-updates.db"; + inline-signing yes; + dnssec-policy inline; + sig-signing-signatures 1; // force incremental processing + allow-update { any; }; }; server 10.53.0.4 { request-ixfr no; }; @@ -97,7 +86,7 @@ file "primary.db"; notify explicit; also-notify { - 10.53.0.3; + @ns.ip@; }; }; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns4/named.conf.j2 2026-07-20 14:47:53.738844904 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns4/named.conf.j2 2026-09-11 19:41:01.225324384 +0000 @@ -14,20 +14,15 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; notify-delay 0; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "noixfr" { type primary; file "noixfr.db"; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns5/named.conf.j2 2026-07-20 14:47:53.738844904 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns5/named.conf.j2 2026-09-11 19:41:01.225324384 +0000 @@ -13,23 +13,12 @@ // NS5 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; notify-delay 0; }; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns5/named2.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns5/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns5/named2.conf.j2 2026-07-20 14:47:53.738844904 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns5/named2.conf.j2 2026-09-11 19:41:01.225324384 +0000 @@ -13,23 +13,12 @@ // NS5 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; notify-delay 0; servfail-ttl 0; }; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns6/named.conf.j2 2026-07-20 14:47:53.738844904 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns6/named.conf.j2 2026-09-11 19:41:01.226324408 +0000 @@ -13,29 +13,14 @@ // NS6 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} notify-delay 0; dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns7/named.conf.j2 2026-07-20 14:47:53.738844904 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns7/named.conf.j2 2026-09-11 19:41:01.226324408 +0000 @@ -27,20 +27,10 @@ * one it was meant for. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; notify no; diff -Nru bind9-9.20.26/bin/tests/system/inline/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/inline/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/inline/ns8/named.conf.j2 2026-07-20 14:47:53.739844920 +0000 +++ bind9-9.20.29/bin/tests/system/inline/ns8/named.conf.j2 2026-09-11 19:41:01.226324408 +0000 @@ -13,23 +13,12 @@ // NS8 -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; recursion no; - notify yes; try-tcp-refresh no; notify-delay 0; allow-new-zones yes; diff -Nru bind9-9.20.26/bin/tests/system/integrity/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/integrity/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/integrity/ns1/named.conf.j2 2026-07-20 14:47:53.740844935 +0000 +++ bind9-9.20.29/bin/tests/system/integrity/ns1/named.conf.j2 2026-09-11 19:41:01.227324432 +0000 @@ -12,24 +12,16 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "mx-cname-fail" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/isctest/__init__.py bind9-9.20.29/bin/tests/system/isctest/__init__.py --- bind9-9.20.26/bin/tests/system/isctest/__init__.py 2026-07-20 14:47:53.740844935 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/__init__.py 2026-09-11 19:41:01.228324456 +0000 @@ -17,6 +17,7 @@ kasp, log, query, + rndc, run, template, transfer, @@ -37,6 +38,7 @@ "kasp", "log", "query", + "rndc", "run", "template", "transfer", diff -Nru bind9-9.20.26/bin/tests/system/isctest/asyncserver.py bind9-9.20.29/bin/tests/system/isctest/asyncserver.py --- bind9-9.20.26/bin/tests/system/isctest/asyncserver.py 2026-07-20 14:47:53.741844951 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/asyncserver.py 2026-09-11 19:41:01.228324456 +0000 @@ -658,6 +658,10 @@ return qctx.qtype in self._qtypes and super().match(qctx) +class _UnsetEdnsType: + pass + + class StaticResponseHandler(ResponseHandler): """ Base class used for deriving custom static response handlers. @@ -712,6 +716,15 @@ """ return 0.0 + @property + def edns(self) -> int | bool | None | _UnsetEdnsType: + """ + Value passed to the response's ``use_edns()``. Left unset by default, + so EDNS is untouched; set it to anything ``use_edns()`` accepts (e.g. + ``None`` to strip EDNS and mimic a non-EDNS server). + """ + return _UnsetEdnsType() + async def get_responses( self, qctx: QueryContext ) -> AsyncGenerator[DnsResponseSend, None]: @@ -721,6 +734,8 @@ qctx.response.additional.extend(self.additional) if self.rcode is not None: qctx.response.set_rcode(self.rcode) + if not isinstance(self.edns, _UnsetEdnsType): + qctx.response.use_edns(self.edns) yield DnsResponseSend( qctx.response, authoritative=self.authoritative, delay=self.delay ) diff -Nru bind9-9.20.26/bin/tests/system/isctest/instance.py bind9-9.20.29/bin/tests/system/isctest/instance.py --- bind9-9.20.26/bin/tests/system/isctest/instance.py 2026-07-20 14:47:53.741844951 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/instance.py 2026-09-11 19:41:01.229324480 +0000 @@ -11,10 +11,12 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. +from collections.abc import Iterator from pathlib import Path from typing import NamedTuple import abc +import contextlib import os import re @@ -24,6 +26,7 @@ from .log import WatchLogFromHere, WatchLogFromStart, debug from .query import udp +from .rndc import RNDCClient from .run import CmdResult, EnvCmd, perl from .text import TextFile @@ -191,6 +194,21 @@ """ return self._rndc(command, timeout=timeout, **kwargs) + @contextlib.contextmanager + def rndc_client(self, timeout: float = 10) -> Iterator[RNDCClient]: + """ + Connect a Python RNDC client to this instance's control channel; + a fast alternative to `rndc()` which does not spawn the rndc + binary. Only usable as a context manager: + + ```python + with ns1.rndc_client() as client: + client.call("status") + ``` + """ + with RNDCClient(self.ip, self.ports.rndc, timeout=timeout) as client: + yield client + def nsupdate( self, update_msg: dns.update.UpdateMessage, expected_rcode=dns.rcode.NOERROR ): diff -Nru bind9-9.20.26/bin/tests/system/isctest/kasp.py bind9-9.20.29/bin/tests/system/isctest/kasp.py --- bind9-9.20.26/bin/tests/system/isctest/kasp.py 2026-07-20 14:47:53.742844966 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/kasp.py 2026-09-11 19:41:01.229324480 +0000 @@ -17,7 +17,6 @@ import glob import os import re -import time import dns.exception import dns.message @@ -788,32 +787,30 @@ def check_dnssec_verify(server, zone, tsig=None): - # Check if zone if DNSSEC valid with dnssec-verify. + # Check if zone is DNSSEC valid with dnssec-verify. fqdn = f"{zone}." - verified = False - for _ in range(10): + def _verify_zone(): transfer = _query(server, fqdn, dns.rdatatype.AXFR, tsig=tsig) if not isinstance(transfer, dns.message.Message): isctest.log.debug(f"no response for {fqdn} AXFR from {server.ip}") - elif transfer.rcode() != dns.rcode.NOERROR: + return False + if transfer.rcode() != dns.rcode.NOERROR: rcode = dns.rcode.to_text(transfer.rcode()) isctest.log.debug(f"{rcode} response for {fqdn} AXFR from {server.ip}") - else: - zonefile = f"{zone}.axfr" - with open(zonefile, "w", encoding="utf-8") as file: - for rr in transfer.answer: - file.write(rr.to_text()) - file.write("\n") - - verify_command = [os.environ.get("VERIFY"), "-z", "-o", fqdn, zonefile] - verified = isctest.run.cmd(verify_command, raise_on_exception=False) - if verified.rc == 0: - return + return False - time.sleep(1) + zonefile = f"{zone}.axfr" + with open(zonefile, "w", encoding="utf-8") as file: + for rr in transfer.answer: + file.write(rr.to_text()) + file.write("\n") + + verify_command = [os.environ.get("VERIFY"), "-z", "-o", fqdn, zonefile] + verified = isctest.run.cmd(verify_command, raise_on_exception=False) + return verified.rc == 0 - assert False, "zone not verified" + isctest.run.retry_with_timeout(_verify_zone, timeout=60, msg="zone not verified") def check_dnssecstatus(server, zone, keys, policy=None, view=None): diff -Nru bind9-9.20.26/bin/tests/system/isctest/mark.py bind9-9.20.29/bin/tests/system/isctest/mark.py --- bind9-9.20.26/bin/tests/system/isctest/mark.py 2026-07-20 14:47:53.742844966 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/mark.py 2026-09-11 19:41:01.229324480 +0000 @@ -44,12 +44,38 @@ return True -def is_host_freebsd(*_): - return platform.system() == "FreeBSD" +def _perl_module_available(module: str) -> bool: + perl = os.environ.get("PERL", "perl") + try: + subprocess.run( + [perl, f"-M{module}", "-e", ""], + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except (subprocess.CalledProcessError, FileNotFoundError): + return False + return True -def is_host_freebsd_13(*_): - return platform.system() == "FreeBSD" and platform.release().startswith("13") +requires_net_dns = pytest.mark.skipif( + not _perl_module_available("Net::DNS"), + reason="Perl Net::DNS module is required", +) + +requires_net_dns_nameserver = pytest.mark.skipif( + not _perl_module_available("Net::DNS::Nameserver"), + reason="Perl Net::DNS::Nameserver module is required", +) + +requires_time_hires = pytest.mark.skipif( + not _perl_module_available("Time::HiRes"), + reason="Perl Time::HiRes module is required", +) + + +def is_host_freebsd(*_): + return platform.system() == "FreeBSD" def with_algorithm(name: str): @@ -58,6 +84,12 @@ return pytest.mark.skipif(os.getenv(key) != "1", reason=f"{name} is not supported") +with_eddsa = pytest.mark.skipif( + os.getenv("ED25519_SUPPORTED") != "1" and os.getenv("ED448_SUPPORTED") != "1", + reason="EdDSA (ED25519 or ED448) is not supported", +) + + with_developer = pytest.mark.skipif( os.getenv("FEATURE_DEVELOPER") != "1", reason="developer mode disabled in the build", @@ -85,6 +117,42 @@ os.getenv("FEATURE_JSON_C") != "1", reason="json-c support disabled in the build" ) +with_libnghttp2 = pytest.mark.skipif( + os.getenv("FEATURE_LIBNGHTTP2") != "1", + reason="libnghttp2 support disabled in the build", +) + +with_geoip2 = pytest.mark.skipif( + os.getenv("FEATURE_GEOIP2") != "1", reason="GeoIP2 support disabled in the build" +) + +with_gssapi = pytest.mark.skipif( + os.getenv("FEATURE_GSSAPI") != "1", reason="GSS-API support disabled in the build" +) + +with_libxml2_or_json_c = pytest.mark.skipif( + os.getenv("FEATURE_LIBXML2") != "1" and os.getenv("FEATURE_JSON_C") != "1", + reason="libxml2 or json-c support is required", +) + +with_fips_dh = pytest.mark.skipif( + os.getenv("FEATURE_FIPS_DH") != "1", reason="FIPS mode Diffie-Hellman is required" +) + +without_tsan = pytest.mark.skipif( + os.getenv("FEATURE_TSAN") == "1", reason="incompatible with ThreadSanitizer (TSAN)" +) + +with_cpu_affinity = pytest.mark.skipif( + not (shutil.which("cpuset") or shutil.which("numactl") or shutil.which("taskset")), + reason="cpuset, numactl, or taskset is required", +) + +with_openssl_cipher_suites = pytest.mark.skipif( + os.getenv("FEATURE_OPENSSL_CIPHER_SUITES") != "1", + reason="SSL_CTX_set_ciphersuites() is required", +) + dnsrps_enabled = pytest.mark.skipif( not is_dnsrps_available(), reason="dnsrps disabled in the build" ) @@ -100,6 +168,11 @@ reason="SOFTHSM2_CONF and SOFTHSM2_MODULE environmental variables must be set and pkcs11-tool and softhsm2-util tools present", ) +with_pkcs11_provider = pytest.mark.skipif( + os.path.basename(os.getenv("OPENSSL_CONF") or "") != "openssl-provider.cnf", + reason="pkcs11-provider not enabled", +) + def have_ipv6(): sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) diff -Nru bind9-9.20.26/bin/tests/system/isctest/query.py bind9-9.20.29/bin/tests/system/isctest/query.py --- bind9-9.20.26/bin/tests/system/isctest/query.py 2026-07-20 14:47:53.742844966 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/query.py 2026-09-11 19:41:01.230324505 +0000 @@ -134,12 +134,7 @@ def tls(*args, **kwargs) -> Any: - try: - return generic_query(dns.query.tls, *args, **kwargs) - except TypeError as e: - raise RuntimeError( - "dnspython 2.5.0 or newer is required for isctest.query.tls()" - ) from e + return generic_query(dns.query.tls, *args, **kwargs) def create( @@ -147,13 +142,22 @@ qtype, qclass=dns.rdataclass.IN, dnssec: bool = True, + use_edns: int | bool = True, + payload: int = 1232, rd: bool = True, cd: bool = False, ad: bool = True, + message_id: int | None = None, ) -> dns.message.Message: """Create DNS query with defaults suitable for our tests.""" msg = dns.message.make_query( - qname, qtype, qclass, use_edns=True, want_dnssec=dnssec + qname, + qtype, + qclass, + use_edns=use_edns, + want_dnssec=dnssec, + payload=payload, + id=message_id, ) msg.flags = 0 if rd: @@ -165,28 +169,53 @@ return msg -def wait_for_serial(server_ip, zone, expected_serial, timeout=30): - """Wait until the server has the expected SOA serial for the zone. - - Queries the server repeatedly until the SOA serial matches or the - timeout expires. +def get_soa_serial(server_ip, zone, timeout=10): + """ + Get the current SOA serial of a zone from a server. - 'server_ip' is the IP address to query (string). - 'zone' is the zone name (string, with or without trailing dot). - 'expected_serial' is the expected SOA serial number (int). - 'timeout' is the maximum time to wait in seconds (default 30). + Queries the server repeatedly until it responds with a well-formed + SOA answer or the timeout expires. """ query = create(zone, "SOA", dnssec=False) + serial = None def check(): - res = tcp(query, server_ip) + nonlocal serial + res = tcp( + query, + server_ip, + timeout=3, + attempts=1, + expected_rcode=dns.rcode.NOERROR, + ) soa = res.get_rrset( res.answer, dns.name.from_text(zone), dns.rdataclass.IN, dns.rdatatype.SOA, ) - return soa is not None and len(soa) == 1 and soa[0].serial == expected_serial + assert soa is not None and len(soa) == 1 + serial = soa[0].serial + return True + + isctest.run.retry_with_timeout( + check, + timeout=timeout, + msg=f"timed out getting SOA serial of {zone} from {server_ip}", + ) + return serial + + +def wait_for_serial(server_ip, zone, expected_serial, timeout=30): + """ + Wait until the server has the expected SOA serial for the zone. + + Queries the server repeatedly until the SOA serial matches or the + timeout expires. + """ + + def check(): + return get_soa_serial(server_ip, zone) == expected_serial isctest.run.retry_with_timeout( check, diff -Nru bind9-9.20.26/bin/tests/system/isctest/rndc.py bind9-9.20.29/bin/tests/system/isctest/rndc.py --- bind9-9.20.26/bin/tests/system/isctest/rndc.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/rndc.py 2026-09-11 19:41:01.230324505 +0000 @@ -0,0 +1,256 @@ +# 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. + +""" +This module implements the RNDC control protocol. +""" + +from typing import Any + +import base64 +import hashlib +import hmac +import random +import socket +import struct +import time + +from .text import Text + + +class RNDCException(Exception): + """ + Raised when an RNDC command returns a non-zero result code. + """ + + def __init__(self, result: "RNDCResult") -> None: + super().__init__(f'rndc command failed with result {result.rc}: "{result.err}"') + self.result = result + + +class RNDCProtocolError(Exception): + """ + Raised when the control channel yields a truncated, malformed, or + unauthenticated response. + """ + + +class RNDCResult: + """ + Result of an RNDC command; mirrors isctest.run.CmdResult. + """ + + def __init__(self, response: dict[str, str]) -> None: + self.response = response + self.rc = int(response.get("result", "0")) + self.out = Text(response.get("text", "")) + self.err = Text(response.get("err", "")) + + +class RNDCClient: + """ + RNDC protocol client. + + A pure-Python alternative to controlling a server with the rndc + binary (`NamedInstance.rndc()`), useful when the overhead of + spawning the binary for every command is undesirable. Exercising + the rndc binary itself remains the primary interface in tests. + """ + + _algos = { + "md5": 157, + "sha1": 161, + "sha224": 162, + "sha256": 163, + "sha384": 164, + "sha512": 165, + } + + def __init__( + self, + ip: str, + port: int, + algo: str = "sha256", + secret: str = "1234abcd8765", + timeout: float = 10, + ) -> None: + """ + Creates a persistent connection to the control channel and logs in. + + algo - HMAC algorithm, one of md5, sha1, sha224, sha256, sha384, sha512 + secret - HMAC secret, base64 encoded + + The `algo` and `secret` defaults match _common/rndc.key, which + virtually all named instances in the system tests use for their + control channel. + """ + self.algo = algo + self.hlalgo = getattr(hashlib, algo) + self.secret = base64.b64decode(secret) + self.ser = random.getrandbits(32) + self.nonce: bytes | None = None + self.socket = socket.create_connection((ip, port), timeout=timeout) + try: + self._login() + except (OSError, RNDCProtocolError): + self.socket.close() + raise + + def __enter__(self) -> "RNDCClient": + return self + + def __exit__(self, *_: Any) -> None: + self.close() + + def close(self) -> None: + self.socket.close() + + def call(self, command: str, *, raise_on_exception: bool = True) -> RNDCResult: + """ + Call an RNDC command and check its result. + """ + response = self._command({b"type": command.encode()}) + data = {k.decode(): v.decode() for k, v in response[b"_data"].items()} + result = RNDCResult(data) + if result.rc != 0 and raise_on_exception: + raise RNDCException(result) + return result + + def _serialize_dict( + self, data: dict[bytes, Any], ignore_auth: bool = False + ) -> bytes: + rv = b"" + for k, v in data.items(): + if ignore_auth and k == b"_auth": + continue + rv += bytes([len(k)]) + rv += k + if isinstance(v, bytes): + rv += struct.pack(">BI", 1, len(v)) + v + elif isinstance(v, dict): + sd = self._serialize_dict(v) + rv += struct.pack(">BI", 2, len(sd)) + sd + else: + raise NotImplementedError(f"Cannot serialize element of type {type(v)}") + return rv + + def _prep_message(self, data: dict[bytes, Any]) -> bytes: + self.ser = (self.ser + 1) & 0xFFFFFFFF + now = int(time.time()) + + d: dict[bytes, Any] = {} + d[b"_auth"] = {} + d[b"_ctrl"] = {} + d[b"_ctrl"][b"_ser"] = b"%d" % self.ser + d[b"_ctrl"][b"_tim"] = b"%d" % now + d[b"_ctrl"][b"_exp"] = b"%d" % (now + 60) + if self.nonce is not None: + d[b"_ctrl"][b"_nonce"] = self.nonce + d[b"_data"] = data + + msg = self._serialize_dict(d, ignore_auth=True) + digest = hmac.new(self.secret, msg, self.hlalgo).digest() + bhash = base64.b64encode(digest) + if self.algo == "md5": + d[b"_auth"][b"hmd5"] = struct.pack("22s", bhash) + else: + d[b"_auth"][b"hsha"] = struct.pack("B88s", self._algos[self.algo], bhash) + msg = self._serialize_dict(d) + msg = struct.pack(">II", len(msg) + 4, 1) + msg + return msg + + def _verify_msg(self, msg: dict[bytes, Any]) -> bool: + if self.nonce is not None and msg[b"_ctrl"][b"_nonce"] != self.nonce: + return False + bhash = msg[b"_auth"][b"hmd5" if self.algo == "md5" else b"hsha"] + bhash += b"=" * (4 - (len(bhash) % 4)) + remote_hash = base64.b64decode(bhash) + my_msg = self._serialize_dict(msg, ignore_auth=True) + my_hash = hmac.new(self.secret, my_msg, self.hlalgo).digest() + return my_hash == remote_hash + + def _recv_exact(self, length: int) -> bytes: + # MSG_WAITALL would not help here: the socket timeout puts the + # socket in non-blocking mode, where the kernel may return + # partial data regardless of the flag. + buf = b"" + while len(buf) < length: + chunk = self.socket.recv(length - len(buf)) + if not chunk: + raise RNDCProtocolError( + "connection closed mid-response; possible authentication failure" + ) + buf += chunk + return buf + + def _command(self, data: dict[bytes, Any]) -> dict[bytes, Any]: + msg = self._prep_message(data) + self.socket.sendall(msg) + + header = self._recv_exact(8) + length, version = struct.unpack(">II", header) + if version != 1: + raise RNDCProtocolError(f"Unsupported message version {version}") + + # the length field also covers the 4-byte version word + payload = self._recv_exact(length - 4) + + try: + response = self._parse_dict(payload) + verified = self._verify_msg(response) + except ( + KeyError, + IndexError, + ValueError, + struct.error, + NotImplementedError, + ) as exc: + raise RNDCProtocolError(f"Malformed response ({exc})") from exc + if not verified: + raise RNDCProtocolError("HMAC verification of the response failed") + + return response + + def _login(self) -> None: + self.nonce = None + msg = self._command({b"type": b"null"}) + try: + self.nonce = msg[b"_ctrl"][b"_nonce"] + except KeyError as exc: + raise RNDCProtocolError("Login response is missing a nonce") from exc + + def _parse_element(self, buf: bytes) -> tuple[bytes, Any, bytes]: + pos = 0 + labellen = buf[pos] + pos += 1 + label = buf[pos : pos + labellen] + pos += labellen + etype = buf[pos] + pos += 1 + datalen = struct.unpack(">I", buf[pos : pos + 4])[0] + pos += 4 + data = buf[pos : pos + datalen] + pos += datalen + rest = buf[pos:] + + if etype == 1: # raw binary value + return label, data, rest + if etype == 2: # dictionary + return label, self._parse_dict(data), rest + # element type 3 (list) is not implemented + raise NotImplementedError(f"Unknown element type {etype}") + + def _parse_dict(self, buf: bytes) -> dict[bytes, Any]: + rv: dict[bytes, Any] = {} + while len(buf) > 0: + label, value, buf = self._parse_element(buf) + rv[label] = value + return rv diff -Nru bind9-9.20.26/bin/tests/system/isctest/template.py bind9-9.20.29/bin/tests/system/isctest/template.py --- bind9-9.20.26/bin/tests/system/isctest/template.py 2026-07-20 14:47:53.743844982 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/template.py 2026-09-11 19:41:01.230324505 +0000 @@ -19,6 +19,9 @@ import re import jinja2 +import jinja2.ext +import jinja2.nodes +import jinja2.parser from .log import debug from .vars import ALL @@ -29,6 +32,59 @@ NS_DIR_RE = Re(r"^(a?ns([0-9]+))/") +class IncludeIndented(jinja2.ext.Extension): + """ + `{% include_indented "template" %}` — like `{% include %}`, but keeps the + inserted block aligned with the tag's own indentation, which a plain + include cannot do. The tag's leading whitespace is detected at parse time + and the tag expands to the equivalent of + + {% filter indent(leading_whitespace) %}{% include ... %}{% endfilter %} + + so the runtime semantics are exactly those of the builtin include and + indent. Only whitespace may precede the tag on its line: that leading + whitespace indents the first included line (which is why lstrip_blocks + must stay disabled), the indent filter indents the rest. + """ + + tags = {"include_indented"} + + def parse(self, parser: jinja2.parser.Parser) -> jinja2.nodes.Node: + lineno = parser.stream.expect("name:include_indented").lineno + template = parser.parse_expression() + indent = self._tag_indentation(parser, lineno) + include = jinja2.nodes.Include(template, True, False, lineno=lineno) + indent_filter = jinja2.nodes.Filter( + None, # filled in with the block contents by the compiler + "indent", + [jinja2.nodes.Const(indent)], + [jinja2.nodes.Keyword("first", jinja2.nodes.Const(False))], + None, + None, + lineno=lineno, + ) + return jinja2.nodes.FilterBlock([include], indent_filter, lineno=lineno) + + def _tag_indentation(self, parser: jinja2.parser.Parser, lineno: int) -> str: + if parser.name is None or self.environment.loader is None: + parser.fail( + "include_indented requires a loader-backed template " + "to detect its indentation", + lineno, + ) + source, _, _ = self.environment.loader.get_source(self.environment, parser.name) + line = source.splitlines()[lineno - 1] + match = re.match( + rf"([ \t]*){re.escape(self.environment.block_start_string)}", line + ) + if match is None: + parser.fail( + "include_indented must be preceded by indentation only", + lineno, + ) + return match.group(1) + + class TemplateEngine: """ Engine for rendering jinja2 templates in system test directories. @@ -60,6 +116,7 @@ variable_end_string="@", trim_blocks=True, keep_trailing_newline=True, + extensions=[IncludeIndented], ) # allow instantiating the template dataclasses in jinja2 templates when # using {% set %} @@ -93,10 +150,10 @@ data = {**self.env_vars, **data} # directory-specific "ns" var - assert "ns" not in data, '"ns" variable is reserved for nameserver data' - match = NS_DIR_RE.search(output) - if match: - data["ns"] = Nameserver(match.group(1)) + if "ns" not in data: + match = NS_DIR_RE.search(output) + if match: + data["ns"] = Nameserver(match.group(1)) debug("rendering template `%s` to file `%s`", template, output) stream = self.j2env.get_template(template).stream(data) @@ -145,6 +202,7 @@ NS9 = Nameserver("ns9") NS10 = Nameserver("ns10") NS11 = Nameserver("ns11") +NO_NS = Nameserver(".", 0, "", "") @dataclass diff -Nru bind9-9.20.26/bin/tests/system/isctest/zone.py bind9-9.20.29/bin/tests/system/isctest/zone.py --- bind9-9.20.26/bin/tests/system/isctest/zone.py 2026-07-20 14:47:53.745845013 +0000 +++ bind9-9.20.29/bin/tests/system/isctest/zone.py 2026-09-11 19:41:01.232324553 +0000 @@ -473,6 +473,7 @@ data = { "zone": self, + "ns": self.ns, "delegations": self.delegations, } templates.render(str(output), data, template=template) diff -Nru bind9-9.20.26/bin/tests/system/ixfr/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/ixfr/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ixfr/ns1/named.conf.j2 2026-07-20 14:47:53.745845013 +0000 +++ bind9-9.20.29/bin/tests/system/ixfr/ns1/named.conf.j2 2026-09-11 19:41:01.232324553 +0000 @@ -12,24 +12,10 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/ixfr/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/ixfr/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ixfr/ns3/named.conf.j2 2026-07-20 14:47:53.745845013 +0000 +++ bind9-9.20.29/bin/tests/system/ixfr/ns3/named.conf.j2 2026-09-11 19:41:01.233324577 +0000 @@ -12,27 +12,13 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view "primary" { ixfr-from-differences yes; diff -Nru bind9-9.20.26/bin/tests/system/ixfr/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/ixfr/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ixfr/ns4/named.conf.j2 2026-07-20 14:47:53.745845013 +0000 +++ bind9-9.20.29/bin/tests/system/ixfr/ns4/named.conf.j2 2026-09-11 19:41:01.233324577 +0000 @@ -12,27 +12,13 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view "primary" { ixfr-from-differences yes; diff -Nru bind9-9.20.26/bin/tests/system/ixfr/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/ixfr/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ixfr/ns5/named.conf.j2 2026-07-20 14:47:53.745845013 +0000 +++ bind9-9.20.29/bin/tests/system/ixfr/ns5/named.conf.j2 2026-09-11 19:41:01.233324577 +0000 @@ -12,28 +12,14 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; provide-ixfr no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view "primary" { ixfr-from-differences yes; diff -Nru bind9-9.20.26/bin/tests/system/ixfr/prereq.sh bind9-9.20.29/bin/tests/system/ixfr/prereq.sh --- bind9-9.20.26/bin/tests/system/ixfr/prereq.sh 2026-07-20 14:47:53.745845013 +0000 +++ bind9-9.20.29/bin/tests/system/ixfr/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/ixfr_nonminimal/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/ixfr_nonminimal/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ixfr_nonminimal/ns1/named.conf.j2 2026-07-20 14:47:53.746845029 +0000 +++ bind9-9.20.29/bin/tests/system/ixfr_nonminimal/ns1/named.conf.j2 2026-09-11 19:41:01.233324577 +0000 @@ -12,27 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "nil" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/ixfr_nonminimal/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/ixfr_nonminimal/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ixfr_nonminimal/ns3/named.conf.j2 2026-07-20 14:47:53.746845029 +0000 +++ bind9-9.20.29/bin/tests/system/ixfr_nonminimal/ns3/named.conf.j2 2026-09-11 19:41:01.234324601 +0000 @@ -12,27 +12,13 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "nil" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/ixfr_nonminimal/prereq.sh bind9-9.20.29/bin/tests/system/ixfr_nonminimal/prereq.sh --- bind9-9.20.26/bin/tests/system/ixfr_nonminimal/prereq.sh 2026-07-20 14:47:53.746845029 +0000 +++ bind9-9.20.29/bin/tests/system/ixfr_nonminimal/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -#!/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. - -. ../conf.sh - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/journal/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/journal/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/journal/ns1/named.conf.j2 2026-07-20 14:47:53.748845060 +0000 +++ bind9-9.20.29/bin/tests/system/journal/ns1/named.conf.j2 2026-09-11 19:41:01.235324625 +0000 @@ -12,29 +12,15 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; dnssec-validation auto; bindkeys-file "../../../../../bind.keys"; minimal-responses no; recursion no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone . { type hint; diff -Nru bind9-9.20.26/bin/tests/system/journal/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/journal/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/journal/ns2/named.conf.j2 2026-07-20 14:47:53.748845060 +0000 +++ bind9-9.20.29/bin/tests/system/journal/ns2/named.conf.j2 2026-09-11 19:41:01.235324625 +0000 @@ -12,29 +12,15 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; dnssec-validation auto; bindkeys-file "../../../../../bind.keys"; minimal-responses no; recursion no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone . { type hint; diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/kasp/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/kasp/ns1/named.conf.j2 2026-07-20 14:47:53.749845075 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns1/named.conf.j2 2026-09-11 19:41:01.236324649 +0000 @@ -1,18 +1,13 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; - allow-transfer { any; }; + allow-transfer { any; }; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/kasp/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/kasp/ns2/named.conf.j2 2026-07-20 14:47:53.749845075 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns2/named.conf.j2 2026-09-11 19:41:01.236324649 +0000 @@ -14,27 +14,14 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-policy "none"; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} /* Inherit dnssec-policy (which is none) */ diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns3/ed25519.conf bind9-9.20.29/bin/tests/system/kasp/ns3/ed25519.conf --- bind9-9.20.26/bin/tests/system/kasp/ns3/ed25519.conf 2026-07-20 14:47:53.750845091 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns3/ed25519.conf 2026-09-11 19:41:01.237324674 +0000 @@ -12,17 +12,17 @@ */ dnssec-policy "ed25519" { - dnskey-ttl 1234; + dnskey-ttl 1234; - keys { - ksk key-directory lifetime P10Y algorithm 15; - zsk key-directory lifetime P5Y algorithm 15; - zsk key-directory lifetime P1Y algorithm 15 256; - }; + keys { + ksk key-directory lifetime P10Y algorithm 15; + zsk key-directory lifetime P5Y algorithm 15; + zsk key-directory lifetime P1Y algorithm 15 256; + }; }; zone "ed25519.kasp" { - type primary; - file "ed25519.kasp.db"; - dnssec-policy "ed25519"; + type primary; + file "ed25519.kasp.db"; + dnssec-policy "ed25519"; }; diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns3/ed448.conf bind9-9.20.29/bin/tests/system/kasp/ns3/ed448.conf --- bind9-9.20.26/bin/tests/system/kasp/ns3/ed448.conf 2026-07-20 14:47:53.750845091 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns3/ed448.conf 2026-09-11 19:41:01.237324674 +0000 @@ -12,17 +12,17 @@ */ dnssec-policy "ed448" { - dnskey-ttl 1234; + dnskey-ttl 1234; - keys { - ksk key-directory lifetime P10Y algorithm 16; - zsk key-directory lifetime P5Y algorithm 16; - zsk key-directory lifetime P1Y algorithm 16 456; - }; + keys { + ksk key-directory lifetime P10Y algorithm 16; + zsk key-directory lifetime P5Y algorithm 16; + zsk key-directory lifetime P1Y algorithm 16 456; + }; }; zone "ed448.kasp" { - type primary; - file "ed448.kasp.db"; - dnssec-policy "ed448"; + type primary; + file "ed448.kasp.db"; + dnssec-policy "ed448"; }; diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns3/named-common.conf.j2 bind9-9.20.29/bin/tests/system/kasp/ns3/named-common.conf.j2 --- bind9-9.20.26/bin/tests/system/kasp/ns3/named-common.conf.j2 2026-07-20 14:47:53.750845091 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns3/named-common.conf.j2 2026-09-11 19:41:01.237324674 +0000 @@ -14,27 +14,14 @@ // NS3 options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-policy "rsasha256"; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns3/named-fips.conf.j2 bind9-9.20.29/bin/tests/system/kasp/ns3/named-fips.conf.j2 --- bind9-9.20.26/bin/tests/system/kasp/ns3/named-fips.conf.j2 2026-07-20 14:47:53.750845091 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns3/named-fips.conf.j2 2026-09-11 19:41:01.237324674 +0000 @@ -22,10 +22,10 @@ /* A zone with special characters. */ zone {% raw %}"i-am.\":\;?&[]\@!\$*+,|=\.\(\)special.kasp."{% endraw %} { - type primary; - file "i-am.special.kasp.db"; - check-names ignore; - dnssec-policy "default"; + type primary; + file "i-am.special.kasp.db"; + check-names ignore; + dnssec-policy "default"; }; /* checkds: Zone with one KSK. */ diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/kasp/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/kasp/ns4/named.conf.j2 2026-07-20 14:47:53.751845106 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns4/named.conf.j2 2026-09-11 19:41:01.238324698 +0000 @@ -15,14 +15,7 @@ include "purgekeys.conf"; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key "sha1" { algorithm "hmac-sha1"; @@ -61,11 +54,7 @@ }; options { - query-source address 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-policy "test"; diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/kasp/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/kasp/ns5/named.conf.j2 2026-07-20 14:47:53.752845122 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns5/named.conf.j2 2026-09-11 19:41:01.239324722 +0000 @@ -13,14 +13,7 @@ // NS5 -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key "sha1" { algorithm "hmac-sha1"; @@ -44,11 +37,7 @@ }; options { - query-source address 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-policy "none"; diff -Nru bind9-9.20.26/bin/tests/system/kasp/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/kasp/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/kasp/ns6/named.conf.j2 2026-07-20 14:47:53.752845122 +0000 +++ bind9-9.20.29/bin/tests/system/kasp/ns6/named.conf.j2 2026-09-11 19:41:01.239324722 +0000 @@ -17,27 +17,14 @@ include "policies/csk1.conf"; options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; key-directory "."; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/keepalive/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/keepalive/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/keepalive/ns1/named.conf.j2 2026-07-20 14:47:53.753845138 +0000 +++ bind9-9.20.29/bin/tests/system/keepalive/ns1/named.conf.j2 2026-09-11 19:41:01.240324746 +0000 @@ -12,26 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/keepalive/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/keepalive/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/keepalive/ns2/named.conf.j2 2026-07-20 14:47:53.753845138 +0000 +++ bind9-9.20.29/bin/tests/system/keepalive/ns2/named.conf.j2 2026-09-11 19:41:01.240324746 +0000 @@ -11,33 +11,16 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} send-cookie yes; tcp-advertised-timeout 150; dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/keepalive/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/keepalive/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/keepalive/ns3/named.conf.j2 2026-07-20 14:47:53.754845153 +0000 +++ bind9-9.20.29/bin/tests/system/keepalive/ns3/named.conf.j2 2026-09-11 19:41:01.241324770 +0000 @@ -12,16 +12,7 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; @@ -30,16 +21,6 @@ tcp-keepalive yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/ksr/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/ksr/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ksr/ns1/named.conf.j2 2026-07-20 14:47:53.754845153 +0000 +++ bind9-9.20.29/bin/tests/system/ksr/ns1/named.conf.j2 2026-09-11 19:41:01.241324770 +0000 @@ -12,27 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; allow-new-zones yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "common" { offline-ksk yes; @@ -100,17 +87,17 @@ ksk lifetime unlimited algorithm @DEFAULT_ALGORITHM@; zsk lifetime 8792 algorithm @DEFAULT_ALGORITHM@; }; - dnskey-ttl 439; - max-zone-ttl 4396; - zone-propagation-delay 439; - signatures-validity 6; - signatures-validity-dnskey 6; - signatures-refresh 2; - signatures-jitter 0; - publish-safety 1; - retire-safety 1; - parent-ds-ttl 5; - parent-propagation-delay 5; + dnskey-ttl 439; + max-zone-ttl 4396; + zone-propagation-delay 439; + signatures-validity 6; + signatures-validity-dnskey 6; + signatures-refresh 2; + signatures-jitter 0; + publish-safety 1; + retire-safety 1; + parent-ds-ttl 5; + parent-propagation-delay 5; }; dnssec-policy "invalid-skr" { diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns1/named.conf.j2 2026-07-20 14:47:53.755845169 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns1/named.conf.j2 2026-09-11 19:41:01.242324794 +0000 @@ -14,26 +14,12 @@ {% set dnssec_validation = dnssec_validation | default("no") %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation @dnssec_validation@; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns10/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns10/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns10/named.conf.j2 2026-07-20 14:47:53.755845169 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns10/named.conf.j2 2026-09-11 19:41:01.242324794 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.10; - notify-source 10.53.0.10; - transfer-source 10.53.0.10; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.10; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "ednsrefused" { type primary; file "ednsrefused.db"; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns2/named.conf.j2 2026-07-20 14:47:53.755845169 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns2/named.conf.j2 2026-09-11 19:41:01.242324794 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "dropedns" { type primary; file "dropedns.db"; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns3/named.conf.j2 2026-07-20 14:47:53.756845184 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns3/named.conf.j2 2026-09-11 19:41:01.243324818 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "dropedns-notcp" { type primary; file "dropedns-notcp.db"; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns4/named.conf.j2 2026-07-20 14:47:53.756845184 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns4/named.conf.j2 2026-09-11 19:41:01.243324818 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "plain" { type primary; file "plain.db"; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns5/named.conf.j2 2026-07-20 14:47:53.756845184 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns5/named.conf.j2 2026-09-11 19:41:01.243324818 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "plain-notcp" { type primary; file "plain-notcp.db"; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns6/named.conf.j2 2026-07-20 14:47:53.757845200 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns6/named.conf.j2 2026-09-11 19:41:01.244324843 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "edns512" { type primary; file "edns512.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns7/named.conf.j2 2026-07-20 14:47:53.757845200 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns7/named.conf.j2 2026-09-11 19:41:01.244324843 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "edns512-notcp" { type primary; file "edns512-notcp.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns8/named.conf.j2 2026-07-20 14:47:53.758845215 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns8/named.conf.j2 2026-09-11 19:41:01.245324867 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "ednsformerr" { type primary; file "ednsformerr.db"; diff -Nru bind9-9.20.26/bin/tests/system/legacy/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/legacy/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/legacy/ns9/named.conf.j2 2026-07-20 14:47:53.758845215 +0000 +++ bind9-9.20.29/bin/tests/system/legacy/ns9/named.conf.j2 2026-09-11 19:41:01.245324867 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "ednsnotimp" { type primary; file "ednsnotimp.db"; diff -Nru bind9-9.20.26/bin/tests/system/limits/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/limits/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/limits/ns1/named.conf.j2 2026-07-20 14:47:53.759845231 +0000 +++ bind9-9.20.29/bin/tests/system/limits/ns1/named.conf.j2 2026-09-11 19:41:01.246324891 +0000 @@ -12,20 +12,15 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; minimal-responses no; dnssec-validation no; max-records-per-type 0; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.abspath.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.abspath.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.abspath.conf.j2 2026-07-20 14:47:53.759845231 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.abspath.conf.j2 2026-09-11 19:41:01.246324891 +0000 @@ -12,41 +12,27 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - buffered no; - file "@TMPDIR@/example.log" versions 1 size 1k suffix increment; # small size - severity debug 100; - print-time yes; + buffered no; + file "@TMPDIR@/example.log" versions 1 size 1k suffix increment; # small size + severity debug 100; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; channel query_log { - file "query_log"; - print-time yes; - buffered yes; + file "query_log"; + print-time yes; + buffered yes; }; category queries { query_log; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm hmac-sha256; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,39 +12,25 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - file "named_log"; - print-time yes; + file "named_log"; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; channel query_log { - file "query_log"; - print-time yes; - buffered yes; + file "query_log"; + print-time yes; + buffered yes; }; category queries { query_log; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.dir.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.dir.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.dir.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.dir.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,32 +12,18 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - file "/tmp"; - print-time yes; + file "/tmp"; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.inc.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.inc.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.inc.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.inc.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,41 +12,27 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - buffered no; - file "named_inc" versions 1 size 1k suffix increment; # small size - severity debug 100; - print-time yes; + buffered no; + file "named_inc" versions 1 size 1k suffix increment; # small size + severity debug 100; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; channel query_log { - file "query_log"; - print-time yes; - buffered yes; + file "query_log"; + print-time yes; + buffered yes; }; category queries { query_log; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm hmac-sha256; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.iso8601-utc.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.iso8601-utc.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.iso8601-utc.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.iso8601-utc.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,16 +12,9 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { @@ -33,11 +26,4 @@ category default { default_log; default_debug; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.iso8601.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.iso8601.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.iso8601.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.iso8601.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,16 +12,9 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { @@ -34,11 +27,4 @@ }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.pipe.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.pipe.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.pipe.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.pipe.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,32 +12,18 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - file "named_pipe"; - print-time yes; + file "named_pipe"; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.plain.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.plain.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.plain.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.plain.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,39 +12,25 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - file "named_log"; - print-time yes; + file "named_log"; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; channel query_log { - file "query_log"; - print-time yes; - buffered yes; + file "query_log"; + print-time yes; + buffered yes; }; category queries { query_log; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.plainlog.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.plainlog.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.plainlog.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.plainlog.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,23 +12,9 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.sym.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.sym.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.sym.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.sym.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,32 +12,18 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - file "named_sym"; - print-time yes; + file "named_sym"; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.ts.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.ts.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.ts.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.ts.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,41 +12,27 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - buffered no; - file "named_ts" versions 3 size 1000 suffix timestamp; # small size - severity debug 100; - print-time yes; + buffered no; + file "named_ts" versions 3 size 1000 suffix timestamp; # small size + severity debug 100; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; channel query_log { - file "query_log"; - print-time yes; - buffered yes; + file "query_log"; + print-time yes; + buffered yes; }; category queries { query_log; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.unlimited.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.unlimited.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.unlimited.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.unlimited.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,41 +12,27 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - buffered no; - file "named_unlimited" versions unlimited size 1000; - severity debug 100; - print-time yes; + buffered no; + file "named_unlimited" versions unlimited size 1000; + severity debug 100; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; channel query_log { - file "query_log"; - print-time yes; - buffered yes; + file "query_log"; + print-time yes; + buffered yes; }; category queries { query_log; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.vers.conf.j2 bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.vers.conf.j2 --- bind9-9.20.26/bin/tests/system/logfileconfig/ns1/named.vers.conf.j2 2026-07-20 14:47:53.760845246 +0000 +++ bind9-9.20.29/bin/tests/system/logfileconfig/ns1/named.vers.conf.j2 2026-09-11 19:41:01.247324915 +0000 @@ -12,41 +12,27 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; - notify yes; }; logging { channel default_log { - buffered no; - file "named_vers" versions 5 size 1000; // really small size - severity debug 100; - print-time yes; + buffered no; + file "named_vers" versions 5 size 1000; // really small size + severity debug 100; + print-time yes; }; category default { default_log; default_debug; }; category lame-servers { null; }; channel query_log { - file "query_log"; - print-time yes; - buffered yes; + file "query_log"; + print-time yes; + buffered yes; }; category queries { query_log; }; }; -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { "rndc-key"; }; -}; - -key rndc-key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/masterfile/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/masterfile/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/masterfile/ns1/named.conf.j2 2026-07-20 14:47:53.761845262 +0000 +++ bind9-9.20.29/bin/tests/system/masterfile/ns1/named.conf.j2 2026-09-11 19:41:01.248324938 +0000 @@ -12,19 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "include" { type primary; file "include.db"; diff -Nru bind9-9.20.26/bin/tests/system/masterfile/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/masterfile/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/masterfile/ns2/named.conf.j2 2026-07-20 14:47:53.761845262 +0000 +++ bind9-9.20.29/bin/tests/system/masterfile/ns2/named.conf.j2 2026-09-11 19:41:01.248324938 +0000 @@ -14,24 +14,15 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/masterformat/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/masterformat/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/masterformat/ns1/named.conf.j2 2026-07-20 14:47:53.762845278 +0000 +++ bind9-9.20.29/bin/tests/system/masterformat/ns1/named.conf.j2 2026-09-11 19:41:01.249324963 +0000 @@ -14,10 +14,7 @@ // NS1 options { - pid-file "named.pid"; - listen-on port @PORT@ { 10.53.0.1; }; - port @PORT@; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; session-keyfile "session.key"; @@ -27,14 +24,7 @@ max-types-per-name 500; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "masterformat" { keys { diff -Nru bind9-9.20.26/bin/tests/system/masterformat/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/masterformat/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/masterformat/ns2/named.conf.j2 2026-07-20 14:47:53.762845278 +0000 +++ bind9-9.20.29/bin/tests/system/masterformat/ns2/named.conf.j2 2026-09-11 19:41:01.249324963 +0000 @@ -14,10 +14,7 @@ // NS2 options { - pid-file "named.pid"; - listen-on port @PORT@ { 10.53.0.2; }; - listen-on-v6 { none; }; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; servfail-ttl 0; @@ -26,6 +23,8 @@ max-types-per-name 200; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/masterformat/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/masterformat/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/masterformat/ns3/named.conf.j2 2026-07-20 14:47:53.762845278 +0000 +++ bind9-9.20.29/bin/tests/system/masterformat/ns3/named.conf.j2 2026-09-11 19:41:01.249324963 +0000 @@ -14,23 +14,13 @@ // NS3 options { - pid-file "named.pid"; - listen-on port @PORT@ { 10.53.0.3; }; - port @PORT@; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/masterformat/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/masterformat/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/masterformat/ns4/named.conf.j2 2026-07-20 14:47:53.763845293 +0000 +++ bind9-9.20.29/bin/tests/system/masterformat/ns4/named.conf.j2 2026-09-11 19:41:01.250324986 +0000 @@ -14,10 +14,7 @@ // NS4 options { - pid-file "named.pid"; - listen-on port @PORT@ { 10.53.0.4; }; - port @PORT@; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; session-keyfile "session.key"; @@ -29,14 +26,7 @@ max-types-per-name 11; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "masterformat" { keys { diff -Nru bind9-9.20.26/bin/tests/system/masterformat/ns4/named2.conf.j2 bind9-9.20.29/bin/tests/system/masterformat/ns4/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/masterformat/ns4/named2.conf.j2 2026-07-20 14:47:53.763845293 +0000 +++ bind9-9.20.29/bin/tests/system/masterformat/ns4/named2.conf.j2 2026-09-11 19:41:01.250324986 +0000 @@ -14,10 +14,7 @@ // NS4 options { - pid-file "named.pid"; - listen-on port @PORT@ { 10.53.0.4; }; - port @PORT@; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; session-keyfile "session.key"; @@ -29,14 +26,7 @@ max-types-per-name 9; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} /* * The template zone is fine, but when adding the DNSSEC records to the apex, diff -Nru bind9-9.20.26/bin/tests/system/migrate2kasp/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/migrate2kasp/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/migrate2kasp/ns3/named.conf.j2 2026-07-20 14:47:53.764845308 +0000 +++ bind9-9.20.29/bin/tests/system/migrate2kasp/ns3/named.conf.j2 2026-09-11 19:41:01.251325010 +0000 @@ -16,26 +16,13 @@ include "kasp.conf"; options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} /* These are zones that migrate to dnssec-policy. */ zone "migrate.kasp" { diff -Nru bind9-9.20.26/bin/tests/system/migrate2kasp/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/migrate2kasp/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/migrate2kasp/ns4/named.conf.j2 2026-07-20 14:47:53.764845308 +0000 +++ bind9-9.20.29/bin/tests/system/migrate2kasp/ns4/named.conf.j2 2026-09-11 19:41:01.251325010 +0000 @@ -14,27 +14,14 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; key-directory "."; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "rsasha256" { keys { @@ -68,7 +55,7 @@ }; view "ext" { - match-clients { key "external"; }; + match-clients { key "external"; }; zone "view-rsasha256.kasp" { type primary; @@ -80,7 +67,7 @@ }; view "int" { - match-clients { key "internal"; }; + match-clients { key "internal"; }; zone "view-rsasha256.kasp" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/mirror/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/mirror/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mirror/ns1/named.conf.j2 2026-07-20 14:47:53.765845324 +0000 +++ bind9-9.20.29/bin/tests/system/mirror/ns1/named.conf.j2 2026-09-11 19:41:01.252325034 +0000 @@ -12,18 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/mirror/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/mirror/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mirror/ns2/named.conf.j2 2026-07-20 14:47:53.765845324 +0000 +++ bind9-9.20.29/bin/tests/system/mirror/ns2/named.conf.j2 2026-09-11 19:41:01.252325034 +0000 @@ -11,23 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; diff -Nru bind9-9.20.26/bin/tests/system/mirror/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/mirror/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mirror/ns3/named.conf.j2 2026-07-20 14:47:53.766845340 +0000 +++ bind9-9.20.29/bin/tests/system/mirror/ns3/named.conf.j2 2026-09-11 19:41:01.253325058 +0000 @@ -11,34 +11,17 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} allow-query-cache { 10.53.0.1; }; trust-anchor-telemetry yes; allow-new-zones yes; dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "." { type mirror; diff -Nru bind9-9.20.26/bin/tests/system/mirror_root_zone/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/mirror_root_zone/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mirror_root_zone/ns1/named.conf.j2 2026-07-20 14:47:53.766845340 +0000 +++ bind9-9.20.29/bin/tests/system/mirror_root_zone/ns1/named.conf.j2 2026-09-11 19:41:01.253325058 +0000 @@ -11,18 +11,17 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { + # This instance transfers the root zone from the live internet. + # The options-level port and the *-source addresses must stay at + # their defaults so that outgoing traffic uses port 53 and a + # routable source address. + port 53; pid-file "named.pid"; - listen-on port @PORT@ {10.53.0.1;}; + listen-on port @PORT@ { @ns.ip@; }; + listen-on-v6 { none; }; }; zone "." { type mirror; }; diff -Nru bind9-9.20.26/bin/tests/system/mismatchtcp/ans2/ans.py bind9-9.20.29/bin/tests/system/mismatchtcp/ans2/ans.py --- bind9-9.20.26/bin/tests/system/mismatchtcp/ans2/ans.py 2026-07-20 14:47:53.766845340 +0000 +++ bind9-9.20.29/bin/tests/system/mismatchtcp/ans2/ans.py 2026-09-11 19:41:01.253325058 +0000 @@ -9,56 +9,46 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. -""" -Authoritative server that simulates Kaminsky-style off-path spoofing on UDP: -for every UDP query for trigger.example./A it sends one response with a -deliberately flipped DNS message id. A resolver that escalates to TCP on -the first id mismatch will still get the correct answer over TCP, which -this server serves normally. -""" - from collections.abc import AsyncGenerator -import dns.name import dns.rdatatype from isctest.asyncserver import ( AsyncDnsServer, DnsProtocol, DnsResponseSend, + QnameQtypeHandler, QueryContext, ResponseAction, - ResponseHandler, ) -class MismatchOnUdpHandler(ResponseHandler): +class MismatchedIdOnUdpHandler(QnameQtypeHandler): """ - Spoof UDP queries for trigger.example./A with a properly-formed - response whose DNS message id does not match the request. Answer - the same query normally on TCP using the zone data prepared by the - framework. + Simulate Kaminsky-style off-path spoofing: answer every UDP query for + trigger.example./A with the correct response prepared from zone data, + but with a deliberately flipped DNS message id. TCP queries do not + match this handler and are answered from zone data as usual, so a + resolver that escalates to TCP on the first id mismatch still gets + the correct answer. """ - def __init__(self) -> None: - self._trigger = dns.name.from_text("trigger.example.") + qnames = ["trigger.example."] + qtypes = [dns.rdatatype.A] def match(self, qctx: QueryContext) -> bool: - return qctx.qname == self._trigger and qctx.qtype == dns.rdatatype.A + return qctx.protocol == DnsProtocol.UDP and super().match(qctx) async def get_responses( self, qctx: QueryContext ) -> AsyncGenerator[ResponseAction, None]: - if qctx.protocol == DnsProtocol.UDP: - qctx.response.id = qctx.query.id ^ 0xFFFF - yield DnsResponseSend(qctx.response) - else: - yield DnsResponseSend(qctx.response) + qctx.response.id = qctx.query.id ^ 0xFFFF + yield DnsResponseSend(qctx.response) def main() -> None: server = AsyncDnsServer() - server.install_response_handler(MismatchOnUdpHandler()) + server.install_response_handler(MismatchedIdOnUdpHandler()) server.run() diff -Nru bind9-9.20.26/bin/tests/system/mismatchtcp/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/mismatchtcp/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mismatchtcp/ns1/named.conf.j2 2026-07-20 14:47:53.767845355 +0000 +++ bind9-9.20.29/bin/tests/system/mismatchtcp/ns1/named.conf.j2 2026-09-11 19:41:01.254325082 +0000 @@ -11,19 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - query-source address 10.53.0.1; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns1/named.conf.j2 2026-07-20 14:47:53.767845355 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns1/named.conf.j2 2026-09-11 19:41:01.254325082 +0000 @@ -19,13 +19,7 @@ }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; dnssec-validation no; @@ -33,14 +27,7 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns1/named2.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns1/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns1/named2.conf.j2 2026-07-20 14:47:53.767845355 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns1/named2.conf.j2 2026-09-11 19:41:01.254325082 +0000 @@ -19,13 +19,7 @@ }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; dnssec-validation no; @@ -33,14 +27,7 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns1/named3.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns1/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns1/named3.conf.j2 2026-07-20 14:47:53.767845355 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns1/named3.conf.j2 2026-09-11 19:41:01.254325082 +0000 @@ -14,27 +14,14 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns2/named.conf.j2 2026-07-20 14:47:53.768845371 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns2/named.conf.j2 2026-09-11 19:41:01.255325106 +0000 @@ -14,30 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation auto; bindkeys-file "managed.conf"; servfail-ttl 0; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns3/named.conf.j2 2026-07-20 14:47:53.768845371 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns3/named.conf.j2 2026-09-11 19:41:01.255325106 +0000 @@ -14,32 +14,15 @@ // NS3 options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation auto; bindkeys-file "managed.conf"; trust-anchor-telemetry no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "broken.conf"; diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns4/named.conf.j2 2026-07-20 14:47:53.768845371 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns4/named.conf.j2 2026-09-11 19:41:01.255325106 +0000 @@ -14,33 +14,16 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation auto; bindkeys-file "managed.conf"; managed-keys-directory "nope"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "sub.foo" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns5/named.conf.j2 2026-07-20 14:47:53.768845371 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns5/named.conf.j2 2026-09-11 19:41:01.255325106 +0000 @@ -14,33 +14,16 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation auto; bindkeys-file "managed.conf"; servfail-ttl 0; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "foo" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns6/named.conf.j2 2026-07-20 14:47:53.769845386 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns6/named.conf.j2 2026-09-11 19:41:01.256325130 +0000 @@ -14,31 +14,14 @@ // NS6 options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation auto; trust-anchor-telemetry no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "managed.conf"; diff -Nru bind9-9.20.26/bin/tests/system/mkeys/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/mkeys/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/mkeys/ns7/named.conf.j2 2026-07-20 14:47:53.769845386 +0000 +++ bind9-9.20.29/bin/tests/system/mkeys/ns7/named.conf.j2 2026-09-11 19:41:01.256325130 +0000 @@ -14,38 +14,18 @@ // NS7 options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation auto; bindkeys-file "managed.conf"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view view1 { - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} }; view view2 { - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} }; diff -Nru bind9-9.20.26/bin/tests/system/multisigner/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/multisigner/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/multisigner/ns3/named.conf.j2 2026-07-20 14:47:53.770845402 +0000 +++ bind9-9.20.29/bin/tests/system/multisigner/ns3/named.conf.j2 2026-09-11 19:41:01.257325154 +0000 @@ -16,27 +16,14 @@ include "../kasp.conf"; options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; key-directory "."; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "model2.multisigner." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/multisigner/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/multisigner/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/multisigner/ns4/named.conf.j2 2026-07-20 14:47:53.770845402 +0000 +++ bind9-9.20.29/bin/tests/system/multisigner/ns4/named.conf.j2 2026-09-11 19:41:01.257325154 +0000 @@ -16,27 +16,14 @@ include "../kasp.conf"; options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; key-directory "."; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "model2.multisigner." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/multisigner/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/multisigner/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/multisigner/ns5/named.conf.j2 2026-07-20 14:47:53.770845402 +0000 +++ bind9-9.20.29/bin/tests/system/multisigner/ns5/named.conf.j2 2026-09-11 19:41:01.257325154 +0000 @@ -16,13 +16,7 @@ include "../kasp.conf"; options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; key-directory "."; @@ -30,14 +24,7 @@ notify-delay 0; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "model2.secondary." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/multisigner/tests_multisigner.py bind9-9.20.29/bin/tests/system/multisigner/tests_multisigner.py --- bind9-9.20.26/bin/tests/system/multisigner/tests_multisigner.py 2026-07-20 14:47:53.770845402 +0000 +++ bind9-9.20.29/bin/tests/system/multisigner/tests_multisigner.py 2026-09-11 19:41:01.257325154 +0000 @@ -14,10 +14,6 @@ import os -import dns.name -import dns.rcode -import dns.rdataclass -import dns.rdatatype import dns.update import pytest @@ -108,45 +104,35 @@ ), "dnssec record found in journal" -def wait_for_serial(primary, server, zone): +def wait_for_serial(primary, server, zone, previous_serial=None): if primary.identifier == server.identifier: - # No need to check if the transfer has been done. + assert previous_serial is not None + + def check_prev_serial(): + return isctest.query.get_soa_serial(server.ip, zone) != previous_serial + + isctest.run.retry_with_timeout(check_prev_serial, timeout=30) return def check_serial(): - response = isctest.query.tcp( - query, primary.ip, primary.ports.dns, timeout=3, attempts=1 - ) - assert response.rcode() == dns.rcode.NOERROR - soa = response.get_rrset( - response.answer, - dns.name.from_text(fqdn), - dns.rdataclass.IN, - dns.rdatatype.SOA, - ) - serial1 = soa[0].serial - - response = isctest.query.tcp( - query, server.ip, server.ports.dns, timeout=3, attempts=1 - ) - assert response.rcode() == dns.rcode.NOERROR - soa = response.get_rrset( - response.answer, - dns.name.from_text(fqdn), - dns.rdataclass.IN, - dns.rdatatype.SOA, - ) - serial2 = soa[0].serial + serial1 = isctest.query.get_soa_serial(primary.ip, zone) + serial2 = isctest.query.get_soa_serial(server.ip, zone) return ( f"zone {zone}/IN (signed): serial {serial2} (unsigned {serial1})" in server.log ) - fqdn = f"{zone}." - query = isctest.query.create(fqdn, dns.rdatatype.SOA) + isctest.run.retry_with_timeout(check_serial, timeout=30) + + +def nsupdate_and_wait(primary, server, zone, update_msg): + previous_serial = None + if primary.identifier == server.identifier: + previous_serial = isctest.query.get_soa_serial(server.ip, zone) - isctest.run.retry_with_timeout(check_serial, timeout=10) + primary.nsupdate(update_msg) + wait_for_serial(primary, server, zone, previous_serial) def check_add_zsk(server, zone, keys, expected, extra_keys, extra, primary=None): @@ -164,9 +150,7 @@ dnskey = str(zsk.dnskey).split() rdata = " ".join(dnskey[4:]) update_msg.add(f"{zone}.", TTL, "DNSKEY", rdata) - primary.nsupdate(update_msg) - - wait_for_serial(primary, server, zone) + nsupdate_and_wait(primary, server, zone, update_msg) # Check the new DNSKEY RRset. isctest.log.info( @@ -262,7 +246,6 @@ ) update_msg = dns.update.UpdateMessage(zone) update_msg.delete(f"{zone}.", "DNSKEY") - primary.nsupdate(update_msg) else: # Remove actual ZSK. update_msg = dns.update.UpdateMessage(zone) @@ -270,9 +253,7 @@ dnskey = str(zsk.dnskey).split() rdata = " ".join(dnskey[4:]) update_msg.delete(f"{zone}.", "DNSKEY", rdata) - primary.nsupdate(update_msg) - - wait_for_serial(primary, server, zone) + nsupdate_and_wait(primary, server, zone, update_msg) # We should have only the KSK and ZSK from server. isctest.log.info( @@ -306,9 +287,7 @@ dnskey = str(ksk.dnskey).split() rdata = " ".join(dnskey[4:]) update_msg.add(f"{zone}.", TTL, "CDNSKEY", rdata) - primary.nsupdate(update_msg) - - wait_for_serial(primary, server, zone) + nsupdate_and_wait(primary, server, zone, update_msg) # Now there should be two CDNSKEY records. isctest.log.info( @@ -397,7 +376,6 @@ ) update_msg = dns.update.UpdateMessage(zone) update_msg.delete(f"{zone}.", "CDNSKEY") - primary.nsupdate(update_msg) else: # Remove actual CDNSKEY. isctest.log.info( @@ -409,9 +387,7 @@ dnskey = str(ksk.dnskey).split() rdata = " ".join(dnskey[4:]) update_msg.delete(f"{zone}.", "CDNSKEY", rdata) - primary.nsupdate(update_msg) - - wait_for_serial(primary, server, zone) + nsupdate_and_wait(primary, server, zone, update_msg) # Now there should be one CDNSKEY record again. isctest.log.info( @@ -445,9 +421,7 @@ ds = dsfromkey(ksk) rdata = " ".join(ds[4:]) update_msg.add(f"{zone}.", TTL, "CDS", rdata) - primary.nsupdate(update_msg) - - wait_for_serial(primary, server, zone) + nsupdate_and_wait(primary, server, zone, update_msg) # Now there should be two CDS records. isctest.log.info( @@ -530,7 +504,6 @@ ) update_msg = dns.update.UpdateMessage(zone) update_msg.delete(f"{zone}.", "CDS") - primary.nsupdate(update_msg) else: # Remove actual CDS. isctest.log.info( @@ -542,9 +515,7 @@ ds = dsfromkey(ksk) rdata = " ".join(ds[4:]) update_msg.delete(f"{zone}.", "CDS", rdata) - primary.nsupdate(update_msg) - - wait_for_serial(primary, server, zone) + nsupdate_and_wait(primary, server, zone, update_msg) # Now there should be one CDS record again. isctest.log.info( diff -Nru bind9-9.20.26/bin/tests/system/names/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/names/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/names/ns1/named.conf.j2 2026-07-20 14:47:53.771845418 +0000 +++ bind9-9.20.29/bin/tests/system/names/ns1/named.conf.j2 2026-09-11 19:41:01.258325178 +0000 @@ -12,23 +12,17 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; ixfr-from-differences yes; check-integrity no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} view compress { - match-clients { 10.53.0.1/32; }; + match-clients { @ns.ip@/32; }; zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/notify/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/notify/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/notify/ns1/named.conf.j2 2026-07-20 14:47:53.772845433 +0000 +++ bind9-9.20.29/bin/tests/system/notify/ns1/named.conf.j2 2026-09-11 19:41:01.259325202 +0000 @@ -12,20 +12,15 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; + {% include_indented "_common/options.conf.j2" %} # invalid notify-source-v6 address notify-source-v6 fd92:7065:b8e:fffe::a35:5; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; recursion no; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/notify/ns2/named-tls.conf.j2 bind9-9.20.29/bin/tests/system/notify/ns2/named-tls.conf.j2 --- bind9-9.20.26/bin/tests/system/notify/ns2/named-tls.conf.j2 2026-07-20 14:47:53.773845449 +0000 +++ bind9-9.20.29/bin/tests/system/notify/ns2/named-tls.conf.j2 2026-09-11 19:41:01.260325226 +0000 @@ -12,29 +12,29 @@ */ tls tls-forward-secrecy { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv02.crt01.example.com.key"; - cert-file "../CA/certs/srv02.crt01.example.com.pem"; - dhparam-file "../dhparam3072.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv02.crt01.example.com.key"; + cert-file "../CA/certs/srv02.crt01.example.com.pem"; + dhparam-file "../dhparam3072.pem"; }; tls tls-forward-secrecy-mutual-tls { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv02.crt01.example.com.key"; - cert-file "../CA/certs/srv02.crt01.example.com.pem"; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv02.crt01.example.com.key"; + cert-file "../CA/certs/srv02.crt01.example.com.pem"; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; tls tls-expired { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv02.crt01-expired.example.com.key"; - cert-file "../CA/certs/srv02.crt01-expired.example.com.pem"; - dhparam-file "../dhparam3072.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv02.crt01-expired.example.com.key"; + cert-file "../CA/certs/srv02.crt01-expired.example.com.pem"; + dhparam-file "../dhparam3072.pem"; }; diff -Nru bind9-9.20.26/bin/tests/system/notify/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/notify/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/notify/ns2/named.conf.j2 2026-07-20 14:47:53.773845449 +0000 +++ bind9-9.20.29/bin/tests/system/notify/ns2/named.conf.j2 2026-09-11 19:41:01.260325226 +0000 @@ -16,43 +16,26 @@ {% endif %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - notify-source-v6 fd92:7065:b8e:ffff::2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} + notify-source-v6 @ns.ip6@; allow-transfer { any; }; recursion no; - notify yes; startup-notify-rate 5; dnssec-validation no; {% if FEATURE_FIPS_DH == "1" %} tls-port @TLSPORT@; - listen-on tls ephemeral { 10.53.0.2; }; - listen-on port @EXTRAPORT1@ tls tls-forward-secrecy { 10.53.0.2; }; - listen-on port @EXTRAPORT3@ tls tls-forward-secrecy-mutual-tls { 10.53.0.2; }; - listen-on port @EXTRAPORT4@ tls tls-expired { 10.53.0.2; }; + listen-on tls ephemeral { @ns.ip@; }; + listen-on port @EXTRAPORT1@ tls tls-forward-secrecy { @ns.ip@; }; + listen-on port @EXTRAPORT3@ tls tls-forward-secrecy-mutual-tls { @ns.ip@; }; + listen-on port @EXTRAPORT4@ tls tls-expired { @ns.ip@; }; {% endif %} }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; @@ -68,7 +51,7 @@ type primary; file "generic.db"; also-notify { 10.53.0.3; }; - notify-source 10.53.0.2 port @EXTRAPORT2@; + notify-source @ns.ip@ port @EXTRAPORT2@; notify primary-only; }; zone x2 { diff -Nru bind9-9.20.26/bin/tests/system/notify/ns3/named-tls.conf.j2 bind9-9.20.29/bin/tests/system/notify/ns3/named-tls.conf.j2 --- bind9-9.20.26/bin/tests/system/notify/ns3/named-tls.conf.j2 2026-07-20 14:47:53.773845449 +0000 +++ bind9-9.20.29/bin/tests/system/notify/ns3/named-tls.conf.j2 2026-09-11 19:41:01.260325226 +0000 @@ -12,39 +12,39 @@ */ tls tls-forward-secrecy { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; tls tls-forward-secrecy-remote-hostname { - protocols { TLSv1.2; }; - ca-file "../CA/CA.pem"; - remote-hostname "srv02.crt01.example.com"; + protocols { TLSv1.2; }; + ca-file "../CA/CA.pem"; + remote-hostname "srv02.crt01.example.com"; }; tls tls-forward-secrecy-bad-remote-hostname { - protocols { TLSv1.2; }; - ca-file "../CA/CA.pem"; - remote-hostname "srv02-bad.crt01.example.com"; + protocols { TLSv1.2; }; + ca-file "../CA/CA.pem"; + remote-hostname "srv02-bad.crt01.example.com"; }; tls tls-forward-secrecy-mutual-tls { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - key-file "../CA/certs/srv03.crt01.example.com.key"; - cert-file "../CA/certs/srv03.crt01.example.com.pem"; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + key-file "../CA/certs/srv03.crt01.example.com.key"; + cert-file "../CA/certs/srv03.crt01.example.com.pem"; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; tls tls-expired { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; zone tls-x1 { diff -Nru bind9-9.20.26/bin/tests/system/notify/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/notify/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/notify/ns3/named.conf.j2 2026-07-20 14:47:53.773845449 +0000 +++ bind9-9.20.29/bin/tests/system/notify/ns3/named.conf.j2 2026-09-11 19:41:01.260325226 +0000 @@ -16,15 +16,7 @@ {% endif %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { fd92:7065:b8e:ffff::3; }; - recursion yes; - notify yes; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation no; {% if FEATURE_FIPS_DH == "1" %} @@ -33,10 +25,9 @@ }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "example" { type secondary; @@ -49,5 +40,5 @@ zone "notify-source-port-test" { type primary; file "notify-source-port-test.db"; - notify-source 10.53.0.3 port @EXTRAPORT2@; + notify-source @ns.ip@ port @EXTRAPORT2@; }; diff -Nru bind9-9.20.26/bin/tests/system/notify/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/notify/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/notify/ns4/named.conf.j2 2026-07-20 14:47:53.774845464 +0000 +++ bind9-9.20.29/bin/tests/system/notify/ns4/named.conf.j2 2026-09-11 19:41:01.261325250 +0000 @@ -12,23 +12,17 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/listen.conf.j2" %} port @EXTRAPORT1@; pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; allow-transfer { any; }; - recursion yes; - notify yes; dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "x21" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/notify/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/notify/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/notify/ns5/named.conf.j2 2026-07-20 14:47:53.774845464 +0000 +++ bind9-9.20.29/bin/tests/system/notify/ns5/named.conf.j2 2026-09-11 19:41:01.261325250 +0000 @@ -27,24 +27,18 @@ }; options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + view "a" { match-clients { key "a"; }; zone "x21" { type primary; - also-notify { 10.53.0.5 key "b"; 10.53.0.5 key "c"; }; + also-notify { @ns.ip@ key "b"; @ns.ip@ key "c"; }; file "x21.db"; allow-update { any; }; }; @@ -54,7 +48,7 @@ match-clients { key "b"; }; zone "x21" { type secondary; - primaries { 10.53.0.5 key "a"; }; + primaries { @ns.ip@ key "a"; }; file "x21.bk-b"; notify no; }; @@ -64,7 +58,7 @@ match-clients { key "c"; }; zone "x21" { type secondary; - primaries { 10.53.0.5 key "a"; }; + primaries { @ns.ip@ key "a"; }; file "x21.bk-c"; notify no; }; diff -Nru bind9-9.20.26/bin/tests/system/nsec/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec/ns1/named.conf.j2 2026-07-20 14:47:53.774845464 +0000 +++ bind9-9.20.29/bin/tests/system/nsec/ns1/named.conf.j2 2026-09-11 19:41:01.261325250 +0000 @@ -12,17 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/nsec/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec/ns2/named.conf.j2 2026-07-20 14:47:53.774845464 +0000 +++ bind9-9.20.29/bin/tests/system/nsec/ns2/named.conf.j2 2026-09-11 19:41:01.261325250 +0000 @@ -12,17 +12,12 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "excessive-nsec-rrsigs" { type primary; file "excessive-nsec-rrsigs.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/nsec/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec/ns3/named.conf.j2 2026-07-20 14:47:53.775845480 +0000 +++ bind9-9.20.29/bin/tests/system/nsec/ns3/named.conf.j2 2026-09-11 19:41:01.262325274 +0000 @@ -14,22 +14,14 @@ // validating resolver options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; max-records-per-type 2; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/nsec3/common.py bind9-9.20.29/bin/tests/system/nsec3/common.py --- bind9-9.20.26/bin/tests/system/nsec3/common.py 2026-07-20 14:47:53.775845480 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/common.py 2026-09-11 19:41:01.262325274 +0000 @@ -9,6 +9,7 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. +from dataclasses import dataclass from datetime import timedelta import dns.rcode @@ -40,6 +41,41 @@ ] ) + +@dataclass(frozen=True) +class NSEC3Saltlen: + initial: int | None + reconfig: int | None + + +NSEC3_SALTLEN = { + "nsec-to-nsec3.kasp": NSEC3Saltlen(initial=None, reconfig=0), + # policy "nsec" on ns3 + "nsec3-xfr-inline.kasp": NSEC3Saltlen(initial=None, reconfig=None), + "nsec3-dynamic-update-inline.kasp": NSEC3Saltlen(initial=None, reconfig=None), + "nsec3.kasp": NSEC3Saltlen(initial=0, reconfig=0), + "nsec3-dynamic.kasp": NSEC3Saltlen(initial=0, reconfig=0), + "nsec3-change.kasp": NSEC3Saltlen(initial=0, reconfig=8), + "nsec3-dynamic-change.kasp": NSEC3Saltlen(initial=0, reconfig=8), + "nsec3-dynamic-to-inline.kasp": NSEC3Saltlen(initial=0, reconfig=0), + "nsec3-inline-to-dynamic.kasp": NSEC3Saltlen(initial=0, reconfig=0), + "nsec3-to-nsec.kasp": NSEC3Saltlen(initial=0, reconfig=None), + "nsec3-to-nsec-altalg.kasp": NSEC3Saltlen(initial=0, reconfig=None), + # the reconfig to opt-out is currently not exercised [GL #2216] + "nsec3-to-optout.kasp": NSEC3Saltlen(initial=0, reconfig=0), + "nsec3-from-optout.kasp": NSEC3Saltlen(initial=0, reconfig=0), + "nsec3-other.kasp": NSEC3Saltlen(initial=8, reconfig=8), + "nsec3-ent.kasp": NSEC3Saltlen(initial=0, reconfig=0), + # Moving to the "rsasha1" policy switches to NSEC right away, while moving + # away from it can only create the NSEC3 chain once the algorithm rollover + # completes - at test time, all zones are expected have NSEC after + # reconfig. + "rsasha1-to-nsec3.kasp": NSEC3Saltlen(initial=None, reconfig=None), + "rsasha1-to-nsec3-wait.kasp": NSEC3Saltlen(initial=None, reconfig=None), + "nsec3-to-rsasha1.kasp": NSEC3Saltlen(initial=0, reconfig=None), + "nsec3-to-rsasha1-ds.kasp": NSEC3Saltlen(initial=0, reconfig=None), +} + default_config = { "dnskey-ttl": timedelta(hours=1), "ds-ttl": timedelta(days=1), @@ -103,6 +139,40 @@ return salt +def wait_for_nsec3param(server, zone, saltlen=None, timeout=60): + """ + Wait until the NSEC3PARAM RRset served for zone matches the expected + NSEC3 chain state: absent if saltlen is None, otherwise present with + a salt of saltlen bytes. + + NSEC3 chain changes are committed by zone maintenance asynchronously + to key management, so the "keymgr: done" log line does not + guarantee that the new chain is visible to queries yet. + """ + query = isctest.query.create(f"{zone}.", dns.rdatatype.NSEC3PARAM) + + def _nsec3param_matches(): + response = isctest.query.tcp(query, server.ip, attempts=1, timeout=3) + assert response.rcode() == dns.rcode.NOERROR + rdatas = [ + rdata + for rrset in response.answer + if rrset.match( + dns.rdataclass.IN, dns.rdatatype.NSEC3PARAM, dns.rdatatype.NONE + ) + for rdata in rrset + ] + if saltlen is None: + return not rdatas + return bool(rdatas) and all(len(rdata.salt) == saltlen for rdata in rdatas) + + isctest.run.retry_with_timeout( + _nsec3param_matches, + timeout=timeout, + msg=f"NSEC3 chain state for zone {zone} not committed within {timeout}s", + ) + + def check_nsec3_case(server, params, nsec3=True): # Get test parameters. zone = params["zone"] diff -Nru bind9-9.20.26/bin/tests/system/nsec3/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec3/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec3/ns2/named.conf.j2 2026-07-20 14:47:53.775845480 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/ns2/named.conf.j2 2026-09-11 19:41:01.262325274 +0000 @@ -18,26 +18,13 @@ }; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} {% if "nsec3-xfr-inline.kasp" in zones %} zone "nsec3-xfr-inline.kasp" { diff -Nru bind9-9.20.26/bin/tests/system/nsec3/ns3/named-common.conf.j2 bind9-9.20.29/bin/tests/system/nsec3/ns3/named-common.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec3/ns3/named-common.conf.j2 2026-07-20 14:47:53.775845480 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/ns3/named-common.conf.j2 2026-09-11 19:41:01.262325274 +0000 @@ -12,26 +12,13 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "nsec" { // no need to change configuration: if no 'nsec3param' is set, diff -Nru bind9-9.20.26/bin/tests/system/nsec3/ns3/named-fips.conf.j2 bind9-9.20.29/bin/tests/system/nsec3/ns3/named-fips.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec3/ns3/named-fips.conf.j2 2026-07-20 14:47:53.775845480 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/ns3/named-fips.conf.j2 2026-09-11 19:41:01.263325298 +0000 @@ -169,10 +169,10 @@ * This zone will have an empty nonterminal node added and a node deleted. */ zone "nsec3-xfr-inline.kasp" { - type secondary; - file "nsec3-xfr-inline.kasp.db"; - dnssec-policy "nsec"; - primaries { 10.53.0.2; }; + type secondary; + file "nsec3-xfr-inline.kasp.db"; + dnssec-policy "nsec"; + primaries { 10.53.0.2; }; }; {% endif %}{# nsec3-xfr-inline.kasp #} diff -Nru bind9-9.20.26/bin/tests/system/nsec3/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec3/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec3/ns4/named.conf.j2 2026-07-20 14:47:53.776845495 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/ns4/named.conf.j2 2026-09-11 19:41:01.263325298 +0000 @@ -14,18 +14,14 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + remote-servers "ns3" { 10.53.0.3 port @PORT@; }; diff -Nru bind9-9.20.26/bin/tests/system/nsec3/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec3/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec3/ns5/named.conf.j2 2026-07-20 14:47:53.776845495 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/ns5/named.conf.j2 2026-09-11 19:41:01.263325298 +0000 @@ -14,25 +14,20 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; dnssec-validation yes; send-cookie no; }; +{% include "_common/controls.conf.j2" %} + trust-anchors { - evil.test. static-key 257 3 13 "yh1W7zgrqOsAZdKAh597SI7F2ye4ReiLmBNsDg+TDLJQ+3C2fXfrsQyY MvA+hmzTQdKX24zlVlD3YAVA6+VmrQ=="; + evil.test. static-key 257 3 13 "yh1W7zgrqOsAZdKAh597SI7F2ye4ReiLmBNsDg+TDLJQ+3C2fXfrsQyY MvA+hmzTQdKX24zlVlD3YAVA6+VmrQ=="; }; zone "evil.test" { - type forward; - forward only; - forwarders { 10.53.0.7 port @PORT@; }; + type forward; + forward only; + forwarders { 10.53.0.7 port @PORT@; }; }; diff -Nru bind9-9.20.26/bin/tests/system/nsec3/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec3/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec3/ns6/named.conf.j2 2026-07-20 14:47:53.777845511 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/ns6/named.conf.j2 2026-09-11 19:41:01.264325322 +0000 @@ -14,19 +14,15 @@ // NS6 options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "evil.test" { - type primary; - file "evil.test.db.signed"; + type primary; + file "evil.test.db.signed"; }; diff -Nru bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_change.py bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_change.py --- bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_change.py 2026-07-20 14:47:53.777845511 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_change.py 2026-09-11 19:41:01.264325322 +0000 @@ -18,7 +18,12 @@ import pytest from isctest.algorithms import Algorithm -from nsec3.common import NSEC3_MARK, check_nsec3_case +from nsec3.common import ( + NSEC3_MARK, + NSEC3_SALTLEN, + check_nsec3_case, + wait_for_nsec3param, +) import isctest @@ -54,7 +59,10 @@ zone = "nsec3-change.kasp" fqdn = f"{zone}." + + # First make sure the zone is properly signed. isctest.kasp.wait_keymgr_done(ns3, zone) + wait_for_nsec3param(ns3, zone, NSEC3_SALTLEN[zone].initial) time.sleep(1) shutil.copyfile(f"{nsdir}/template2.db.in", f"{nsdir}/{zone}.db") @@ -70,17 +78,11 @@ } templates.render(f"{nsdir}/named-fips.conf", data) templates.render(f"{nsdir}/named-rsasha1.conf", data) + ns3.reconfigure() - # Wait for the NSEC3 chain is finished rebuilding. - messages = [ - f"zone {zone}/IN (signed): generated salt", - f"zone_nsec3chain: zone {zone}/IN (signed): enter", - f"add {zone}. 900 IN NSEC3PARAM 1 0 0", - f"zone_needdump: zone {zone}/IN (signed): enter", - ] - with ns3.watch_log_from_start() as watcher: - ns3.reconfigure() - watcher.wait_for_sequence(messages) + # Wait until the NSEC3 chain has finished rebuilding. + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + wait_for_nsec3param(ns3, zone, NSEC3_SALTLEN[zone].reconfig) def test_nsec3_case(ns3): @@ -99,9 +101,6 @@ } zone = params["zone"] - # First make sure the zone is properly signed. - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - # Test case. check_nsec3_case(ns3, params) diff -Nru bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_initial.py bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_initial.py --- bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_initial.py 2026-07-20 14:47:53.777845511 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_initial.py 2026-09-11 19:41:01.264325322 +0000 @@ -16,7 +16,12 @@ import pytest from isctest.algorithms import RSASHA1, Algorithm -from nsec3.common import NSEC3_MARK, check_nsec3_case +from nsec3.common import ( + NSEC3_MARK, + NSEC3_SALTLEN, + check_nsec3_case, + wait_for_nsec3param, +) import isctest import isctest.mark @@ -57,6 +62,14 @@ } +@pytest.fixture(scope="module", autouse=True) +def after_servers_start(ns3): + # Make sure the zones are properly signed. + for zone in ZONES: + isctest.kasp.wait_keymgr_done(ns3, zone) + wait_for_nsec3param(ns3, zone, NSEC3_SALTLEN[zone].initial) + + @pytest.mark.parametrize( "params", [ @@ -124,9 +137,6 @@ # Get test parameters. zone = params["zone"] - # First make sure the zone is properly signed. - isctest.kasp.wait_keymgr_done(ns3, zone) - # Test case. check_nsec3_case(ns3, params, nsec3=False) @@ -284,11 +294,4 @@ ], ) def test_nsec3_case(ns3, params): - # Get test parameters. - zone = params["zone"] - - # First make sure the zone is properly signed. - isctest.kasp.wait_keymgr_done(ns3, zone) - - # Test case. check_nsec3_case(ns3, params) diff -Nru bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_reconfig.py bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_reconfig.py --- bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_reconfig.py 2026-07-20 14:47:53.777845511 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_reconfig.py 2026-09-11 19:41:01.265325346 +0000 @@ -19,7 +19,12 @@ import pytest from isctest.algorithms import RSASHA1, Algorithm -from nsec3.common import NSEC3_MARK, check_nsec3_case +from nsec3.common import ( + NSEC3_MARK, + NSEC3_SALTLEN, + check_nsec3_case, + wait_for_nsec3param, +) import isctest import isctest.mark @@ -60,12 +65,10 @@ @pytest.fixture(scope="module", autouse=True) def after_servers_start(ns3, templates): - # First make sure all zones are properly signed. Here we specifically need - # to wait until all zones have finished key management before we can - # reconfigure the server, because changing the DNSSEC policy relies on - # zones having finished applying their initial policy. + # First make sure all zones are properly signed. for zone in ZONES: isctest.kasp.wait_keymgr_done(ns3, zone) + wait_for_nsec3param(ns3, zone, NSEC3_SALTLEN[zone].initial) # Ensure rsasha1-to-nsec3-wait.kasp is fully signed prior to reconfig. with_rsasha1 = "RSASHA1_SUPPORTED" @@ -83,6 +86,11 @@ templates.render(f"{ns3.identifier}/named-rsasha1.conf", data) ns3.reconfigure() + # Wait until the NSEC3 chain has finished rebuilding. + for zone in ZONES: + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + wait_for_nsec3param(ns3, zone, NSEC3_SALTLEN[zone].reconfig) + @pytest.mark.parametrize( "params", @@ -148,12 +156,6 @@ ], ) def test_nsec_case(ns3, params): - zone = params["zone"] - - # First make sure the zone is properly signed. - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # Test case. check_nsec3_case(ns3, params, nsec3=False) @@ -271,13 +273,6 @@ ], ) def test_nsec3_case(ns3, params): - # Get test parameters. - zone = params["zone"] - - # First make sure the zone is properly signed. - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # Test case. check_nsec3_case(ns3, params) @@ -294,9 +289,6 @@ zone = params["zone"] fqdn = f"{zone}." - # First make sure the zone is properly signed. - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - # Test case. check_nsec3_case(ns3, params) diff -Nru bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_reload.py bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_reload.py --- bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_reload.py 2026-07-20 14:47:53.777845511 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_reload.py 2026-09-11 19:41:01.265325346 +0000 @@ -11,7 +11,7 @@ import shutil -from nsec3.common import NSEC3_MARK, check_nsec3_case +from nsec3.common import NSEC3_MARK, check_nsec3_case, wait_for_nsec3param import isctest @@ -50,6 +50,7 @@ # First make sure the zone is properly signed. isctest.kasp.wait_keymgr_done(ns3, zone) + wait_for_nsec3param(ns3, zone, saltlen=0) # Test case. check_nsec3_case(ns3, params) diff -Nru bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_restart.py bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_restart.py --- bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_restart.py 2026-07-20 14:47:53.778845526 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_restart.py 2026-09-11 19:41:01.265325346 +0000 @@ -15,7 +15,12 @@ import pytest from isctest.algorithms import Algorithm -from nsec3.common import NSEC3_MARK, check_nsec3_case, check_nsec3param +from nsec3.common import ( + NSEC3_MARK, + check_nsec3_case, + check_nsec3param, + wait_for_nsec3param, +) import isctest @@ -40,7 +45,9 @@ fqdn = f"{zone}." # First make sure the zone is properly signed. + saltlen = params.get("nsec3param", {}).get("salt-length", 0) isctest.kasp.wait_keymgr_done(server, zone) + wait_for_nsec3param(server, zone, saltlen) # Test case. check_nsec3_case(server, params) @@ -48,9 +55,6 @@ # Return salt. minimum = params.get("soa-minimum", 3600) iterations = 0 - saltlen = 0 - if "nsec3param" in params: - saltlen = params["nsec3param"].get("salt-length", 0) match = f"{fqdn} {minimum} IN NSEC3PARAM 1 0 {iterations}" diff -Nru bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_retransfer.py bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_retransfer.py --- bind9-9.20.26/bin/tests/system/nsec3/tests_nsec3_retransfer.py 2026-07-20 14:47:53.778845526 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3/tests_nsec3_retransfer.py 2026-09-11 19:41:01.265325346 +0000 @@ -17,7 +17,12 @@ import dns.rdatatype from isctest.algorithms import RSASHA256 -from nsec3.common import NSEC3_MARK, check_auth_nsec3, check_nsec3param +from nsec3.common import ( + NSEC3_MARK, + check_auth_nsec3, + check_nsec3param, + wait_for_nsec3param, +) import isctest @@ -60,6 +65,7 @@ # First make sure the zone is properly signed. isctest.kasp.wait_keymgr_done(server, zone) + wait_for_nsec3param(server, zone, saltlen) keys = isctest.kasp.keydir_to_keylist(zone, keydir) ksks = [k for k in keys if k.is_ksk()] diff -Nru bind9-9.20.26/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 2026-07-20 14:47:53.778845526 +0000 +++ bind9-9.20.29/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 2026-09-11 19:41:01.265325346 +0000 @@ -1,27 +1,13 @@ // validating resolver options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; }; -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "tld.test" { type static-stub; diff -Nru bind9-9.20.26/bin/tests/system/nsec_grandparent/ans1/ans.py bind9-9.20.29/bin/tests/system/nsec_grandparent/ans1/ans.py --- bind9-9.20.26/bin/tests/system/nsec_grandparent/ans1/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_grandparent/ans1/ans.py 2026-09-11 19:41:01.265325346 +0000 @@ -0,0 +1,456 @@ +#!/usr/bin/python3 + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 + +from collections.abc import AsyncGenerator +from dataclasses import dataclass +from pathlib import Path + +import json + +from cryptography.hazmat.primitives import serialization + +import dns.dnssec +import dns.flags +import dns.message +import dns.name +import dns.rcode +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset + +from isctest.asyncserver import ( + AsyncDnsServer, + DnsResponseSend, + QueryContext, + ResponseHandler, +) + +TTL = 300 +PARENT = "p031.test." +CHILD = f"c.{PARENT}" +# The attacker-controlled sibling zone: a genuine, correctly delegated and +# signed zone under the same parent as CHILD. Its crafted NSEC3 is made +# to sort first in the ncache via the salt choice below (see _ordering_salts). +SIBLING = f"attacker.{PARENT}" +# #5967 (grandparent-zone NSEC/NSEC3): a grandchild whose forged NSEC/NSEC3 +# insecure-delegation proof is owned by its grandparent zone. +GRANDCHILD = f"grand.{CHILD}" +GRANDCHILD3 = f"grand3.{CHILD}" +# #6234 (sibling-zone NSEC3): a grandchild whose forged NSEC3 +# insecure-delegation proof is owned by an unrelated but correctly delegated +# and signed sibling zone. +GRANDCHILD3_SIBLING = f"grandsib.{CHILD}" +# #6321 (mixed-signer RRSIG): grandchildren whose grandparent-signed NSEC +# forgery also carries a dummy RRSIG naming the NSEC owner itself as signer, +# in either order relative to the genuine one. +GRANDCHILD_DUMMY_FIRST = f"grand-dummy-first.{CHILD}" +GRANDCHILD_DUMMY_LAST = f"grand-dummy-last.{CHILD}" +# RRSIG count cap: grandchildren whose grandparent-signed NSEC forgery carries +# as many same-signer RRSIGs as ns2 allows validations per fetch, or one fewer. +GRANDCHILD_TOO_MANY = f"grand-too-many.{CHILD}" +GRANDCHILD_ALMOST_TOO_MANY = f"grand-almost-too-many.{CHILD}" +# The names under attack. +ATTACK = f"www-bind.{GRANDCHILD}" +ATTACK3 = f"www-bind.{GRANDCHILD3}" +FORGED_A = "6.6.6.60" +# Not a DNSSEC algorithm; the validator skips RRSIGs using it as unsupported +# rather than rejecting them, which is what the mixed-signer forgery needs. +DUMMY_ALGORITHM = 0 +# ns2's max-validations-per-fetch; keep in sync with the test module. +MAX_VALIDATIONS_PER_FETCH = 16 + + +@dataclass(frozen=True) +class Key: + zone: dns.name.Name + private_key: object + dnskey: dns.rdata.Rdata + + +def name(text: str) -> dns.name.Name: + return dns.name.from_text(text) + + +def _ordering_salts(qname: str) -> tuple[str, str]: + # Pick NSEC3 salts (as hex) so the sibling's owner hash sorts strictly + # before the child's. The ncache slab is ordered by wire-format owner + # name -- i.e. by the leftmost hash label -- and is_insecure_referral()'s + # trynsec3 arm returns on the *first* exact hash match, so the sibling's + # crafted NS-set NSEC3 must precede the child's genuine NS-clear NODATA + # proof. Deterministic search over one-octet salts keeps this true no + # matter what GRANDCHILD3_SIBLING is named. + hashes = sorted( + (dns.dnssec.nsec3_hash(name(qname), f"{i:02X}", 0, 1).lower(), f"{i:02X}") + for i in range(256) + ) + return hashes[0][1], hashes[-1][1] + + +# Sibling salt yields the smallest hash, child salt the largest. +SIBLING_SALT, CHILD_SALT = _ordering_salts(GRANDCHILD3_SIBLING) + + +def load_keys() -> dict[str, Key]: + path = Path(__file__).resolve().parent / "keys.json" + with path.open(encoding="utf-8") as keys_file: + raw = json.load(keys_file) + + keys: dict[str, Key] = {} + for zone, raw_key in raw.items(): + private_key = serialization.load_pem_private_key( + raw_key["private_pem"].encode("ascii"), + password=None, + ) + dnskey = dns.rdata.from_text( + dns.rdataclass.IN, dns.rdatatype.DNSKEY, raw_key["dnskey"] + ) + keys[zone] = Key(name(zone), private_key, dnskey) + return keys + + +def rrset(owner: str, rdtype: dns.rdatatype.RdataType, *rdatas: str) -> dns.rrset.RRset: + return dns.rrset.from_text(owner, TTL, dns.rdataclass.IN, rdtype, *rdatas) + + +def rrset_from_rdata(owner: str, rdata: dns.rdata.Rdata) -> dns.rrset.RRset: + return dns.rrset.from_rdata(name(owner), TTL, rdata) + + +def sign(covered: dns.rrset.RRset, signer: Key) -> dns.rdata.Rdata: + return dns.dnssec.sign( + covered, + signer.private_key, + signer.zone, + signer.dnskey, + lifetime=86400, + verify=True, + ) + + +def add_signed( + section: list[dns.rrset.RRset], covered: dns.rrset.RRset, signer: Key +) -> None: + rrsig = sign(covered, signer) + section.append(covered) + section.append(dns.rrset.from_rdata(covered.name, covered.ttl, rrsig)) + + +def soa_rrset() -> dns.rrset.RRset: + return rrset( + PARENT, + dns.rdatatype.SOA, + f"ns.{PARENT} hostmaster.{PARENT} 1 3600 600 86400 300", + ) + + +def nsec_rrset(owner: str, next_name: str, *types: str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.NSEC, f"{next_name} {' '.join(types)}") + + +def child_soa_rrset() -> dns.rrset.RRset: + return rrset( + CHILD, + dns.rdatatype.SOA, + f"ns.{CHILD} hostmaster.{CHILD} 1 3600 600 86400 300", + ) + + +def nsec_lie(owner: str) -> dns.rrset.RRset: + # An NSEC owned by the grandparent zone P at a name that really belongs + # to the secure child C, showing an (insecure) delegation: NS bit set, + # DS bit clear. + return nsec_rrset(owner, f"grandz.{CHILD}", "NS", "RRSIG", "NSEC") + + +def grandchild_nsec_lie() -> dns.rrset.RRset: + return nsec_lie(GRANDCHILD) + + +def nsec3_ns_lie( + qname: str, zone: str, salt: str | None, salt_text: str +) -> dns.rrset.RRset: + # An NSEC3 owned by 'zone' whose owner hash matches 'qname' under this + # record's own parameters, showing an (insecure) delegation: NS bit set, DS + # bit clear. is_insecure_referral()'s trynsec3 arm takes the exact-match + # branch (order == 0) before it ever consults the "next" field, so reusing + # the owner digest as the next hash is sufficient for it to parse. + digest = dns.dnssec.nsec3_hash(name(qname), salt, 0, 1).lower() + owner = f"{digest}.{zone}" + return rrset(owner, dns.rdatatype.NSEC3, f"1 0 0 {salt_text} {digest} NS") + + +def nsec3_nodata( + qname: str, zone: str, salt: str | None, salt_text: str +) -> dns.rrset.RRset: + # A genuine matching NSEC3 for 'qname' in 'zone' with the DS bit clear: a + # legitimate NODATA-DS proof (the name exists as an ordinary, non-delegation + # node). The NS bit is clear, so it does not itself assert a delegation. + digest = dns.dnssec.nsec3_hash(name(qname), salt, 0, 1).lower() + owner = f"{digest}.{zone}" + return rrset(owner, dns.rdatatype.NSEC3, f"1 0 0 {salt_text} {digest} TXT RRSIG") + + +def grandchild3_nsec3_lie() -> dns.rrset.RRset: + # Same forgery as grandchild_nsec_lie(), but expressed as an NSEC3 signed by + # the grandparent so that the resolver reaches is_insecure_referral()'s + # trynsec3 arm. + return nsec3_ns_lie(GRANDCHILD3, PARENT, None, "-") + + +def add_parent_nodata( + response: dns.message.Message, parent_key: Key, nsec: dns.rrset.RRset +) -> None: + add_signed(response.authority, soa_rrset(), parent_key) + add_signed(response.authority, nsec, parent_key) + + +def add_nsec3_nodata_from_sibling( + response: dns.message.Message, child_key: Key, sibling_key: Key +) -> None: + # #6234: a genuinely signed NSEC3 owned by an unrelated sibling zone whose + # owner hash matches the grandchild under the sibling's own parameters and + # whose NS bit is set. Its owner hash sorts before the child proof's (the + # salts are chosen for exactly that, see _ordering_salts), so the ncache + # iterates it first; trynsec3 matches it and derives the signer as + # owner-minus-hash-label -> SIBLING (4 labels), which empties + # closer_secure_ds_exists(). No owner-zone relevance check rejects it. The + # child-signed NSEC3 that follows is the real NODATA-DS proof: + # dns_nsec3_noexistnodata() ignores the sibling record as out-of-zone, so + # the negative answer still validates normally. + add_signed( + response.authority, + nsec3_ns_lie(GRANDCHILD3_SIBLING, SIBLING, SIBLING_SALT, SIBLING_SALT), + sibling_key, + ) + add_signed( + response.authority, + nsec3_nodata(GRANDCHILD3_SIBLING, CHILD, CHILD_SALT, CHILD_SALT), + child_key, + ) + add_signed(response.authority, child_soa_rrset(), child_key) + + +def add_mixed_signer_nodata( + response: dns.message.Message, + parent_key: Key, + nsec: dns.rrset.RRset, + dummy_first: bool, +) -> None: + """ + The same NODATA lie as add_parent_nodata(), but the NSEC carries two + RRSIGs: the genuine one from the grandparent P and a dummy one naming + the NSEC owner itself as signer. The dummy uses an unsupported + algorithm, so the validator skips it and the NSEC still authenticates + through the genuine RRSIG. All the dummy changes is which signer name + comes first in the RRSIG rdataset (#6321). + """ + add_signed(response.authority, soa_rrset(), parent_key) + genuine = sign(nsec, parent_key) + dummy = genuine.replace(algorithm=DUMMY_ALGORITHM, signer=nsec.name) + rrsigs = [dummy, genuine] if dummy_first else [genuine, dummy] + + response.authority.append(nsec) + # One single-rdata RRset per RRSIG: dnspython shuffles the rdatas of an + # rdataset when rendering it, and this forgery is all about the order + # in which the two signatures arrive. Separate RRsets keep their list + # order on the wire, and the resolver merges them back into one RRSIG + # rdataset in that order. + for rrsig in rrsigs: + response.authority.append(dns.rrset.from_rdata(nsec.name, nsec.ttl, rrsig)) + + +def add_many_rrsig_nodata( + response: dns.message.Message, + parent_key: Key, + nsec: dns.rrset.RRset, + count: int, +) -> None: + """ + The NODATA lie with 'count' RRSIGs over the NSEC, all naming the + grandparent P as signer: count - 1 unsupported-algorithm dummies with + distinct key tags and a one-byte signature, then the genuine signature + last, so the validator has to skip every dummy before the NSEC + authenticates. With a uniform signer this exercises only the RRSIG + count cap in is_insecure_referral(), not the mixed-signer rule. + """ + add_signed(response.authority, soa_rrset(), parent_key) + genuine = sign(nsec, parent_key) + dummies = [ + genuine.replace(algorithm=DUMMY_ALGORITHM, key_tag=tag, signature=b"\0") + for tag in range(count - 1) + ] + + response.authority.append(nsec) + # Separate single-rdata RRsets, for the same wire-order reason as in + # add_mixed_signer_nodata(). + for rrsig in [*dummies, genuine]: + response.authority.append(dns.rrset.from_rdata(nsec.name, nsec.ttl, rrsig)) + + +def prepare_response(qctx: QueryContext) -> dns.message.Message: + qctx.prepare_new_response(with_zone_data=False) + qctx.response.flags |= dns.flags.AA + qctx.response.set_rcode(dns.rcode.NOERROR) + return qctx.response + + +class GrandparentNsecHandler(ResponseHandler): + def __init__(self, keys: dict[str, Key]) -> None: + self.parent_key = keys[PARENT] + self.child_key = keys[CHILD] + self.sibling_key = keys[SIBLING] + self.parent = name(PARENT) + self.child = name(CHILD) + self.sibling = name(SIBLING) + self.grandchild = name(GRANDCHILD) + self.grandchild3 = name(GRANDCHILD3) + self.grandchild3_sibling = name(GRANDCHILD3_SIBLING) + self.grandchild_dummy_first = name(GRANDCHILD_DUMMY_FIRST) + self.grandchild_dummy_last = name(GRANDCHILD_DUMMY_LAST) + self.grandchild_too_many = name(GRANDCHILD_TOO_MANY) + self.grandchild_almost_too_many = name(GRANDCHILD_ALMOST_TOO_MANY) + self.forged_grandchildren = ( + self.grandchild, + self.grandchild3, + self.grandchild3_sibling, + self.grandchild_dummy_first, + self.grandchild_dummy_last, + self.grandchild_too_many, + self.grandchild_almost_too_many, + ) + + def match(self, qctx: QueryContext) -> bool: + return qctx.qname.is_subdomain(self.parent) + + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + response = prepare_response(qctx) + + if qctx.qname == self.parent and qctx.qtype == dns.rdatatype.DNSKEY: + # Priming, parent DNSKEY + add_signed( + response.answer, + rrset_from_rdata(PARENT, self.parent_key.dnskey), + self.parent_key, + ) + elif qctx.qname == self.parent and qctx.qtype == dns.rdatatype.SOA: + # Priming, parent SOA + add_signed(response.answer, soa_rrset(), self.parent_key) + elif qctx.qname == self.child and qctx.qtype == dns.rdatatype.DS: + # Priming, child DS. + # + # A real DS matching the child key, signed by the parent. It must + # be real rather than a placeholder because the sibling-zone + # variant includes an NSEC3 signed by the child, so the child's + # DNSKEY has to chain to the parent. It is also the secure DS at + # CHILD that closer_secure_ds_exists() finds when it refuses the + # grandparent-signed proofs of the #5967 variants. + ds = dns.dnssec.make_ds(self.child, self.child_key.dnskey, "SHA256") + add_signed( + response.answer, + dns.rrset.from_rdata(self.child, TTL, ds), + self.parent_key, + ) + elif qctx.qname == self.child and qctx.qtype == dns.rdatatype.DNSKEY: + # Priming, child DNSKEY. + add_signed( + response.answer, + rrset_from_rdata(CHILD, self.child_key.dnskey), + self.child_key, + ) + elif qctx.qname == self.sibling and qctx.qtype == dns.rdatatype.DS: + # Priming, sibling DS. + # + # The sibling zone is a genuine secure delegation: real DS signed by + # the parent, so its own NSEC3 (used in the sibling-zone attack + # variant) really validates. + ds = dns.dnssec.make_ds(self.sibling, self.sibling_key.dnskey, "SHA256") + add_signed( + response.answer, + dns.rrset.from_rdata(self.sibling, TTL, ds), + self.parent_key, + ) + elif qctx.qname == self.sibling and qctx.qtype == dns.rdatatype.DNSKEY: + # Priming, sibling DNSKEY. + add_signed( + response.answer, + rrset_from_rdata(SIBLING, self.sibling_key.dnskey), + self.sibling_key, + ) + elif qctx.qname == self.grandchild and qctx.qtype == dns.rdatatype.DS: + # #5967: Forge no data for grand child DS (NSEC variant). + add_parent_nodata(response, self.parent_key, grandchild_nsec_lie()) + elif qctx.qname == self.grandchild3 and qctx.qtype == dns.rdatatype.DS: + # #5967: Forge no data for grand child DS (NSEC3 variant). + add_parent_nodata(response, self.parent_key, grandchild3_nsec3_lie()) + elif qctx.qname == self.grandchild3_sibling and qctx.qtype == dns.rdatatype.DS: + # #6234: Sibling-zone-signed NSEC3 ahead of the real child proof. + add_nsec3_nodata_from_sibling(response, self.child_key, self.sibling_key) + elif ( + qctx.qname == self.grandchild_dummy_first and qctx.qtype == dns.rdatatype.DS + ): + # Forge no data for grand child DS, dummy RRSIG before the + # genuine one (mixed-signer variant, #6321) + add_mixed_signer_nodata( + response, + self.parent_key, + nsec_lie(GRANDCHILD_DUMMY_FIRST), + dummy_first=True, + ) + elif ( + qctx.qname == self.grandchild_dummy_last and qctx.qtype == dns.rdatatype.DS + ): + # Same forgery, genuine RRSIG before the dummy one + add_mixed_signer_nodata( + response, + self.parent_key, + nsec_lie(GRANDCHILD_DUMMY_LAST), + dummy_first=False, + ) + elif qctx.qname == self.grandchild_too_many and qctx.qtype == dns.rdatatype.DS: + # Forge no data for grand child DS with as many RRSIGs as ns2 + # allows validations per fetch (RRSIG count cap variant) + add_many_rrsig_nodata( + response, + self.parent_key, + nsec_lie(GRANDCHILD_TOO_MANY), + count=MAX_VALIDATIONS_PER_FETCH, + ) + elif ( + qctx.qname == self.grandchild_almost_too_many + and qctx.qtype == dns.rdatatype.DS + ): + # Same forgery with one RRSIG fewer, so it stays under the cap + add_many_rrsig_nodata( + response, + self.parent_key, + nsec_lie(GRANDCHILD_ALMOST_TOO_MANY), + count=MAX_VALIDATIONS_PER_FETCH - 1, + ) + elif ( + any(qctx.qname.is_subdomain(g) for g in self.forged_grandchildren) + and qctx.qtype == dns.rdatatype.A + ): + # Attack query + response.answer.append( + rrset(qctx.qname.to_text(), dns.rdatatype.A, FORGED_A) + ) + else: + response.set_rcode(dns.rcode.NXDOMAIN) + + yield DnsResponseSend(response, authoritative=True) + + +def main() -> None: + server = AsyncDnsServer(default_aa=True) + server.install_response_handlers(GrandparentNsecHandler(load_keys())) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/nsec_grandparent/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec_grandparent/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec_grandparent/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_grandparent/ns2/named.conf.j2 2026-09-11 19:41:01.265325346 +0000 @@ -0,0 +1,27 @@ +// validating resolver + +options { + {% include_indented "_common/options.conf.j2" %} + dnssec-validation yes; + minimal-responses no; + // Keep the DS insecurity proof deterministic: without this, a cached + // NSEC from an earlier forgery lets aggressive-NSEC synthesis answer the + // grandchild query before the DS fetch that drives is_insecure_referral(). + synth-from-dnssec no; + // Pinned so the RRSIG-count cap in is_insecure_referral() is tested + // against a known number rather than the built-in default. + max-validations-per-fetch @MAX_VALIDATIONS@; +}; + +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} + +zone "p031.test" { + type static-stub; + server-addresses { 10.53.0.1; }; +}; + +trust-anchors { + p031.test. static-key 257 3 13 "@PARENT_DNSKEY@"; +}; diff -Nru bind9-9.20.26/bin/tests/system/nsec_grandparent/tests_nsec_grandparent.py bind9-9.20.29/bin/tests/system/nsec_grandparent/tests_nsec_grandparent.py --- bind9-9.20.26/bin/tests/system/nsec_grandparent/tests_nsec_grandparent.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_grandparent/tests_nsec_grandparent.py 2026-09-11 19:41:01.266325370 +0000 @@ -0,0 +1,450 @@ +#!/usr/bin/python3 + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 + +from pathlib import Path + +import json + +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec + +import dns.dnssec +import dns.name +import dns.rdataclass +import dns.rdatatype +import pytest + +import isctest +import isctest.mark + +PARENT = "p031.test." +CHILD = f"c.{PARENT}" +# The attacker-controlled sibling zone. +SIBLING = f"attacker.{PARENT}" +# #5967 (grandparent-zone NSEC/NSEC3): a grandchild whose forged NSEC/NSEC3 +# insecure-delegation proof is owned by its grandparent zone. +GRANDCHILD = f"grand.{CHILD}" +GRANDCHILD3 = f"grand3.{CHILD}" +# #6234 (sibling-zone NSEC3): a grandchild whose forged NSEC3 +# insecure-delegation proof is owned by an unrelated but correctly delegated +# and signed sibling zone. +GRANDCHILD3_SIBLING = f"grandsib.{CHILD}" +# #6321 (mixed-signer RRSIG): grandchildren whose grandparent-signed NSEC +# forgery also carries a dummy RRSIG naming the NSEC owner itself as signer, +# in either order relative to the genuine one. +GRANDCHILD_DUMMY_FIRST = f"grand-dummy-first.{CHILD}" +GRANDCHILD_DUMMY_LAST = f"grand-dummy-last.{CHILD}" +# RRSIG count cap: grandchildren whose grandparent-signed NSEC forgery carries +# as many same-signer RRSIGs as ns2 allows validations per fetch, or one fewer. +GRANDCHILD_TOO_MANY = f"grand-too-many.{CHILD}" +GRANDCHILD_ALMOST_TOO_MANY = f"grand-almost-too-many.{CHILD}" +# The names under attack. +ATTACK = f"www-bind.{GRANDCHILD}" +ATTACK3 = f"www-bind.{GRANDCHILD3}" +ATTACK3_SIBLING = f"www-bind.{GRANDCHILD3_SIBLING}" +ATTACK_CACHED = f"www2-bind.{GRANDCHILD}" +ATTACK_DUMMY_FIRST = f"www-bind.{GRANDCHILD_DUMMY_FIRST}" +ATTACK_DUMMY_FIRST_CACHED = f"www2-bind.{GRANDCHILD_DUMMY_FIRST}" +ATTACK_DUMMY_LAST = f"www-bind.{GRANDCHILD_DUMMY_LAST}" +ATTACK_TOO_MANY = f"www-bind.{GRANDCHILD_TOO_MANY}" +ATTACK_ALMOST_TOO_MANY = f"www-bind.{GRANDCHILD_ALMOST_TOO_MANY}" +FORGED_A = "6.6.6.60" +GENUINE_ALGORITHM = 13 # ECDSAP256SHA256, the parent key +DUMMY_ALGORITHM = 0 # keep in sync with ans1/ans.py +MAX_VALIDATIONS_PER_FETCH = 16 # keep in sync with ans1/ans.py + +AUTH = "10.53.0.1" # ans1, the attacker-controlled authoritative server +RESOLVER = "10.53.0.2" # ns2, the validating resolver under test + +REFUSED_NSEC_LOG = ( + "is_insecure_referral: NSEC signer above known secure DS; " + "refusing insecure-delegation proof" +) +REFUSED_NSEC3_LOG = ( + "is_insecure_referral: NSEC3 signer above known secure DS; " + "refusing insecure-delegation proof" +) +IGNORED_NSEC3_LOG = ( + "is_insecure_referral: NSEC3 owner zone does not enclose the DS name; ignoring" +) +REFUSED_MIXED_LOG = ( + "is_insecure_referral: NSEC RRSIG signers differ; " + "refusing insecure-delegation proof" +) +REFUSED_TOO_MANY_LOG = ( + "is_insecure_referral: NSEC RRSIG too many signatures; " + "refusing insecure-delegation proof" +) + +pytestmark = [ + isctest.mark.with_ecdsa_deterministic, + pytest.mark.extra_artifacts( + [ + "ans*/ans.run", + "ans*/keys.json", + ] + ), +] + + +def _make_key(): + private_key = ec.generate_private_key(ec.SECP256R1()) + dnskey = dns.dnssec.make_dnskey( + private_key.public_key(), + algorithm="ECDSAP256SHA256", + flags=257, + ) + private_pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption(), + ).decode("ascii") + return { + "private_pem": private_pem, + "dnskey": dnskey.to_text(), + } + + +def bootstrap(): + keys = {PARENT: _make_key(), CHILD: _make_key(), SIBLING: _make_key()} + Path("ans1/keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii") + parent_dnskey = "".join(keys[PARENT]["dnskey"].split()[3:]) + return { + "PARENT_DNSKEY": parent_dnskey, + "MAX_VALIDATIONS": str(MAX_VALIDATIONS_PER_FETCH), + } + + +def _query(server, qname, qtype): + query = isctest.query.create(qname, qtype) + return isctest.query.tcp(query, server) + + +def _rrset(response, section, owner, rdtype, covers=None): + if covers is None: + return response.get_rrset( + section, + dns.name.from_text(owner), + dns.rdataclass.IN, + rdtype, + ) + return response.get_rrset( + section, + dns.name.from_text(owner), + dns.rdataclass.IN, + rdtype, + covers=covers, + ) + + +def _has_a(response, section, owner, address): + rrset = _rrset(response, section, owner, dns.rdatatype.A) + return rrset is not None and any(rdata.address == address for rdata in rrset) + + +def _check_signed_rrset(response, section, owner, rdtype, signer): + rrsig = _rrset( + response, + section, + owner, + dns.rdatatype.RRSIG, + covers=rdtype, + ) + assert rrsig is not None, response.to_text() + assert rrsig[0].signer == dns.name.from_text(signer), response.to_text() + + +def _rrsig_signers(response, section, owner, covered): + """(signer, algorithm) of every RRSIG covering owner/covered, in wire order.""" + rrsig = _rrset(response, section, owner, dns.rdatatype.RRSIG, covers=covered) + assert rrsig is not None, response.to_text() + return [(rdata.signer.to_text(), int(rdata.algorithm)) for rdata in rrsig] + + +def _auth_query_count(qname, qtype): + """Number of times the mock auth server received qname/qtype.""" + log = Path("ans1/ans.run").read_text(encoding="utf-8") + return log.count(f"Received {qname.rstrip('.')}/IN/{qtype} (ID=") + + +def _check_no_downgrade(response, qname): + """The forged proof must not downgrade the signed namespace.""" + isctest.check.servfail(response) + isctest.check.noadflag(response) + assert not _has_a(response, response.answer, qname, FORGED_A), response.to_text() + + +def _check_refusal_logged(server, qname, expected_log): + """ + Check that the validator logged why it refused the forged proof. + + Call this after the query has returned, never around it: + watch_log_from_start() rescans named.run from the beginning, so the + line is already there, and an assertion that fails inside a WatchLog + context manager is masked on the way out by the "wait_for_*() was not + called" exception __exit__ raises. Keeping _check_no_downgrade() + outside the block lets a real regression report the forged answer + rather than a missing log line. + """ + with server.watch_log_from_start() as watcher: + watcher.wait_for_line(f"validating {qname.rstrip('.')}/A: {expected_log}") + + +def test_auth_serves_forged_grandparent_nsec(): + """ + Check the attacker's server, not the resolver. + + This queries ans1 directly, so ns2's validator never sees it and the + test passes whether or not BIND rejects the forgery -- it is not a + reproducer for #5967. It guards the premise the reproducers below + rest on: that c.p031.test is a secure delegation, and that a DS query + for grand.c.p031.test is answered with an NSEC signed by the + grandparent p031.test rather than by the real parent c.p031.test. If + ans1/ans.py ever stops serving that forgery, this fails here instead + of quietly turning every test_resolver_rejects_* below into a pass. + """ + child_ds = _query(AUTH, CHILD, "DS") + isctest.check.noerror(child_ds) + assert _rrset(child_ds, child_ds.answer, CHILD, dns.rdatatype.DS) is not None + _check_signed_rrset(child_ds, child_ds.answer, CHILD, dns.rdatatype.DS, PARENT) + + grandchild_ds = _query(AUTH, GRANDCHILD, "DS") + isctest.check.noerror(grandchild_ds) + nsec = _rrset( + grandchild_ds, grandchild_ds.authority, GRANDCHILD, dns.rdatatype.NSEC + ) + assert nsec is not None, grandchild_ds.to_text() + assert nsec[0].next == dns.name.from_text( + f"grandz.{CHILD}" + ), grandchild_ds.to_text() + _check_signed_rrset( + grandchild_ds, + grandchild_ds.authority, + GRANDCHILD, + dns.rdatatype.NSEC, + PARENT, + ) + + +def test_resolver_rejects_grandparent_nsec_downgrade(servers): + """ + Reproducer for #5967: an NSEC signed by the grandparent must not + downgrade a secure delegation to insecure. Here the forged proof + arrives in a fresh DS fetch, so the refusal runs in + fetch_callback_ds(). + """ + _check_no_downgrade(_query(RESOLVER, ATTACK, "A"), ATTACK) + _check_refusal_logged(servers["ns2"], ATTACK, REFUSED_NSEC_LOG) + + # The rejected proof must also stop the insecurity walk: without the + # early stop, the validator descends and asks the (attacker-controlled) + # server for a DS at the attack name. + assert _auth_query_count(ATTACK, "DS") == 0 + + +def test_resolver_rejects_grandparent_nsec3_downgrade(servers): + """ + The same downgrade as above, with the forgery expressed as an NSEC3, + which reaches is_insecure_referral()'s trynsec3 arm instead. + """ + _check_no_downgrade(_query(RESOLVER, ATTACK3, "A"), ATTACK3) + _check_refusal_logged(servers["ns2"], ATTACK3, REFUSED_NSEC3_LOG) + + assert _auth_query_count(ATTACK3, "DS") == 0 + + +def test_resolver_rejects_sibling_zone_nsec3(servers): + """ + Reproducer for #6234 (sibling-zone NSEC3). + + The forged DS NODATA answer carries, ahead of the real child-signed proof, + an NSEC3 owned by an unrelated but genuinely delegated and signed sibling + zone, whose owner hash matches the grandchild under the sibling's own + parameters and whose NS bit is set. Every signature in the answer is + valid. is_insecure_referral()'s trynsec3 arm sorts this record first (the + salts are chosen so its hash does) and, before the fix, derived its signer + as owner-minus-hash-label -> SIBLING, which is not on the path between the + grandparent and the grandchild, so the label-count check in + closer_secure_ds_exists() was vacuous and the secure DS at CHILD was never + consulted. + + Before the fix this fails: the resolver returns the forged answer. + """ + _check_no_downgrade(_query(RESOLVER, ATTACK3_SIBLING, "A"), ATTACK3_SIBLING) + _check_refusal_logged(servers["ns2"], ATTACK3_SIBLING, IGNORED_NSEC3_LOG) + + +def test_auth_serves_mixed_signer_grandparent_nsec(): + """ + Premise check for the #6321 reproducers below, again against ans1 + directly rather than the resolver. + + The DS query for each mixed-signer grandchild must be answered with + the same grandparent-signed NSEC forgery as above, plus a second, + dummy RRSIG that names the NSEC owner itself as signer and uses an + algorithm the validator does not support. The order of the two + RRSIGs on the wire is the whole point, so it is checked here for + both names: if dnspython ever started shuffling them, the reproducer + would flap instead of failing cleanly. + """ + for grandchild, expected in [ + ( + GRANDCHILD_DUMMY_FIRST, + [(GRANDCHILD_DUMMY_FIRST, DUMMY_ALGORITHM), (PARENT, GENUINE_ALGORITHM)], + ), + ( + GRANDCHILD_DUMMY_LAST, + [(PARENT, GENUINE_ALGORITHM), (GRANDCHILD_DUMMY_LAST, DUMMY_ALGORITHM)], + ), + ]: + grandchild_ds = _query(AUTH, grandchild, "DS") + isctest.check.noerror(grandchild_ds) + nsec = _rrset( + grandchild_ds, grandchild_ds.authority, grandchild, dns.rdatatype.NSEC + ) + assert nsec is not None, grandchild_ds.to_text() + assert nsec[0].next == dns.name.from_text( + f"grandz.{CHILD}" + ), grandchild_ds.to_text() + signers = _rrsig_signers( + grandchild_ds, grandchild_ds.authority, grandchild, dns.rdatatype.NSEC + ) + assert signers == expected, grandchild_ds.to_text() + + +def test_resolver_rejects_mixed_signer_nsec_dummy_first(servers): + """ + Reproducer for #6321: the NSEC is still the grandparent's forgery from + test_resolver_rejects_grandparent_nsec_downgrade(), and it still + authenticates only through the grandparent's RRSIG. But the RRSIG + rdataset now starts with a dummy signature (unsupported algorithm, + skipped by the validator) whose signer is the NSEC owner itself. If + the signer used to bound the NSEC's authority is taken from the first + RRSIG rather than from the one that verified, the bound collapses to + the queried name, the secure DS at c.p031.test is never consulted, + and the forged answer below the secure delegation is accepted. + """ + _check_no_downgrade(_query(RESOLVER, ATTACK_DUMMY_FIRST, "A"), ATTACK_DUMMY_FIRST) + _check_refusal_logged(servers["ns2"], ATTACK_DUMMY_FIRST, REFUSED_MIXED_LOG) + + # A mixed-signer set is forged outright, so the walk must stop there + # just like the plain grandparent forgery does. + assert _auth_query_count(ATTACK_DUMMY_FIRST, "DS") == 0 + + +def test_resolver_rejects_mixed_signer_nsec_dummy_last(servers): + """ + Control for the test above with the RRSIGs in the other order: the + genuine grandparent signature first, the dummy second. Whatever the + resolver does with the mixed-signer rdataset must not depend on the + wire order the attacker chooses. + """ + _check_no_downgrade(_query(RESOLVER, ATTACK_DUMMY_LAST, "A"), ATTACK_DUMMY_LAST) + _check_refusal_logged(servers["ns2"], ATTACK_DUMMY_LAST, REFUSED_MIXED_LOG) + + assert _auth_query_count(ATTACK_DUMMY_LAST, "DS") == 0 + + +def test_resolver_rejects_mixed_signer_nsec_from_cache(servers): + """ + The dummy-first forgery again, with a second name below the same + grandchild so that whatever the first walk left in the cache (the + negative DS proof, complete with its mixed RRSIG rdataset, if the + resolver accepted it) is what the insecurity walk finds this time. + """ + _check_no_downgrade(_query(RESOLVER, ATTACK_DUMMY_FIRST, "A"), ATTACK_DUMMY_FIRST) + + ds_fetches = _auth_query_count(GRANDCHILD_DUMMY_FIRST, "DS") + _check_no_downgrade( + _query(RESOLVER, ATTACK_DUMMY_FIRST_CACHED, "A"), ATTACK_DUMMY_FIRST_CACHED + ) + _check_refusal_logged(servers["ns2"], ATTACK_DUMMY_FIRST_CACHED, REFUSED_MIXED_LOG) + + # As in test_resolver_rejects_downgrade_from_cached_proof(): no new DS + # fetch for the grandchild proves the mixed proof came from the cache, + # none for the attack name proves the walk stopped there. + assert _auth_query_count(GRANDCHILD_DUMMY_FIRST, "DS") == ds_fetches + assert _auth_query_count(ATTACK_DUMMY_FIRST_CACHED, "DS") == 0 + + +def test_auth_serves_many_rrsig_grandparent_nsec(): + """ + Premise check for the RRSIG-count tests below, against ans1 directly. + + Both grandchildren must get the grandparent NSEC forgery with the + intended number of RRSIGs, every one of them naming the grandparent + as signer, and the single genuine signature last. + """ + for grandchild, count in [ + (GRANDCHILD_TOO_MANY, MAX_VALIDATIONS_PER_FETCH), + (GRANDCHILD_ALMOST_TOO_MANY, MAX_VALIDATIONS_PER_FETCH - 1), + ]: + grandchild_ds = _query(AUTH, grandchild, "DS") + isctest.check.noerror(grandchild_ds) + assert ( + _rrset( + grandchild_ds, grandchild_ds.authority, grandchild, dns.rdatatype.NSEC + ) + is not None + ), grandchild_ds.to_text() + signers = _rrsig_signers( + grandchild_ds, grandchild_ds.authority, grandchild, dns.rdatatype.NSEC + ) + assert len(signers) == count, grandchild_ds.to_text() + assert all(signer == PARENT for signer, _ in signers), grandchild_ds.to_text() + assert [alg for _, alg in signers] == [DUMMY_ALGORITHM] * (count - 1) + [ + GENUINE_ALGORITHM + ], grandchild_ds.to_text() + + +def test_resolver_rejects_nsec_with_too_many_rrsigs(servers): + """ + An NSEC proof carrying at least max-validations-per-fetch RRSIGs is + refused outright, before any signer is looked at. The signatures + here are uniform (all the grandparent's), so without the cap this + would be the plain #5967 forgery and be refused for that reason + instead; the log line pins which rule fired. + """ + _check_no_downgrade(_query(RESOLVER, ATTACK_TOO_MANY, "A"), ATTACK_TOO_MANY) + _check_refusal_logged(servers["ns2"], ATTACK_TOO_MANY, REFUSED_TOO_MANY_LOG) + + assert _auth_query_count(ATTACK_TOO_MANY, "DS") == 0 + + +def test_resolver_bounds_nsec_just_below_rrsig_cap(servers): + """ + Control for the test above with one RRSIG fewer: the cap must not + fire, the validator must still authenticate the NSEC through the + genuine signature after skipping every dummy, and the proof must then + be refused by the ordinary grandparent-signer bound. + """ + _check_no_downgrade( + _query(RESOLVER, ATTACK_ALMOST_TOO_MANY, "A"), ATTACK_ALMOST_TOO_MANY + ) + _check_refusal_logged(servers["ns2"], ATTACK_ALMOST_TOO_MANY, REFUSED_NSEC_LOG) + + assert _auth_query_count(ATTACK_ALMOST_TOO_MANY, "DS") == 0 + + +def test_resolver_rejects_downgrade_from_cached_proof(servers): + """ + The same downgrade as above, with the forged proof already in the + cache when the insecurity walk reaches it, so the refusal runs in + seek_ds() rather than in fetch_callback_ds(). + """ + # Prime the cache: walking the insecurity proof for ATTACK fetches the + # forged NODATA proof for GRANDCHILD/DS, which is validated and cached + # independently of the failed A validation. + isctest.check.servfail(_query(RESOLVER, ATTACK, "A")) + + ds_fetches = _auth_query_count(GRANDCHILD, "DS") + _check_no_downgrade(_query(RESOLVER, ATTACK_CACHED, "A"), ATTACK_CACHED) + _check_refusal_logged(servers["ns2"], ATTACK_CACHED, REFUSED_NSEC_LOG) + + # No new DS fetch for GRANDCHILD confirms the proof really did come from + # the cache; none for ATTACK_CACHED confirms the walk stopped there. + assert _auth_query_count(GRANDCHILD, "DS") == ds_fetches + assert _auth_query_count(ATTACK_CACHED, "DS") == 0 diff -Nru bind9-9.20.26/bin/tests/system/nsec_ixfr/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec_ixfr/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec_ixfr/ns1/named.conf.j2 2026-07-20 14:47:53.778845526 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_ixfr/ns1/named.conf.j2 2026-09-11 19:41:01.266325370 +0000 @@ -1,23 +1,9 @@ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/nsec_ixfr/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec_ixfr/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec_ixfr/ns2/named.conf.j2 2026-07-20 14:47:53.778845526 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_ixfr/ns2/named.conf.j2 2026-09-11 19:41:01.266325370 +0000 @@ -1,22 +1,8 @@ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/nsec_piggyback/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec_piggyback/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec_piggyback/ns2/named.conf.j2 2026-07-20 14:47:53.779845542 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_piggyback/ns2/named.conf.j2 2026-09-11 19:41:01.266325370 +0000 @@ -1,28 +1,14 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; minimal-any no; minimal-responses no; recursion no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "c.p22.hack" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsec_piggyback/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec_piggyback/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec_piggyback/ns3/named.conf.j2 2026-07-20 14:47:53.779845542 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_piggyback/ns3/named.conf.j2 2026-09-11 19:41:01.267325394 +0000 @@ -1,28 +1,14 @@ // validating resolver options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; synth-from-dnssec yes; }; -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "p22.hack" { type static-stub; diff -Nru bind9-9.20.26/bin/tests/system/nsec_synthesis/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec_synthesis/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec_synthesis/ns2/named.conf.j2 2026-07-20 14:47:53.780845557 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_synthesis/ns2/named.conf.j2 2026-09-11 19:41:01.267325394 +0000 @@ -1,28 +1,14 @@ // validating resolver options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; synth-from-dnssec yes; }; -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "f004.test" { type static-stub; diff -Nru bind9-9.20.26/bin/tests/system/nsec_synthesis/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec_synthesis/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec_synthesis/ns3/named.conf.j2 2026-07-20 14:47:53.780845557 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_synthesis/ns3/named.conf.j2 2026-09-11 19:41:01.267325394 +0000 @@ -1,26 +1,13 @@ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; }; -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -include "../../_common/rndc.key"; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "f007.test" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsec_wildcard_wrong_zone/ans1/ans.py bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/ans1/ans.py --- bind9-9.20.26/bin/tests/system/nsec_wildcard_wrong_zone/ans1/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/ans1/ans.py 2026-09-11 19:41:01.268325417 +0000 @@ -0,0 +1,216 @@ +#!/usr/bin/python3 + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 + +from collections.abc import AsyncGenerator +from dataclasses import dataclass +from pathlib import Path + +import json + +from cryptography.hazmat.primitives import serialization + +import dns.dnssec +import dns.flags +import dns.name +import dns.rcode +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset + +from isctest.asyncserver import ( + AsyncDnsServer, + DnsResponseSend, + DomainHandler, + QueryContext, +) + +TTL = 300 +VICTIM = "victim.example." +ATTACKER = "abc.example." +ATTACK = f"foo.{VICTIM}" +VALID_NXDOMAIN = f"bar.{ATTACKER}" +CONTROL = f"wild1.{VICTIM}" +CONTROL_NODATA = f"wild2.{VICTIM}" +WILDCARD = f"*.{VICTIM}" +VICTIM_NSEC_OWNER = f"a.{VICTIM}" +VICTIM_NSEC_NEXT = f"z.{VICTIM}" +ATTACKER_NSEC_OWNER = f"z.{ATTACKER}" +ATTACKER_VALID_NSEC_OWNER = f"a.{ATTACKER}" +CONTROL_A = "192.0.2.1" + + +@dataclass(frozen=True) +class Key: + zone: dns.name.Name + private_key: object + dnskey: dns.rdata.Rdata + + +def name(text: str) -> dns.name.Name: + return dns.name.from_text(text) + + +def load_keys() -> dict[str, Key]: + path = Path(__file__).resolve().parent / "keys.json" + with path.open(encoding="utf-8") as keys_file: + raw_keys = json.load(keys_file) + + keys = {} + for zone, raw_key in raw_keys.items(): + private_key = serialization.load_pem_private_key( + raw_key["private_pem"].encode("ascii"), + password=None, + ) + dnskey = dns.rdata.from_text( + dns.rdataclass.IN, dns.rdatatype.DNSKEY, raw_key["dnskey"] + ) + keys[zone] = Key(name(zone), private_key, dnskey) + + return keys + + +def rrset(owner: str, rdtype: dns.rdatatype.RdataType, rdata: str) -> dns.rrset.RRset: + return dns.rrset.from_text(owner, TTL, dns.rdataclass.IN, rdtype, rdata) + + +def add_signed( + section: list[dns.rrset.RRset], covered: dns.rrset.RRset, signer: Key +) -> None: + rrsig = dns.dnssec.sign( + covered, + signer.private_key, + signer.zone, + signer.dnskey, + lifetime=86400, + verify=True, + ) + section.append(covered) + section.append(dns.rrset.from_rdata(covered.name, covered.ttl, rrsig)) + + +def add_dnskey(response, key: Key) -> None: + dnskey = dns.rrset.from_rdata(key.zone, TTL, key.dnskey) + add_signed(response.answer, dnskey, key) + + +def soa(zone: str) -> dns.rrset.RRset: + return rrset( + zone, + dns.rdatatype.SOA, + f"ns.{zone} hostmaster.{zone} 1 3600 600 86400 300", + ) + + +def nsec(owner: str, next_name: str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.NSEC, f"{next_name} A RRSIG NSEC") + + +def add_wildcard_answer(response, key: Key) -> None: + wildcard = rrset(WILDCARD, dns.rdatatype.A, CONTROL_A) + rrsig = dns.dnssec.sign( + wildcard, + key.private_key, + key.zone, + key.dnskey, + lifetime=86400, + verify=True, + ) + response.answer.append(rrset(CONTROL, dns.rdatatype.A, CONTROL_A)) + response.answer.append(dns.rrset.from_rdata(name(CONTROL), TTL, rrsig)) + + +class NsecWildcardWrongZoneHandler(DomainHandler): + domains = [VICTIM, ATTACKER] + + def __init__(self, keys: dict[str, Key]) -> None: + super().__init__() + self.keys = keys + self.victim = keys[VICTIM] + self.attacker = keys[ATTACKER] + + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + qctx.prepare_new_response(with_zone_data=False) + qctx.response.flags |= dns.flags.AA + qctx.response.set_rcode(dns.rcode.NOERROR) + + if qctx.qtype == dns.rdatatype.DNSKEY and qctx.qname in { + self.victim.zone, + self.attacker.zone, + }: + add_dnskey(qctx.response, self.keys[qctx.qname.to_text()]) + elif qctx.qtype == dns.rdatatype.SOA and qctx.qname in { + self.victim.zone, + self.attacker.zone, + }: + zone = qctx.qname.to_text() + add_signed(qctx.response.answer, soa(zone), self.keys[zone]) + elif qctx.qname == name(ATTACK) and qctx.qtype == dns.rdatatype.A: + qctx.response.set_rcode(dns.rcode.NXDOMAIN) + add_signed(qctx.response.authority, soa(VICTIM), self.victim) + + # This secure terminal NSEC from an unrelated zone sorts across + # the victim wildcard and used to be accepted as NOWILDCARD. + add_signed( + qctx.response.authority, + nsec(ATTACKER_NSEC_OWNER, ATTACKER), + self.attacker, + ) + add_signed( + qctx.response.authority, + nsec(VICTIM_NSEC_OWNER, VICTIM_NSEC_NEXT), + self.victim, + ) + elif qctx.qname == name(VALID_NXDOMAIN) and qctx.qtype == dns.rdatatype.A: + qctx.response.set_rcode(dns.rcode.NXDOMAIN) + add_signed(qctx.response.authority, soa(ATTACKER), self.attacker) + add_signed( + qctx.response.authority, + nsec(ATTACKER_VALID_NSEC_OWNER, ATTACKER_NSEC_OWNER), + self.attacker, + ) + add_signed( + qctx.response.authority, + nsec(ATTACKER, ATTACKER_VALID_NSEC_OWNER), + self.attacker, + ) + elif qctx.qname == name(CONTROL) and qctx.qtype == dns.rdatatype.A: + add_wildcard_answer(qctx.response, self.victim) + add_signed( + qctx.response.authority, + nsec(VICTIM_NSEC_OWNER, VICTIM_NSEC_NEXT), + self.victim, + ) + elif qctx.qname == name(CONTROL_NODATA) and qctx.qtype == dns.rdatatype.AAAA: + add_signed(qctx.response.authority, soa(VICTIM), self.victim) + add_signed( + qctx.response.authority, + nsec(VICTIM_NSEC_OWNER, VICTIM_NSEC_NEXT), + self.victim, + ) + add_signed( + qctx.response.authority, + nsec(WILDCARD, VICTIM_NSEC_OWNER), + self.victim, + ) + else: + qctx.response.set_rcode(dns.rcode.NXDOMAIN) + zone = VICTIM if qctx.qname.is_subdomain(self.victim.zone) else ATTACKER + add_signed(qctx.response.authority, soa(zone), self.keys[zone]) + + yield DnsResponseSend(qctx.response, authoritative=True) + + +def main() -> None: + server = AsyncDnsServer(default_aa=True) + server.install_response_handler(NsecWildcardWrongZoneHandler(load_keys())) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/nsec_wildcard_wrong_zone/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsec_wildcard_wrong_zone/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/ns2/named.conf.j2 2026-09-11 19:41:01.268325417 +0000 @@ -0,0 +1,25 @@ +// validating resolver + +options { + {% include_indented "_common/options.conf.j2" %} + dnssec-validation yes; +}; + +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} + +zone "victim.example" { + type static-stub; + server-addresses { 10.53.0.1; }; +}; + +zone "abc.example" { + type static-stub; + server-addresses { 10.53.0.1; }; +}; + +trust-anchors { + victim.example. static-key 257 3 13 "@VICTIM_DNSKEY@"; + abc.example. static-key 257 3 13 "@ATTACKER_DNSKEY@"; +}; diff -Nru bind9-9.20.26/bin/tests/system/nsec_wildcard_wrong_zone/tests_nsec_wildcard_wrong_zone.py bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/tests_nsec_wildcard_wrong_zone.py --- bind9-9.20.26/bin/tests/system/nsec_wildcard_wrong_zone/tests_nsec_wildcard_wrong_zone.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/nsec_wildcard_wrong_zone/tests_nsec_wildcard_wrong_zone.py 2026-09-11 19:41:01.268325417 +0000 @@ -0,0 +1,159 @@ +#!/usr/bin/python3 + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 + +from pathlib import Path + +import json + +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec + +import dns.dnssec +import dns.name +import dns.rdataclass +import dns.rdatatype +import pytest + +import isctest +import isctest.mark + +VICTIM = "victim.example." +ATTACKER = "abc.example." +ATTACK = f"foo.{VICTIM}" +VALID_NXDOMAIN = f"bar.{ATTACKER}" +CONTROL = f"wild1.{VICTIM}" +CONTROL_NODATA = f"wild2.{VICTIM}" +VICTIM_NSEC_OWNER = f"a.{VICTIM}" +ATTACKER_NSEC_OWNER = f"z.{ATTACKER}" +CONTROL_A = "192.0.2.1" +AUTH = "10.53.0.1" +RESOLVER = "10.53.0.2" + +pytestmark = [ + isctest.mark.with_ecdsa_deterministic, + pytest.mark.extra_artifacts( + [ + "ans*/ans.run", + "ans*/keys.json", + ] + ), +] + + +def _make_key(): + private_key = ec.generate_private_key(ec.SECP256R1()) + dnskey = dns.dnssec.make_dnskey( + private_key.public_key(), + algorithm="ECDSAP256SHA256", + flags=257, + ) + private_pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption(), + ).decode("ascii") + return { + "private_pem": private_pem, + "dnskey": dnskey.to_text(), + } + + +def bootstrap(): + keys = {zone: _make_key() for zone in [VICTIM, ATTACKER]} + Path("ans1/keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii") + return { + "VICTIM_DNSKEY": "".join(keys[VICTIM]["dnskey"].split()[3:]), + "ATTACKER_DNSKEY": "".join(keys[ATTACKER]["dnskey"].split()[3:]), + } + + +def _query(server, qname, qtype): + query = isctest.query.create(qname, qtype) + return isctest.query.tcp(query, server) + + +def _rrset(response, section, owner, rdtype, covers=None): + if covers is None: + return response.get_rrset( + section, + dns.name.from_text(owner), + dns.rdataclass.IN, + rdtype, + ) + return response.get_rrset( + section, + dns.name.from_text(owner), + dns.rdataclass.IN, + rdtype, + covers=covers, + ) + + +def _check_signer(response, section, owner, covered, signer): + rrsig = _rrset( + response, + section, + owner, + dns.rdatatype.RRSIG, + covers=covered, + ) + assert rrsig is not None, response.to_text() + assert rrsig[0].signer == dns.name.from_text(signer), response.to_text() + + +def test_forged_response_contains_cross_zone_nsec(): + response = _query(AUTH, ATTACK, "A") + isctest.check.nxdomain(response) + + assert _rrset(response, response.authority, ATTACKER_NSEC_OWNER, dns.rdatatype.NSEC) + _check_signer( + response, + response.authority, + ATTACKER_NSEC_OWNER, + dns.rdatatype.NSEC, + ATTACKER, + ) + + assert _rrset(response, response.authority, VICTIM_NSEC_OWNER, dns.rdatatype.NSEC) + _check_signer( + response, + response.authority, + VICTIM_NSEC_OWNER, + dns.rdatatype.NSEC, + VICTIM, + ) + + +def test_resolver_rejects_cross_zone_nowildcard_proof(): + response = _query(RESOLVER, ATTACKER, "SOA") + isctest.check.noerror(response) + isctest.check.adflag(response) + + response = _query(RESOLVER, ATTACK, "A") + isctest.check.servfail(response) + isctest.check.noadflag(response) + + +def test_valid_same_zone_nxdomain_still_validates(): + response = _query(RESOLVER, VALID_NXDOMAIN, "A") + isctest.check.nxdomain(response) + isctest.check.adflag(response) + + +def test_valid_wildcard_still_validates(): + response = _query(RESOLVER, CONTROL, "A") + isctest.check.noerror(response) + isctest.check.adflag(response) + answer = _rrset(response, response.answer, CONTROL, dns.rdatatype.A) + assert answer is not None, response.to_text() + assert any(rdata.address == CONTROL_A for rdata in answer), response.to_text() + + +def test_valid_wildcard_nodata_still_validates(): + response = _query(RESOLVER, CONTROL_NODATA, "AAAA") + isctest.check.noerror(response) + isctest.check.adflag(response) + isctest.check.rr_count_eq(response.answer, 0) diff -Nru bind9-9.20.26/bin/tests/system/nslookup/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/nslookup/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nslookup/ns1/named.conf.j2 2026-07-20 14:47:53.780845557 +0000 +++ bind9-9.20.29/bin/tests/system/nslookup/ns1/named.conf.j2 2026-09-11 19:41:01.268325417 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns1/named.conf.j2 2026-07-20 14:47:53.781845573 +0000 +++ bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns1/named.conf.j2 2026-09-11 19:41:01.269325442 +0000 @@ -12,12 +12,7 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -29,11 +24,4 @@ }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns2/named.conf.j2 2026-07-20 14:47:53.781845573 +0000 +++ bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns2/named.conf.j2 2026-09-11 19:41:01.269325442 +0000 @@ -12,12 +12,7 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -27,11 +22,4 @@ file "tld.db"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns3/named.conf.j2 2026-07-20 14:47:53.781845573 +0000 +++ bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns3/named.conf.j2 2026-09-11 19:41:01.269325442 +0000 @@ -12,12 +12,7 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -27,11 +22,4 @@ file "example.tld.db"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns4/named.conf.j2 2026-07-20 14:47:53.781845573 +0000 +++ bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns4/named.conf.j2 2026-09-11 19:41:01.269325442 +0000 @@ -12,28 +12,12 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; dnstap { resolver query; }; dnstap-output file "dnstap.out"; }; -zone "." { - type hint; - file "root.hint"; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/root.hint.conf" %} -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns4/root.hint bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns4/root.hint --- bind9-9.20.26/bin/tests/system/nsprocessinglimit/ns4/root.hint 2026-07-20 14:47:53.781845573 +0000 +++ bind9-9.20.29/bin/tests/system/nsprocessinglimit/ns4/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns1/grant-external.test.db.in bind9-9.20.29/bin/tests/system/nsupdate/ns1/grant-external.test.db.in --- bind9-9.20.26/bin/tests/system/nsupdate/ns1/grant-external.test.db.in 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns1/grant-external.test.db.in 2026-09-11 19:41:01.272325513 +0000 @@ -0,0 +1,10 @@ +$TTL 300 ; 5 minutes +@ IN SOA ns1.example.nil. hostmaster.example.nil. ( + 1 ; serial + 2000 ; refresh (2000 seconds) + 2000 ; retry (2000 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) +@ NS ns1.example.nil. + NS ns2.example.nil. diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns1/named.conf.j2 2026-07-20 14:47:53.785845635 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns1/named.conf.j2 2026-09-11 19:41:01.274325561 +0000 @@ -16,26 +16,22 @@ {% endif %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.1; 127.0.0.1; }; + listen-on { @ns.ip@; 127.0.0.1; }; listen-on-v6 { none; }; recursion no; - notify yes; minimal-responses no; update-quota 1; dnssec-validation no; {% if FEATURE_FIPS_DH == "1" %} tls-port @TLSPORT@; - listen-on tls ephemeral { 10.53.0.1; }; - listen-on port @EXTRAPORT1@ tls tls-forward-secrecy { 10.53.0.1; }; - listen-on port @EXTRAPORT2@ tls tls-forward-secrecy-mutual-tls { 10.53.0.1; }; - listen-on port @EXTRAPORT3@ tls tls-expired { 10.53.0.1; }; + listen-on tls ephemeral { @ns.ip@; }; + listen-on port @EXTRAPORT1@ tls tls-forward-secrecy { @ns.ip@; }; + listen-on port @EXTRAPORT2@ tls tls-forward-secrecy-mutual-tls { @ns.ip@; }; + listen-on port @EXTRAPORT3@ tls tls-expired { @ns.ip@; }; {% endif %} }; @@ -44,14 +40,7 @@ any; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key altkey { algorithm @DEFAULT_HMAC@; @@ -100,7 +89,7 @@ check-mx warn; update-policy local; allow-query { !10.53.0.2; any; }; - allow-query-on { 10.53.0.1; 127.0.0.1; }; + allow-query-on { @ns.ip@; 127.0.0.1; }; allow-transfer { any; }; }; @@ -154,18 +143,26 @@ type primary; file "keytests.db"; update-policy { - grant md5-key name md5.keytests.nil. ANY; - grant sha1-key name sha1.keytests.nil. ANY; - grant sha224-key name sha224.keytests.nil. ANY; - grant sha256-key name sha256.keytests.nil. ANY; - grant sha384-key name sha384.keytests.nil. ANY; - grant sha512-key name sha512.keytests.nil. ANY; - grant legacy-157 name 157.keytests.nil. ANY; - grant legacy-161 name 161.keytests.nil. ANY; - grant legacy-162 name 162.keytests.nil. ANY; - grant legacy-163 name 163.keytests.nil. ANY; - grant legacy-164 name 164.keytests.nil. ANY; - grant legacy-165 name 165.keytests.nil. ANY; + grant md5-key name md5.keytests.nil. ANY; + grant sha1-key name sha1.keytests.nil. ANY; + grant sha224-key name sha224.keytests.nil. ANY; + grant sha256-key name sha256.keytests.nil. ANY; + grant sha384-key name sha384.keytests.nil. ANY; + grant sha512-key name sha512.keytests.nil. ANY; + grant legacy-157 name 157.keytests.nil. ANY; + grant legacy-161 name 161.keytests.nil. ANY; + grant legacy-162 name 162.keytests.nil. ANY; + grant legacy-163 name 163.keytests.nil. ANY; + grant legacy-164 name 164.keytests.nil. ANY; + grant legacy-165 name 165.keytests.nil. ANY; + }; +}; + +zone "grant-external.test" { + type primary; + file "grant-external.test.db"; + update-policy { + grant "local:auth.sock" external * CNAME; }; }; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns1/tls.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns1/tls.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns1/tls.conf.j2 2026-07-20 14:47:53.785845635 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns1/tls.conf.j2 2026-09-11 19:41:01.274325561 +0000 @@ -12,29 +12,29 @@ */ tls tls-forward-secrecy { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv01.crt01.example.nil.key"; - cert-file "../CA/certs/srv01.crt01.example.nil.pem"; - dhparam-file "../dhparam3072.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv01.crt01.example.nil.key"; + cert-file "../CA/certs/srv01.crt01.example.nil.pem"; + dhparam-file "../dhparam3072.pem"; }; tls tls-forward-secrecy-mutual-tls { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv01.crt01.example.nil.key"; - cert-file "../CA/certs/srv01.crt01.example.nil.pem"; - dhparam-file "../dhparam3072.pem"; - ca-file "../CA/CA.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv01.crt01.example.nil.key"; + cert-file "../CA/certs/srv01.crt01.example.nil.pem"; + dhparam-file "../dhparam3072.pem"; + ca-file "../CA/CA.pem"; }; tls tls-expired { - protocols { TLSv1.2; }; - ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; - prefer-server-ciphers yes; - key-file "../CA/certs/srv01.crt02-expired.example.nil.key"; - cert-file "../CA/certs/srv01.crt02-expired.example.nil.pem"; - dhparam-file "../dhparam3072.pem"; + protocols { TLSv1.2; }; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + key-file "../CA/certs/srv01.crt02-expired.example.nil.key"; + cert-file "../CA/certs/srv01.crt02-expired.example.nil.pem"; + dhparam-file "../dhparam3072.pem"; }; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns10/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns10/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns10/named.conf.j2 2026-07-20 14:47:53.786845651 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns10/named.conf.j2 2026-09-11 19:41:01.274325561 +0000 @@ -12,18 +12,11 @@ */ options { - query-source address 10.53.0.10; - notify-source 10.53.0.10; - transfer-source 10.53.0.10; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; session-keyfile "session.key"; - listen-on { 10.53.0.10; }; - listen-on tls ephemeral { 10.53.0.10; }; - listen-on-v6 { none; }; + listen-on tls ephemeral { @ns.ip@; }; recursion no; - notify yes; minimal-responses no; dnssec-validation no; @@ -35,14 +28,7 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.10 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "in-addr.arpa" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns2/named.conf.j2 2026-07-20 14:47:53.786845651 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns2/named.conf.j2 2026-09-11 19:41:01.274325561 +0000 @@ -12,27 +12,12 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} serial-query-rate 1; // workaround for KB AA-01213 dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key altkey { algorithm @DEFAULT_HMAC@; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns3/named.conf.j2 2026-07-20 14:47:53.787845667 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns3/named.conf.j2 2026-09-11 19:41:01.275325585 +0000 @@ -14,27 +14,13 @@ // NS3 options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns5/named.conf.j2 2026-07-20 14:47:53.787845667 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns5/named.conf.j2 2026-09-11 19:41:01.275325585 +0000 @@ -12,28 +12,14 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; recursion no; - notify yes; minimal-responses no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "local.nil" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns6/named.conf.j2 2026-07-20 14:47:53.830846336 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns6/named.conf.j2 2026-09-11 19:41:01.276325609 +0000 @@ -12,31 +12,14 @@ */ options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - query-source-v6 address fd92:7065:b8e:ffff::6; - notify-source-v6 fd92:7065:b8e:ffff::6; - transfer-source-v6 fd92:7065:b8e:ffff::6; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options-dual.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.6; }; - listen-on-v6 { fd92:7065:b8e:ffff::6; }; recursion no; - notify yes; minimal-responses no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "in-addr.arpa" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns7/named.conf.j2 2026-07-20 14:47:53.831846352 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns7/named.conf.j2 2026-09-11 19:41:01.276325609 +0000 @@ -12,28 +12,14 @@ */ options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; recursion no; - notify yes; minimal-responses no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "in-addr.arpa" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns7/named2.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns7/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns7/named2.conf.j2 2026-07-20 14:47:53.831846352 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns7/named2.conf.j2 2026-09-11 19:41:01.276325609 +0000 @@ -12,29 +12,15 @@ */ options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; recursion no; - notify yes; minimal-responses no; dnssec-validation no; tkey-gssapi-keytab "dns.keytab"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "in-addr.arpa" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns8/named.conf.j2 2026-07-20 14:47:53.831846352 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns8/named.conf.j2 2026-09-11 19:41:01.277325633 +0000 @@ -12,29 +12,15 @@ */ options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; recursion no; - notify yes; minimal-responses no; dnssec-validation no; tkey-gssapi-keytab "dns-other-than-KRB5_KTNAME.keytab"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "in-addr.arpa" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/nsupdate/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nsupdate/ns9/named.conf.j2 2026-07-20 14:47:53.832846367 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/ns9/named.conf.j2 2026-09-11 19:41:01.277325633 +0000 @@ -12,16 +12,9 @@ */ options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; recursion no; - notify yes; minimal-responses no; dnssec-validation no; @@ -33,19 +26,12 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - key subkey { secret "1234abcd8765"; algorithm @DEFAULT_HMAC@; }; -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "in-addr.arpa" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/prereq.sh bind9-9.20.29/bin/tests/system/nsupdate/prereq.sh --- bind9-9.20.26/bin/tests/system/nsupdate/prereq.sh 2026-07-20 14:47:53.832846367 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/setup.sh bind9-9.20.29/bin/tests/system/nsupdate/setup.sh --- bind9-9.20.26/bin/tests/system/nsupdate/setup.sh 2026-07-20 14:47:53.832846367 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/setup.sh 2026-09-11 19:41:01.277325633 +0000 @@ -14,6 +14,7 @@ . ../conf.sh cp -f ns1/example1.db ns1/example.db +cp -f ns1/grant-external.test.db.in ns1/grant-external.test.db sed 's/example.nil/other.nil/g' ns1/example1.db >ns1/other.db sed 's/example.nil/unixtime.nil/g' ns1/example1.db >ns1/unixtime.db sed 's/example.nil/yyyymmddvv.nil/g' ns1/example1.db >ns1/yyyymmddvv.db diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/tests.sh bind9-9.20.29/bin/tests/system/nsupdate/tests.sh --- bind9-9.20.26/bin/tests/system/nsupdate/tests.sh 2026-07-20 14:47:53.832846367 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/tests.sh 2026-09-11 19:41:01.277325633 +0000 @@ -2150,6 +2150,32 @@ status=1 } +n=$((n + 1)) +ret=0 +echo_i "check that grant external pass client address properly ($n)" { +($PERL "${TOP_SRCDIR}/bin/tests/system/authsock.pl" --type=CNAME --path=ns1/auth.sock --pidfile=authsock.pid --timeout=120 >authsock.out.test$n 2>&1 &) & +sleep 1 +nextpart authsock.out.test$n >/dev/null +$NSUPDATE -k ns1/ddns.key -d <nsupdate.udp.test$n 2>&1 || ret=1 +server 10.53.0.1 ${PORT} +zone grant-external.test +update add cnameoverudp.grant-external.test 0 IN CNAME grant-external.test. +send +EOF +nextpart authsock.out.test$n | grep ' addr= ' >/dev/null || ret=1 +$NSUPDATE -v -d <nsupdate.tcp.test$n 2>&1 || ret=1 +server 10.53.0.1 ${PORT} +zone grant-external.test +update add cnameovertcp.grant-external.test 0 IN CNAME grant-external.test. +send +EOF +nextpart authsock.out.test$n | grep ' addr=10.53.0.1 ' >/dev/null || ret=1 +kill $(cat authsock.pid) || true +[ $ret = 0 ] || { + echo_i "failed" + status=1 +} + if ! $FEATURETEST --gssapi; then echo_i "SKIPPED: GSSAPI tests" else diff -Nru bind9-9.20.26/bin/tests/system/nsupdate/tests_sh_nsupdate.py bind9-9.20.29/bin/tests/system/nsupdate/tests_sh_nsupdate.py --- bind9-9.20.26/bin/tests/system/nsupdate/tests_sh_nsupdate.py 2026-07-20 14:47:53.832846367 +0000 +++ bind9-9.20.29/bin/tests/system/nsupdate/tests_sh_nsupdate.py 2026-09-11 19:41:01.278325657 +0000 @@ -13,12 +13,18 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "Kxxx*", + "authsock.out.*", + "authsock.pid", "dig.out.*", "nextpart.out.*", "nsupdate.*out*", + "nsupdate.tcp.*", + "nsupdate.udp.*", "perl.update_test.out", "typelist.out.*", "update.in.*", @@ -26,8 +32,10 @@ "ans*/ans.run", "ns*/*.jnl", "ns*/*.jnl", + "ns1/auth.sock", "ns1/ddns.key", "ns1/example.db", + "ns1/grant-external.test.db", "ns1/keytests.db", "ns1/legacy*.key", "ns1/many.test.db", @@ -75,6 +83,11 @@ ] ) +pytestmark = [ + isctest.mark.requires_net_dns, + EXTRA_ARTIFACTS, +] + MAX_RUNS = 2 if platform.system() == "FreeBSD" else 1 # GL#3846 diff -Nru bind9-9.20.26/bin/tests/system/nta/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/nta/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nta/ns1/named.conf.j2 2026-07-20 14:47:53.833846383 +0000 +++ bind9-9.20.29/bin/tests/system/nta/ns1/named.conf.j2 2026-09-11 19:41:01.278325657 +0000 @@ -14,20 +14,15 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; /* test that we can turn off trust-anchor-telemetry */ trust-anchor-telemetry no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/nta/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/nta/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nta/ns2/named.conf.j2 2026-07-20 14:47:53.833846383 +0000 +++ bind9-9.20.29/bin/tests/system/nta/ns2/named.conf.j2 2026-09-11 19:41:01.278325657 +0000 @@ -14,29 +14,15 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; - notify-delay 1; + notify-delay 1; dnssec-validation no; minimal-responses no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/nta/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/nta/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nta/ns3/named.conf.j2 2026-07-20 14:47:53.834846398 +0000 +++ bind9-9.20.29/bin/tests/system/nta/ns3/named.conf.j2 2026-09-11 19:41:01.279325681 +0000 @@ -14,28 +14,14 @@ // NS3 options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; - notify yes; dnssec-validation no; minimal-responses no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/nta/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/nta/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nta/ns4/named.conf.j2 2026-07-20 14:47:53.834846398 +0000 +++ bind9-9.20.29/bin/tests/system/nta/ns4/named.conf.j2 2026-09-11 19:41:01.279325681 +0000 @@ -14,14 +14,7 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} minimal-responses no; nta-lifetime 12s; @@ -33,19 +26,9 @@ include "trusted.conf"; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "corp" { type static-stub; diff -Nru bind9-9.20.26/bin/tests/system/nta/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/nta/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nta/ns9/named.conf.j2 2026-07-20 14:47:53.834846398 +0000 +++ bind9-9.20.29/bin/tests/system/nta/ns9/named.conf.j2 2026-09-11 19:41:01.279325681 +0000 @@ -14,27 +14,13 @@ // NS9 options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; forward only; forwarders { 10.53.0.4; }; servfail-ttl 0; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/nta/tests_nta.py bind9-9.20.29/bin/tests/system/nta/tests_nta.py --- bind9-9.20.26/bin/tests/system/nta/tests_nta.py 2026-07-20 14:47:53.834846398 +0000 +++ bind9-9.20.29/bin/tests/system/nta/tests_nta.py 2026-09-11 19:41:01.279325681 +0000 @@ -14,13 +14,25 @@ import os import time +import dns.edns + import isctest +# Extended DNS Error INFO-CODE disclosing that a Negative Trust Anchor was +# applied to a response (draft-farrokhi-dnsop-ede-nta). +NTA_EDE_CODE = 33 + def active(blob): return len([x for x in blob.splitlines() if " expiry" in x]) +def has_ede(res, code): + return any( + opt.otype == dns.edns.OptionType.EDE and opt.code == code for opt in res.options + ) + + # global start-time variable # pylint: disable=global-statement START = 0 @@ -418,3 +430,31 @@ isctest.check.servfail(res) isctest.check.empty_answer(res) isctest.check.noadflag(res) + + +def test_nta_ede(servers): + # A response whose DNSSEC validation was suppressed by a Negative Trust + # Anchor must disclose that via EDE code 33 (draft-farrokhi-dnsop-ede-nta). + ns9 = servers["ns9"] + + m = isctest.query.create("badds.example", "SOA") + + # Without an NTA, validation fails: SERVFAIL and no NTA EDE. + res = isctest.query.tcp(m, "10.53.0.9") + isctest.check.servfail(res) + assert not has_ede(res, NTA_EDE_CODE), res + + # With an NTA in place, the answer is returned (AD=0) and carries EDE 33. + ns9.rndc("nta badds.example") + try: + res = isctest.query.tcp(m, "10.53.0.9") + isctest.check.noerror(res) + isctest.check.noadflag(res) + isctest.check.ede(res, NTA_EDE_CODE) + finally: + ns9.rndc("nta -remove badds.example") + + # Once the NTA is gone, the disclosure stops too. + res = isctest.query.tcp(m, "10.53.0.9") + isctest.check.servfail(res) + assert not has_ede(res, NTA_EDE_CODE), res diff -Nru bind9-9.20.26/bin/tests/system/nzd2nzf/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/nzd2nzf/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/nzd2nzf/ns1/named.conf.j2 2026-07-20 14:47:53.834846398 +0000 +++ bind9-9.20.29/bin/tests/system/nzd2nzf/ns1/named.conf.j2 2026-09-11 19:41:01.280325705 +0000 @@ -12,21 +12,11 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-query { any; }; recursion no; allow-new-zones yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/optout/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/optout/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/optout/ns2/named.conf.j2 2026-07-20 14:47:53.835846414 +0000 +++ bind9-9.20.29/bin/tests/system/optout/ns2/named.conf.j2 2026-09-11 19:41:01.280325705 +0000 @@ -15,14 +15,11 @@ {% set policy = "optout" if not reconfiged else "nsec" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion no; - dnssec-validation no; - ixfr-from-differences yes; + recursion no; + dnssec-validation no; + ixfr-from-differences yes; sig-signing-nodes 900; sig-signing-signatures 900; }; diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns1/attacker.db bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/attacker.db --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns1/attacker.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/attacker.db 2026-09-11 19:41:01.280325705 +0000 @@ -0,0 +1,5 @@ +$TTL 300 +attacker. IN SOA ns.attacker. hostmaster.attacker. 1 3600 900 2419200 300 +attacker. NS ns.attacker. +ns.attacker. A 10.53.0.1 +*.attacker. A 192.0.2.66 diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns1/example.db bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/example.db --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns1/example.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/example.db 2026-09-11 19:41:01.280325705 +0000 @@ -0,0 +1,4 @@ +$TTL 300 +example. IN SOA ns.attacker. hostmaster.attacker. 1 3600 900 2419200 300 +example. NS ns.attacker. +example. DNAME attacker. diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/named.conf.j2 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/* + * Root server and the "attacker" infrastructure: the nameserver named by + * the out-of-zone delegations in the ns2/ns3 databases, serving an apex + * DNAME for "example." that would poison the "example." namespace in + * a resolver cache if it were ever followed. + */ + +options { + {% include_indented "_common/options.conf.j2" %} + recursion no; + dnssec-validation no; +}; + +{% include "_common/controls.conf.j2" %} + +zone "." { + type primary; + file "root.db"; +}; + +zone "attacker" { + type primary; + file "attacker.db"; +}; + +zone "example" { + type primary; + file "example.db"; +}; diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns1/root.db bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/root.db --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns1/root.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns1/root.db 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,6 @@ +$TTL 300 +. IN SOA a.root-servers.nil. hostmaster.nil. 1 3600 900 2419200 300 +. NS a.root-servers.nil. +a.root-servers.nil. A 10.53.0.1 +attacker. NS ns.attacker. +ns.attacker. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns2/dnamezone.db bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/dnamezone.db --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns2/dnamezone.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/dnamezone.db 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,8 @@ +$TTL 300 +dnamezone.example. IN SOA ns.dnamezone.example. hostmaster.dnamezone.example. 1 3600 900 2419200 300 +dnamezone.example. NS ns.dnamezone.example. +ns.dnamezone.example. A 10.53.0.2 +www.dnamezone.example. A 10.0.0.1 +; Out-of-zone data above the apex, as persisted by a secondary that +; accepted it from its primary in a zone transfer. +example. DNAME attacker. diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/named.conf.j2 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/* Authoritative-only server. */ + +options { + {% include_indented "_common/options.conf.j2" %} + recursion no; + dnssec-validation no; +}; + +{% include "_common/controls.conf.j2" %} + +/* + * Secondary zones whose backup files carry records above the zone apex. + * The primaries are unreachable, so the databases are only ever loaded + * from these files and never replaced by a transfer. + */ + +zone "nszone.example" { + type secondary; + primaries { 10.53.0.100; }; + file "nszone.db"; + masterfile-format text; +}; + +zone "dnamezone.example" { + type secondary; + primaries { 10.53.0.100; }; + file "dnamezone.db"; + masterfile-format text; +}; diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns2/nszone.db bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/nszone.db --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns2/nszone.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns2/nszone.db 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,8 @@ +$TTL 300 +nszone.example. IN SOA ns.nszone.example. hostmaster.nszone.example. 1 3600 900 2419200 300 +nszone.example. NS ns.nszone.example. +ns.nszone.example. A 10.53.0.2 +www.nszone.example. A 10.0.0.1 +; Out-of-zone data above the apex, as persisted by a secondary that +; accepted it from its primary in a zone transfer. +example. NS ns.attacker. diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns3/dnamezone.db bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/dnamezone.db --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns3/dnamezone.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/dnamezone.db 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,8 @@ +$TTL 300 +dnamezone.example. IN SOA ns.dnamezone.example. hostmaster.dnamezone.example. 1 3600 900 2419200 300 +dnamezone.example. NS ns.dnamezone.example. +ns.dnamezone.example. A 10.53.0.2 +www.dnamezone.example. A 10.0.0.1 +; Out-of-zone data above the apex, as persisted by a secondary that +; accepted it from its primary in a zone transfer. +example. DNAME attacker. diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/named.conf.j2 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/* Recursive server that is also authoritative for the affected zones. */ + +options { + {% include_indented "_common/options.conf.j2" %} + recursion yes; + dnssec-validation no; +}; + +{% include "_common/controls.conf.j2" %} +{% include "_common/root.hint.conf" %} + +/* + * Secondary zones whose backup files carry records above the zone apex. + * The primaries are unreachable, so the databases are only ever loaded + * from these files and never replaced by a transfer. + */ + +zone "nszone.example" { + type secondary; + primaries { 10.53.0.100; }; + file "nszone.db"; + masterfile-format text; +}; + +zone "dnamezone.example" { + type secondary; + primaries { 10.53.0.100; }; + file "dnamezone.db"; + masterfile-format text; +}; diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns3/nszone.db bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/nszone.db --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/ns3/nszone.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/ns3/nszone.db 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,8 @@ +$TTL 300 +nszone.example. IN SOA ns.nszone.example. hostmaster.nszone.example. 1 3600 900 2419200 300 +nszone.example. NS ns.nszone.example. +ns.nszone.example. A 10.53.0.2 +www.nszone.example. A 10.0.0.1 +; Out-of-zone data above the apex, as persisted by a secondary that +; accepted it from its primary in a zone transfer. +example. NS ns.attacker. diff -Nru bind9-9.20.26/bin/tests/system/outofzone_zonecut/tests_outofzone_zonecut.py bind9-9.20.29/bin/tests/system/outofzone_zonecut/tests_outofzone_zonecut.py --- bind9-9.20.26/bin/tests/system/outofzone_zonecut/tests_outofzone_zonecut.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/outofzone_zonecut/tests_outofzone_zonecut.py 2026-09-11 19:41:01.281325729 +0000 @@ -0,0 +1,102 @@ +# 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. + +""" +A zone database that contains nodes above the zone apex (for example a +secondary backup file written by a version that accepted out-of-zone +data in zone transfers) must not let those nodes act as zone cuts: +queries for names inside the zone have to be answered authoritatively +from the zone, and a recursive server must not follow the bogus +delegation or DNAME. +""" + +import dns.name +import dns.rdataclass +import dns.rdatatype +import pytest + +import isctest + +ZONES = { + "nszone.example.": "NS", + "dnamezone.example.": "DNAME", +} + + +def check_in_zone(response, zone): + """Nothing in the response may be owned by a name outside the zone.""" + origin = dns.name.from_text(zone) + for section in (response.answer, response.authority, response.additional): + for rrset in section: + assert rrset.name.is_subdomain( + origin + ), f"{rrset.name} {dns.rdatatype.to_text(rrset.rdtype)} leaked into the response:\n{response}" + + +def check_authoritative_a(response, zone): + isctest.check.noerror(response) + isctest.check.aaflag(response) + check_in_zone(response, zone) + rrset = response.get_rrset( + response.answer, + dns.name.from_text(f"www.{zone}"), + dns.rdataclass.IN, + dns.rdatatype.A, + ) + assert rrset is not None, f"no A record in the answer:\n{response}" + assert [str(rdata) for rdata in rrset] == ["10.0.0.1"] + + +def check_authoritative_soa(response, zone): + isctest.check.noerror(response) + isctest.check.aaflag(response) + check_in_zone(response, zone) + rrset = response.get_rrset( + response.answer, + dns.name.from_text(zone), + dns.rdataclass.IN, + dns.rdatatype.SOA, + ) + assert rrset is not None, f"no SOA record in the answer:\n{response}" + + +@pytest.mark.parametrize("zone", ZONES.keys(), ids=ZONES.values()) +@pytest.mark.parametrize("server", ["ns2", "ns3"]) +def test_above_apex_node_is_not_a_zone_cut(server, zone, request): + ns = request.getfixturevalue(server) + + msg = isctest.query.create(f"www.{zone}", "A", rd=False) + check_authoritative_a(isctest.query.udp(msg, ns.ip), zone) + + msg = isctest.query.create(zone, "SOA", rd=False) + check_authoritative_soa(isctest.query.udp(msg, ns.ip), zone) + + +@pytest.mark.parametrize("zone", ZONES.keys(), ids=ZONES.values()) +def test_resolver_does_not_follow_above_apex_node(ns3, zone): + # A recursive query for a name in the zone is answered from the zone + # itself; the out-of-zone NS/DNAME must not start a recursion towards + # the nameserver it names. + msg = isctest.query.create(f"www.{zone}", "A") + check_authoritative_a(isctest.query.udp(msg, ns3.ip), zone) + + # Had the bogus delegation been followed, the "attacker" server would + # have supplied an "example." DNAME that is now in the cache and + # rewrites every sibling name under "example.". + msg = isctest.query.create("sibling.example.", "A", rd=False) + response = isctest.query.udp(msg, ns3.ip) + isctest.check.empty_answer(response) + for section in (response.answer, response.authority, response.additional): + for rrset in section: + assert rrset.rdtype not in ( + dns.rdatatype.DNAME, + dns.rdatatype.CNAME, + ), f"poisoned cache entry:\n{response}" diff -Nru bind9-9.20.26/bin/tests/system/padding/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/padding/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/padding/ns1/named.conf.j2 2026-07-20 14:47:53.835846414 +0000 +++ bind9-9.20.29/bin/tests/system/padding/ns1/named.conf.j2 2026-09-11 19:41:01.282325753 +0000 @@ -12,26 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/padding/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/padding/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/padding/ns2/named.conf.j2 2026-07-20 14:47:53.836846429 +0000 +++ bind9-9.20.29/bin/tests/system/padding/ns2/named.conf.j2 2026-09-11 19:41:01.282325753 +0000 @@ -11,33 +11,16 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} send-cookie yes; response-padding { !10.53.0.8; any; } block-size 64; dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/padding/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/padding/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/padding/ns3/named.conf.j2 2026-07-20 14:47:53.836846429 +0000 +++ bind9-9.20.29/bin/tests/system/padding/ns3/named.conf.j2 2026-09-11 19:41:01.282325753 +0000 @@ -12,16 +12,7 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; @@ -30,16 +21,6 @@ padding 64; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/padding/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/padding/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/padding/ns4/named.conf.j2 2026-07-20 14:47:53.836846429 +0000 +++ bind9-9.20.29/bin/tests/system/padding/ns4/named.conf.j2 2026-09-11 19:41:01.282325753 +0000 @@ -12,16 +12,7 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; @@ -30,16 +21,6 @@ padding 64; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/pending/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/pending/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/pending/ns1/named.conf.j2 2026-07-20 14:47:53.836846429 +0000 +++ bind9-9.20.29/bin/tests/system/pending/ns1/named.conf.j2 2026-09-11 19:41:01.282325753 +0000 @@ -14,17 +14,13 @@ include "trusted.conf"; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/pending/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/pending/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/pending/ns2/named.conf.j2 2026-07-20 14:47:53.837846445 +0000 +++ bind9-9.20.29/bin/tests/system/pending/ns2/named.conf.j2 2026-09-11 19:41:01.283325777 +0000 @@ -16,22 +16,14 @@ include "trusted.conf"; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/pending/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/pending/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/pending/ns3/named.conf.j2 2026-07-20 14:47:53.837846445 +0000 +++ bind9-9.20.29/bin/tests/system/pending/ns3/named.conf.j2 2026-09-11 19:41:01.283325777 +0000 @@ -16,22 +16,15 @@ include "trusted.conf"; options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "mail.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/pending/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/pending/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/pending/ns4/named.conf.j2 2026-07-20 14:47:53.837846445 +0000 +++ bind9-9.20.29/bin/tests/system/pending/ns4/named.conf.j2 2026-09-11 19:41:01.283325777 +0000 @@ -14,18 +14,10 @@ include "trusted.conf"; options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/pipelined/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/pipelined/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/pipelined/ns1/named.conf.j2 2026-07-20 14:47:53.838846461 +0000 +++ bind9-9.20.29/bin/tests/system/pipelined/ns1/named.conf.j2 2026-09-11 19:41:01.284325801 +0000 @@ -12,26 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/pipelined/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/pipelined/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/pipelined/ns2/named.conf.j2 2026-07-20 14:47:53.838846461 +0000 +++ bind9-9.20.29/bin/tests/system/pipelined/ns2/named.conf.j2 2026-09-11 19:41:01.284325801 +0000 @@ -12,32 +12,14 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "examplea" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/pipelined/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/pipelined/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/pipelined/ns3/named.conf.j2 2026-07-20 14:47:53.838846461 +0000 +++ bind9-9.20.29/bin/tests/system/pipelined/ns3/named.conf.j2 2026-09-11 19:41:01.285325824 +0000 @@ -12,32 +12,14 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "exampleb" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/pipelined/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/pipelined/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/pipelined/ns4/named.conf.j2 2026-07-20 14:47:53.838846461 +0000 +++ bind9-9.20.29/bin/tests/system/pipelined/ns4/named.conf.j2 2026-09-11 19:41:01.285325824 +0000 @@ -12,30 +12,11 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/proxy/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/proxy/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/proxy/ns1/named.conf.j2 2026-07-20 14:47:53.839846476 +0000 +++ bind9-9.20.29/bin/tests/system/proxy/ns1/named.conf.j2 2026-09-11 19:41:01.285325824 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,29 +19,30 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic test - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; - listen-on port @EXTRAPORT1@ proxy plain { 10.53.0.1; }; + listen-on port @EXTRAPORT1@ proxy plain { @ns.ip@; }; listen-on port @EXTRAPORT1@ proxy plain { 10.53.0.2; }; - listen-on port @TLSPORT@ proxy encrypted tls self-signed { 10.53.0.1; }; - listen-on port @EXTRAPORT2@ proxy plain tls self-signed { 10.53.0.1; }; - listen-on port @HTTPSPORT@ proxy encrypted tls self-signed http default { 10.53.0.1; }; - listen-on port @EXTRAPORT3@ proxy plain tls self-signed http default { 10.53.0.1; }; - listen-on port @HTTPPORT@ proxy plain tls none http default { 10.53.0.1; }; + listen-on port @TLSPORT@ proxy encrypted tls self-signed { @ns.ip@; }; + listen-on port @EXTRAPORT2@ proxy plain tls self-signed { @ns.ip@; }; + listen-on port @HTTPSPORT@ proxy encrypted tls self-signed http default { @ns.ip@; }; + listen-on port @EXTRAPORT3@ proxy plain tls self-signed http default { @ns.ip@; }; + listen-on port @HTTPPORT@ proxy plain tls none http default { @ns.ip@; }; - listen-on-v6 port @EXTRAPORT1@ proxy plain { fd92:7065:b8e:ffff::1; }; + listen-on-v6 port @EXTRAPORT1@ proxy plain { @ns.ip6@; }; listen-on-v6 port @EXTRAPORT1@ proxy plain { fd92:7065:b8e:ffff::2; }; - listen-on-v6 port @TLSPORT@ proxy encrypted tls self-signed { fd92:7065:b8e:ffff::1; }; - listen-on-v6 port @EXTRAPORT2@ proxy plain tls self-signed { fd92:7065:b8e:ffff::1; }; - listen-on-v6 port @HTTPSPORT@ proxy encrypted tls self-signed http default { fd92:7065:b8e:ffff::1; }; - listen-on-v6 port @EXTRAPORT3@ proxy plain tls self-signed http default { fd92:7065:b8e:ffff::1; }; - listen-on-v6 port @HTTPPORT@ proxy plain tls none http default { fd92:7065:b8e:ffff::1; }; + listen-on-v6 port @TLSPORT@ proxy encrypted tls self-signed { @ns.ip6@; }; + listen-on-v6 port @EXTRAPORT2@ proxy plain tls self-signed { @ns.ip6@; }; + listen-on-v6 port @HTTPSPORT@ proxy encrypted tls self-signed http default { @ns.ip6@; }; + listen-on-v6 port @EXTRAPORT3@ proxy plain tls self-signed http default { @ns.ip6@; }; + listen-on-v6 port @HTTPPORT@ proxy plain tls none http default { @ns.ip6@; }; allow-proxy { 10.53.0.10; fd92:7065:b8e:ffff::10; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; recursion no; notify explicit; @@ -54,7 +51,6 @@ tcp-initial-timeout 1200; }; - zone "example0" { type primary; file "example.db"; @@ -73,7 +69,7 @@ file "example.db"; # allow the real addresses only so that we can test LOCAL requests allow-query { 10.53.0.10; fd92:7065:b8e:ffff::10; }; - allow-query-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-query-on { @ns.ip@; @ns.ip6@; }; }; # Let's define some zones that will help us verify that ports diff -Nru bind9-9.20.26/bin/tests/system/proxy/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/proxy/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/proxy/ns3/named.conf.j2 2026-07-20 14:47:53.839846476 +0000 +++ bind9-9.20.29/bin/tests/system/proxy/ns3/named.conf.j2 2026-09-11 19:41:01.285325824 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,24 +19,25 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic test - listen-on port @PORT@ { 10.53.0.3; }; + listen-on { @ns.ip@; }; - listen-on port @EXTRAPORT1@ proxy plain { 10.53.0.3; }; - listen-on port @TLSPORT@ proxy encrypted tls self-signed { 10.53.0.3; }; - listen-on port @EXTRAPORT2@ proxy plain tls self-signed { 10.53.0.3; }; - listen-on port @HTTPSPORT@ proxy encrypted tls self-signed http default { 10.53.0.3; }; - listen-on port @EXTRAPORT3@ proxy plain tls self-signed http default { 10.53.0.3; }; - listen-on port @HTTPPORT@ proxy plain tls none http default { 10.53.0.3; }; - - listen-on-v6 port @EXTRAPORT1@ proxy plain { fd92:7065:b8e:ffff::3; }; - listen-on-v6 port @TLSPORT@ proxy encrypted tls self-signed { fd92:7065:b8e:ffff::3; }; - listen-on-v6 port @EXTRAPORT2@ proxy plain tls self-signed { fd92:7065:b8e:ffff::3; }; - listen-on-v6 port @HTTPSPORT@ proxy encrypted tls self-signed http default { fd92:7065:b8e:ffff::3; }; - listen-on-v6 port @EXTRAPORT3@ proxy plain tls self-signed http default { fd92:7065:b8e:ffff::3; }; - listen-on-v6 port @HTTPPORT@ proxy plain tls none http default { fd92:7065:b8e:ffff::3; }; + listen-on port @EXTRAPORT1@ proxy plain { @ns.ip@; }; + listen-on port @TLSPORT@ proxy encrypted tls self-signed { @ns.ip@; }; + listen-on port @EXTRAPORT2@ proxy plain tls self-signed { @ns.ip@; }; + listen-on port @HTTPSPORT@ proxy encrypted tls self-signed http default { @ns.ip@; }; + listen-on port @EXTRAPORT3@ proxy plain tls self-signed http default { @ns.ip@; }; + listen-on port @HTTPPORT@ proxy plain tls none http default { @ns.ip@; }; + + listen-on-v6 port @EXTRAPORT1@ proxy plain { @ns.ip6@; }; + listen-on-v6 port @TLSPORT@ proxy encrypted tls self-signed { @ns.ip6@; }; + listen-on-v6 port @EXTRAPORT2@ proxy plain tls self-signed { @ns.ip6@; }; + listen-on-v6 port @HTTPSPORT@ proxy encrypted tls self-signed http default { @ns.ip6@; }; + listen-on-v6 port @EXTRAPORT3@ proxy plain tls self-signed http default { @ns.ip6@; }; + listen-on-v6 port @HTTPPORT@ proxy plain tls none http default { @ns.ip6@; }; recursion no; notify explicit; @@ -49,7 +46,6 @@ tcp-initial-timeout 1200; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/proxy/prereq.sh bind9-9.20.29/bin/tests/system/proxy/prereq.sh --- bind9-9.20.26/bin/tests/system/proxy/prereq.sh 2026-07-20 14:47:53.839846476 +0000 +++ bind9-9.20.29/bin/tests/system/proxy/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -$FEATURETEST --with-libnghttp2 || { - echo_i "This test requires libnghttp2 support." >&2 - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/proxy/tests_sh_proxy.py bind9-9.20.29/bin/tests/system/proxy/tests_sh_proxy.py --- bind9-9.20.26/bin/tests/system/proxy/tests_sh_proxy.py 2026-07-20 14:47:53.840846492 +0000 +++ bind9-9.20.29/bin/tests/system/proxy/tests_sh_proxy.py 2026-09-11 19:41:01.286325849 +0000 @@ -11,13 +11,20 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "ns*/example.db", ] ) +pytestmark = [ + isctest.mark.with_libnghttp2, + EXTRA_ARTIFACTS, +] + def test_proxy(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/qmin/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/qmin/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/qmin/ns1/named.conf.j2 2026-07-20 14:47:53.841846507 +0000 +++ bind9-9.20.29/bin/tests/system/qmin/ns1/named.conf.j2 2026-09-11 19:41:01.312326471 +0000 @@ -14,18 +14,13 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/qmin/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/qmin/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/qmin/ns5/named.conf.j2 2026-07-20 14:47:53.842846523 +0000 +++ bind9-9.20.29/bin/tests/system/qmin/ns5/named.conf.j2 2026-09-11 19:41:01.312326471 +0000 @@ -14,14 +14,7 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} qname-minimization disabled; querylog yes; resolver-query-timeout 30000; # 30 seconds @@ -30,19 +23,9 @@ fetches-per-zone 40; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "in-addr.arpa" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/qmin/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/qmin/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/qmin/ns6/named.conf.j2 2026-07-20 14:47:53.842846523 +0000 +++ bind9-9.20.29/bin/tests/system/qmin/ns6/named.conf.j2 2026-09-11 19:41:01.313326495 +0000 @@ -14,30 +14,13 @@ // NS6 options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} qname-minimization strict; querylog yes; resolver-query-timeout 30000; # 30 seconds dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/qmin/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/qmin/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/qmin/ns7/named.conf.j2 2026-07-20 14:47:53.842846523 +0000 +++ bind9-9.20.29/bin/tests/system/qmin/ns7/named.conf.j2 2026-09-11 19:41:01.313326495 +0000 @@ -14,14 +14,7 @@ // NS7 options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} qname-minimization relaxed; querylog yes; resolver-query-timeout 30000; # 30 seconds @@ -29,19 +22,9 @@ disable-empty-zone 10.in-addr.arpa; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "fwd." IN { type forward; diff -Nru bind9-9.20.26/bin/tests/system/qpcache_rrsig_any/ans3/ans.py bind9-9.20.29/bin/tests/system/qpcache_rrsig_any/ans3/ans.py --- bind9-9.20.26/bin/tests/system/qpcache_rrsig_any/ans3/ans.py 2026-07-20 14:47:53.842846523 +0000 +++ bind9-9.20.29/bin/tests/system/qpcache_rrsig_any/ans3/ans.py 2026-09-11 19:41:01.313326495 +0000 @@ -9,17 +9,11 @@ See the COPYRIGHT file distributed with this work for additional information regarding copyright ownership. - -For any query, returns a hand-crafted RRSIG whose Type-Covered field -is selected by the leftmost label of QNAME. The label is parsed as a -DNS type via `dns.rdatatype.from_text()`, so the resolver can be -probed with any meta-type by querying e.g. `any.attacker.test.`, -`axfr.attacker.test.`, `tsig.attacker.test.`, etc. """ from collections.abc import AsyncGenerator -import dns.flags +import dns.name import dns.rcode import dns.rdataclass import dns.rdatatype @@ -28,34 +22,65 @@ from isctest.asyncserver import ( AsyncDnsServer, DnsResponseSend, + QnameHandler, QueryContext, + ResponseAction, ResponseHandler, + StaticResponseHandler, ) -class RrsigCoversHandler(ResponseHandler): +def rrsig_covering( + owner: dns.name.Name | str, covered: dns.rdatatype.RdataType +) -> dns.rrset.RRset: + return dns.rrset.from_text( + owner, + 3600, + dns.rdataclass.IN, + dns.rdatatype.RRSIG, + f"TYPE{int(covered)} 8 2 3600 20300101000000 20200101000000 " + "12345 attacker.test. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + ) + + +class RrsigCoversRrsigHandler(QnameHandler, StaticResponseHandler): + """ + An RRSIG covering RRSIG only trips the QP-cache RRSIG-pairing assertion when + a second RRSIG header shares the owner name, so serve two ordinary RRSIGs + (covering A and AAAA) alongside the RRSIG-covers-RRSIG poison. A lone + RRSIG-covers-RRSIG record is cached harmlessly. + """ + + qnames = ["rrsig.attacker.test."] + answer = [ + rrsig_covering(qnames[0], dns.rdatatype.A), + rrsig_covering(qnames[0], dns.rdatatype.AAAA), + rrsig_covering(qnames[0], dns.rdatatype.RRSIG), + ] + + +class RrsigCoversTypeHandler(ResponseHandler): + """ + Answer any other query with a single RRSIG whose Type-Covered field is the + leftmost QNAME label parsed as a DNS type, so the resolver can be probed + with any meta-type (e.g. any.attacker.test., axfr.attacker.test.). + """ + async def get_responses( self, qctx: QueryContext - ) -> AsyncGenerator[DnsResponseSend, None]: - covers_label = qctx.qname.labels[0].decode("ascii").upper() - covers = dns.rdatatype.from_text(covers_label) - rrset = dns.rrset.from_text( - qctx.qname, - 3600, - dns.rdataclass.IN, - dns.rdatatype.RRSIG, - f"TYPE{int(covers)} 8 2 3600 20300101000000 20200101000000 " - "12345 attacker.test. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - ) - qctx.response.set_rcode(dns.rcode.NOERROR) - qctx.response.flags |= dns.flags.AA - qctx.response.answer.append(rrset) + ) -> AsyncGenerator[ResponseAction, None]: + covered_label = qctx.qname.labels[0].decode("ascii").upper() + covered = dns.rdatatype.from_text(covered_label) + qctx.response.answer.append(rrsig_covering(qctx.qname, covered)) yield DnsResponseSend(qctx.response) def main() -> None: - server = AsyncDnsServer() - server.install_response_handler(RrsigCoversHandler()) + server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR) + server.install_response_handlers( + RrsigCoversRrsigHandler(), + RrsigCoversTypeHandler(), + ) server.run() diff -Nru bind9-9.20.26/bin/tests/system/qpcache_rrsig_any/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/qpcache_rrsig_any/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/qpcache_rrsig_any/ns2/named.conf.j2 2026-07-20 14:47:53.843846538 +0000 +++ bind9-9.20.29/bin/tests/system/qpcache_rrsig_any/ns2/named.conf.j2 2026-09-11 19:41:01.313326495 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/query_source/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/query_source/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/query_source/ns1/named.conf.j2 2026-07-20 14:47:53.843846538 +0000 +++ bind9-9.20.29/bin/tests/system/query_source/ns1/named.conf.j2 2026-09-11 19:41:01.314326519 +0000 @@ -11,24 +11,15 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on-v6 { fd92:7065:b8e:ffff::1; }; - listen-on { 10.53.0.1; }; + {% include_indented "_common/options/server.conf.j2" %} + {% include_indented "_common/options/listen-dual.conf.j2" %} recursion no; dnssec-validation no; - query-source 10.53.0.1; - query-source-v6 fd92:7065:b8e:ffff::1; + query-source @ns.ip@; + query-source-v6 @ns.ip6@; }; zone "." { diff -Nru bind9-9.20.26/bin/tests/system/query_source/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/query_source/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/query_source/ns2/named.conf.j2 2026-07-20 14:47:53.843846538 +0000 +++ bind9-9.20.29/bin/tests/system/query_source/ns2/named.conf.j2 2026-09-11 19:41:01.314326519 +0000 @@ -11,24 +11,14 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; - recursion yes; + {% include_indented "_common/options/server.conf.j2" %} + {% include_indented "_common/options/listen-dual.conf.j2" %} dnssec-validation no; query-source none; - query-source-v6 fd92:7065:b8e:ffff::2; + query-source-v6 @ns.ip6@; }; zone "." { diff -Nru bind9-9.20.26/bin/tests/system/query_source/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/query_source/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/query_source/ns3/named.conf.j2 2026-07-20 14:47:53.843846538 +0000 +++ bind9-9.20.29/bin/tests/system/query_source/ns3/named.conf.j2 2026-09-11 19:41:01.314326519 +0000 @@ -11,27 +11,14 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { fd92:7065:b8e:ffff::3; }; - recursion yes; + {% include_indented "_common/options/server.conf.j2" %} + {% include_indented "_common/options/listen-dual.conf.j2" %} dnssec-validation no; query-source-v6 none; - query-source 10.53.0.3; + query-source @ns.ip@; }; -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/query_source/ns3/root.hint bind9-9.20.29/bin/tests/system/query_source/ns3/root.hint --- bind9-9.20.26/bin/tests/system/query_source/ns3/root.hint 2026-07-20 14:47:53.843846538 +0000 +++ bind9-9.20.29/bin/tests/system/query_source/ns3/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/query_source/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/query_source/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/query_source/ns4/named.conf.j2 2026-07-20 14:47:53.843846538 +0000 +++ bind9-9.20.29/bin/tests/system/query_source/ns4/named.conf.j2 2026-09-11 19:41:01.314326519 +0000 @@ -11,27 +11,14 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { fd92:7065:b8e:ffff::4; }; - recursion yes; + {% include_indented "_common/options/server.conf.j2" %} + {% include_indented "_common/options/listen-dual.conf.j2" %} dnssec-validation no; query-source none; - query-source-v6 fd92:7065:b8e:ffff::4; + query-source-v6 @ns.ip6@; }; -zone "." { - type hint; - file "root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/query_source/ns4/root.hint bind9-9.20.29/bin/tests/system/query_source/ns4/root.hint --- bind9-9.20.26/bin/tests/system/query_source/ns4/root.hint 2026-07-20 14:47:53.843846538 +0000 +++ bind9-9.20.29/bin/tests/system/query_source/ns4/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/query_source/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/query_source/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/query_source/ns5/named.conf.j2 2026-07-20 14:47:53.844846554 +0000 +++ bind9-9.20.29/bin/tests/system/query_source/ns5/named.conf.j2 2026-09-11 19:41:01.314326519 +0000 @@ -11,23 +11,13 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { fd92:7065:b8e:ffff::5; }; - recursion yes; + {% include_indented "_common/options/server.conf.j2" %} + {% include_indented "_common/options/listen-dual.conf.j2" %} dnssec-validation no; - query-source 10.53.0.5; + query-source @ns.ip@; query-source-v6 none; }; diff -Nru bind9-9.20.26/bin/tests/system/randomizens/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/randomizens/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/randomizens/ns1/named.conf.j2 2026-07-20 14:47:53.844846554 +0000 +++ bind9-9.20.29/bin/tests/system/randomizens/ns1/named.conf.j2 2026-09-11 19:41:01.315326543 +0000 @@ -12,17 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/randomizens/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/randomizens/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/randomizens/ns2/named.conf.j2 2026-07-20 14:47:53.844846554 +0000 +++ bind9-9.20.29/bin/tests/system/randomizens/ns2/named.conf.j2 2026-09-11 19:41:01.315326543 +0000 @@ -12,25 +12,11 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/randomizens/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/randomizens/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/randomizens/ns3/named.conf.j2 2026-07-20 14:47:53.845846569 +0000 +++ bind9-9.20.29/bin/tests/system/randomizens/ns3/named.conf.j2 2026-09-11 19:41:01.315326543 +0000 @@ -12,25 +12,11 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "1st" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/randomizens/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/randomizens/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/randomizens/ns4/named.conf.j2 2026-07-20 14:47:53.845846569 +0000 +++ bind9-9.20.29/bin/tests/system/randomizens/ns4/named.conf.j2 2026-09-11 19:41:01.315326543 +0000 @@ -12,25 +12,11 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/randomizens/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/randomizens/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/randomizens/ns5/named.conf.j2 2026-07-20 14:47:53.845846569 +0000 +++ bind9-9.20.29/bin/tests/system/randomizens/ns5/named.conf.j2 2026-09-11 19:41:01.316326567 +0000 @@ -12,25 +12,11 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "1st" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/randomizens/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/randomizens/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/randomizens/ns6/named.conf.j2 2026-07-20 14:47:53.846846585 +0000 +++ bind9-9.20.29/bin/tests/system/randomizens/ns6/named.conf.j2 2026-09-11 19:41:01.316326567 +0000 @@ -13,27 +13,10 @@ options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ans2/ans.pl bind9-9.20.29/bin/tests/system/reclimit/ans2/ans.pl --- bind9-9.20.26/bin/tests/system/reclimit/ans2/ans.pl 2026-07-20 14:47:53.846846585 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ans2/ans.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,235 +0,0 @@ -#!/usr/bin/env perl - -# 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. - -use strict; -use warnings; - -use IO::File; -use IO::Socket; -use Net::DNS; - -my $localaddr = "10.53.0.2"; -my $limit = getlimit(); -my $no_more_waiting = 0; -my @delayed_response; -my $timeout; - -my $localport = int($ENV{'PORT'}); -if (!$localport) { $localport = 5300; } - -my $udpsock = IO::Socket::INET->new(LocalAddr => "$localaddr", - LocalPort => $localport, Proto => "udp", Reuse => 1) or die "$!"; - -my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; -print $pidf "$$\n" or die "cannot write pid file: $!"; -$pidf->close or die "cannot close pid file: $!"; -sub rmpid { unlink "ans.pid"; exit 1; }; - -$SIG{INT} = \&rmpid; -$SIG{TERM} = \&rmpid; - -my $count = 0; -my $send_response = 0; - -sub getlimit { - if ( -e "ans.limit") { - open(FH, "<", "ans.limit"); - my $line = ; - chomp $line; - close FH; - if ($line =~ /^\d+$/) { - return $line; - } - } - - return 0; -} - -# If $wait == 0 is returned, returned reply will be sent immediately. -# If $wait == 1 is returned, sending the returned reply might be delayed; see -# comments inside handle_UDP() for details. -sub reply_handler { - my ($qname, $qclass, $qtype) = @_; - my ($rcode, @ans, @auth, @add, $wait); - - print ("request: $qname/$qtype\n"); - STDOUT->flush(); - - $wait = 0; - $count += 1; - - if ($qname eq "count" ) { - if ($qtype eq "TXT") { - my ($ttl, $rdata) = (0, "$count"); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - print ("\tcount: $count\n"); - } - $rcode = "NOERROR"; - } elsif ($qname eq "reset" ) { - $count = 0; - $send_response = 0; - $limit = getlimit(); - $rcode = "NOERROR"; - print ("\tlimit: $limit\n"); - } elsif ($qname eq "direct.example.org" ) { - if ($qtype eq "A") { - my ($ttl, $rdata) = (3600, $localaddr); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "indirect1.example.org" || - $qname eq "indirect2.example.org" || - $qname eq "indirect3.example.org" || - $qname eq "indirect4.example.org" || - $qname eq "indirect5.example.org" || - $qname eq "indirect6.example.org" || - $qname eq "indirect7.example.org" || - $qname eq "indirect8.example.org") { - if (! $send_response) { - my $rr = new Net::DNS::RR("$qname 86400 $qclass NS ns1.1.example.org"); - push @auth, $rr; - } elsif ($qtype eq "A") { - my ($ttl, $rdata) = (3600, $localaddr); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname =~ /^ns1\.(\d+)\.example\.org$/) { - my $next = $1 + 1; - $wait = 1; - if ($limit == 0 || (! $send_response && $next <= $limit)) { - my $rr = new Net::DNS::RR("$1.example.org 86400 $qclass NS ns1.$next.example.org"); - push @auth, $rr; - } else { - $send_response = 1; - if ($qtype eq "A") { - my ($ttl, $rdata) = (3600, "10.53.0.4"); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - print("\tresponse: $qname $ttl $qclass $qtype $rdata\n"); - push @ans, $rr; - } - } - $rcode = "NOERROR"; - } elsif ($qname eq "direct.example.net" ) { - if ($qtype eq "A") { - my ($ttl, $rdata) = (3600, $localaddr); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - } - $rcode = "NOERROR"; - } elsif( $qname =~ /^ns1\.(\d+)\.example\.net$/ ) { - my $next = ($1 + 1) * 16; - for (my $i = 1; $i < 16; $i++) { - my $s = $next + $i; - my $rr = new Net::DNS::RR("$1.example.net 86400 $qclass NS ns1.$s.example.net"); - push @auth, $rr; - $rr = new Net::DNS::RR("ns1.$s.example.net 86400 $qclass A 10.53.0.7"); - push @add, $rr; - } - $rcode = "NOERROR"; - } else { - $rcode = "NXDOMAIN"; - } - - return ($rcode, \@ans, \@auth, \@add, $wait); -} - -sub handleUDP { - my ($buf, $peer) = @_; - my ($request, $rcode, $ans, $auth, $add, $wait); - - $request = new Net::DNS::Packet(\$buf, 0); - $@ and die $@; - - my ($question) = $request->question; - my $qname = $question->qname; - my $qclass = $question->qclass; - my $qtype = $question->qtype; - - ($rcode, $ans, $auth, $add, $wait) = reply_handler($qname, $qclass, $qtype); - - my $reply = $request->reply(); - - $reply->header->rcode($rcode); - $reply->header->aa(@$ans ? 1 : 0); - $reply->header->id($request->header->id); - $reply->{answer} = $ans if $ans; - $reply->{authority} = $auth if $auth; - $reply->{additional} = $add if $add; - - if ($wait) { - # reply_handler() asked us to delay sending this reply until - # another reply with $wait == 1 is generated or a timeout - # occurs. - if (@delayed_response) { - # A delayed reply is already queued, so we can now send - # both the delayed reply and the current reply. - send_delayed_response(); - return $reply; - } elsif ($no_more_waiting) { - # It was determined before that there is no point in - # waiting for "accompanying" queries. Thus, send the - # current reply immediately. - return $reply; - } else { - # No delayed reply is queued and the client is expected - # to send an "accompanying" query shortly. Do not send - # the current reply right now, just save it for later - # and wait for an "accompanying" query to be received. - @delayed_response = ($reply, $peer); - $timeout = 0.5; - return; - } - } else { - # Send reply immediately. - return $reply; - } -} - -sub send_delayed_response { - my ($reply, $peer) = @delayed_response; - # Truncation to 512 bytes is required for triggering "NS explosion" on - # builds without IPv6 support - $udpsock->send($reply->data(512), 0, $peer); - undef @delayed_response; - undef $timeout; -} - -# Main -my $rin; -my $rout; -for (;;) { - $rin = ''; - vec($rin, fileno($udpsock), 1) = 1; - - select($rout = $rin, undef, undef, $timeout); - - if (vec($rout, fileno($udpsock), 1)) { - my ($buf, $peer, $reply); - $udpsock->recv($buf, 512); - $peer = $udpsock->peername(); - $reply = handleUDP($buf, $peer); - # Truncation to 512 bytes is required for triggering "NS - # explosion" on builds without IPv6 support - $udpsock->send($reply->data(512), 0, $peer) if $reply; - } else { - # An "accompanying" query was expected to come in, but did not. - # Assume the client never sends "accompanying" queries to - # prevent pointlessly waiting for them ever again. - $no_more_waiting = 1; - # Send the delayed reply to the query which caused us to wait. - send_delayed_response(); - } -} diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ans2/ans.py bind9-9.20.29/bin/tests/system/reclimit/ans2/ans.py --- bind9-9.20.26/bin/tests/system/reclimit/ans2/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ans2/ans.py 2026-09-11 19:41:01.316326567 +0000 @@ -0,0 +1,79 @@ +""" +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. +""" + +from collections.abc import AsyncGenerator + +import dns.rcode + +from isctest.asyncserver import ( + ControllableAsyncDnsServer, + DnsResponseSend, + QueryContext, +) + +from ..reclimit_ans import ( + DirectExampleHandler, + FallbackNxdomainHandler, + IndirectExampleOrgHandler, + LimitControlCommand, + Ns1ExampleOrgHandler, + ReclimitHandler, + ReclimitStateHandler, + a, + is_ns1_example, + ns, +) + + +class Ns1ExampleNetHandler(ReclimitHandler): + def match(self, qctx: QueryContext) -> bool: + return is_ns1_example(qctx.qname, "net") + + async def _get_counted_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + current_ns_number = int(qctx.qname.labels[1]) + next_ns_block_start = (current_ns_number + 1) * 16 + for offset in range(1, 16): + target_ns_number = next_ns_block_start + offset + qctx.response.authority.append( + ns( + f"{current_ns_number}.example.net.", + f"ns1.{target_ns_number}.example.net.", + ) + ) + qctx.response.additional.append( + a(f"ns1.{target_ns_number}.example.net.", 7) + ) + + yield DnsResponseSend(qctx.response, authoritative=False) + + +def main() -> None: + server = ControllableAsyncDnsServer( + default_aa=True, default_rcode=dns.rcode.NOERROR + ) + server.install_response_handlers( + state_handler := ReclimitStateHandler(indirect_send_response_default=False), + DirectExampleHandler(state_handler, 2), + IndirectExampleOrgHandler(state_handler, 2), + Ns1ExampleOrgHandler(state_handler), + Ns1ExampleNetHandler(state_handler), + FallbackNxdomainHandler(state_handler), + ) + server.install_control_command(LimitControlCommand(state_handler)) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ans4/ans.pl bind9-9.20.29/bin/tests/system/reclimit/ans4/ans.pl --- bind9-9.20.26/bin/tests/system/reclimit/ans4/ans.pl 2026-07-20 14:47:53.846846585 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ans4/ans.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,240 +0,0 @@ -#!/usr/bin/env perl - -# 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. - -use strict; -use warnings; - -use IO::File; -use IO::Socket; -use Net::DNS; - -my $localaddr = "10.53.0.4"; -my $limit = getlimit(); -my $no_more_waiting = 0; -my @delayed_response; -my $timeout; - -my $localport = int($ENV{'PORT'}); -if (!$localport) { $localport = 5300; } - -my $udpsock = IO::Socket::INET->new(LocalAddr => "$localaddr", - LocalPort => $localport, Proto => "udp", Reuse => 1) or die "$!"; - -my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; -print $pidf "$$\n" or die "cannot write pid file: $!"; -$pidf->close or die "cannot close pid file: $!"; -sub rmpid { unlink "ans.pid"; exit 1; }; - -$SIG{INT} = \&rmpid; -$SIG{TERM} = \&rmpid; - -my $count = 0; -my $send_response = 1; - -sub getlimit { - if ( -e "ans.limit") { - open(FH, "<", "ans.limit"); - my $line = ; - chomp $line; - close FH; - if ($line =~ /^\d+$/) { - return $line; - } - } - - return 0; -} - -# If $wait == 0 is returned, returned reply will be sent immediately. -# If $wait == 1 is returned, sending the returned reply might be delayed; see -# comments inside handle_UDP() for details. -sub reply_handler { - my ($qname, $qclass, $qtype) = @_; - my ($rcode, @ans, @auth, @add, $wait); - - print ("request: $qname/$qtype\n"); - STDOUT->flush(); - - $wait = 0; - $count += 1; - - if ($qname eq "count" ) { - if ($qtype eq "TXT") { - my ($ttl, $rdata) = (0, "$count"); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - print ("\tcount: $count\n"); - } - $rcode = "NOERROR"; - } elsif ($qname eq "reset" ) { - $count = 0; - $send_response = 1; - $limit = getlimit(); - $rcode = "NOERROR"; - print ("\tlimit: $limit\n"); - } elsif ($qname eq "direct.example.org" ) { - if ($qtype eq "A") { - my ($ttl, $rdata) = (3600, $localaddr); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - print ("\twait=$wait ans: $qname $ttl $qclass $qtype $rdata\n"); - } - $rcode = "NOERROR"; - } elsif ($qname eq "indirect1.example.org" || - $qname eq "indirect2.example.org" || - $qname eq "indirect3.example.org" || - $qname eq "indirect4.example.org" || - $qname eq "indirect5.example.org" || - $qname eq "indirect6.example.org" || - $qname eq "indirect7.example.org" || - $qname eq "indirect8.example.org") { - if ($qtype eq "A") { - my ($ttl, $rdata) = (3600, $localaddr); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - print ("\twait=$wait ans: $qname $ttl $qclass $qtype $rdata\n"); - } - $rcode = "NOERROR"; - } elsif ($qname =~ /^ns1\.(\d+)\.example\.org$/) { - my $next = $1 + 1; - $wait = 1; - if ($limit == 0) { - my $rr = new Net::DNS::RR("$1.example.org 86400 $qclass NS ns1.$next.example.org"); - push @auth, $rr; - print ("\twait=$wait auth: $1.example.org 86400 $qclass NS ns1.$next.example.org\n"); - } else { - $send_response = 1; - if ($qtype eq "A") { - my ($ttl, $rdata) = (3600, $localaddr); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - print("\tresponse: $qname $ttl $qclass $qtype $rdata\n"); - push @ans, $rr; - } - } - $rcode = "NOERROR"; - } elsif ($qname eq "direct.example.net" ) { - if ($qtype eq "A") { - my ($ttl, $rdata) = (3600, $localaddr); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - print ("\twait=$wait ans: $qname $ttl $qclass $qtype $rdata\n"); - } - $rcode = "NOERROR"; - } elsif( $qname =~ /^ns1\.(\d+)\.example\.net$/ ) { - my $next = ($1 + 1) * 16; - for (my $i = 1; $i < 16; $i++) { - my $s = $next + $i; - my $rr = new Net::DNS::RR("$1.example.net 86400 $qclass NS ns1.$s.example.net"); - push @auth, $rr; - print ("\twait=$wait auth: $1.example.net 86400 $qclass NS ns1.$s.example.net\n"); - $rr = new Net::DNS::RR("ns1.$s.example.net 86400 $qclass A 10.53.0.7"); - print ("\twait=$wait add: ns1.$s.example.net 86400 $qclass A 10.53.0.7\n"); - push @add, $rr; - } - $rcode = "NOERROR"; - } else { - $rcode = "NXDOMAIN"; - print ("\twait=$wait NXDOMAIN\n"); - } - - return ($rcode, \@ans, \@auth, \@add, $wait); -} - -sub handleUDP { - my ($buf, $peer) = @_; - my ($request, $rcode, $ans, $auth, $add, $wait); - - $request = new Net::DNS::Packet(\$buf, 0); - $@ and die $@; - - my ($question) = $request->question; - my $qname = $question->qname; - my $qclass = $question->qclass; - my $qtype = $question->qtype; - - ($rcode, $ans, $auth, $add, $wait) = reply_handler($qname, $qclass, $qtype); - - my $reply = $request->reply(); - - $reply->header->rcode($rcode); - $reply->header->aa(@$ans ? 1 : 0); - $reply->header->id($request->header->id); - $reply->{answer} = $ans if $ans; - $reply->{authority} = $auth if $auth; - $reply->{additional} = $add if $add; - - if ($wait) { - # reply_handler() asked us to delay sending this reply until - # another reply with $wait == 1 is generated or a timeout - # occurs. - if (@delayed_response) { - # A delayed reply is already queued, so we can now send - # both the delayed reply and the current reply. - send_delayed_response(); - return $reply; - } elsif ($no_more_waiting) { - # It was determined before that there is no point in - # waiting for "accompanying" queries. Thus, send the - # current reply immediately. - return $reply; - } else { - # No delayed reply is queued and the client is expected - # to send an "accompanying" query shortly. Do not send - # the current reply right now, just save it for later - # and wait for an "accompanying" query to be received. - @delayed_response = ($reply, $peer); - $timeout = 0.5; - return; - } - } else { - # Send reply immediately. - return $reply; - } -} - -sub send_delayed_response { - my ($reply, $peer) = @delayed_response; - # Truncation to 512 bytes is required for triggering "NS explosion" on - # builds without IPv6 support - $udpsock->send($reply->data(512), 0, $peer); - undef @delayed_response; - undef $timeout; - print ("send_delayed_response\n"); -} - -# Main -my $rin; -my $rout; -for (;;) { - $rin = ''; - vec($rin, fileno($udpsock), 1) = 1; - - select($rout = $rin, undef, undef, $timeout); - - if (vec($rout, fileno($udpsock), 1)) { - my ($buf, $peer, $reply); - $udpsock->recv($buf, 512); - $peer = $udpsock->peername(); - $reply = handleUDP($buf, $peer); - # Truncation to 512 bytes is required for triggering "NS - # explosion" on builds without IPv6 support - $udpsock->send($reply->data(512), 0, $peer) if $reply; - } else { - # An "accompanying" query was expected to come in, but did not. - # Assume the client never sends "accompanying" queries to - # prevent pointlessly waiting for them ever again. - $no_more_waiting = 1; - # Send the delayed reply to the query which caused us to wait. - send_delayed_response(); - } -} diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ans4/ans.py bind9-9.20.29/bin/tests/system/reclimit/ans4/ans.py --- bind9-9.20.26/bin/tests/system/reclimit/ans4/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ans4/ans.py 2026-09-11 19:41:01.317326591 +0000 @@ -0,0 +1,44 @@ +""" +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. +""" + +import dns.rcode + +from isctest.asyncserver import ControllableAsyncDnsServer + +from ..reclimit_ans import ( + DirectExampleHandler, + FallbackNxdomainHandler, + IndirectExampleOrgHandler, + LimitControlCommand, + Ns1ExampleOrgHandler, + ReclimitStateHandler, +) + + +def main() -> None: + server = ControllableAsyncDnsServer( + default_aa=True, default_rcode=dns.rcode.NOERROR + ) + server.install_response_handlers( + state_handler := ReclimitStateHandler(), + DirectExampleHandler(state_handler, 4), + IndirectExampleOrgHandler(state_handler, 4), + Ns1ExampleOrgHandler(state_handler), + FallbackNxdomainHandler(state_handler), + ) + server.install_control_command(LimitControlCommand(state_handler)) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ans7/ans.pl bind9-9.20.29/bin/tests/system/reclimit/ans7/ans.pl --- bind9-9.20.26/bin/tests/system/reclimit/ans7/ans.pl 2026-07-20 14:47:53.846846585 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ans7/ans.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -#!/usr/bin/env perl - -# 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. - -use strict; -use warnings; - -use IO::File; -use Getopt::Long; -use Net::DNS::Nameserver; - -my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; -print $pidf "$$\n" or die "cannot write pid file: $!"; -$pidf->close or die "cannot close pid file: $!"; -sub rmpid { unlink "ans.pid"; exit 1; }; -sub term { }; - -$SIG{INT} = \&rmpid; -if ($Net::DNS::VERSION >= 1.42) { - $SIG{TERM} = \&term; -} else { - $SIG{TERM} = \&rmpid; -} - -my $count = 0; - -my $localaddr = "10.53.0.7"; -my $localport = int($ENV{'PORT'}); -if (!$localport) { $localport = 5300; } -my $verbose = 0; - -sub reply_handler { - my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_; - my ($rcode, @ans, @auth, @add); - - print ("request: $qname/$qtype\n"); - STDOUT->flush(); - - $count += 1; - - if ($qname eq "count" ) { - if ($qtype eq "TXT") { - my ($ttl, $rdata) = (0, "$count"); - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata"); - push @ans, $rr; - print ("\tcount: $count\n"); - } - $rcode = "NOERROR"; - } elsif ($qname eq "reset") { - $count = 0; - $rcode = "NOERROR"; - } else { - $rcode = "REFUSED"; - } - - # mark the answer as authoritative (by setting the 'aa' flag - return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); -} - -GetOptions( - 'port=i' => \$localport, - 'verbose!' => \$verbose, -); - -my $ns = Net::DNS::Nameserver->new( - LocalAddr => $localaddr, - LocalPort => $localport, - ReplyHandler => \&reply_handler, - Verbose => $verbose, -); - -if ($Net::DNS::VERSION >= 1.42) { - $ns->start_server(); - select(undef, undef, undef, undef); - $ns->stop_server(); - unlink "ans.pid"; -} else { - $ns->main_loop; -} diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ans7/ans.py bind9-9.20.29/bin/tests/system/reclimit/ans7/ans.py --- bind9-9.20.26/bin/tests/system/reclimit/ans7/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ans7/ans.py 2026-09-11 19:41:01.317326591 +0000 @@ -0,0 +1,41 @@ +""" +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. +""" + +from collections.abc import AsyncGenerator + +import dns.rcode + +from isctest.asyncserver import AsyncDnsServer, DnsResponseSend, QueryContext + +from ..reclimit_ans import ReclimitHandler, ReclimitStateHandler + + +class FallbackRefusedHandler(ReclimitHandler): + async def _get_counted_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + qctx.response.set_rcode(dns.rcode.REFUSED) + yield DnsResponseSend(qctx.response) + + +def main() -> None: + server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR) + server.install_response_handlers( + state_handler := ReclimitStateHandler(), + FallbackRefusedHandler(state_handler), + ) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/reclimit/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/reclimit/ns1/named.conf.j2 2026-07-20 14:47:53.847846600 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ns1/named.conf.j2 2026-09-11 19:41:01.317326591 +0000 @@ -12,20 +12,15 @@ */ options { - directory "."; - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; max-records-per-type 0; max-types-per-name 0; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; }; zone "big." { diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/reclimit/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/reclimit/ns3/named.conf.j2 2026-07-20 14:47:53.847846600 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ns3/named.conf.j2 2026-09-11 19:41:01.317326591 +0000 @@ -12,30 +12,15 @@ */ options { - directory "."; - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} servfail-ttl 0; qname-minimization disabled; max-recursion-queries 50; max-recursion-depth 12; - recursion yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/reclimit/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/reclimit/ns3/named2.conf.j2 2026-07-20 14:47:53.847846600 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ns3/named2.conf.j2 2026-09-11 19:41:01.317326591 +0000 @@ -12,29 +12,14 @@ */ options { - directory "."; - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} servfail-ttl 0; qname-minimization disabled; max-recursion-depth 5; - recursion yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ns3/named3.conf.j2 bind9-9.20.29/bin/tests/system/reclimit/ns3/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/reclimit/ns3/named3.conf.j2 2026-07-20 14:47:53.847846600 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ns3/named3.conf.j2 2026-09-11 19:41:01.318326615 +0000 @@ -12,30 +12,15 @@ */ options { - directory "."; - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} servfail-ttl 0; qname-minimization disabled; max-recursion-depth 100; max-recursion-queries 50; - recursion yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ns3/named4.conf.j2 bind9-9.20.29/bin/tests/system/reclimit/ns3/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/reclimit/ns3/named4.conf.j2 2026-07-20 14:47:53.847846600 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ns3/named4.conf.j2 2026-09-11 19:41:01.318326615 +0000 @@ -12,30 +12,15 @@ */ options { - directory "."; - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} servfail-ttl 0; qname-minimization disabled; max-recursion-depth 100; max-recursion-queries 40; - recursion yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ns3/named5.conf.j2 bind9-9.20.29/bin/tests/system/reclimit/ns3/named5.conf.j2 --- bind9-9.20.26/bin/tests/system/reclimit/ns3/named5.conf.j2 2026-07-20 14:47:53.847846600 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ns3/named5.conf.j2 2026-09-11 19:41:01.318326615 +0000 @@ -12,31 +12,16 @@ */ options { - directory "."; - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} servfail-ttl 0; qname-minimization disabled; max-recursion-depth 12; - recursion yes; dnssec-validation no; max-records-per-type 0; max-types-per-name 10; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/reclimit/ns3/named6.conf.j2 bind9-9.20.29/bin/tests/system/reclimit/ns3/named6.conf.j2 --- bind9-9.20.26/bin/tests/system/reclimit/ns3/named6.conf.j2 2026-07-20 14:47:53.847846600 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/ns3/named6.conf.j2 2026-09-11 19:41:01.318326615 +0000 @@ -12,31 +12,16 @@ */ options { - directory "."; - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} servfail-ttl 0; qname-minimization disabled; max-recursion-depth 12; - recursion yes; dnssec-validation no; max-records-per-type 0; max-types-per-name 0; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/reclimit/prereq.sh bind9-9.20.29/bin/tests/system/reclimit/prereq.sh --- bind9-9.20.26/bin/tests/system/reclimit/prereq.sh 2026-07-20 14:47:53.847846600 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -if ! ${PERL} -MNet::DNS::Nameserver -e ''; then - echo_i "perl Net::DNS::Nameserver module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/reclimit/reclimit_ans.py bind9-9.20.29/bin/tests/system/reclimit/reclimit_ans.py --- bind9-9.20.26/bin/tests/system/reclimit/reclimit_ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/reclimit_ans.py 2026-09-11 19:41:01.318326615 +0000 @@ -0,0 +1,236 @@ +""" +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. +""" + +from collections.abc import AsyncGenerator +from typing import final + +import abc +import asyncio + +import dns.flags +import dns.name +import dns.rcode +import dns.rdataclass +import dns.rdatatype +import dns.rrset + +from isctest.asyncserver import ( + ControlCommand, + ControllableAsyncDnsServer, + DnsResponseSend, + QnameHandler, + QueryContext, + ResponseAction, + ResponseHandler, +) + + +class ReclimitStateHandler(QnameHandler): + """ + Handler for the "count." and "reset." queries that also holds the state + shared by all the handlers in one server. + """ + + qnames = ["count.", "reset."] + + def __init__(self, indirect_send_response_default: bool = True) -> None: + self._indirect_send_response_default = indirect_send_response_default + self.count = 0 + self.limit = 0 + self.indirect_send_response = indirect_send_response_default + super().__init__() + + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + if f"{qctx.qname}" == "count.": + self.count += 1 + qctx.response.answer.append( + dns.rrset.from_text( + "count.", 0, dns.rdataclass.IN, dns.rdatatype.TXT, f"{self.count}" + ) + ) + yield DnsResponseSend(qctx.response, authoritative=True) + elif f"{qctx.qname}" == "reset.": + self.reset() + yield DnsResponseSend(qctx.response, authoritative=False) + + def reset(self) -> None: + self.count = 0 + self.indirect_send_response = self._indirect_send_response_default + + +class ReclimitHandler(ResponseHandler): + """ + Base class for handlers in this test. + + Increments the shared query counter on each query and delegates the actual + response generation to the `_get_counted_responses()` method. + """ + + def __init__(self, state_handler: ReclimitStateHandler) -> None: + self._state = state_handler + super().__init__() + + @final + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[ResponseAction, None]: + self._state.count += 1 + async for response in self._get_counted_responses(qctx): + yield response + + @abc.abstractmethod + async def _get_counted_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[ResponseAction, None]: + yield DnsResponseSend(qctx.response) + + +class LimitControlCommand(ControlCommand): + control_subdomain = "limit" + + def __init__(self, state_handler: ReclimitStateHandler) -> None: + self._state_handler = state_handler + super().__init__() + + def handle( + self, args: list[str], server: ControllableAsyncDnsServer, qctx: QueryContext + ) -> str | None: + if len(args) != 1: + return "Expected exactly one label" + + try: + limit = int(args[0]) + except ValueError: + return "Expected an integer" + + self._state_handler.limit = limit + return f"Limit set to {limit}" + + +def a(owner: str | dns.name.Name, ns_number: int) -> dns.rrset.RRset: + return dns.rrset.from_text( + f"{owner}", 3600, dns.rdataclass.IN, dns.rdatatype.A, f"10.53.0.{ns_number}" + ) + + +def ns(owner: str | dns.name.Name, target: str | dns.name.Name) -> dns.rrset.RRset: + return dns.rrset.from_text( + f"{owner}", 86400, dns.rdataclass.IN, dns.rdatatype.NS, f"{target}" + ) + + +class DirectExampleHandler(ReclimitHandler, QnameHandler): + qnames = ["direct.example.org", "direct.example.net"] + + def __init__( + self, state_handler: ReclimitStateHandler, local_ns_number: int + ) -> None: + self._local_ns_number = local_ns_number + super().__init__(state_handler) + + async def _get_counted_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + if qctx.qtype == dns.rdatatype.A: + qctx.response.answer.append(a(qctx.qname, self._local_ns_number)) + yield DnsResponseSend(qctx.response) + + +class IndirectExampleOrgHandler(ReclimitHandler, QnameHandler): + qnames = [f"indirect{i}.example.org" for i in range(1, 9)] + + def __init__( + self, state_handler: ReclimitStateHandler, local_ns_number: int + ) -> None: + self._local_ns_number = local_ns_number + super().__init__(state_handler) + + async def _get_counted_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + if not self._state.indirect_send_response: + qctx.response.authority.append(ns(f"{qctx.qname}", "ns1.1.example.org.")) + qctx.response.flags &= ~dns.flags.AA + elif qctx.qtype == dns.rdatatype.A: + qctx.response.answer.append(a(qctx.qname, self._local_ns_number)) + yield DnsResponseSend(qctx.response) + + +def is_ns1_example(qname: dns.name.Name, tld: str) -> bool: + labels = qname.labels + return ( + len(labels) == 5 + and labels[3] == tld.encode() + and labels[2] == b"example" + and labels[1].isdigit() + and labels[0] == b"ns1" + ) + + +class Ns1ExampleOrgHandler(ReclimitHandler): + def __init__(self, state_handler: ReclimitStateHandler) -> None: + self._second_query_events: dict[dns.name.Name, asyncio.Event] = {} + super().__init__(state_handler) + + def match(self, qctx: QueryContext) -> bool: + return is_ns1_example(qctx.qname, "org") and qctx.qtype in ( + dns.rdatatype.A, + dns.rdatatype.AAAA, + ) + + async def _get_counted_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[ResponseAction, None]: + ns_number = int(qctx.qname.labels[1]) + next_ns_number = ns_number + 1 + if not self._state.limit or ( + not self._state.indirect_send_response + and next_ns_number <= self._state.limit + ): + qctx.response.authority.append( + ns(f"{ns_number}.example.org.", f"ns1.{next_ns_number}.example.org.") + ) + qctx.response.flags &= ~dns.flags.AA + else: + self._state.indirect_send_response = True + if qctx.qtype == dns.rdatatype.A: + qctx.response.answer.append(a(qctx.qname, 4)) + + second_query_event = self._second_query_events.get(qctx.qname) + if second_query_event is not None: + # Second query arrived, release the first response. + second_query_event.set() + await asyncio.sleep(0) # Yield to allow the first response to be sent. + yield DnsResponseSend(qctx.response) + else: + # Delay the response until the second query for the same QNAME + # arrives; give up waiting after 500 ms. + second_query_event = asyncio.Event() + self._second_query_events[qctx.qname] = second_query_event + try: + await asyncio.wait_for(second_query_event.wait(), timeout=0.5) + except asyncio.TimeoutError: + pass + finally: + del self._second_query_events[qctx.qname] + yield DnsResponseSend(qctx.response) + + +class FallbackNxdomainHandler(ReclimitHandler): + async def _get_counted_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + qctx.response.set_rcode(dns.rcode.NXDOMAIN) + yield DnsResponseSend(qctx.response) diff -Nru bind9-9.20.26/bin/tests/system/reclimit/tests.sh bind9-9.20.29/bin/tests/system/reclimit/tests.sh --- bind9-9.20.26/bin/tests/system/reclimit/tests.sh 2026-07-20 14:47:53.848846616 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/tests.sh 2026-09-11 19:41:01.318326615 +0000 @@ -31,32 +31,22 @@ $RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} flush | sed 's/^/I:ns3 /' } -ns3_sends_aaaa_queries() { - if grep "started AAAA fetch" ns3/named.run >/dev/null; then - return 0 - else - return 1 - fi +set_limit() { + IP=$1 + LIMIT=$2 + LOGID=$3 + dig_with_opts @${IP} $LIMIT.limit._control TXT >dig.out.limit.${LOGID} } -# Check whether the number of queries ans2 received from ns3 (this value is -# read from dig output stored in file $1) is as expected. The expected query -# count is variable: -# - if ns3 sends AAAA queries, the query count should equal $2, -# - if ns3 does not send AAAA queries, the query count should equal $3. +# Check whether the total number of queries ans2 and ans4 received from ns3 +# (read from the dig outputs stored in files $1 and $2) equals the expected +# count ($3). check_query_count() { count1=$(sed 's/[^0-9]//g;' $1) count2=$(sed 's/[^0-9]//g;' $2) count=$((count1 + count2)) #echo_i "count1=$count1 count2=$count2 count=$count" - expected_count_with_aaaa=$3 - expected_count_without_aaaa=$4 - - if ns3_sends_aaaa_queries; then - expected_count=$expected_count_with_aaaa - else - expected_count=$expected_count_without_aaaa - fi + expected_count=$3 if [ $count -ne $expected_count ]; then echo_i "count $count (actual) != $expected_count (expected)" @@ -69,23 +59,23 @@ n=$((n + 1)) echo_i "attempt excessive-depth lookup ($n)" ret=0 -echo "1000" >ans2/ans.limit -echo "1000" >ans4/ans.limit +set_limit 10.53.0.2 1000 $n +set_limit 10.53.0.4 1000 $n dig_with_opts @10.53.0.2 reset >/dev/null || ret=1 dig_with_opts @10.53.0.4 reset >/dev/null || ret=1 dig_with_opts @10.53.0.3 indirect1.example.org >dig.out.1.test$n || ret=1 grep "status: SERVFAIL" dig.out.1.test$n >/dev/null || ret=1 dig_with_opts +short @10.53.0.2 count txt >dig.out.2.test$n || ret=1 dig_with_opts +short @10.53.0.4 count txt >dig.out.4.test$n || ret=1 -check_query_count dig.out.2.test$n dig.out.4.test$n 27 14 +check_query_count dig.out.2.test$n dig.out.4.test$n 27 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) n=$((n + 1)) echo_i "attempt permissible lookup ($n)" ret=0 -echo "12" >ans2/ans.limit -echo "12" >ans4/ans.limit +set_limit 10.53.0.2 12 $n +set_limit 10.53.0.4 12 $n ns3_reset dig_with_opts @10.53.0.2 reset >/dev/null || ret=1 dig_with_opts @10.53.0.4 reset >/dev/null || ret=1 @@ -93,7 +83,7 @@ grep "status: NOERROR" dig.out.1.test$n >/dev/null || ret=1 dig_with_opts +short @10.53.0.2 count txt >dig.out.2.test$n || ret=1 dig_with_opts +short @10.53.0.4 count txt >dig.out.4.test$n || ret=1 -check_query_count dig.out.2.test$n dig.out.4.test$n 50 26 +check_query_count dig.out.2.test$n dig.out.4.test$n 50 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -102,7 +92,7 @@ n=$((n + 1)) echo_i "attempt excessive-depth lookup ($n)" ret=0 -echo "12" >ans2/ans.limit +set_limit 10.53.0.2 12 $n cp ns3/named2.conf ns3/named.conf ns3_reset dig_with_opts @10.53.0.2 reset >/dev/null || ret=1 @@ -111,15 +101,15 @@ grep "status: SERVFAIL" dig.out.1.test$n >/dev/null || ret=1 dig_with_opts +short @10.53.0.2 count txt >dig.out.2.test$n || ret=1 dig_with_opts +short @10.53.0.4 count txt >dig.out.4.test$n || ret=1 -check_query_count dig.out.2.test$n dig.out.4.test$n 13 7 +check_query_count dig.out.2.test$n dig.out.4.test$n 13 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) n=$((n + 1)) echo_i "attempt permissible lookup ($n)" ret=0 -echo "5" >ans2/ans.limit -echo "5" >ans4/ans.limit +set_limit 10.53.0.2 5 $n +set_limit 10.53.0.4 5 $n ns3_reset dig_with_opts @10.53.0.2 reset >/dev/null || ret=1 dig_with_opts @10.53.0.4 reset >/dev/null || ret=1 @@ -127,7 +117,7 @@ grep "status: NOERROR" dig.out.1.test$n >/dev/null || ret=1 dig_with_opts +short @10.53.0.2 count txt >dig.out.2.test$n || ret=1 dig_with_opts +short @10.53.0.4 count txt >dig.out.4.test$n || ret=1 -check_query_count dig.out.2.test$n dig.out.4.test$n 22 12 +check_query_count dig.out.2.test$n dig.out.4.test$n 22 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -136,16 +126,14 @@ n=$((n + 1)) echo_i "attempt excessive-queries lookup ($n)" ret=0 -echo "13" >ans2/ans.limit -echo "13" >ans4/ans.limit +set_limit 10.53.0.2 13 $n +set_limit 10.53.0.4 13 $n cp ns3/named3.conf ns3/named.conf ns3_reset dig_with_opts @10.53.0.2 reset >/dev/null || ret=1 dig_with_opts @10.53.0.4 reset >/dev/null || ret=1 dig_with_opts @10.53.0.3 indirect5.example.org >dig.out.1.test$n || ret=1 -if ns3_sends_aaaa_queries; then - grep "status: SERVFAIL" dig.out.1.test$n >/dev/null || ret=1 -fi +grep "status: SERVFAIL" dig.out.1.test$n >/dev/null || ret=1 dig_with_opts +short @10.53.0.2 count txt >dig.out.2.test$n || ret=1 dig_with_opts +short @10.53.0.4 count txt >dig.out.4.test$n || ret=1 eval count=$(cat dig.out.2.test$n) @@ -159,7 +147,7 @@ n=$((n + 1)) echo_i "attempt permissible lookup ($n)" ret=0 -echo "12" >ans2/ans.limit +set_limit 10.53.0.2 12 $n ns3_reset dig_with_opts @10.53.0.2 reset >/dev/null || ret=1 dig_with_opts @10.53.0.3 indirect6.example.org >dig.out.1.test$n || ret=1 @@ -178,14 +166,12 @@ n=$((n + 1)) echo_i "attempt excessive-queries lookup ($n)" ret=0 -echo "11" >ans2/ans.limit +set_limit 10.53.0.2 11 $n cp ns3/named4.conf ns3/named.conf ns3_reset dig_with_opts @10.53.0.2 reset >/dev/null || ret=1 dig_with_opts @10.53.0.3 indirect7.example.org >dig.out.1.test$n || ret=1 -if ns3_sends_aaaa_queries; then - grep "status: SERVFAIL" dig.out.1.test$n >/dev/null || ret=1 -fi +grep "status: SERVFAIL" dig.out.1.test$n >/dev/null || ret=1 dig_with_opts +short @10.53.0.2 count txt >dig.out.2.test$n || ret=1 eval count=$(cat dig.out.2.test$n) [ $count -le 40 ] || { @@ -198,7 +184,7 @@ n=$((n + 1)) echo_i "attempt permissible lookup ($n)" ret=0 -echo "9" >ans2/ans.limit +set_limit 10.53.0.2 9 $n ns3_reset dig_with_opts @10.53.0.2 reset >/dev/null || ret=1 dig_with_opts @10.53.0.3 indirect8.example.org >dig.out.1.test$n || ret=1 diff -Nru bind9-9.20.26/bin/tests/system/reclimit/tests_sh_reclimit.py bind9-9.20.29/bin/tests/system/reclimit/tests_sh_reclimit.py --- bind9-9.20.26/bin/tests/system/reclimit/tests_sh_reclimit.py 2026-07-20 14:47:53.848846616 +0000 +++ bind9-9.20.29/bin/tests/system/reclimit/tests_sh_reclimit.py 2026-09-11 19:41:01.318326615 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "dsset-signed.", @@ -23,6 +25,11 @@ ] ) +pytestmark = [ + isctest.mark.with_ipv6, + EXTRA_ARTIFACTS, +] + # The reclimit is known to be quite unstable. GL #1587 @pytest.mark.flaky(max_runs=2) diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns1/named.conf.j2 2026-07-20 14:47:53.848846616 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns1/named.conf.j2 2026-09-11 19:41:01.319326639 +0000 @@ -16,18 +16,12 @@ acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - allow-recursion { 10.53.0.1; }; - notify yes; + {% include_indented "_common/options.conf.j2" %} + allow-recursion { @ns.ip@; }; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns10/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns10/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns10/named.conf.j2 2026-07-20 14:47:53.849846631 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns10/named.conf.j2 2026-09-11 19:41:01.319326639 +0000 @@ -3,9 +3,7 @@ // locally, then nxdomain-redirect+dns64 hit the same buggy path as ns7). options { - port @PORT@; - listen-on port @PORT@ { 10.53.0.10; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} nxdomain-redirect redirect; dnssec-validation yes; synth-from-dnssec yes; @@ -16,6 +14,8 @@ }; }; +{% include "_common/controls.conf.j2" %} + include "trusted.conf"; zone "." { diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns2/named.conf.j2 2026-07-20 14:47:53.849846631 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns2/named.conf.j2 2026-09-11 19:41:01.320326663 +0000 @@ -13,38 +13,18 @@ // NS2 -controls { /* empty */ }; - acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "." { type redirect; diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns3/named.conf.j2 2026-07-20 14:47:53.849846631 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns3/named.conf.j2 2026-09-11 19:41:01.320326663 +0000 @@ -14,18 +14,12 @@ acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-recursion { 10.53.0.3; }; - notify yes; + {% include_indented "_common/options.conf.j2" %} + allow-recursion { @ns.ip@; }; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns4/named.conf.j2 2026-07-20 14:47:53.850846647 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns4/named.conf.j2 2026-09-11 19:41:01.320326663 +0000 @@ -13,33 +13,20 @@ // NS2 -controls { /* empty */ }; - acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; options { - query-source address 10.53.0.2; /* note this is not 10.53.0.4 */ - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options/server.conf.j2" %} + {% include_indented "_common/options/listen.conf.j2" %} + query-source address 10.53.0.2; /* note this is not @ns.ip@ */ + notify-source @ns.ip@; + transfer-source @ns.ip@; dnssec-validation no; nxdomain-redirect "redirect"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns5/named.conf.j2 2026-07-20 14:47:53.850846647 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns5/named.conf.j2 2026-09-11 19:41:01.320326663 +0000 @@ -14,20 +14,20 @@ // NS5 options { - port @PORT@; - listen-on port @PORT@ { 10.53.0.5; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} nxdomain-redirect signed; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { - type primary; - file "root.db.signed"; + type primary; + file "root.db.signed"; }; // An unsigned zone that ns6 has a delegation for. zone "unsigned." { - type primary; - file "unsigned.db"; + type primary; + file "unsigned.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns6/named.conf.j2 2026-07-20 14:47:53.850846647 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns6/named.conf.j2 2026-09-11 19:41:01.321326687 +0000 @@ -14,20 +14,20 @@ // NS6 options { - port @PORT@; - listen-on port @PORT@ { 10.53.0.6; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} nxdomain-redirect unsigned; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { - type primary; - file "root.db"; + type primary; + file "root.db"; }; // A signed zone that ns5 has a delegation for. zone "signed." { - type primary; - file "signed.db.signed"; + type primary; + file "signed.db.signed"; }; diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns7/named.conf.j2 2026-07-20 14:47:53.851846662 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns7/named.conf.j2 2026-09-11 19:41:01.321326687 +0000 @@ -1,9 +1,7 @@ // NS7 options { - port @PORT@; - listen-on port @PORT@ { 10.53.0.7; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} nxdomain-redirect redirect; dnssec-validation no; dns64 64:ff9b::/96 { @@ -13,12 +11,14 @@ }; }; +{% include "_common/controls.conf.j2" %} + zone "." { - type primary; - file "root.db"; + type primary; + file "root.db"; }; zone "redirect" { - type primary; - file "redirect.db"; + type primary; + file "redirect.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns8/named.conf.j2 2026-07-20 14:47:53.851846662 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns8/named.conf.j2 2026-09-11 19:41:01.321326687 +0000 @@ -1,9 +1,7 @@ // NS8 options { - port @PORT@; - listen-on port @PORT@ { 10.53.0.8; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} nxdomain-redirect redirect; dnssec-validation no; dns64 64:ff9b::/96 { @@ -13,7 +11,9 @@ }; }; +{% include "_common/controls.conf.j2" %} + zone "." { - type hint; - file "root.hints"; + type hint; + file "root.hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/redirect/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/redirect/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/redirect/ns9/named.conf.j2 2026-07-20 14:47:53.851846662 +0000 +++ bind9-9.20.29/bin/tests/system/redirect/ns9/named.conf.j2 2026-09-11 19:41:01.322326711 +0000 @@ -2,13 +2,13 @@ // (synth-from-dnssec path) options { - port @PORT@; - listen-on port @PORT@ { 10.53.0.9; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/requirements.txt bind9-9.20.29/bin/tests/system/requirements.txt --- bind9-9.20.26/bin/tests/system/requirements.txt 2026-07-20 14:47:53.852846678 +0000 +++ bind9-9.20.29/bin/tests/system/requirements.txt 2026-09-11 19:41:01.322326711 +0000 @@ -5,9 +5,10 @@ cryptography h2 hypothesis>=4.41.2 -jinja2 +jinja2>=3.0.0 pytest>=7.0.0 pytest-xdist +pyyaml requests ### Optional packages diff -Nru bind9-9.20.26/bin/tests/system/resend_loop/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/resend_loop/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/resend_loop/ns4/named.conf.j2 2026-07-20 14:47:53.852846678 +0000 +++ bind9-9.20.29/bin/tests/system/resend_loop/ns4/named.conf.j2 2026-09-11 19:41:01.323326735 +0000 @@ -1,15 +1,10 @@ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." IN { type hint; file "root.hint"; diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns1/named.conf.j2 2026-07-20 14:47:53.853846693 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns1/named.conf.j2 2026-09-11 19:41:01.324326759 +0000 @@ -12,20 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; } - except-from { "example.org"; }; + except-from { "example.org"; }; deny-answer-aliases { "example.org"; } - except-from { "goodcname.example.net"; - "gooddname.example.net"; }; + except-from { "goodcname.example.net"; + "gooddname.example.net"; }; allow-query {!10.53.0.8; any; }; max-zone-ttl unlimited; resolver-query-timeout 5000; # 5 seconds @@ -39,15 +32,15 @@ }; server 10.42.23.3/32 { - notify-source 10.42.22.1; - query-source address 10.42.22.1 port 0; - transfer-source 10.42.22.1; + notify-source 10.42.22.1; + query-source address 10.42.22.1 port 0; + transfer-source 10.42.22.1; }; server fd92:7065:b8e:ffff::1000 { - notify-source-v6 fd92:7065:b8e:ffff::1001; - query-source-v6 address fd92:7065:b8e:ffff::1001 port 0; - transfer-source-v6 fd92:7065:b8e:ffff::1001; + notify-source-v6 fd92:7065:b8e:ffff::1001; + query-source-v6 address fd92:7065:b8e:ffff::1001 port 0; + transfer-source-v6 fd92:7065:b8e:ffff::1001; }; /* @@ -56,9 +49,9 @@ */ view "class" chaos { zone "chaostest" CHAOS { - type primary; - file "chaostest.db"; - }; + type primary; + file "chaostest.db"; + }; }; /* @@ -79,11 +72,4 @@ }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns1/named2.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns1/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns1/named2.conf.j2 2026-07-20 14:47:53.853846693 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns1/named2.conf.j2 2026-09-11 19:41:01.324326759 +0000 @@ -13,19 +13,12 @@ {% set wrongoption = wrongoption | default(False) %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; attach-cache "globalcache"; - max-zone-ttl unlimited; - resolver-query-timeout 5000; # 5 seconds - max-recursion-queries 100; + max-zone-ttl unlimited; + resolver-query-timeout 5000; # 5 seconds + max-recursion-queries 100; }; view "default" { @@ -33,16 +26,9 @@ type hint; file "root.hint"; }; -{% if wrongoption %} + {% if wrongoption %} forwarders port 9999999 { 127.0.0.1; }; -{% endif %} + {% endif %} }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns11/named.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns11/named.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns11/named.conf.j2 2026-07-20 14:47:53.853846693 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns11/named.conf.j2 2026-09-11 19:41:01.324326759 +0000 @@ -12,13 +12,9 @@ */ options { - query-source address 10.53.0.11; - notify-source 10.53.0.11; - transfer-source 10.53.0.11; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.11; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; + +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns4/named.conf.j2 2026-07-20 14:47:53.854846709 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns4/named.conf.j2 2026-09-11 19:41:01.324326759 +0000 @@ -14,13 +14,7 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -51,8 +45,8 @@ }; zone "sourcens" { - type primary; - file "sourcens.db"; + type primary; + file "sourcens.db"; }; zone "v4only.net" { @@ -60,11 +54,4 @@ file "v4only.net.db"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns5/named.conf.j2 2026-07-20 14:47:53.855846725 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns5/named.conf.j2 2026-09-11 19:41:01.325326782 +0000 @@ -14,14 +14,7 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; querylog yes; prefetch 4 10; @@ -51,11 +44,4 @@ include "trusted.conf"; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns6/named.conf.j2 2026-07-20 14:47:53.855846725 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns6/named.conf.j2 2026-09-11 19:41:01.326326807 +0000 @@ -14,13 +14,7 @@ // NS6 options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { fd92:7065:b8e:ffff::6; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; dnssec-validation no; querylog yes; @@ -83,11 +77,4 @@ file "targetns.db"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns7/named.conf.j2 2026-07-20 14:47:53.856846740 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns7/named.conf.j2 2026-09-11 19:41:01.327326830 +0000 @@ -14,14 +14,7 @@ // NS7 options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { fd92:7065:b8e:ffff::7; }; - recursion yes; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation no; empty-zones-enable yes; disable-empty-zone 20.172.in-addr.arpa; @@ -35,14 +28,7 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns7/named2.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns7/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns7/named2.conf.j2 2026-07-20 14:47:53.856846740 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns7/named2.conf.j2 2026-09-11 19:41:01.327326830 +0000 @@ -14,14 +14,7 @@ // NS7 options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { fd92:7065:b8e:ffff::7; }; - recursion yes; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation no; empty-zones-enable yes; disable-empty-zone 20.172.in-addr.arpa; @@ -35,14 +28,7 @@ }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/resolver/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/resolver/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/resolver/ns9/named.conf.j2 2026-07-20 14:47:53.857846756 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/ns9/named.conf.j2 2026-09-11 19:41:01.327326830 +0000 @@ -14,11 +14,10 @@ // NS9 options { - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} listen-on { none; }; - listen-on-v6 { fd92:7065:b8e:ffff::9; }; - recursion yes; + listen-on-v6 { @ns.ip6@; }; recursive-clients 0; // regression test for [GL #4987] dnssec-validation no; dual-stack-servers { fd92:7065:b8e:ffff::7; }; @@ -31,8 +30,9 @@ algorithm @DEFAULT_HMAC@; }; +/* deliberately not _common/controls.conf.j2: IPv6 control channel; the shared template is IPv4-only */ controls { - inet fd92:7065:b8e:ffff::9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; + inet @ns.ip6@ port @CONTROLPORT@ allow { any; } keys { rndc_key; }; }; zone "." { diff -Nru bind9-9.20.26/bin/tests/system/resolver/prereq.sh bind9-9.20.29/bin/tests/system/resolver/prereq.sh --- bind9-9.20.26/bin/tests/system/resolver/prereq.sh 2026-07-20 14:47:53.857846756 +0000 +++ bind9-9.20.29/bin/tests/system/resolver/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/rfc5011/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rfc5011/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rfc5011/ns1/named.conf.j2 2026-07-20 14:47:53.858846771 +0000 +++ bind9-9.20.29/bin/tests/system/rfc5011/ns1/named.conf.j2 2026-09-11 19:41:01.328326854 +0000 @@ -16,17 +16,14 @@ */ options { + # This instance queries the root servers on the live internet. + # The options-level port and the *-source addresses must stay at + # their defaults so that outgoing traffic uses port 53 and a + # routable source address. + port 53; pid-file "named.pid"; - listen-on port @PORT@ { 10.53.0.1; }; - recursion yes; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; + listen-on port @PORT@ { @ns.ip@; }; + listen-on-v6 { none; }; }; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/rndc/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rndc/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rndc/ns2/named.conf.j2 2026-07-20 14:47:53.858846771 +0000 +++ bind9-9.20.29/bin/tests/system/rndc/ns2/named.conf.j2 2026-09-11 19:41:01.329326878 +0000 @@ -12,11 +12,8 @@ */ options { - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; recursion no; dnssec-validation no; }; @@ -31,15 +28,13 @@ algorithm @DEFAULT_HMAC@; }; +/* deliberately not _common/controls.conf.j2: multi-key control channel is the test subject */ controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; secondkey; }; + inet @ns.ip@ port @CONTROLPORT@ allow { any; } keys { rndc_key; secondkey; }; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "nil" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/rndc/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rndc/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rndc/ns3/named.conf.j2 2026-07-20 14:47:53.859846787 +0000 +++ bind9-9.20.29/bin/tests/system/rndc/ns3/named.conf.j2 2026-09-11 19:41:01.329326878 +0000 @@ -12,36 +12,23 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - key secondkey { secret "abcd1234abcd8765"; algorithm @DEFAULT_HMAC@; }; -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view all { match-clients { any; }; recursion no; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} }; view none { diff -Nru bind9-9.20.26/bin/tests/system/rndc/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/rndc/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rndc/ns4/named.conf.j2 2026-07-20 14:47:53.859846787 +0000 +++ bind9-9.20.29/bin/tests/system/rndc/ns4/named.conf.j2 2026-09-11 19:41:01.329326878 +0000 @@ -11,12 +11,9 @@ * information regarding copyright ownership. */ +/* deliberately not _common/controls.conf.j2: setup.sh appends a runtime-generated multi-key channel on EXTRAPORT7 */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; diff -Nru bind9-9.20.26/bin/tests/system/rndc/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/rndc/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rndc/ns5/named.conf.j2 2026-07-20 14:47:53.859846787 +0000 +++ bind9-9.20.29/bin/tests/system/rndc/ns5/named.conf.j2 2026-09-11 19:41:01.329326878 +0000 @@ -12,10 +12,7 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; @@ -25,11 +22,9 @@ algorithm @DEFAULT_HMAC@; }; +/* deliberately not _common/controls.conf.j2: read-only control channel is the test subject */ controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; } read-only yes; + inet @ns.ip@ port @CONTROLPORT@ allow { any; } keys { rndc_key; } read-only yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/rndc/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/rndc/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rndc/ns6/named.conf.j2 2026-07-20 14:47:53.859846787 +0000 +++ bind9-9.20.29/bin/tests/system/rndc/ns6/named.conf.j2 2026-09-11 19:41:01.329326878 +0000 @@ -12,19 +12,9 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/rndc/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/rndc/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rndc/ns7/named.conf.j2 2026-07-20 14:47:53.859846787 +0000 +++ bind9-9.20.29/bin/tests/system/rndc/ns7/named.conf.j2 2026-09-11 19:41:01.330326902 +0000 @@ -12,18 +12,10 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - key int { algorithm @DEFAULT_HMAC@; secret "FrSt77yPTFx6hTs4i2tKLB9LmE0="; @@ -34,9 +26,7 @@ secret "FrSt77yPTFx6hTs4i2tKLB9LmE0="; }; -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view internal { match-clients { key "int"; }; diff -Nru bind9-9.20.26/bin/tests/system/rndc/tests_cve_2023_3341.py bind9-9.20.29/bin/tests/system/rndc/tests_cve_2023_3341.py --- bind9-9.20.26/bin/tests/system/rndc/tests_cve_2023_3341.py 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rndc/tests_cve_2023_3341.py 2026-09-11 19:41:01.330326902 +0000 @@ -20,6 +20,7 @@ pytestmark = pytest.mark.extra_artifacts( [ + "ns*/*.db.jnl", "ns2/nil.db", "ns2/other.db", "ns2/secondkey.conf", diff -Nru bind9-9.20.26/bin/tests/system/rndc_confgen/tests_rndc_confgen.py bind9-9.20.29/bin/tests/system/rndc_confgen/tests_rndc_confgen.py --- bind9-9.20.26/bin/tests/system/rndc_confgen/tests_rndc_confgen.py 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rndc_confgen/tests_rndc_confgen.py 2026-09-11 19:41:01.330326902 +0000 @@ -12,11 +12,60 @@ import base64 import os import re +import subprocess import pytest import isctest +INJECTION = 'backdoor"{algorithm hmac-sha256;secret "AAAA";};key "rndc-key' + +ESCAPED_KEY = ( + b'key "backdoor\\"{algorithm hmac-sha256;secret \\"AAAA\\";};key \\"rndc-key"' +) + +TOO_BIG_LABEL = "key012345678901234567890123456789012345678901234567890123456789X" + + +def test_rndc_confgen_default(): + cmd = isctest.run.cmd([os.environ["RNDCCONFGEN"]]) + assert b'key "rndc-key" {' in cmd.proc.stdout + + +def test_rndc_confgen_keyonly(): + cmd = isctest.run.cmd([os.environ["RNDCCONFGEN"], "-a", "-c", "rndc.key"]) + assert b'wrote key file "rndc.key"' in cmd.proc.stdout + + +def test_rndc_confgen_keyonlyquiet(): + cmd = isctest.run.cmd([os.environ["RNDCCONFGEN"], "-a", "-c", "rndc.key", "-q"]) + assert b'wrote key file "rndc.key"' not in cmd.proc.stdout + + +def test_rndc_confgen_keyname_with_dots(): + cmd = isctest.run.cmd([os.environ["RNDCCONFGEN"], "-k", "key.example.com"]) + assert b'key "key.example.com" {' in cmd.proc.stdout + + +def test_rndc_confgen_escapes_injection(): + cmd = isctest.run.cmd([os.environ["RNDCCONFGEN"], "-k", INJECTION]) + assert ESCAPED_KEY in cmd.proc.stdout + + +def test_rndc_confgen_rejects_to_big_label(): + with pytest.raises(subprocess.CalledProcessError): + isctest.run.cmd([os.environ["RNDCCONFGEN"], "-k", TOO_BIG_LABEL]) + + +def test_tsig_keygen_default(): + cmd = isctest.run.cmd([os.environ["TSIGKEYGEN"]]) + assert b'key "tsig-key" {' in cmd.proc.stdout + + +def test_tsig_keygen_escapes_injection(): + cmd = isctest.run.cmd([os.environ["TSIGKEYGEN"], INJECTION]) + assert ESCAPED_KEY in cmd.proc.stdout + def _extract_secret(stdout: bytes) -> bytes: match = re.search(rb'secret\s+"([^"]+)"', stdout) diff -Nru bind9-9.20.26/bin/tests/system/rollover/common.py bind9-9.20.29/bin/tests/system/rollover/common.py --- bind9-9.20.26/bin/tests/system/rollover/common.py 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/common.py 2026-09-11 19:41:01.330326902 +0000 @@ -34,6 +34,7 @@ "ns*/K*.state", "ns*/keygen.out.*", "ns*/managed-keys.**", + "ns*/policy/*.conf", "ns*/settime.out.*", "ns*/signer.out.*", "ns*/zones", diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns1/named.conf.j2 2026-09-11 19:41:01.330326902 +0000 @@ -14,17 +14,12 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns2/named.conf.j2 2026-09-11 19:41:01.331326926 +0000 @@ -14,36 +14,22 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; allow-notify { 10.53.0.3; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} +{% if tlds is defined %} {% for zone in tlds %} zone "@zone@" { type primary; file "@zone@.db.signed"; }; {% endfor %} +{% endif %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/dynamic2inline.kasp.db bind9-9.20.29/bin/tests/system/rollover/ns3/dynamic2inline.kasp.db --- bind9-9.20.26/bin/tests/system/rollover/ns3/dynamic2inline.kasp.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/dynamic2inline.kasp.db 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,27 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns3 +ns3 A 10.53.0.3 + +a A 10.0.0.1 +b A 10.0.0.2 +c A 10.0.0.3 + diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/lifetime.db.in bind9-9.20.29/bin/tests/system/rollover/ns3/lifetime.db.in --- bind9-9.20.26/bin/tests/system/rollover/ns3/lifetime.db.in 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/lifetime.db.in 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,27 @@ +; 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. + +$TTL 300 +@ IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns3 +ns3 A 10.53.0.3 + +a A 10.0.0.1 +b A 10.0.0.2 +c A 10.0.0.3 + diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-algo-csk.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-algo-csk.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-algo-csk.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-algo-csk.conf.j2 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,59 @@ +/* + * 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 csk_roll = csk_roll | default(False) %} +{% set _csk_file = "policy/csk1.conf" if not csk_roll else "policy/csk2.conf" %} +{% set zones = ["kasp", "manual"] %} + +include "@_csk_file@"; +include "named.common.conf"; + +{% for tld in zones %} +zone "step1.csk-algorithm-roll.@tld@" { + type primary; + file "step1.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; +}; + +{% if csk_roll %} +zone "step2.csk-algorithm-roll.@tld@" { + type primary; + file "step2.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; +}; + +zone "step3.csk-algorithm-roll.@tld@" { + type primary; + file "step3.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; +}; + +zone "step4.csk-algorithm-roll.@tld@" { + type primary; + file "step4.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; +}; + +zone "step5.csk-algorithm-roll.@tld@" { + type primary; + file "step5.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; +}; + +zone "step6.csk-algorithm-roll.@tld@" { + type primary; + file "step6.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; +}; +{% endif %} +{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-algo-ksk-zsk.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-algo-ksk-zsk.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-algo-ksk-zsk.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-algo-ksk-zsk.conf.j2 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,60 @@ +/* + * 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 alg_roll = alg_roll | default(False) %} +{% set policy = "rsasha256" if not alg_roll else "ecdsa256" %} +{% set zones = ["kasp", "manual"] %} + +include "policy/ksk-zsk.conf"; +include "named.common.conf"; + +{% for tld in zones %} +zone "step1.algorithm-roll.@tld@" { + type primary; + file "step1.algorithm-roll.@tld@.db"; + dnssec-policy @policy@-@tld@; +}; + +{% if alg_roll %} +zone "step2.algorithm-roll.@tld@" { + type primary; + file "step2.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; +}; + +zone "step3.algorithm-roll.@tld@" { + type primary; + file "step3.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; +}; + +zone "step4.algorithm-roll.@tld@" { + type primary; + file "step4.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; +}; + +zone "step5.algorithm-roll.@tld@" { + type primary; + file "step5.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; +}; + +zone "step6.algorithm-roll.@tld@" { + type primary; + file "step6.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; +}; + +{% endif %} +{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-csk-roll1.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-csk-roll1.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-csk-roll1.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-csk-roll1.conf.j2 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,61 @@ +/* + * 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 zones = ["autosign", "manual"] %} + +include "policy/csk-roll1.conf"; +include "named.common.conf"; + +{% for tld in zones %} +zone "step1.csk-roll1.@tld@" { + type primary; + file "step1.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; +}; +zone "step2.csk-roll1.@tld@" { + type primary; + file "step2.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; +}; +zone "step3.csk-roll1.@tld@" { + type primary; + file "step3.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; +}; +zone "step4.csk-roll1.@tld@" { + type primary; + file "step4.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; +}; +zone "step5.csk-roll1.@tld@" { + type primary; + file "step5.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; +}; +zone "step6.csk-roll1.@tld@" { + type primary; + file "step6.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; +}; +zone "step7.csk-roll1.@tld@" { + type primary; + file "step7.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; +}; +zone "step8.csk-roll1.@tld@" { + type primary; + file "step8.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; +}; + +{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-csk-roll2.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-csk-roll2.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-csk-roll2.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-csk-roll2.conf.j2 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,56 @@ +/* + * 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 zones = ["autosign", "manual"] %} + +include "policy/csk-roll2.conf"; +include "named.common.conf"; + +{% for tld in zones %} +zone "step1.csk-roll2.@tld@" { + type primary; + file "step1.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; +}; +zone "step2.csk-roll2.@tld@" { + type primary; + file "step2.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; +}; +zone "step3.csk-roll2.@tld@" { + type primary; + file "step3.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; +}; +zone "step4.csk-roll2.@tld@" { + type primary; + file "step4.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; +}; +zone "step5.csk-roll2.@tld@" { + type primary; + file "step5.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; +}; +zone "step6.csk-roll2.@tld@" { + type primary; + file "step6.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; +}; +zone "step7.csk-roll2.@tld@" { + type primary; + file "step7.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; +}; + +{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-dynamic2inline.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-dynamic2inline.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-dynamic2inline.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-dynamic2inline.conf.j2 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,21 @@ +/* + * 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. + */ + +include "named.common.conf"; + +zone "dynamic2inline.kasp" { + type primary; + file "dynamic2inline.kasp.db"; + allow-update { any; }; + dnssec-policy "default"; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-enable-dnssec.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-enable-dnssec.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-enable-dnssec.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-enable-dnssec.conf.j2 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,41 @@ +/* + * 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 zones = ["autosign", "manual"] %} + +include "policy/enable-dnssec.conf"; +include "named.common.conf"; + +{% for tld in zones %} +zone "step1.enable-dnssec.@tld@" { + type primary; + file "step1.enable-dnssec.@tld@.db"; + dnssec-policy "enable-dnssec-@tld@"; +}; +zone "step2.enable-dnssec.@tld@" { + type primary; + file "step2.enable-dnssec.@tld@.db"; + dnssec-policy "enable-dnssec-@tld@"; +}; +zone "step3.enable-dnssec.@tld@" { + type primary; + file "step3.enable-dnssec.@tld@.db"; + dnssec-policy "enable-dnssec-@tld@"; +}; +zone "step4.enable-dnssec.@tld@" { + type primary; + file "step4.enable-dnssec.@tld@.db"; + dnssec-policy "enable-dnssec-@tld@"; +}; + +{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-going-insecure.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-going-insecure.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-going-insecure.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-going-insecure.conf.j2 2026-09-11 19:41:01.331326926 +0000 @@ -0,0 +1,49 @@ +/* + * 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 policy = policy | default("unsigning") %} + +include "policy/going-insecure.conf"; +include "named.common.conf"; + +zone "step1.going-insecure.kasp" { + type primary; + file "step1.going-insecure.kasp.db"; + dnssec-policy @policy@; +}; + +{% if policy == "insecure" %} +zone "step2.going-insecure.kasp" { + type primary; + file "step2.going-insecure.kasp.db"; + dnssec-policy insecure; +}; +{% endif %} + +zone "step1.going-insecure-dynamic.kasp" { + type primary; + file "step1.going-insecure-dynamic.kasp.db"; + dnssec-policy @policy@; + inline-signing no; + allow-update { any; }; +}; + +{% if policy == "insecure" %} +zone "step2.going-insecure-dynamic.kasp" { + type primary; + file "step2.going-insecure-dynamic.kasp.db"; + dnssec-policy insecure; + inline-signing no; + allow-update { any; }; +}; +{% endif %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-ksk-3crowd.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-ksk-3crowd.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-ksk-3crowd.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-ksk-3crowd.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,23 @@ +/* + * 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. + */ + +include "policy/ksk.conf"; +include "named.common.conf"; + +zone "three-is-a-crowd.kasp" { + type primary; + file "three-is-a-crowd.kasp.db"; + inline-signing yes; + /* Use same policy as KSK rollover test zones. */ + dnssec-policy "ksk-doubleksk-autosign"; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-ksk-doubleksk.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-ksk-doubleksk.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-ksk-doubleksk.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-ksk-doubleksk.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,50 @@ +/* + * 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 zones = ["autosign", "manual"] %} + +include "policy/ksk.conf"; +include "named.common.conf"; + +{% for tld in zones %} +zone "step1.ksk-doubleksk.@tld@" { + type primary; + file "step1.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; +}; +zone "step2.ksk-doubleksk.@tld@" { + type primary; + file "step2.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; +}; +zone "step3.ksk-doubleksk.@tld@" { + type primary; + file "step3.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; +}; +zone "step4.ksk-doubleksk.@tld@" { + type primary; + file "step4.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; +}; +zone "step5.ksk-doubleksk.@tld@" { + type primary; + file "step5.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; +}; +zone "step6.ksk-doubleksk.@tld@" { + type primary; + file "step6.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; +}; +{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-lifetime.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-lifetime.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-lifetime.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-lifetime.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,45 @@ +/* + * 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 change_lifetime = change_lifetime | default(False) %} +{% set longer = "short-lifetime" if not change_lifetime else "long-lifetime" %} +{% set shorter = "long-lifetime" if not change_lifetime else "short-lifetime" %} +{% set limit = "unlimited-lifetime" if not change_lifetime else "short-lifetime" %} +{% set unlimit = "short-lifetime" if not change_lifetime else "unlimited-lifetime" %} + +include "policy/lifetime.conf"; +include "named.common.conf"; + +zone longer-lifetime.kasp { + type primary; + file "longer-lifetime.db"; + dnssec-policy @longer@; +}; + +zone shorter-lifetime.kasp { + type primary; + file "shorter-lifetime.db"; + dnssec-policy @shorter@; +}; + +zone limit-lifetime.kasp { + type primary; + file "limit-lifetime.db"; + dnssec-policy @limit@; +}; + +zone unlimit-lifetime.kasp { + type primary; + file "unlimit-lifetime.db"; + dnssec-policy @unlimit@; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-manual.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-manual.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-manual.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-manual.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,12 @@ +include "kasp.conf"; +include "named.common.conf"; + +{% for zone in ['manual-rollover.kasp', 'manual-rollover-zrrsig-rumoured.kasp'] %} +zone "@zone@" { + type primary; + file "@zone@.db"; + dnssec-policy "manual-rollover"; + notify no; +}; + +{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-multisigner.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-multisigner.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-multisigner.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-multisigner.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,34 @@ +/* + * 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. + */ + +include "policy/multisigner.conf"; +include "named.common.conf"; + +/* RFC 8901 Multi-signer Model 2. */ +zone "multisigner-model2.kasp" { + type primary; + file "multisigner-model2.kasp.db"; + dnssec-policy "multisigner-model2"; + allow-update { any; }; +}; + +/* + * A zone that starts with keys that have tags that are + * outside of the desired multi-signer key tag range. + */ +zone "single-to-multisigner.kasp" { + type primary; + file "single-to-multisigner.kasp.db"; + dnssec-policy "multisigner-model2"; + allow-update { any; }; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-straight2none.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-straight2none.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-straight2none.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-straight2none.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,31 @@ +/* + * 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 policy = policy | default("default") %} + +include "policy/going-insecure.conf"; +include "named.common.conf"; + +zone "going-straight-to-none.kasp" { + type primary; + file "going-straight-to-none.kasp.db"; + dnssec-policy @policy@; +}; + +zone "going-straight-to-none-dynamic.kasp" { + type primary; + file "going-straight-to-none-dynamic.kasp.db.signed"; + inline-signing no; + dnssec-policy @policy@; + allow-update { any; }; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named-zsk-prepub.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named-zsk-prepub.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named-zsk-prepub.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named-zsk-prepub.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,50 @@ +/* + * 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 zones = ["autosign", "manual"] %} + +include "policy/zsk-prepub.conf"; +include "named.common.conf"; + +{% for tld in zones %} +zone "step1.zsk-prepub.@tld@" { + type primary; + file "step1.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; +}; +zone "step2.zsk-prepub.@tld@" { + type primary; + file "step2.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; +}; +zone "step3.zsk-prepub.@tld@" { + type primary; + file "step3.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; +}; +zone "step4.zsk-prepub.@tld@" { + type primary; + file "step4.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; +}; +zone "step5.zsk-prepub.@tld@" { + type primary; + file "step5.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; +}; +zone "step6.zsk-prepub.@tld@" { + type primary; + file "step6.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; +}; +{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named.common.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -20,28 +20,11 @@ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; + {% include_indented "_common/options.conf.j2" %} + allow-transfer { any; }; + dnssec-validation @dnssec_validation@; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/named.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/named.conf.j2 2026-09-11 19:41:01.332326950 +0000 @@ -11,15 +11,4 @@ * information regarding copyright ownership. */ -include "kasp.conf"; -include "named.common.conf"; - -{% for zone in ['manual-rollover.kasp', 'manual-rollover-zrrsig-rumoured.kasp'] %} -zone "@zone@" { - type primary; - file "@zone@.db"; - dnssec-policy "manual-rollover"; - notify no; -}; - -{% endfor %} +include "named-@testconf@.conf"; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/csk-roll1.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk-roll1.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/csk-roll1.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk-roll1.conf 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,58 @@ +/* + * 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. + */ + +dnssec-policy "csk-roll1-autosign" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + purge-keys PT1H; + + cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes + keys { + csk key-directory lifetime P6M algorithm ecdsa256; + }; + + zone-propagation-delay 1h; + max-zone-ttl P1D; + + parent-ds-ttl 1h; + parent-propagation-delay 1h; +}; + +dnssec-policy "csk-roll1-manual" { + manual-mode yes; + + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + purge-keys PT1H; + + cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes + keys { + csk key-directory lifetime P6M algorithm ecdsa256; + }; + + zone-propagation-delay 1h; + max-zone-ttl P1D; + + parent-ds-ttl 1h; + parent-propagation-delay 1h; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/csk-roll2.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk-roll2.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/csk-roll2.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk-roll2.conf 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,58 @@ +/* + * 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. + */ + +dnssec-policy "csk-roll2-autosign" { + signatures-refresh 12h; + signatures-validity P1D; + signatures-validity-dnskey P1D; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 1h; + purge-keys 0; + + cds-digest-types { "sha-256"; "sha-384"; }; // use two digest type for testing purposes + keys { + csk key-directory lifetime P6M algorithm ecdsa256; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; + + parent-ds-ttl PT1H; + parent-propagation-delay P1W; +}; + +dnssec-policy "csk-roll2-manual" { + manual-mode yes; + + signatures-refresh 12h; + signatures-validity P1D; + signatures-validity-dnskey P1D; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 1h; + purge-keys 0; + + cds-digest-types { "sha-256"; "sha-384"; }; // use two digest type for testing purposes + keys { + csk key-directory lifetime P6M algorithm ecdsa256; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; + + parent-ds-ttl PT1H; + parent-propagation-delay P1W; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/csk1.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk1.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/csk1.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk1.conf 2026-09-11 19:41:01.332326950 +0000 @@ -0,0 +1,50 @@ +/* + * 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. + */ + +dnssec-policy "csk-algoroll-kasp" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + csk lifetime unlimited algorithm rsasha256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "csk-algoroll-manual" { + manual-mode yes; + + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + csk lifetime unlimited algorithm rsasha256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/csk2.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk2.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/csk2.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/csk2.conf 2026-09-11 19:41:01.333326974 +0000 @@ -0,0 +1,50 @@ +/* + * 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. + */ + +dnssec-policy "csk-algoroll-kasp" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + csk lifetime unlimited algorithm ecdsa256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "csk-algoroll-manual" { + manual-mode yes; + + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + csk lifetime unlimited algorithm ecdsa256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/enable-dnssec.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/enable-dnssec.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/enable-dnssec.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/enable-dnssec.conf 2026-09-11 19:41:01.333326974 +0000 @@ -0,0 +1,52 @@ +/* + * 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. + */ + +dnssec-policy "enable-dnssec-autosign" { + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 300; + max-zone-ttl PT12H; + zone-propagation-delay PT5M; + retire-safety PT20M; + publish-safety PT5M; + + parent-propagation-delay 1h; + parent-ds-ttl 2h; + + keys { + csk lifetime unlimited algorithm 13; + }; +}; + +dnssec-policy "enable-dnssec-manual" { + manual-mode yes; + + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 300; + max-zone-ttl PT12H; + zone-propagation-delay PT5M; + retire-safety PT20M; + publish-safety PT5M; + + parent-propagation-delay 1h; + parent-ds-ttl 2h; + + keys { + csk lifetime unlimited algorithm 13; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/going-insecure.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/going-insecure.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/going-insecure.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/going-insecure.conf 2026-09-11 19:41:01.333326974 +0000 @@ -0,0 +1,21 @@ +/* + * 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. + */ + +dnssec-policy "unsigning" { + dnskey-ttl 7200; + + keys { + ksk key-directory lifetime unlimited algorithm ecdsa256; + zsk key-directory lifetime P60D algorithm ecdsa256; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/ksk-zsk.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/ksk-zsk.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/ksk-zsk.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/ksk-zsk.conf 2026-09-11 19:41:01.333326974 +0000 @@ -0,0 +1,92 @@ +/* + * 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. + */ + +dnssec-policy "rsasha256-kasp" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm rsasha256; + zsk lifetime unlimited algorithm rsasha256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "rsasha256-manual" { + manual-mode yes; + + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm rsasha256; + zsk lifetime unlimited algorithm rsasha256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "ecdsa256-kasp" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm ecdsa256; + zsk lifetime unlimited algorithm ecdsa256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "ecdsa256-manual" { + manual-mode yes; + + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm ecdsa256; + zsk lifetime unlimited algorithm ecdsa256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/ksk.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/ksk.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/ksk.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/ksk.conf 2026-09-11 19:41:01.333326974 +0000 @@ -0,0 +1,60 @@ +/* + * 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. + */ + +dnssec-policy "ksk-doubleksk-autosign" { + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 2h; + publish-safety P1D; + retire-safety P2D; + purge-keys PT1H; + + cdnskey no; + keys { + ksk key-directory lifetime P60D algorithm ecdsa256; + zsk key-directory lifetime unlimited algorithm ecdsa256; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; + + parent-ds-ttl 3600; + parent-propagation-delay PT1H; +}; + +dnssec-policy "ksk-doubleksk-manual" { + manual-mode yes; + + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 2h; + publish-safety P1D; + retire-safety P2D; + purge-keys PT1H; + + cdnskey no; + keys { + ksk key-directory lifetime P60D algorithm ecdsa256; + zsk key-directory lifetime unlimited algorithm ecdsa256; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; + + parent-ds-ttl 3600; + parent-propagation-delay PT1H; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/lifetime.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/lifetime.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/lifetime.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/lifetime.conf.j2 2026-09-11 19:41:01.333326974 +0000 @@ -0,0 +1,29 @@ +/* + * 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. + */ + +dnssec-policy "unlimited-lifetime" { + keys { + csk lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; +}; +dnssec-policy "short-lifetime" { + keys { + csk lifetime P6M algorithm @DEFAULT_ALGORITHM@; + }; +}; + +dnssec-policy "long-lifetime" { + keys { + csk lifetime P1Y algorithm @DEFAULT_ALGORITHM@; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/multisigner.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns3/policy/multisigner.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/multisigner.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/multisigner.conf.j2 2026-09-11 19:41:01.333326974 +0000 @@ -0,0 +1,22 @@ +/* + * 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. + */ + +dnssec-policy "multisigner-model2" { + dnskey-ttl 3600; + inline-signing no; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; + zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns3/policy/zsk-prepub.conf bind9-9.20.29/bin/tests/system/rollover/ns3/policy/zsk-prepub.conf --- bind9-9.20.26/bin/tests/system/rollover/ns3/policy/zsk-prepub.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns3/policy/zsk-prepub.conf 2026-09-11 19:41:01.333326974 +0000 @@ -0,0 +1,52 @@ +/* + * 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. + */ + +dnssec-policy "zsk-prepub-autosign" { + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 3600; + publish-safety P1D; + retire-safety P2D; + purge-keys PT1H; + + keys { + ksk key-directory lifetime unlimited algorithm ecdsa256; + zsk key-directory lifetime P30D algorithm ecdsa256; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; +}; + +dnssec-policy "zsk-prepub-manual" { + manual-mode yes; + + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 3600; + publish-safety P1D; + retire-safety P2D; + purge-keys PT1H; + + keys { + ksk key-directory lifetime unlimited algorithm ecdsa256; + zsk key-directory lifetime P30D algorithm ecdsa256; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; +}; diff -Nru bind9-9.20.26/bin/tests/system/rollover/ns4/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover/ns4/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover/ns4/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/ns4/named.common.conf.j2 2026-09-11 19:41:01.333326974 +0000 @@ -12,28 +12,15 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion no; - dnssec-validation no; + {% include_indented "_common/options.conf.j2" %} + allow-transfer { any; }; + recursion no; + dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { - type hint; - file "../../_common/root.hint.blackhole"; + type hint; + file "../../_common/root.hint.blackhole"; }; diff -Nru bind9-9.20.26/bin/tests/system/rollover/setup.py bind9-9.20.29/bin/tests/system/rollover/setup.py --- bind9-9.20.26/bin/tests/system/rollover/setup.py 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/setup.py 2026-09-11 19:41:01.334326998 +0000 @@ -154,7 +154,9 @@ TsbmN = "now-161h" csktimes = f"-P {TactN} -A {TactN}" # Key generation. - csk_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip() + csk_name = keygen( + f"-l policy/csk1.conf {csktimes} {zonename}", cwd="ns3" + ).out.strip() settime( f"-g OMNIPRESENT -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk_name}", cwd="ns3", @@ -173,8 +175,12 @@ csktimes = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I now" newtimes = f"-P {TpubN1} -A {TpubN1}" # Key generation. - csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip() - csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip() + csk1_name = keygen( + f"-l policy/csk1.conf {csktimes} {zonename}", cwd="ns3" + ).out.strip() + csk2_name = keygen( + f"-l policy/csk2.conf {newtimes} {zonename}", cwd="ns3" + ).out.strip() settime( f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk1_name}", cwd="ns3", @@ -197,8 +203,12 @@ csktimes = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}" newtimes = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}" # Key generation. - csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip() - csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip() + csk1_name = keygen( + f"-l policy/csk1.conf {csktimes} {zonename}", cwd="ns3" + ).out.strip() + csk2_name = keygen( + f"-l policy/csk2.conf {newtimes} {zonename}", cwd="ns3" + ).out.strip() settime( f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TactN} -d OMNIPRESENT {TactN} {csk1_name}", cwd="ns3", @@ -221,8 +231,12 @@ csktimes = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}" newtimes = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}" # Key generation. - csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip() - csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip() + csk1_name = keygen( + f"-l policy/csk1.conf {csktimes} {zonename}", cwd="ns3" + ).out.strip() + csk2_name = keygen( + f"-l policy/csk2.conf {newtimes} {zonename}", cwd="ns3" + ).out.strip() settime( f"-g HIDDEN -k OMNIPRESENT {TactN} -r OMNIPRESENT {TactN} -z OMNIPRESENT {TsbmN1} -d UNRETENTIVE {TsbmN1} -D ds {TsbmN1} {csk1_name}", cwd="ns3", @@ -245,8 +259,12 @@ csktimes = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}" newtimes = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}" # Key generation. - csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip() - csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip() + csk1_name = keygen( + f"-l policy/csk1.conf {csktimes} {zonename}", cwd="ns3" + ).out.strip() + csk2_name = keygen( + f"-l policy/csk2.conf {newtimes} {zonename}", cwd="ns3" + ).out.strip() settime( f"-g HIDDEN -k UNRETENTIVE {TactN} -r UNRETENTIVE {TactN} -z UNRETENTIVE {TsbmN1} -d HIDDEN {TsbmN1} {csk1_name}", cwd="ns3", @@ -269,8 +287,12 @@ csktimes = f"-P {TactN} -A {TactN} -P sync {TsbmN} -I {TsbmN1}" newtimes = f"-P {TpubN1} -A {TpubN1} -P sync {TsbmN1}" # Key generation. - csk1_name = keygen(f"-l csk1.conf {csktimes} {zonename}", cwd="ns3").out.strip() - csk2_name = keygen(f"-l csk2.conf {newtimes} {zonename}", cwd="ns3").out.strip() + csk1_name = keygen( + f"-l policy/csk1.conf {csktimes} {zonename}", cwd="ns3" + ).out.strip() + csk2_name = keygen( + f"-l policy/csk2.conf {newtimes} {zonename}", cwd="ns3" + ).out.strip() settime( f"-g HIDDEN -k HIDDEN {TactN} -r UNRETENTIVE {TactN} -z UNRETENTIVE {TactN} -d HIDDEN {TsbmN1} {csk1_name}", cwd="ns3", @@ -547,7 +569,7 @@ zones = [] zone = f"csk-roll1.{tld}" cds = "cdnskey,cds:sha384" - keygen = EnvCmd("KEYGEN", f"-k {policy} -l kasp.conf") + keygen = EnvCmd("KEYGEN", f"-k {policy} -l policy/csk-roll1.conf") settime = EnvCmd("SETTIME", "-s") # Step 1: @@ -878,7 +900,7 @@ zones = [] zone = f"csk-roll2.{tld}" cds = "cdnskey,cds:sha-256,cds:sha-384" - keygen = EnvCmd("KEYGEN", f"-k {policy} -l kasp.conf") + keygen = EnvCmd("KEYGEN", f"-k {policy} -l policy/csk-roll2.conf") settime = EnvCmd("SETTIME", "-s") # Step 1: @@ -1219,7 +1241,7 @@ # initial signing of a zone. zones = [] zone = f"enable-dnssec.{tld}" - keygen = EnvCmd("KEYGEN", f"-k {policy} -l kasp.conf") + keygen = EnvCmd("KEYGEN", f"-k {policy} -l policy/enable-dnssec.conf") settime = EnvCmd("SETTIME", "-s") # Step 1: diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_algo_csk_initial.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_csk_initial.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_algo_csk_initial.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_csk_initial.py 2026-09-11 19:41:01.334326998 +0000 @@ -0,0 +1,74 @@ +# 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. + +import pytest + +from isctest.util import param +from rollover.common import ALGOROLL_CONFIG, CDSS, DURATION, ROLLOVER_MARK, TIMEDELTA +from rollover.setup import configure_algo_csk, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + +POLICY = "csk-algoroll" + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "algo-csk", + } + + tlds = [] + for tld_name in [ + "kasp", + "manual", + ]: + delegations = configure_algo_csk( + tld_name, f"{POLICY}-{tld_name}", reconfig=False + ) + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_initial(tld, ns3): + config = ALGOROLL_CONFIG + zone = f"step1.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", + ], + "nextev": TIMEDELTA["PT1H"], + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_algo_csk_reconfig.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_csk_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_algo_csk_reconfig.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_csk_reconfig.py 2026-09-11 19:41:01.334326998 +0000 @@ -0,0 +1,361 @@ +# 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. + +import pytest + +from isctest.kasp import KeyTimingMetadata +from isctest.util import param +from rollover.common import ( + ALGOROLL_CONFIG, + ALGOROLL_IPUB, + ALGOROLL_IPUBC, + ALGOROLL_IRET, + ALGOROLL_IRETKSK, + ALGOROLL_KEYTTLPROP, + ALGOROLL_OFFSETS, + ALGOROLL_OFFVAL, + CDSS, + DURATION, + ROLLOVER_MARK, + TIMEDELTA, +) +from rollover.setup import configure_algo_csk, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + +CONFIG = ALGOROLL_CONFIG +POLICY = "csk-algoroll" +TIME_PASSED = 0 # set in reconfigure() fixture + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "algo-csk", + } + + tlds = [] + for tld_name in [ + "kasp", + "manual", + ]: + delegations = configure_algo_csk( + tld_name, f"{POLICY}-{tld_name}", reconfig=True + ) + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.fixture(scope="module", autouse=True) +def after_servers_start(ns3, templates): + global TIME_PASSED # pylint: disable=global-statement + + isctest.kasp.wait_keymgr_done(ns3, "step1.csk-algorithm-roll.kasp") + + templates.render("ns3/named-algo-csk.conf", {"csk_roll": True}) + start_time = KeyTimingMetadata.now() + ns3.reconfigure() + + # Calculate time passed to correctly check for next key events. + TIME_PASSED = KeyTimingMetadata.now().value - start_time.value + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step1(tld, ns3, default_algorithm): + zone = f"step1.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + if tld == "manual": + # Same as initial. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg1 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{tag} (CSK)" + msg2 = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" + assert msg1 in ns3.log + assert msg2 in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/RSASHA256" + ) + + # Check state after step. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The RSASHA keys are outroducing. + f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", + # The ECDSAP256SHA256 keys are introducing. + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden", + ], + # Next key event is when the ecdsa256 keys have been propagated. + "nextev": ALGOROLL_IPUB, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step2(tld, ns3, default_algorithm): + zone = f"step2.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The RSASHA keys are outroducing, but need to stay present + # until the new algorithm chain of trust has been established. + # Thus the expected key states of these keys stay the same. + f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", + # The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset is + # omnipresent, but the zone signatures are not. + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:hidden offset:{ALGOROLL_OFFSETS['step2']}", + ], + # Next key event is when all zone signatures are signed with the + # new algorithm. This is the child publication interval, minus + # the publication interval has already passed. Also, prevent + # intermittent false positives on slow platforms by subtracting + # the time passed between key creation and invoking 'rndc reconfig'. + "nextev": ALGOROLL_IPUBC - ALGOROLL_IPUB - TIME_PASSED, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step3(tld, ns3, default_algorithm): + zone = f"step3.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + if tld == "manual": + # Same as step 2, but the zone signatures have become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFSETS['step3']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" + ) + tag = keys[1].key.tag + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The DS can be swapped. + f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:unretentive offset:{ALGOROLL_OFFVAL}", + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:rumoured offset:{ALGOROLL_OFFSETS['step3']}", + ], + # Next key event is when the DS becomes OMNIPRESENT. This happens + # after the publication interval of the parent side. + "nextev": ALGOROLL_IRETKSK - TIME_PASSED, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step4(tld, ns3, default_algorithm): + zone = f"step4.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + if tld == "manual": + # Same as step 3, but the DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFVAL}", + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/RSASHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + assert msg in ns3.log + + # Force step. + tag = keys[1].key.tag + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The old DS is HIDDEN, we can remove the old algorithm records. + f"csk 0 8 2048 goal:hidden dnskey:unretentive krrsig:unretentive zrrsig:unretentive ds:hidden offset:{ALGOROLL_OFFVAL}", + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + ], + # Next key event is when the old DNSKEY becomes HIDDEN. + # This happens after the DNSKEY TTL plus zone propagation delay. + "nextev": ALGOROLL_KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step5(tld, ns3, default_algorithm): + zone = f"step5.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The DNSKEY becomes HIDDEN. + f"csk 0 8 2048 goal:hidden dnskey:hidden krrsig:hidden zrrsig:unretentive ds:hidden offset:{ALGOROLL_OFFVAL}", + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step5']}", + ], + # Next key event is when the RSASHA signatures become HIDDEN. + # This happens after the max-zone-ttl plus zone propagation delay + # minus the time already passed since the UNRETENTIVE state has + # been reached. Prevent intermittent false positives on slow + # platforms by subtracting the number of seconds which passed + # between key creation and invoking 'rndc reconfig'. + "nextev": ALGOROLL_IRET - ALGOROLL_IRETKSK - ALGOROLL_KEYTTLPROP - TIME_PASSED, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step6(tld, ns3, default_algorithm): + zone = f"step6.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The zone signatures are now HIDDEN. + f"csk 0 8 2048 goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{ALGOROLL_OFFVAL}", + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step6']}", + ], + # Next key event is never since we established the policy and the + # keys have an unlimited lifetime. Fallback to the default + # loadkeys interval. + "nextev": TIMEDELTA["PT1H"], + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_initial.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_initial.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_initial.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_initial.py 2026-09-11 19:41:01.334326998 +0000 @@ -0,0 +1,71 @@ +# 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. + +import pytest + +from isctest.util import param +from rollover.common import ALGOROLL_CONFIG, CDSS, DURATION, ROLLOVER_MARK, TIMEDELTA +from rollover.setup import configure_algo_ksk_zsk, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "algo-ksk-zsk", + } + + tlds = [] + for tld_name in [ + "kasp", + "manual", + ]: + delegations = configure_algo_ksk_zsk(tld_name, reconfig=False) + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_initial(tld, ns3): + config = ALGOROLL_CONFIG + policy = f"rsasha256-{tld}" + zone = f"step1.algorithm-roll.{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", + f"zsk 0 8 2048 goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P7D']}", + ], + "nextev": TIMEDELTA["PT1H"], + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_reconfig.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_reconfig.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_algo_ksk_zsk_reconfig.py 2026-09-11 19:41:01.334326998 +0000 @@ -0,0 +1,381 @@ +# 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. + +import pytest + +from isctest.kasp import KeyTimingMetadata +from isctest.util import param +from rollover.common import ( + ALGOROLL_CONFIG, + ALGOROLL_IPUB, + ALGOROLL_IPUBC, + ALGOROLL_IRET, + ALGOROLL_IRETKSK, + ALGOROLL_KEYTTLPROP, + ALGOROLL_OFFSETS, + ALGOROLL_OFFVAL, + CDSS, + DURATION, + ROLLOVER_MARK, + TIMEDELTA, +) +from rollover.setup import configure_algo_ksk_zsk, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + +CONFIG = ALGOROLL_CONFIG +POLICY = "ecdsa256" +TIME_PASSED = 0 # set in reconfigure() fixture + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "algo-ksk-zsk", + } + + tlds = [] + for tld_name in [ + "kasp", + "manual", + ]: + delegations = configure_algo_ksk_zsk(tld_name, reconfig=True) + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.fixture(scope="module", autouse=True) +def after_servers_start(ns3, templates): + global TIME_PASSED # pylint: disable=global-statement + + isctest.kasp.wait_keymgr_done(ns3, "step1.algorithm-roll.kasp") + + templates.render("ns3/named-algo-ksk-zsk.conf", {"alg_roll": True}) + start_time = KeyTimingMetadata.now() + ns3.reconfigure() + + # Calculate time passed to correctly check for next key events. + TIME_PASSED = KeyTimingMetadata.now().value - start_time.value + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step1(tld, ns3, default_algorithm): + zone = f"step1.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + if tld == "manual": + # Same as initial. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", + f"zsk 0 8 2048 goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P7D']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + ktag = keys[0].key.tag + ztag = keys[1].key.tag + msg1 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{ktag} (KSK)" + msg2 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{ztag} (ZSK)" + msg3 = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" # twice + assert msg1 in ns3.log + assert msg2 in ns3.log + assert len(ns3.log.grep(msg3)) == 2 + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {ktag}/RSASHA256" + ) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The RSASHA keys are outroducing. + f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", + # The ECDSAP256SHA256 keys are introducing. + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden", + f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured zrrsig:rumoured", + ], + # Next key event is when the ecdsa256 keys have been propagated. + "nextev": ALGOROLL_IPUB, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step2(tld, ns3, default_algorithm): + zone = f"step2.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The RSASHA keys are outroducing, but need to stay present + # until the new algorithm chain of trust has been established. + # Thus the expected key states of these keys stay the same. + f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", + # The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset is + # omnipresent, but the zone signatures are not. + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFSETS['step2']}", + f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:rumoured offset:{ALGOROLL_OFFSETS['step2']}", + ], + # Next key event is when all zone signatures are signed with the new + # algorithm. This is the max-zone-ttl plus zone propagation delay. But + # the publication interval has already passed. Also, prevent intermittent + # false positives on slow platforms by subtracting the time passed between + # key creation and invoking 'rndc reconfig'. + "nextev": ALGOROLL_IPUBC - ALGOROLL_IPUB - TIME_PASSED, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step3(tld, ns3, default_algorithm): + zone = f"step3.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + if tld == "manual": + # Same as step 2, but the zone signatures have become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFSETS['step3']}", + f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step3']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[2].key.tag + msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition KSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" + ) + tag = keys[2].key.tag + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The DS can be swapped. + f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{ALGOROLL_OFFSETS['step3']}", + f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step3']}", + ], + # Next key event is when the DS becomes OMNIPRESENT. This happens + # after the retire interval. + "nextev": ALGOROLL_IRETKSK - TIME_PASSED, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step4(tld, ns3, default_algorithm): + zone = f"step4.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + if tld == "manual": + # Same as step 3, but the DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + ktag = keys[0].key.tag + ztag = keys[1].key.tag + msg1 = f"keymgr-manual-mode: block transition KSK {zone}/RSASHA256/{ktag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + msg2 = f"keymgr-manual-mode: block transition ZSK {zone}/RSASHA256/{ztag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + assert msg1 in ns3.log + assert msg2 in ns3.log + + # Force step. + ktag = keys[3].key.tag + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {ktag}/ECDSAP256SHA256" + ) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The old DS is HIDDEN, we can remove the old algorithm records. + f"ksk 0 8 2048 goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:unretentive zrrsig:unretentive offset:{ALGOROLL_OFFVAL}", + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + ], + # Next key event is when the old DNSKEY becomes HIDDEN. + # This happens after the DNSKEY TTL plus zone propagation delay. + "nextev": ALGOROLL_KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step5(tld, ns3, default_algorithm): + zone = f"step5.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The DNSKEY becomes HIDDEN. + f"ksk 0 8 2048 goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:hidden zrrsig:unretentive offset:{ALGOROLL_OFFVAL}", + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step5']}", + f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step5']}", + ], + # Next key event is when the RSASHA signatures become HIDDEN. + # This happens after the max-zone-ttl plus zone propagation delay + # minus the time already passed since the UNRETENTIVE state has + # been reached. Prevent intermittent false positives on slow + # platforms by subtracting the number of seconds which passed + # between key creation and invoking 'rndc reconfig'. + "nextev": ALGOROLL_IRET - ALGOROLL_IRETKSK - ALGOROLL_KEYTTLPROP - TIME_PASSED, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step6(tld, ns3, default_algorithm): + zone = f"step6.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + # The zone signatures are now HIDDEN. + f"ksk 0 8 2048 goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:hidden zrrsig:hidden offset:{ALGOROLL_OFFVAL}", + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step6']}", + f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step6']}", + ], + # Next key event is never since we established the policy and the + # keys have an unlimited lifetime. Fallback to the default + # loadkeys interval. + "nextev": TIMEDELTA["PT1H"], + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_csk_roll1.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_csk_roll1.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_csk_roll1.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_csk_roll1.py 2026-09-11 19:41:01.334326998 +0000 @@ -0,0 +1,454 @@ +# 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. + +from datetime import timedelta + +import pytest + +from isctest.kasp import Ipub, Iret +from isctest.util import param +from rollover.common import ROLLOVER_MARK, TIMEDELTA +from rollover.setup import configure_cskroll1, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + +CDSS = ["CDNSKEY", "CDS (SHA-384)"] +CONFIG = { + "dnskey-ttl": TIMEDELTA["PT1H"], + "ds-ttl": TIMEDELTA["PT1H"], + "max-zone-ttl": TIMEDELTA["P1D"], + "parent-propagation-delay": TIMEDELTA["PT1H"], + "publish-safety": TIMEDELTA["PT1H"], + "purge-keys": TIMEDELTA["PT1H"], + "retire-safety": TIMEDELTA["PT2H"], + "signatures-refresh": TIMEDELTA["P5D"], + "signatures-validity": TIMEDELTA["P30D"], + "zone-propagation-delay": TIMEDELTA["PT1H"], +} +POLICY = "csk-roll1" +CSK_LIFETIME = timedelta(days=31 * 6) +LIFETIME_POLICY = int(CSK_LIFETIME.total_seconds()) +IPUB = Ipub(CONFIG) +IRETZSK = Iret(CONFIG) +IRETKSK = Iret(CONFIG, zsk=False, ksk=True) +KEYTTLPROP = CONFIG["dnskey-ttl"] + CONFIG["zone-propagation-delay"] +SIGNDELAY = IRETZSK - IRETKSK - KEYTTLPROP +OFFSETS = {} +OFFSETS["step1-p"] = -int(timedelta(days=7).total_seconds()) +OFFSETS["step2-p"] = -int(CSK_LIFETIME.total_seconds() - IPUB.total_seconds()) +OFFSETS["step2-s"] = 0 +OFFSETS["step3-p"] = -int(CSK_LIFETIME.total_seconds()) +OFFSETS["step3-s"] = -int(IPUB.total_seconds()) +OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(IRETKSK.total_seconds()) +OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(IRETKSK.total_seconds()) +OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KEYTTLPROP.total_seconds()) +OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KEYTTLPROP.total_seconds()) +OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(SIGNDELAY.total_seconds()) +OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(SIGNDELAY.total_seconds()) +OFFSETS["step7-p"] = OFFSETS["step6-p"] - int(KEYTTLPROP.total_seconds()) +OFFSETS["step7-s"] = OFFSETS["step6-s"] - int(KEYTTLPROP.total_seconds()) +OFFSETS["step8-p"] = OFFSETS["step7-p"] - int(CONFIG["purge-keys"].total_seconds()) +OFFSETS["step8-s"] = OFFSETS["step7-s"] - int(CONFIG["purge-keys"].total_seconds()) + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": POLICY, + } + + tlds = [] + for tld_name in [ + "autosign", + "manual", + ]: + delegations = configure_cskroll1(tld_name, f"{POLICY}-{tld_name}") + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step1(tld, ns3, default_algorithm): + zone = f"step1.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + # Note that the key was already generated during setup. + + step = { + # Introduce the first key. This will immediately be active. + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", + ], + # Next key event is when the successor CSK needs to be published + # minus time already elapsed. This is Lcsk - Ipub + Dreg (we ignore + # registration delay). + "nextev": CSK_LIFETIME - IPUB - timedelta(days=7), + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step2(tld, ns3, default_algorithm): + zone = f"step2.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 1. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block CSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # Successor CSK is prepublished (signs DNSKEY RRset, but not yet + # other RRsets). + # CSK1 goal: omnipresent -> hidden + # CSK2 goal: hidden -> omnipresent + # CSK2 dnskey: hidden -> rumoured + # CSK2 krrsig: hidden -> rumoured + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:hidden ds:hidden offset:{OFFSETS['step2-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the successor CSK becomes OMNIPRESENT. + "nextev": IPUB, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step3(tld, ns3, default_algorithm): + zone = f"step3.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 2, but DNSKEY has become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [0, 1], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # Successor CSK becomes omnipresent, meaning we can start signing + # the remainder of the zone with the successor CSK, and we can + # submit the DS. + "zone": zone, + "cdss": CDSS, + # Predecessor CSK will be removed, so moving to UNRETENTIVE. + # CSK1 zrrsig: omnipresent -> unretentive + # Successor CSK DNSKEY is OMNIPRESENT, so moving ZRRSIG to RUMOURED. + # CSK2 dnskey: rumoured -> omnipresent + # CSK2 krrsig: rumoured -> omnipresent + # CSK2 zrrsig: hidden -> rumoured + # The predecessor DS can be withdrawn and the successor DS can be + # introduced. + # CSK1 ds: omnipresent -> unretentive + # CSK2 ds: hidden -> rumoured + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:unretentive offset:{OFFSETS['step3-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:rumoured offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the predecessor DS has been replaced with + # the successor DS and enough time has passed such that the all + # validators that have this DS RRset cached only know about the + # successor DS. This is the the retire interval. + "nextev": IRETKSK, + # Set 'smooth' to true so expected signatures of subdomain are + # from the predecessor ZSK. + "smooth": True, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step4(tld, ns3, default_algorithm): + zone = f"step4.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 3, but DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [0, 1], + "manual-mode": True, + "nextev": None, + # We already swapped the DS in the previous step, so disable ds-swap. + "ds-swap": False, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" + assert msg in ns3.log + + # Force step. + tag = keys[1].key.tag + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + "zone": zone, + "cdss": CDSS, + # The predecessor CSK is no longer signing the DNSKEY RRset. + # CSK1 krrsig: omnipresent -> unretentive + # The predecessor DS is hidden. The successor DS is now omnipresent. + # CSK1 ds: unretentive -> hidden + # CSK2 ds: rumoured -> omnipresent + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:unretentive zrrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the KRRSIG enters the HIDDEN state. + # This is the DNSKEY TTL plus zone propagation delay. + "nextev": KEYTTLPROP, + # We already swapped the DS in the previous step, so disable ds-swap. + "ds-swap": False, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step5(tld, ns3, default_algorithm): + zone = f"step5.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + # The predecessor KRRSIG records are now all hidden. + # CSK1 krrsig: unretentive -> hidden + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:hidden zrrsig:unretentive ds:hidden offset:{OFFSETS['step5-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step5-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the DNSKEY can be removed. This is when + # all ZRRSIG records have been replaced with signatures of the new + # CSK. + "nextev": SIGNDELAY, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step6(tld, ns3, default_algorithm): + zone = f"step6.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + return + + step = { + "zone": zone, + "cdss": CDSS, + # The predecessor ZRRSIG records are now all hidden (so the DNSKEY + # can be removed). + # CSK1 dnskey: omnipresent -> unretentive + # CSK1 zrrsig: unretentive -> hidden + # CSK2 zrrsig: rumoured -> omnipresent + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step6-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the DNSKEY enters the HIDDEN state. + # This is the DNSKEY TTL plus zone propagation delay. + "nextev": KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step7(tld, ns3, default_algorithm): + zone = f"step7.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + # The predecessor CSK is now completely HIDDEN. + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step7-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step7-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the new successor needs to be published. + # This is the Lcsk, minus time passed since the key started signing, + # minus the prepublication time. + "nextev": CSK_LIFETIME - IRETZSK - IPUB - KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step8(tld, ns3, default_algorithm): + zone = f"step8.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step8-s']}", + ], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_csk_roll2.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_csk_roll2.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_csk_roll2.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_csk_roll2.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,430 @@ +# 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. + +from datetime import timedelta + +import pytest + +from isctest.kasp import Ipub, Iret +from isctest.util import param +from rollover.common import ROLLOVER_MARK, TIMEDELTA +from rollover.setup import configure_cskroll2, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + +CDSS = ["CDNSKEY", "CDS (SHA-256)", "CDS (SHA-384)"] +CONFIG = { + "dnskey-ttl": TIMEDELTA["PT1H"], + "ds-ttl": TIMEDELTA["PT1H"], + "max-zone-ttl": TIMEDELTA["P1D"], + "parent-propagation-delay": TIMEDELTA["P7D"], + "publish-safety": TIMEDELTA["PT1H"], + "purge-keys": TIMEDELTA[0], + "retire-safety": TIMEDELTA["PT1H"], + "signatures-refresh": TIMEDELTA["PT12H"], + "signatures-validity": TIMEDELTA["P1D"], + "zone-propagation-delay": TIMEDELTA["PT1H"], +} +POLICY = "csk-roll2" +CSK_LIFETIME = timedelta(days=31 * 6) +LIFETIME_POLICY = int(CSK_LIFETIME.total_seconds()) + +IPUB = Ipub(CONFIG) +IRET = Iret(CONFIG, zsk=True, ksk=True) +IRETZSK = Iret(CONFIG) +IRETKSK = Iret(CONFIG, ksk=True) +KEYTTLPROP = CONFIG["dnskey-ttl"] + CONFIG["zone-propagation-delay"] +OFFSETS = {} +OFFSETS["step1-p"] = -int(timedelta(days=7).total_seconds()) +OFFSETS["step2-p"] = -int(CSK_LIFETIME.total_seconds() - IPUB.total_seconds()) +OFFSETS["step2-s"] = 0 +OFFSETS["step3-p"] = -int(CSK_LIFETIME.total_seconds()) +OFFSETS["step3-s"] = -int(IPUB.total_seconds()) +OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(IRETZSK.total_seconds()) +OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(IRETZSK.total_seconds()) +OFFSETS["step5-p"] = OFFSETS["step4-p"] - int( + IRETKSK.total_seconds() - IRETZSK.total_seconds() +) +OFFSETS["step5-s"] = OFFSETS["step4-s"] - int( + IRETKSK.total_seconds() - IRETZSK.total_seconds() +) +OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(KEYTTLPROP.total_seconds()) +OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KEYTTLPROP.total_seconds()) +OFFSETS["step7-p"] = OFFSETS["step6-p"] - int(timedelta(days=90).total_seconds()) +OFFSETS["step7-s"] = OFFSETS["step6-s"] - int(timedelta(days=90).total_seconds()) + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": POLICY, + } + + tlds = [] + for tld_name in [ + "autosign", + "manual", + ]: + delegations = configure_cskroll2(tld_name, f"{POLICY}-{tld_name}") + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step1(tld, ns3, default_algorithm): + zone = f"step1.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + # Note that the key was already generated during setup. + + step = { + # Introduce the first key. This will immediately be active. + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", + ], + # Next key event is when the successor CSK needs to be published + # minus time already elapsed. This is Lcsk - Ipub + Dreg (we ignore + # registration delay). + "nextev": CSK_LIFETIME - IPUB - TIMEDELTA["P7D"], + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step2(tld, ns3, default_algorithm): + zone = f"step2.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 1. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block CSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # Successor CSK is prepublished (signs DNSKEY RRset, but not yet + # other RRsets). + # CSK1 goal: omnipresent -> hidden + # CSK2 goal: hidden -> omnipresent + # CSK2 dnskey: hidden -> rumoured + # CSK2 krrsig: hidden -> rumoured + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:hidden ds:hidden offset:{OFFSETS['step2-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the successor CSK becomes OMNIPRESENT. + "nextev": IPUB, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step3(tld, ns3, default_algorithm): + zone = f"step3.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 2, but DNSKEY has become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [0, 1], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # Successor CSK becomes omnipresent, meaning we can start signing + # the remainder of the zone with the successor CSK, and we can + # submit the DS. + "zone": zone, + "cdss": CDSS, + # Predecessor CSK will be removed, so moving to UNRETENTIVE. + # CSK1 zrrsig: omnipresent -> unretentive + # Successor CSK DNSKEY is OMNIPRESENT, so moving ZRRSIG to RUMOURED. + # CSK2 dnskey: rumoured -> omnipresent + # CSK2 krrsig: rumoured -> omnipresent + # CSK2 zrrsig: hidden -> rumoured + # The predecessor DS can be withdrawn and the successor DS can be + # introduced. + # CSK1 ds: omnipresent -> unretentive + # CSK2 ds: hidden -> rumoured + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:unretentive offset:{OFFSETS['step3-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:rumoured offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the predecessor DS has been replaced with + # the successor DS and enough time has passed such that the all + # validators that have this DS RRset cached only know about the + # successor DS. This is the the retire interval. + "nextev": IRETZSK, + # Set 'smooth' to true so expected signatures of subdomain are + # from the predecessor ZSK. + "smooth": True, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step4(tld, ns3, default_algorithm): + zone = f"step4.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + # The predecessor ZRRSIG is HIDDEN. The successor ZRRSIG is + # OMNIPRESENT. + # CSK1 zrrsig: unretentive -> hidden + # CSK2 zrrsig: rumoured -> omnipresent + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:unretentive offset:{OFFSETS['step4-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:rumoured offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the predecessor DS has been replaced with + # the successor DS and enough time has passed such that the all + # validators that have this DS RRset cached only know about the + # successor DS. This is the retire interval of the KSK part (minus) + # time already elapsed). + "nextev": IRET - IRETZSK, + # We already swapped the DS in the previous step, so disable ds-swap. + "ds-swap": False, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step5(tld, ns3, default_algorithm): + zone = f"step5.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 4, but DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", + ], + "keyrelationships": [0, 1], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg1 = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + msg2 = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" + assert msg1 in ns3.log + assert msg2 in ns3.log + + # Force step. + tag = keys[1].key.tag + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + "zone": zone, + "cdss": CDSS, + # The predecessor DNSKEY can be removed. + # CSK1 dnskey: omnipresent -> unretentive + # CSK1 krrsig: omnipresent -> unretentive + # CSK1 ds: unretentive -> hidden + # The successor key is now fully OMNIPRESENT. + # CSK2 ds: rumoured -> omnipresent + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive krrsig:unretentive zrrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the DNSKEY enters the HIDDEN state. + # This is the DNSKEY TTL plus zone propagation delay. + "nextev": KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step6(tld, ns3, default_algorithm): + zone = f"step6.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + # The predecessor CSK is now completely HIDDEN. + # CSK1 dnskey: unretentive -> hidden + # CSK1 krrsig: unretentive -> hidden + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step6-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}", + ], + "keyrelationships": [0, 1], + # Next key event is when the new successor needs to be published. + # This is the Lcsk, minus time passed since the key was published. + "nextev": CSK_LIFETIME - IRET - IPUB - KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step7(tld, ns3, default_algorithm): + zone = f"step7.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + # The predecessor CSK is now completely HIDDEN. + "keyprops": [ + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step7-p']}", + f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step7-s']}", + ], + "keyrelationships": [0, 1], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_dynamic2inline.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_dynamic2inline.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_dynamic2inline.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_dynamic2inline.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,50 @@ +# 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. + +from rollover.common import CDSS, DEFAULT_CONFIG, ROLLOVER_MARK + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + data = { + "testconf": "dynamic2inline", + "trust_anchors": [], + } + + return data + + +def test_dynamic2inline(ns3, default_algorithm, templates): + config = DEFAULT_CONFIG + policy = "default" + zone = "dynamic2inline.kasp" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden", + ], + "nextev": None, + } + + isctest.kasp.check_rollover_step(ns3, config, policy, step) + + templates.render("ns3/named-dynamic2inline.conf", {"change_lifetime": True}) + ns3.reconfigure() + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_enable_dnssec.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_enable_dnssec.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_enable_dnssec.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_enable_dnssec.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,231 @@ +# 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. + +import pytest + +from isctest.kasp import Ipub, IpubC, Iret +from isctest.util import param +from rollover.common import CDSS, ROLLOVER_MARK, TIMEDELTA +from rollover.setup import configure_enable_dnssec, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + +CONFIG = { + "dnskey-ttl": TIMEDELTA["PT5M"], + "ds-ttl": TIMEDELTA["PT2H"], + "max-zone-ttl": TIMEDELTA["PT12H"], + "parent-propagation-delay": TIMEDELTA["PT1H"], + "publish-safety": TIMEDELTA["PT5M"], + "retire-safety": TIMEDELTA["PT20M"], + "signatures-refresh": TIMEDELTA["P7D"], + "signatures-validity": TIMEDELTA["P14D"], + "zone-propagation-delay": TIMEDELTA["PT5M"], +} +POLICY = "enable-dnssec" +IPUB = Ipub(CONFIG) +IPUBC = IpubC(CONFIG, rollover=False) +IRETZSK = Iret(CONFIG, rollover=False) +IRETKSK = Iret(CONFIG, zsk=False, ksk=True, rollover=False) +OFFSETS = {} +OFFSETS["step1"] = 0 +OFFSETS["step2"] = -int(IPUB.total_seconds()) +OFFSETS["step3"] = -int(IRETZSK.total_seconds()) +OFFSETS["step4"] = -int(IPUBC.total_seconds() + IRETKSK.total_seconds()) + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": POLICY, + } + + tlds = [] + for tld_name in [ + "autosign", + "manual", + ]: + delegations = configure_enable_dnssec(tld_name, f"{POLICY}-{tld_name}") + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_rollover_enable_dnssec_step1(tld, default_algorithm, ns3): + zone = f"step1.enable-dnssec.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as insecure. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [], + "manual-mode": True, + "zone-signed": False, + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + msg = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden offset:{OFFSETS['step1']}", + ], + # Next key event is when the DNSKEY RRset becomes OMNIPRESENT, + # after the publication interval. + "nextev": IPUB, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_rollover_enable_dnssec_step2(tld, default_algorithm, ns3): + zone = f"step2.enable-dnssec.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + # The DNSKEY is omnipresent, but the zone signatures not yet. + # Thus, the DS remains hidden. + # dnskey: rumoured -> omnipresent + # krrsig: rumoured -> omnipresent + "keyprops": [ + f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:hidden offset:{OFFSETS['step2']}", + ], + # Next key event is when the zone signatures become OMNIPRESENT, + # Minus the time already elapsed. + "nextev": IRETZSK - IPUB, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_rollover_enable_dnssec_step3(tld, default_algorithm, ns3): + zone = f"step3.enable-dnssec.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 2, but zone signatures have become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{OFFSETS['step3']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + "zone": zone, + "cdss": CDSS, + # All signatures should be omnipresent, so the DS can be submitted. + # zrrsig: rumoured -> omnipresent + # ds: hidden -> rumoured + "keyprops": [ + f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:rumoured offset:{OFFSETS['step3']}", + ], + # Next key event is when the DS can move to the OMNIPRESENT state. + # This is after the retire interval. + "nextev": IRETKSK, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_rollover_enable_dnssec_step4(tld, default_algorithm, ns3): + zone = f"step4.enable-dnssec.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + "zone": zone, + "cdss": CDSS, + # DS has been published long enough. + # ds: rumoured -> omnipresent + "keyprops": [ + f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4']}", + ], + # Next key event is never, the zone dnssec-policy has been + # established. So we fall back to the default loadkeys interval. + "nextev": TIMEDELTA["PT1H"], + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_going_insecure_initial.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_going_insecure_initial.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_going_insecure_initial.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_going_insecure_initial.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,63 @@ +# 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. + +import pytest + +from rollover.common import CDSS, DURATION, ROLLOVER_MARK, UNSIGNING_CONFIG +from rollover.setup import configure_going_insecure, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "going-insecure", + } + + tlds = [] + tld_name = "kasp" + delegations = configure_going_insecure(tld_name, reconfig=False) + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + data["tlds"].append(tld_name) + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + return data + + +@pytest.mark.parametrize( + "zone", + [ + "going-insecure.kasp", + "going-insecure-dynamic.kasp", + ], +) +def test_going_insecure_initial(zone, ns3, default_algorithm): + config = UNSIGNING_CONFIG + policy = "unsigning" + zone = f"step1.{zone}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P10D']}", + f"zsk {DURATION['P60D']} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P10D']}", + ], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_going_insecure_reconfig.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_going_insecure_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_going_insecure_reconfig.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_going_insecure_reconfig.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,117 @@ +# 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. + +import pytest + +from rollover.common import ( + CDSS, + DEFAULT_CONFIG, + DURATION, + ROLLOVER_MARK, + UNSIGNING_CONFIG, +) +from rollover.setup import configure_going_insecure, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "going-insecure", + } + + tlds = [] + tld_name = "kasp" + delegations = configure_going_insecure(tld_name, reconfig=True) + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + data["tlds"].append(tld_name) + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + return data + + +@pytest.fixture(scope="module", autouse=True) +def after_servers_start(ns3, templates): + templates.render("ns3/named-going-insecure.conf", {"policy": "insecure"}) + ns3.reconfigure() # move from "unsigning" to "insecure" + + +@pytest.mark.parametrize( + "zone", + [ + "going-insecure.kasp", + "going-insecure-dynamic.kasp", + ], +) +def test_going_insecure_reconfig_step1(zone, ns3, default_algorithm): + config = DEFAULT_CONFIG + policy = "insecure" + zone = f"step1.{zone}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + # Key goal states should be HIDDEN. + # The DS may be removed if we are going insecure. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{-DURATION['P10D']}", + f"zsk {DURATION['P60D']} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P10D']}", + ], + # Next key event is when the DS becomes HIDDEN. This + # happens after the# parent propagation delay plus DS TTL. + "nextev": DEFAULT_CONFIG["ds-ttl"] + DEFAULT_CONFIG["parent-propagation-delay"], + # Going insecure, check for CDS/CDNSKEY DELETE, and skip key timing checks. + "cds-delete": True, + "check-keytimes": False, + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) + + +@pytest.mark.parametrize( + "zone", + [ + "going-insecure.kasp", + "going-insecure-dynamic.kasp", + ], +) +def test_going_insecure_reconfig_step2(zone, ns3, default_algorithm): + config = DEFAULT_CONFIG + policy = "insecure" + zone = f"step2.{zone}" + + isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) + + # The DS is long enough removed from the zone to be considered + # HIDDEN. This means the DNSKEY and the KSK signatures can be + # removed. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{-DURATION['P10D']}", + f"zsk {DURATION['P60D']} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive zrrsig:unretentive offset:{-DURATION['P10D']}", + ], + # Next key event is when the DNSKEY becomes HIDDEN. + # This happens after the propagation delay, plus DNSKEY TTL. + "nextev": UNSIGNING_CONFIG["dnskey-ttl"] + + DEFAULT_CONFIG["zone-propagation-delay"], + # Zone is no longer signed. + "zone-signed": False, + "check-keytimes": False, + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_ksk_doubleksk.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_ksk_doubleksk.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_ksk_doubleksk.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_ksk_doubleksk.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,372 @@ +# 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. + +from datetime import timedelta + +import pytest + +from isctest.util import param +from rollover.common import ( + KSK_CONFIG, + KSK_IPUB, + KSK_IPUBC, + KSK_IRET, + KSK_KEYTTLPROP, + KSK_LIFETIME, + KSK_LIFETIME_POLICY, + ROLLOVER_MARK, + TIMEDELTA, +) +from rollover.setup import configure_ksk_doubleksk, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + +CDSS = ["CDS (SHA-256)"] +POLICY = "ksk-doubleksk" +OFFSETS = {} +OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds()) +OFFSETS["step2-p"] = -int(KSK_LIFETIME.total_seconds() - KSK_IPUBC.total_seconds()) +OFFSETS["step2-s"] = 0 +OFFSETS["step3-p"] = -int(KSK_LIFETIME.total_seconds()) +OFFSETS["step3-s"] = -int(KSK_IPUBC.total_seconds()) +OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(KSK_IRET.total_seconds()) +OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(KSK_IRET.total_seconds()) +OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KSK_KEYTTLPROP.total_seconds()) +OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KSK_KEYTTLPROP.total_seconds()) +OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(KSK_CONFIG["purge-keys"].total_seconds()) +OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KSK_CONFIG["purge-keys"].total_seconds()) + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "ksk-doubleksk", + } + + tlds = [] + for tld_name in [ + "autosign", + "manual", + ]: + delegations = configure_ksk_doubleksk(tld_name) + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step1(tld, ns3, default_algorithm): + zone = f"step1.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + # Note that the key was already generated during setup. + + step = { + # Introduce the first key. This will immediately be active. + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step1-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", + ], + # Next key event is when the successor KSK needs to be published. + # That is the KSK lifetime - prepublication time (minus time + # already passed). + "nextev": KSK_LIFETIME - KSK_IPUB - timedelta(days=7), + } + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step2(tld, ns3, default_algorithm): + zone = f"step2.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 1. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block KSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # Successor KSK is prepublished (and signs DNSKEY RRset). + # KSK1 goal: omnipresent -> hidden + # KSK2 goal: hidden -> omnipresent + # KSK2 dnskey: hidden -> rumoured + # KSK2 krrsig: hidden -> rumoured + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:{OFFSETS['step2-s']}", + ], + "keyrelationships": [1, 2], + # Next key event is when the successor KSK becomes OMNIPRESENT. + "nextev": KSK_IPUB, + } + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step3(tld, ns3, default_algorithm): + zone = f"step3.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 2, but DNSKEY has become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [1, 2], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + # Check logs. + tag = keys[2].key.tag + msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # The successor DNSKEY RRset has become omnipresent. The + # predecessor DS can be withdrawn and the successor DS can be + # introduced. + # KSK1 ds: omnipresent -> unretentive + # KSK2 dnskey: rumoured -> omnipresent + # KSK2 krrsig: rumoured -> omnipresent + # KSK2 ds: hidden -> rumoured + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSETS['step3-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [1, 2], + # Next key event is when the predecessor DS has been replaced with + # the successor DS and enough time has passed such that the all + # validators that have this DS RRset cached only know about the + # successor DS. This is the the retire interval. + "nextev": KSK_IRET, + } + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step4(tld, ns3, default_algorithm): + zone = f"step4.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 3, but DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step4-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [1, 2], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg1 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + msg2 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" + assert msg1 in ns3.log + assert msg2 in ns3.log + + # Force step. + tag = keys[2].key.tag + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # The predecessor DNSKEY may be removed, the successor DS is + # omnipresent. + # KSK1 dnskey: omnipresent -> unretentive + # KSK1 krrsig: omnipresent -> unretentive + # KSK1 ds: unretentive -> hidden + # KSK2 ds: rumoured -> omnipresent + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [1, 2], + # Next key event is when the DNSKEY enters the HIDDEN state. + # This is the DNSKEY TTL plus zone propagation delay. + "nextev": KSK_KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step5(tld, ns3, default_algorithm): + zone = f"step5.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + # The predecessor DNSKEY is long enough removed from the zone it + # has become hidden. + # KSK1 dnskey: unretentive -> hidden + # KSK1 krrsig: unretentive -> hidden + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step5-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", + ], + "keyrelationships": [1, 2], + # Next key event is when the new successor needs to be published. + # This is the KSK lifetime minus Ipub minus Iret minus time elapsed. + "nextev": KSK_LIFETIME - KSK_IPUB - KSK_IRET - KSK_KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step6(tld, ns3, default_algorithm): + zone = f"step6.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + # Predecessor KSK is now purged. + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step6-p']}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}", + ], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_lifetime_initial.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_lifetime_initial.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_lifetime_initial.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_lifetime_initial.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,60 @@ +# 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. + +import shutil + +import pytest + +from isctest.util import param +from rollover.common import CDSS, DEFAULT_CONFIG, DURATION, ROLLOVER_MARK + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + data = { + "testconf": "lifetime", + "trust_anchors": [], + } + + shutil.copyfile("ns3/lifetime.db.in", "ns3/longer-lifetime.db") + shutil.copyfile("ns3/lifetime.db.in", "ns3/shorter-lifetime.db") + shutil.copyfile("ns3/lifetime.db.in", "ns3/limit-lifetime.db") + shutil.copyfile("ns3/lifetime.db.in", "ns3/unlimit-lifetime.db") + + return data + + +@pytest.mark.parametrize( + "zone, policy, lifetime", + [ + param("shorter-lifetime", "long-lifetime", "P1Y"), + param("longer-lifetime", "short-lifetime", "P6M"), + param("limit-lifetime", "unlimited-lifetime", 0), + param("unlimit-lifetime", "short-lifetime", "P6M"), + ], +) +def test_lifetime_initial(zone, policy, lifetime, ns3, default_algorithm): + config = DEFAULT_CONFIG + + isctest.kasp.wait_keymgr_done(ns3, f"{zone}.kasp") + + step = { + "zone": f"{zone}.kasp", + "cdss": CDSS, + "keyprops": [ + f"csk {DURATION[lifetime]} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden", + ], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_lifetime_reconfig.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_lifetime_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_lifetime_reconfig.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_lifetime_reconfig.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,75 @@ +# 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. + +import shutil + +import pytest + +from isctest.util import param +from rollover.common import CDSS, DEFAULT_CONFIG, DURATION, ROLLOVER_MARK + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + data = { + "testconf": "lifetime", + "trust_anchors": [], + } + + shutil.copyfile("ns3/lifetime.db.in", "ns3/longer-lifetime.db") + shutil.copyfile("ns3/lifetime.db.in", "ns3/shorter-lifetime.db") + shutil.copyfile("ns3/lifetime.db.in", "ns3/limit-lifetime.db") + shutil.copyfile("ns3/lifetime.db.in", "ns3/unlimit-lifetime.db") + + return data + + +@pytest.fixture(scope="module", autouse=True) +def after_servers_start(ns3, templates): + isctest.kasp.wait_keymgr_done(ns3, "shorter-lifetime.kasp") + isctest.kasp.wait_keymgr_done(ns3, "longer-lifetime.kasp") + isctest.kasp.wait_keymgr_done(ns3, "limit-lifetime.kasp") + isctest.kasp.wait_keymgr_done(ns3, "unlimit-lifetime.kasp") + + templates.render("ns3/named-lifetime.conf", {"change_lifetime": True}) + ns3.reconfigure() + + +@pytest.mark.parametrize( + "zone, policy, lifetime", + [ + param("shorter-lifetime", "short-lifetime", "P6M"), + param("longer-lifetime", "long-lifetime", "P1Y"), + param( + "limit-lifetime", + "short-lifetime", + "P6M", + ), + param("unlimit-lifetime", "unlimited-lifetime", 0), + ], +) +def test_lifetime_reconfig(zone, policy, lifetime, ns3, default_algorithm): + config = DEFAULT_CONFIG + + isctest.kasp.wait_keymgr_done(ns3, f"{zone}.kasp", reconfig=True) + + step = { + "zone": f"{zone}.kasp", + "cdss": CDSS, + "keyprops": [ + f"csk {DURATION[lifetime]} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden", + ], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_manual.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_manual.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_manual.py 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_manual.py 2026-09-11 19:41:01.335327022 +0000 @@ -101,6 +101,7 @@ data = { "tlds": [], "trust_anchors": [], + "testconf": "manual", } tld = configure_tld("kasp", zones) data["tlds"].append("kasp") diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_multisigner.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_multisigner.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_multisigner.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_multisigner.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,243 @@ +# 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. + +from datetime import timedelta + +import os + +import dns.update + +from isctest.kasp import Iret +from isctest.run import EnvCmd +from rollover.common import ROLLOVER_MARK +from rollover.setup import fake_lifetime, render_and_sign_zone + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + templates = isctest.template.TemplateEngine(".") + + # Multi-signer zones. + keygen = EnvCmd("KEYGEN", "-a ECDSA256 -L 3600") + settime = EnvCmd("SETTIME", "-s") + + # Model 2. + zonename = "multisigner-model2.kasp" + isctest.log.info(f"setup {zonename}") + # Key generation. + ksk_name = keygen(f"-M 32768:65535 -f KSK {zonename}", cwd="ns3").out.strip() + zsk_name = keygen(f"-M 32768:65535 {zonename}", cwd="ns3").out.strip() + # Signing. + dnskeys = [] + for key_name in [ksk_name, zsk_name]: + key = isctest.kasp.Key(key_name, keydir="ns3") + dnskeys.append(key.dnskey) + # Import a ZSK of another provider into the DNSKEY RRset. + zsk_extra = keygen(f"-M 0:32767 {zonename}").out.strip() + key = isctest.kasp.Key(zsk_extra) + dnskeys.append(key.dnskey) + # Render zone file. + outfile = f"{zonename}.db" + templates = isctest.template.TemplateEngine(".") + template = "template.db.j2.manual" + tdata = { + "fqdn": f"{zonename}.", + "dnskeys": dnskeys, + "privaterrs": [], + } + templates.render(f"ns3/{outfile}", tdata, template=f"ns3/{template}") + + # We are changing an existing single-signed zone to multi-signed + # zone where the key tags do not match the dnssec-policy key tag range + zonename = "single-to-multisigner.kasp" + isctest.log.info(f"setup {zonename}") + # Timing metadata. + TpubN = "now-7d" + TsbmN = "now-8635mi" # T - 1d5m + keytimes = f"-P {TpubN} -A {TpubN}" + cdstimes = f"-P sync {TsbmN}" + # Key generation. + ksk_name = keygen( + f"-M 0:32767 -f KSK {keytimes} {cdstimes} {zonename}", cwd="ns3" + ).out.strip() + zsk_name = keygen(f"-M 0:32767 {keytimes} {zonename}", cwd="ns3").out.strip() + settime( + f"-g OMNIPRESENT -d OMNIPRESENT {TpubN} -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} {ksk_name}", + cwd="ns3", + ) + settime( + f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} {zsk_name}", + cwd="ns3", + ) + # Signing. + fake_lifetime(ksk_name, 0) + fake_lifetime(zsk_name, 0) + render_and_sign_zone(zonename, [ksk_name, zsk_name]) + + data = { + "testconf": "multisigner", + "trust_anchors": [], + } + + return data + + +def test_rollover_multisigner(ns3, default_algorithm): + policy = "multisigner-model2" + config = { + "dnskey-ttl": timedelta(hours=1), + "ds-ttl": timedelta(days=1), + "max-zone-ttl": timedelta(days=1), + "parent-propagation-delay": timedelta(hours=1), + "publish-safety": timedelta(hours=1), + "retire-safety": timedelta(hours=1), + "signatures-refresh": timedelta(days=5), + "signatures-validity": timedelta(days=14), + "zone-propagation-delay": timedelta(minutes=5), + } + ttl = int(config["dnskey-ttl"].total_seconds()) + + offset = -timedelta(days=7) + offval = int(offset.total_seconds()) + + def keygen(zone): + keygen_command = [ + os.environ.get("KEYGEN"), + "-a", + default_algorithm.name, + "-L", + "3600", + "-M", + "0:32767", + zone, + ] + + return isctest.run.cmd(keygen_command).out + + zone = "multisigner-model2.kasp" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + isctest.kasp.check_dnssec_verify(ns3, zone) + + key_properties = [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden tag-range:32768-65535", + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured zrrsig:rumoured tag-range:32768-65535", + ] + expected = isctest.kasp.policy_to_properties(ttl, key_properties) + + newprops = [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} tag-range:0-32767" + ] + expected2 = isctest.kasp.policy_to_properties(ttl, newprops) + expected2[0].private = False + expected2[0].legacy = True + expected = expected + expected2 + + ownkeys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier) + extkeys = isctest.kasp.keydir_to_keylist(zone) + keys = ownkeys + extkeys + ksks = [k for k in ownkeys if k.is_ksk()] + zsks = [k for k in ownkeys if not k.is_ksk()] + zsks = zsks + extkeys + + isctest.kasp.check_keys(zone, keys, expected) + for kp in expected: + kp.set_expected_keytimes(config) + isctest.kasp.check_keytimes(keys, expected) + isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=policy) + isctest.kasp.check_apex(ns3, zone, ksks, zsks) + isctest.kasp.check_subdomain(ns3, zone, ksks, zsks) + + # Update zone with ZSK from another provider for zone. + out = keygen(zone) + newkeys = isctest.kasp.keystr_to_keylist(out) + newprops = [ + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} tag-range:0-32767" + ] + expected2 = isctest.kasp.policy_to_properties(ttl, newprops) + expected2[0].private = False + expected2[0].legacy = True + expected = expected + expected2 + + dnskey = newkeys[0].dnskey + + update_msg = dns.update.UpdateMessage(zone) + update_msg.add(dnskey.name, dnskey.ttl, dnskey[0]) + ns3.nsupdate(update_msg) + + isctest.kasp.check_dnssec_verify(ns3, zone) + + keys = keys + newkeys + zsks = zsks + newkeys + isctest.kasp.check_keys(zone, keys, expected) + isctest.kasp.check_apex(ns3, zone, ksks, zsks) + isctest.kasp.check_subdomain(ns3, zone, ksks, zsks) + + # Remove ZSKs from the other providers for zone. + dnskey2 = extkeys[0].dnskey + update_msg = dns.update.UpdateMessage(zone) + update_msg.delete(dnskey.name, dnskey[0]) + update_msg.delete(dnskey2.name, dnskey2[0]) + ns3.nsupdate(update_msg) + + isctest.kasp.check_dnssec_verify(ns3, zone) + + expected = isctest.kasp.policy_to_properties(ttl, key_properties) + keys = ownkeys + ksks = [k for k in ownkeys if k.is_ksk()] + zsks = [k for k in ownkeys if not k.is_ksk()] + isctest.kasp.check_keys(zone, keys, expected) + isctest.kasp.check_apex(ns3, zone, ksks, zsks) + isctest.kasp.check_subdomain(ns3, zone, ksks, zsks) + + # A zone transitioning from single-signed to multi-signed. We should have + # the old omnipresent keys outside of the desired key range and the new + # keys in the desired key range. + zone = "single-to-multisigner.kasp" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + isctest.kasp.check_dnssec_verify(ns3, zone) + + key_properties = [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden tag-range:32768-65535", + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured zrrsig:hidden tag-range:32768-65535", + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent tag-range:0-32767 offset:{offval}", + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:omnipresent tag-range:0-32767 offset:{offval}", + ] + expected = isctest.kasp.policy_to_properties(ttl, key_properties) + keys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier) + ksks = [k for k in keys if k.is_ksk()] + zsks = [k for k in keys if not k.is_ksk()] + + isctest.kasp.check_keys(zone, keys, expected) + + for kp in expected: + kp.set_expected_keytimes(config) + + start = expected[0].key.get_timing("Created") + expected[2].timing["Retired"] = start + expected[2].timing["Removed"] = expected[2].timing["Retired"] + Iret( + config, zsk=False, ksk=True + ) + expected[3].timing["Retired"] = start + expected[3].timing["Removed"] = expected[3].timing["Retired"] + Iret( + config, zsk=True, ksk=False + ) + + isctest.kasp.check_keytimes(keys, expected) + isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=policy) + isctest.kasp.check_apex(ns3, zone, ksks, zsks) + isctest.kasp.check_subdomain(ns3, zone, ksks, zsks) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_straight2none_initial.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_straight2none_initial.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_straight2none_initial.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_straight2none_initial.py 2026-09-11 19:41:01.335327022 +0000 @@ -0,0 +1,61 @@ +# 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. + +import pytest + +from rollover.common import CDSS, DEFAULT_CONFIG, DURATION, ROLLOVER_MARK +from rollover.setup import configure_root, configure_straight2none, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "straight2none", + } + + tlds = [] + tld_name = "kasp" + delegations = configure_straight2none(tld_name) + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + data["tlds"].append(tld_name) + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + return data + + +@pytest.mark.parametrize( + "zone", + [ + "going-straight-to-none.kasp", + "going-straight-to-none-dynamic.kasp", + ], +) +def test_straight2none_initial(zone, ns3, default_algorithm): + config = DEFAULT_CONFIG + policy = "default" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P10D']}", + ], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_straight2none_reconfig.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_straight2none_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_straight2none_reconfig.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_straight2none_reconfig.py 2026-09-11 19:41:01.336327046 +0000 @@ -0,0 +1,70 @@ +# 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. + +import pytest + +from rollover.common import CDSS, DEFAULT_CONFIG, DURATION, ROLLOVER_MARK +from rollover.setup import configure_root, configure_straight2none, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "straight2none", + } + + tlds = [] + tld_name = "kasp" + delegations = configure_straight2none(tld_name) + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + data["tlds"].append(tld_name) + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + return data + + +@pytest.fixture(scope="module", autouse=True) +def after_servers_start(ns3, templates): + isctest.kasp.wait_keymgr_done(ns3, "going-straight-to-none.kasp") + isctest.kasp.wait_keymgr_done(ns3, "going-straight-to-none-dynamic.kasp") + + templates.render("ns3/named-straight2none.conf", {"policy": "none"}) + ns3.reconfigure() + + +@pytest.mark.parametrize( + "zone", + [ + "going-straight-to-none.kasp", + "going-straight-to-none-dynamic.kasp", + ], +) +def test_straight2none_reconfig(zone, ns3, default_algorithm): + config = DEFAULT_CONFIG + policy = None + + step = { + "zone": zone, + "cdss": CDSS, + # These zones will go bogus after signatures expire, but + # remain validly signed for now. + "keyprops": [ + f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P10D']}", + ], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_three_is_a_crowd.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_three_is_a_crowd.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_three_is_a_crowd.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_three_is_a_crowd.py 2026-09-11 19:41:01.336327046 +0000 @@ -0,0 +1,112 @@ +# 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. + +from datetime import timedelta + +from isctest.kasp import KeyTimingMetadata +from rollover.common import ( + KSK_CONFIG, + KSK_IPUB, + KSK_IRET, + KSK_LIFETIME_POLICY, + ROLLOVER_MARK, +) +from rollover.setup import configure_ksk_3crowd, configure_root, configure_tld + +import isctest + +pytestmark = ROLLOVER_MARK + +CDSS = ["CDS (SHA-256)"] +POLICY = "ksk-doubleksk-autosign" +OFFSET1 = -int(timedelta(days=60).total_seconds()) +OFFSET2 = -int(timedelta(hours=27).total_seconds()) +TTL = int(KSK_CONFIG["dnskey-ttl"].total_seconds()) + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "ksk-3crowd", + } + + tlds = [] + tld_name = "kasp" + delegations = configure_ksk_3crowd(tld_name) + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + data["tlds"].append(tld_name) + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + return data + + +def test_rollover_ksk_three_is_a_crowd(ns3, default_algorithm): + """Test #2375: Scheduled rollovers are happening faster than they can finish.""" + zone = "three-is-a-crowd.kasp" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSET1}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSET2}", + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSET1}", + ], + "keyrelationships": [0, 1], + } + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) + + # Rollover successor KSK (with DS in rumoured state). + expected = isctest.kasp.policy_to_properties(TTL, step["keyprops"]) + keys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier) + isctest.kasp.check_keys(zone, keys, expected) + key = expected[1].key + now = KeyTimingMetadata.now() + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -rollover -key {key.tag} -when {now} {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # We now expect four keys (3x KSK, 1x ZSK). + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSET1}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSET2}", + f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:0", + f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSET1}", + ], + "check-keytimes": False, # checked manually with modified values + } + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) + + expected = isctest.kasp.policy_to_properties(TTL, step["keyprops"]) + keys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier) + isctest.kasp.check_keys(zone, keys, expected) + + expected[0].metadata["Successor"] = expected[1].key.tag + expected[1].metadata["Predecessor"] = expected[0].key.tag + # Three is a crowd scenario. + expected[1].metadata["Successor"] = expected[2].key.tag + expected[2].metadata["Predecessor"] = expected[1].key.tag + isctest.kasp.check_keyrelationships(keys, expected) + for kp in expected: + kp.set_expected_keytimes(KSK_CONFIG) + + # The first successor KSK is already being retired. + expected[1].timing["Retired"] = now + KSK_IPUB + expected[1].timing["Removed"] = now + KSK_IPUB + KSK_IRET + + isctest.kasp.check_keytimes(keys, expected) diff -Nru bind9-9.20.26/bin/tests/system/rollover/tests_rollover_zsk_prepublication.py bind9-9.20.29/bin/tests/system/rollover/tests_rollover_zsk_prepublication.py --- bind9-9.20.26/bin/tests/system/rollover/tests_rollover_zsk_prepublication.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rollover/tests_rollover_zsk_prepublication.py 2026-09-11 19:41:01.336327046 +0000 @@ -0,0 +1,375 @@ +# 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. + +from datetime import timedelta + +import pytest + +from isctest.kasp import Ipub, Iret +from isctest.util import param +from rollover.common import ROLLOVER_MARK, TIMEDELTA +from rollover.setup import configure_root, configure_tld, configure_zsk_prepub + +import isctest + +pytestmark = ROLLOVER_MARK + +CONFIG = { + "dnskey-ttl": TIMEDELTA["PT1H"], + "ds-ttl": TIMEDELTA["P1D"], + "max-zone-ttl": TIMEDELTA["P1D"], + "parent-propagation-delay": TIMEDELTA["PT1H"], + "publish-safety": TIMEDELTA["P1D"], + "purge-keys": TIMEDELTA["PT1H"], + "retire-safety": TIMEDELTA["P2D"], + "signatures-refresh": TIMEDELTA["P7D"], + "signatures-validity": TIMEDELTA["P14D"], + "zone-propagation-delay": TIMEDELTA["PT1H"], +} +POLICY = "zsk-prepub" +ZSK_LIFETIME = TIMEDELTA["P30D"] +LIFETIME_POLICY = int(ZSK_LIFETIME.total_seconds()) +IPUB = Ipub(CONFIG) +IRET = Iret(CONFIG) +KEYTTLPROP = CONFIG["dnskey-ttl"] + CONFIG["zone-propagation-delay"] +OFFSETS = {} +OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds()) +OFFSETS["step2-p"] = -int(ZSK_LIFETIME.total_seconds() - IPUB.total_seconds()) +OFFSETS["step2-s"] = 0 +OFFSETS["step3-p"] = -int(ZSK_LIFETIME.total_seconds()) +OFFSETS["step3-s"] = -int(IPUB.total_seconds()) +OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(IRET.total_seconds()) +OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(IRET.total_seconds()) +OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KEYTTLPROP.total_seconds()) +OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KEYTTLPROP.total_seconds()) +OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(CONFIG["purge-keys"].total_seconds()) +OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(CONFIG["purge-keys"].total_seconds()) + + +def bootstrap(): + data = { + "tlds": [], + "trust_anchors": [], + "testconf": "zsk-prepub", + } + + tlds = [] + for tld_name in [ + "autosign", + "manual", + ]: + delegations = configure_zsk_prepub(tld_name) + + tld = configure_tld(tld_name, delegations) + tlds.append(tld) + + data["tlds"].append(tld_name) + + ta = configure_root(tlds) + data["trust_anchors"].append(ta) + + return data + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step1(tld, ns3, default_algorithm): + zone = f"step1.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + # Note that the key was already generated during setup. + + step = { + # Introduce the first key. This will immediately be active. + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step1-p']}", + ], + # Next key event is when the successor ZSK needs to be published. + # That is the ZSK lifetime - prepublication time (minus time + # already passed). + "nextev": ZSK_LIFETIME - IPUB - timedelta(days=7), + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step2(tld, ns3, default_algorithm): + zone = f"step2.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 1. + step = { + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block ZSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # it is time to pre-publish the successor zsk. + # zsk1 goal: omnipresent -> hidden + # zsk2 goal: hidden -> omnipresent + # zsk2 dnskey: hidden -> rumoured + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured zrrsig:hidden offset:{OFFSETS['step2-s']}", + ], + "keyrelationships": [1, 2], + # next key event is when the successor zsk becomes omnipresent. + # that is the dnskey ttl plus the zone propagation delay + "nextev": IPUB, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step3(tld, ns3, default_algorithm): + zone = f"step3.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 2, but DNSKEY has become OMNIPRESENT. + step = { + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:hidden offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [1, 2], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[2].key.tag + msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" + assert msg in ns3.log + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # predecessor zsk is no longer actively signing. successor zsk is + # now actively signing. + # zsk1 zrrsig: omnipresent -> unretentive + # zsk2 dnskey: rumoured -> omnipresent + # zsk2 zrrsig: hidden -> rumoured + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:unretentive offset:{OFFSETS['step3-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:rumoured offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [1, 2], + # next key event is when all the rrsig records have been replaced + # with signatures of the new zsk, in other words when zrrsig + # becomes omnipresent. + "nextev": IRET, + # set 'smooth' to true so expected signatures of subdomain are + # from the predecessor zsk. + "smooth": True, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Force full resign and check all signatures have been replaced. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"sign {zone}") + watcher.wait_for_line(f"zone {zone}/IN (signed): sending notifies") + + step["smooth"] = False + step["nextev"] = Iret(CONFIG, smooth=False) + isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step4(tld, ns3, default_algorithm): + zone = f"step4.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + if tld == "manual": + # Same as step 3, but zone signatures have become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:hidden offset:{OFFSETS['step4-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [1, 2], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + assert msg in ns3.log + + # Force step. + tag = keys[2].key.tag + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" + ) + + step = { + # predecessor zsk is no longer needed. all rrsets are signed with + # the successor zsk. + # zsk1 dnskey: omnipresent -> unretentive + # zsk1 zrrsig: unretentive -> hidden + # zsk2 zrrsig: rumoured -> omnipresent + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive zrrsig:hidden offset:{OFFSETS['step4-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [1, 2], + # next key event is when the dnskey enters the hidden state. + # this is the dnskey ttl plus zone propagation delay. + "nextev": KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step5(tld, ns3, default_algorithm): + zone = f"step5.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + # predecessor zsk is now removed. + # zsk1 dnskey: unretentive -> hidden + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden zrrsig:hidden offset:{OFFSETS['step5-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step5-s']}", + ], + "keyrelationships": [1, 2], + # next key event is when the new successor needs to be published. + # this is the zsk lifetime minus IRET minus IPUB minus time + # elapsed. + "nextev": ZSK_LIFETIME - IRET - IPUB - KEYTTLPROP, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step6(tld, ns3, default_algorithm): + zone = f"step6.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" + + isctest.kasp.wait_keymgr_done(ns3, zone) + + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + + step = { + # predecessor zsk is now purged. + "zone": zone, + "keyprops": [ + f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-p']}", + f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step6-s']}", + ], + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/csk1.conf bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/csk1.conf --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/csk1.conf 2026-07-20 14:47:53.862846833 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/csk1.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "csk-algoroll-kasp" { - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - keys { - csk lifetime unlimited algorithm rsasha256; - }; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - zone-propagation-delay 3600; - max-zone-ttl 6h; - parent-propagation-delay pt1h; - parent-ds-ttl 7200; -}; - -dnssec-policy "csk-algoroll-manual" { - manual-mode yes; - - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - keys { - csk lifetime unlimited algorithm rsasha256; - }; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - zone-propagation-delay 3600; - max-zone-ttl 6h; - parent-propagation-delay pt1h; - parent-ds-ttl 7200; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/csk2.conf bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/csk2.conf --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/csk2.conf 2026-07-20 14:47:53.862846833 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/csk2.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "csk-algoroll-kasp" { - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - keys { - csk lifetime unlimited algorithm ecdsa256; - }; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - zone-propagation-delay 3600; - max-zone-ttl 6h; - parent-propagation-delay pt1h; - parent-ds-ttl 7200; -}; - -dnssec-policy "csk-algoroll-manual" { - manual-mode yes; - - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - keys { - csk lifetime unlimited algorithm ecdsa256; - }; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - zone-propagation-delay 3600; - max-zone-ttl 6h; - parent-propagation-delay pt1h; - parent-ds-ttl 7200; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/named.conf.j2 2026-07-20 14:47:53.862846833 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -/* - * 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 csk_roll = csk_roll | default(False) %} -{% set _csk_file = "csk1.conf" if not csk_roll else "csk2.conf" %} -{% set zones = ["kasp", "manual"] %} - -include "@_csk_file@"; -include "named.common.conf"; - -{% for tld in zones %} -zone "step1.csk-algorithm-roll.@tld@" { - type primary; - file "step1.csk-algorithm-roll.@tld@.db"; - dnssec-policy "csk-algoroll-@tld@"; -}; - -{% if csk_roll %} -zone "step2.csk-algorithm-roll.@tld@" { - type primary; - file "step2.csk-algorithm-roll.@tld@.db"; - dnssec-policy "csk-algoroll-@tld@"; -}; - -zone "step3.csk-algorithm-roll.@tld@" { - type primary; - file "step3.csk-algorithm-roll.@tld@.db"; - dnssec-policy "csk-algoroll-@tld@"; -}; - -zone "step4.csk-algorithm-roll.@tld@" { - type primary; - file "step4.csk-algorithm-roll.@tld@.db"; - dnssec-policy "csk-algoroll-@tld@"; -}; - -zone "step5.csk-algorithm-roll.@tld@" { - type primary; - file "step5.csk-algorithm-roll.@tld@.db"; - dnssec-policy "csk-algoroll-@tld@"; -}; - -zone "step6.csk-algorithm-roll.@tld@" { - type primary; - file "step6.csk-algorithm-roll.@tld@.db"; - dnssec-policy "csk-algoroll-@tld@"; -}; -{% endif %} -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_initial.py bind9-9.20.29/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_initial.py --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_initial.py 2026-07-20 14:47:53.862846833 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_initial.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -# 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. - -import pytest - -from isctest.util import param -from rollover.common import ALGOROLL_CONFIG, CDSS, DURATION, ROLLOVER_MARK, TIMEDELTA -from rollover.setup import configure_algo_csk, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - -POLICY = "csk-algoroll" - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "kasp", - "manual", - ]: - delegations = configure_algo_csk( - tld_name, f"{POLICY}-{tld_name}", reconfig=False - ) - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_csk_initial(tld, ns3): - config = ALGOROLL_CONFIG - zone = f"step1.csk-algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", - ], - "nextev": TIMEDELTA["PT1H"], - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_reconfig.py bind9-9.20.29/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_reconfig.py 2026-07-20 14:47:53.862846833 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_csk/tests_rollover_algo_csk_reconfig.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,360 +0,0 @@ -# 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. - -import pytest - -from isctest.kasp import KeyTimingMetadata -from isctest.util import param -from rollover.common import ( - ALGOROLL_CONFIG, - ALGOROLL_IPUB, - ALGOROLL_IPUBC, - ALGOROLL_IRET, - ALGOROLL_IRETKSK, - ALGOROLL_KEYTTLPROP, - ALGOROLL_OFFSETS, - ALGOROLL_OFFVAL, - CDSS, - DURATION, - ROLLOVER_MARK, - TIMEDELTA, -) -from rollover.setup import configure_algo_csk, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - -CONFIG = ALGOROLL_CONFIG -POLICY = "csk-algoroll" -TIME_PASSED = 0 # set in reconfigure() fixture - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "kasp", - "manual", - ]: - delegations = configure_algo_csk( - tld_name, f"{POLICY}-{tld_name}", reconfig=True - ) - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.fixture(scope="module", autouse=True) -def after_servers_start(ns3, templates): - global TIME_PASSED # pylint: disable=global-statement - - isctest.kasp.wait_keymgr_done(ns3, "step1.csk-algorithm-roll.kasp") - - templates.render("ns3/named.conf", {"csk_roll": True}) - start_time = KeyTimingMetadata.now() - ns3.reconfigure() - - # Calculate time passed to correctly check for next key events. - TIME_PASSED = KeyTimingMetadata.now().value - start_time.value - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_csk_reconfig_step1(tld, ns3, default_algorithm): - zone = f"step1.csk-algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - if tld == "manual": - # Same as initial. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[0].key.tag - msg1 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{tag} (CSK)" - msg2 = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" - assert msg1 in ns3.log - assert msg2 in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/RSASHA256" - ) - - # Check state after step. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The RSASHA keys are outroducing. - f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", - # The ECDSAP256SHA256 keys are introducing. - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden", - ], - # Next key event is when the ecdsa256 keys have been propagated. - "nextev": ALGOROLL_IPUB, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_csk_reconfig_step2(tld, ns3, default_algorithm): - zone = f"step2.csk-algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The RSASHA keys are outroducing, but need to stay present - # until the new algorithm chain of trust has been established. - # Thus the expected key states of these keys stay the same. - f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", - # The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset is - # omnipresent, but the zone signatures are not. - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:hidden offset:{ALGOROLL_OFFSETS['step2']}", - ], - # Next key event is when all zone signatures are signed with the - # new algorithm. This is the child publication interval, minus - # the publication interval has already passed. Also, prevent - # intermittent false positives on slow platforms by subtracting - # the time passed between key creation and invoking 'rndc reconfig'. - "nextev": ALGOROLL_IPUBC - ALGOROLL_IPUB - TIME_PASSED, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_csk_reconfig_step3(tld, ns3, default_algorithm): - zone = f"step3.csk-algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - if tld == "manual": - # Same as step 2, but the zone signatures have become OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFSETS['step3']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[1].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" - if msg in ns3.log: - # Force step. - isctest.log.debug( - f"keymgr-manual-mode blocking transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" - ) - tag = keys[1].key.tag - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The DS can be swapped. - f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:unretentive offset:{ALGOROLL_OFFVAL}", - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:rumoured offset:{ALGOROLL_OFFSETS['step3']}", - ], - # Next key event is when the DS becomes OMNIPRESENT. This happens - # after the publication interval of the parent side. - "nextev": ALGOROLL_IRETKSK - TIME_PASSED, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_csk_reconfig_step4(tld, ns3, default_algorithm): - zone = f"step4.csk-algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - if tld == "manual": - # Same as step 3, but the DS has become HIDDEN/OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFVAL}", - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/RSASHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" - assert msg in ns3.log - - # Force step. - tag = keys[1].key.tag - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The old DS is HIDDEN, we can remove the old algorithm records. - f"csk 0 8 2048 goal:hidden dnskey:unretentive krrsig:unretentive zrrsig:unretentive ds:hidden offset:{ALGOROLL_OFFVAL}", - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", - ], - # Next key event is when the old DNSKEY becomes HIDDEN. - # This happens after the DNSKEY TTL plus zone propagation delay. - "nextev": ALGOROLL_KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_csk_reconfig_step5(tld, ns3, default_algorithm): - zone = f"step5.csk-algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The DNSKEY becomes HIDDEN. - f"csk 0 8 2048 goal:hidden dnskey:hidden krrsig:hidden zrrsig:unretentive ds:hidden offset:{ALGOROLL_OFFVAL}", - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step5']}", - ], - # Next key event is when the RSASHA signatures become HIDDEN. - # This happens after the max-zone-ttl plus zone propagation delay - # minus the time already passed since the UNRETENTIVE state has - # been reached. Prevent intermittent false positives on slow - # platforms by subtracting the number of seconds which passed - # between key creation and invoking 'rndc reconfig'. - "nextev": ALGOROLL_IRET - ALGOROLL_IRETKSK - ALGOROLL_KEYTTLPROP - TIME_PASSED, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_csk_reconfig_step6(tld, ns3, default_algorithm): - zone = f"step6.csk-algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The zone signatures are now HIDDEN. - f"csk 0 8 2048 goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{ALGOROLL_OFFVAL}", - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step6']}", - ], - # Next key event is never since we established the policy and the - # keys have an unlimited lifetime. Fallback to the default - # loadkeys interval. - "nextev": TIMEDELTA["PT1H"], - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/kasp.conf 2026-07-20 14:47:53.862846833 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "rsasha256-kasp" { - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - keys { - ksk lifetime unlimited algorithm rsasha256; - zsk lifetime unlimited algorithm rsasha256; - }; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - zone-propagation-delay 3600; - max-zone-ttl 6h; - parent-propagation-delay pt1h; - parent-ds-ttl 7200; -}; - -dnssec-policy "rsasha256-manual" { - manual-mode yes; - - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - keys { - ksk lifetime unlimited algorithm rsasha256; - zsk lifetime unlimited algorithm rsasha256; - }; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - zone-propagation-delay 3600; - max-zone-ttl 6h; - parent-propagation-delay pt1h; - parent-ds-ttl 7200; -}; - -dnssec-policy "ecdsa256-kasp" { - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - keys { - ksk lifetime unlimited algorithm ecdsa256; - zsk lifetime unlimited algorithm ecdsa256; - }; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - zone-propagation-delay 3600; - max-zone-ttl 6h; - parent-propagation-delay pt1h; - parent-ds-ttl 7200; -}; - -dnssec-policy "ecdsa256-manual" { - manual-mode yes; - - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - keys { - ksk lifetime unlimited algorithm ecdsa256; - zsk lifetime unlimited algorithm ecdsa256; - }; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - zone-propagation-delay 3600; - max-zone-ttl 6h; - parent-propagation-delay pt1h; - parent-ds-ttl 7200; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.conf.j2 2026-07-20 14:47:53.862846833 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/* - * 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 alg_roll = alg_roll | default(False) %} -{% set policy = "rsasha256" if not alg_roll else "ecdsa256" %} -{% set zones = ["kasp", "manual"] %} - -include "kasp.conf"; -include "named.common.conf"; - -{% for tld in zones %} -zone "step1.algorithm-roll.@tld@" { - type primary; - file "step1.algorithm-roll.@tld@.db"; - dnssec-policy @policy@-@tld@; -}; - -{% if alg_roll %} -zone "step2.algorithm-roll.@tld@" { - type primary; - file "step2.algorithm-roll.@tld@.db"; - dnssec-policy "ecdsa256-@tld@"; -}; - -zone "step3.algorithm-roll.@tld@" { - type primary; - file "step3.algorithm-roll.@tld@.db"; - dnssec-policy "ecdsa256-@tld@"; -}; - -zone "step4.algorithm-roll.@tld@" { - type primary; - file "step4.algorithm-roll.@tld@.db"; - dnssec-policy "ecdsa256-@tld@"; -}; - -zone "step5.algorithm-roll.@tld@" { - type primary; - file "step5.algorithm-roll.@tld@.db"; - dnssec-policy "ecdsa256-@tld@"; -}; - -zone "step6.algorithm-roll.@tld@" { - type primary; - file "step6.algorithm-roll.@tld@.db"; - dnssec-policy "ecdsa256-@tld@"; -}; - -{% endif %} -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_initial.py bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_initial.py --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_initial.py 2026-07-20 14:47:53.863846849 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_initial.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -# 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. - -import pytest - -from isctest.util import param -from rollover.common import ALGOROLL_CONFIG, CDSS, DURATION, ROLLOVER_MARK, TIMEDELTA -from rollover.setup import configure_algo_ksk_zsk, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "kasp", - "manual", - ]: - delegations = configure_algo_ksk_zsk(tld_name, reconfig=False) - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_ksk_zsk_initial(tld, ns3): - config = ALGOROLL_CONFIG - policy = f"rsasha256-{tld}" - zone = f"step1.algorithm-roll.{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", - f"zsk 0 8 2048 goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P7D']}", - ], - "nextev": TIMEDELTA["PT1H"], - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_reconfig.py bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_reconfig.py 2026-07-20 14:47:53.863846849 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_algo_ksk_zsk/tests_rollover_algo_ksk_zsk_reconfig.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,380 +0,0 @@ -# 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. - -import pytest - -from isctest.kasp import KeyTimingMetadata -from isctest.util import param -from rollover.common import ( - ALGOROLL_CONFIG, - ALGOROLL_IPUB, - ALGOROLL_IPUBC, - ALGOROLL_IRET, - ALGOROLL_IRETKSK, - ALGOROLL_KEYTTLPROP, - ALGOROLL_OFFSETS, - ALGOROLL_OFFVAL, - CDSS, - DURATION, - ROLLOVER_MARK, - TIMEDELTA, -) -from rollover.setup import configure_algo_ksk_zsk, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - -CONFIG = ALGOROLL_CONFIG -POLICY = "ecdsa256" -TIME_PASSED = 0 # set in reconfigure() fixture - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "kasp", - "manual", - ]: - delegations = configure_algo_ksk_zsk(tld_name, reconfig=True) - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.fixture(scope="module", autouse=True) -def after_servers_start(ns3, templates): - global TIME_PASSED # pylint: disable=global-statement - - isctest.kasp.wait_keymgr_done(ns3, "step1.algorithm-roll.kasp") - - templates.render("ns3/named.conf", {"alg_roll": True}) - start_time = KeyTimingMetadata.now() - ns3.reconfigure() - - # Calculate time passed to correctly check for next key events. - TIME_PASSED = KeyTimingMetadata.now().value - start_time.value - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_ksk_zsk_reconfig_step1(tld, ns3, default_algorithm): - zone = f"step1.algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - if tld == "manual": - # Same as initial. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", - f"zsk 0 8 2048 goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P7D']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - ktag = keys[0].key.tag - ztag = keys[1].key.tag - msg1 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{ktag} (KSK)" - msg2 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{ztag} (ZSK)" - msg3 = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" # twice - assert msg1 in ns3.log - assert msg2 in ns3.log - assert len(ns3.log.grep(msg3)) == 2 - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {ktag}/RSASHA256" - ) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The RSASHA keys are outroducing. - f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", - f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", - # The ECDSAP256SHA256 keys are introducing. - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden", - f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured zrrsig:rumoured", - ], - # Next key event is when the ecdsa256 keys have been propagated. - "nextev": ALGOROLL_IPUB, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_ksk_zsk_reconfig_step2(tld, ns3, default_algorithm): - zone = f"step2.algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The RSASHA keys are outroducing, but need to stay present - # until the new algorithm chain of trust has been established. - # Thus the expected key states of these keys stay the same. - f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", - f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", - # The ECDSAP256SHA256 keys are introducing. The DNSKEY RRset is - # omnipresent, but the zone signatures are not. - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFSETS['step2']}", - f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:rumoured offset:{ALGOROLL_OFFSETS['step2']}", - ], - # Next key event is when all zone signatures are signed with the new - # algorithm. This is the max-zone-ttl plus zone propagation delay. But - # the publication interval has already passed. Also, prevent intermittent - # false positives on slow platforms by subtracting the time passed between - # key creation and invoking 'rndc reconfig'. - "nextev": ALGOROLL_IPUBC - ALGOROLL_IPUB - TIME_PASSED, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_ksk_zsk_reconfig_step3(tld, ns3, default_algorithm): - zone = f"step3.algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - if tld == "manual": - # Same as step 2, but the zone signatures have become OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", - f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFSETS['step3']}", - f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step3']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[2].key.tag - msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block transition KSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" - if msg in ns3.log: - # Force step. - isctest.log.debug( - f"keymgr-manual-mode blocking transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" - ) - tag = keys[2].key.tag - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The DS can be swapped. - f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{ALGOROLL_OFFVAL}", - f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{ALGOROLL_OFFSETS['step3']}", - f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step3']}", - ], - # Next key event is when the DS becomes OMNIPRESENT. This happens - # after the retire interval. - "nextev": ALGOROLL_IRETKSK - TIME_PASSED, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_ksk_zsk_reconfig_step4(tld, ns3, default_algorithm): - zone = f"step4.algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - if tld == "manual": - # Same as step 3, but the DS has become HIDDEN/OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFVAL}", - f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", - f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - ktag = keys[0].key.tag - ztag = keys[1].key.tag - msg1 = f"keymgr-manual-mode: block transition KSK {zone}/RSASHA256/{ktag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" - msg2 = f"keymgr-manual-mode: block transition ZSK {zone}/RSASHA256/{ztag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" - assert msg1 in ns3.log - assert msg2 in ns3.log - - # Force step. - ktag = keys[3].key.tag - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {ktag}/ECDSAP256SHA256" - ) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The old DS is HIDDEN, we can remove the old algorithm records. - f"ksk 0 8 2048 goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{ALGOROLL_OFFVAL}", - f"zsk 0 8 2048 goal:hidden dnskey:unretentive zrrsig:unretentive offset:{ALGOROLL_OFFVAL}", - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", - f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", - ], - # Next key event is when the old DNSKEY becomes HIDDEN. - # This happens after the DNSKEY TTL plus zone propagation delay. - "nextev": ALGOROLL_KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_ksk_zsk_reconfig_step5(tld, ns3, default_algorithm): - zone = f"step5.algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The DNSKEY becomes HIDDEN. - f"ksk 0 8 2048 goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{ALGOROLL_OFFVAL}", - f"zsk 0 8 2048 goal:hidden dnskey:hidden zrrsig:unretentive offset:{ALGOROLL_OFFVAL}", - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step5']}", - f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step5']}", - ], - # Next key event is when the RSASHA signatures become HIDDEN. - # This happens after the max-zone-ttl plus zone propagation delay - # minus the time already passed since the UNRETENTIVE state has - # been reached. Prevent intermittent false positives on slow - # platforms by subtracting the number of seconds which passed - # between key creation and invoking 'rndc reconfig'. - "nextev": ALGOROLL_IRET - ALGOROLL_IRETKSK - ALGOROLL_KEYTTLPROP - TIME_PASSED, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("kasp"), - param("manual"), - ], -) -def test_algoroll_ksk_zsk_reconfig_step6(tld, ns3, default_algorithm): - zone = f"step6.algorithm-roll.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - # The zone signatures are now HIDDEN. - f"ksk 0 8 2048 goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{ALGOROLL_OFFVAL}", - f"zsk 0 8 2048 goal:hidden dnskey:hidden zrrsig:hidden offset:{ALGOROLL_OFFVAL}", - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step6']}", - f"zsk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step6']}", - ], - # Next key event is never since we established the policy and the - # keys have an unlimited lifetime. Fallback to the default - # loadkeys interval. - "nextev": TIMEDELTA["PT1H"], - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/kasp.conf 2026-07-20 14:47:53.863846849 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "csk-roll1-autosign" { - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - purge-keys PT1H; - - cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes - keys { - csk key-directory lifetime P6M algorithm ecdsa256; - }; - - zone-propagation-delay 1h; - max-zone-ttl P1D; - - parent-ds-ttl 1h; - parent-propagation-delay 1h; -}; - -dnssec-policy "csk-roll1-manual" { - manual-mode yes; - - signatures-refresh P5D; - signatures-validity 30d; - signatures-validity-dnskey 30d; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 2h; - purge-keys PT1H; - - cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes - keys { - csk key-directory lifetime P6M algorithm ecdsa256; - }; - - zone-propagation-delay 1h; - max-zone-ttl P1D; - - parent-ds-ttl 1h; - parent-propagation-delay 1h; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/named.conf.j2 2026-07-20 14:47:53.863846849 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - * 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 zones = ["autosign", "manual"] %} - -include "kasp.conf"; -include "named.common.conf"; - -{% for tld in zones %} -zone "step1.csk-roll1.@tld@" { - type primary; - file "step1.csk-roll1.@tld@.db"; - dnssec-policy "csk-roll1-@tld@"; -}; -zone "step2.csk-roll1.@tld@" { - type primary; - file "step2.csk-roll1.@tld@.db"; - dnssec-policy "csk-roll1-@tld@"; -}; -zone "step3.csk-roll1.@tld@" { - type primary; - file "step3.csk-roll1.@tld@.db"; - dnssec-policy "csk-roll1-@tld@"; -}; -zone "step4.csk-roll1.@tld@" { - type primary; - file "step4.csk-roll1.@tld@.db"; - dnssec-policy "csk-roll1-@tld@"; -}; -zone "step5.csk-roll1.@tld@" { - type primary; - file "step5.csk-roll1.@tld@.db"; - dnssec-policy "csk-roll1-@tld@"; -}; -zone "step6.csk-roll1.@tld@" { - type primary; - file "step6.csk-roll1.@tld@.db"; - dnssec-policy "csk-roll1-@tld@"; -}; -zone "step7.csk-roll1.@tld@" { - type primary; - file "step7.csk-roll1.@tld@.db"; - dnssec-policy "csk-roll1-@tld@"; -}; -zone "step8.csk-roll1.@tld@" { - type primary; - file "step8.csk-roll1.@tld@.db"; - dnssec-policy "csk-roll1-@tld@"; -}; - -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll1/tests_rollover_csk_roll1.py bind9-9.20.29/bin/tests/system/rollover_csk_roll1/tests_rollover_csk_roll1.py --- bind9-9.20.26/bin/tests/system/rollover_csk_roll1/tests_rollover_csk_roll1.py 2026-07-20 14:47:53.863846849 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll1/tests_rollover_csk_roll1.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,453 +0,0 @@ -# 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. - -from datetime import timedelta - -import pytest - -from isctest.kasp import Ipub, Iret -from isctest.util import param -from rollover.common import ROLLOVER_MARK, TIMEDELTA -from rollover.setup import configure_cskroll1, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - -CDSS = ["CDNSKEY", "CDS (SHA-384)"] -CONFIG = { - "dnskey-ttl": TIMEDELTA["PT1H"], - "ds-ttl": TIMEDELTA["PT1H"], - "max-zone-ttl": TIMEDELTA["P1D"], - "parent-propagation-delay": TIMEDELTA["PT1H"], - "publish-safety": TIMEDELTA["PT1H"], - "purge-keys": TIMEDELTA["PT1H"], - "retire-safety": TIMEDELTA["PT2H"], - "signatures-refresh": TIMEDELTA["P5D"], - "signatures-validity": TIMEDELTA["P30D"], - "zone-propagation-delay": TIMEDELTA["PT1H"], -} -POLICY = "csk-roll1" -CSK_LIFETIME = timedelta(days=31 * 6) -LIFETIME_POLICY = int(CSK_LIFETIME.total_seconds()) -IPUB = Ipub(CONFIG) -IRETZSK = Iret(CONFIG) -IRETKSK = Iret(CONFIG, zsk=False, ksk=True) -KEYTTLPROP = CONFIG["dnskey-ttl"] + CONFIG["zone-propagation-delay"] -SIGNDELAY = IRETZSK - IRETKSK - KEYTTLPROP -OFFSETS = {} -OFFSETS["step1-p"] = -int(timedelta(days=7).total_seconds()) -OFFSETS["step2-p"] = -int(CSK_LIFETIME.total_seconds() - IPUB.total_seconds()) -OFFSETS["step2-s"] = 0 -OFFSETS["step3-p"] = -int(CSK_LIFETIME.total_seconds()) -OFFSETS["step3-s"] = -int(IPUB.total_seconds()) -OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(IRETKSK.total_seconds()) -OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(IRETKSK.total_seconds()) -OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(SIGNDELAY.total_seconds()) -OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(SIGNDELAY.total_seconds()) -OFFSETS["step7-p"] = OFFSETS["step6-p"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step7-s"] = OFFSETS["step6-s"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step8-p"] = OFFSETS["step7-p"] - int(CONFIG["purge-keys"].total_seconds()) -OFFSETS["step8-s"] = OFFSETS["step7-s"] - int(CONFIG["purge-keys"].total_seconds()) - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "autosign", - "manual", - ]: - delegations = configure_cskroll1(tld_name, f"{POLICY}-{tld_name}") - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll1_step1(tld, ns3, default_algorithm): - zone = f"step1.csk-roll1.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - # Note that the key was already generated during setup. - - step = { - # Introduce the first key. This will immediately be active. - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", - ], - # Next key event is when the successor CSK needs to be published - # minus time already elapsed. This is Lcsk - Ipub + Dreg (we ignore - # registration delay). - "nextev": CSK_LIFETIME - IPUB - timedelta(days=7), - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll1_step2(tld, ns3, default_algorithm): - zone = f"step2.csk-roll1.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 1. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block CSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # Successor CSK is prepublished (signs DNSKEY RRset, but not yet - # other RRsets). - # CSK1 goal: omnipresent -> hidden - # CSK2 goal: hidden -> omnipresent - # CSK2 dnskey: hidden -> rumoured - # CSK2 krrsig: hidden -> rumoured - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:hidden ds:hidden offset:{OFFSETS['step2-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the successor CSK becomes OMNIPRESENT. - "nextev": IPUB, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll1_step3(tld, ns3, default_algorithm): - zone = f"step3.csk-roll1.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 2, but DNSKEY has become OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step3-s']}", - ], - "keyrelationships": [0, 1], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[1].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" - if msg in ns3.log: - # Force step. - isctest.log.debug( - f"keymgr-manual-mode blocking transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" - ) - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # Successor CSK becomes omnipresent, meaning we can start signing - # the remainder of the zone with the successor CSK, and we can - # submit the DS. - "zone": zone, - "cdss": CDSS, - # Predecessor CSK will be removed, so moving to UNRETENTIVE. - # CSK1 zrrsig: omnipresent -> unretentive - # Successor CSK DNSKEY is OMNIPRESENT, so moving ZRRSIG to RUMOURED. - # CSK2 dnskey: rumoured -> omnipresent - # CSK2 krrsig: rumoured -> omnipresent - # CSK2 zrrsig: hidden -> rumoured - # The predecessor DS can be withdrawn and the successor DS can be - # introduced. - # CSK1 ds: omnipresent -> unretentive - # CSK2 ds: hidden -> rumoured - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:unretentive offset:{OFFSETS['step3-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:rumoured offset:{OFFSETS['step3-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the predecessor DS has been replaced with - # the successor DS and enough time has passed such that the all - # validators that have this DS RRset cached only know about the - # successor DS. This is the the retire interval. - "nextev": IRETKSK, - # Set 'smooth' to true so expected signatures of subdomain are - # from the predecessor ZSK. - "smooth": True, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll1_step4(tld, ns3, default_algorithm): - zone = f"step4.csk-roll1.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 3, but DS has become HIDDEN/OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step4-s']}", - ], - "keyrelationships": [0, 1], - "manual-mode": True, - "nextev": None, - # We already swapped the DS in the previous step, so disable ds-swap. - "ds-swap": False, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" - assert msg in ns3.log - - # Force step. - tag = keys[1].key.tag - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - "zone": zone, - "cdss": CDSS, - # The predecessor CSK is no longer signing the DNSKEY RRset. - # CSK1 krrsig: omnipresent -> unretentive - # The predecessor DS is hidden. The successor DS is now omnipresent. - # CSK1 ds: unretentive -> hidden - # CSK2 ds: rumoured -> omnipresent - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:unretentive zrrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step4-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the KRRSIG enters the HIDDEN state. - # This is the DNSKEY TTL plus zone propagation delay. - "nextev": KEYTTLPROP, - # We already swapped the DS in the previous step, so disable ds-swap. - "ds-swap": False, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll1_step5(tld, ns3, default_algorithm): - zone = f"step5.csk-roll1.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - # The predecessor KRRSIG records are now all hidden. - # CSK1 krrsig: unretentive -> hidden - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:hidden zrrsig:unretentive ds:hidden offset:{OFFSETS['step5-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step5-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the DNSKEY can be removed. This is when - # all ZRRSIG records have been replaced with signatures of the new - # CSK. - "nextev": SIGNDELAY, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll1_step6(tld, ns3, default_algorithm): - zone = f"step6.csk-roll1.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - return - - step = { - "zone": zone, - "cdss": CDSS, - # The predecessor ZRRSIG records are now all hidden (so the DNSKEY - # can be removed). - # CSK1 dnskey: omnipresent -> unretentive - # CSK1 zrrsig: unretentive -> hidden - # CSK2 zrrsig: rumoured -> omnipresent - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step6-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the DNSKEY enters the HIDDEN state. - # This is the DNSKEY TTL plus zone propagation delay. - "nextev": KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll1_step7(tld, ns3, default_algorithm): - zone = f"step7.csk-roll1.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - # The predecessor CSK is now completely HIDDEN. - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step7-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step7-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the new successor needs to be published. - # This is the Lcsk, minus time passed since the key started signing, - # minus the prepublication time. - "nextev": CSK_LIFETIME - IRETZSK - IPUB - KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll1_step8(tld, ns3, default_algorithm): - zone = f"step8.csk-roll1.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step8-s']}", - ], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/kasp.conf 2026-07-20 14:47:53.863846849 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "csk-roll2-autosign" { - signatures-refresh 12h; - signatures-validity P1D; - signatures-validity-dnskey P1D; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 1h; - purge-keys 0; - - cds-digest-types { "sha-256"; "sha-384"; }; // use two digest type for testing purposes - keys { - csk key-directory lifetime P6M algorithm ecdsa256; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; - - parent-ds-ttl PT1H; - parent-propagation-delay P1W; -}; - -dnssec-policy "csk-roll2-manual" { - manual-mode yes; - - signatures-refresh 12h; - signatures-validity P1D; - signatures-validity-dnskey P1D; - - dnskey-ttl 1h; - publish-safety PT1H; - retire-safety 1h; - purge-keys 0; - - cds-digest-types { "sha-256"; "sha-384"; }; // use two digest type for testing purposes - keys { - csk key-directory lifetime P6M algorithm ecdsa256; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; - - parent-ds-ttl PT1H; - parent-propagation-delay P1W; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/named.conf.j2 2026-07-20 14:47:53.863846849 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - * 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 zones = ["autosign", "manual"] %} - -include "kasp.conf"; -include "named.common.conf"; - -{% for tld in zones %} -zone "step1.csk-roll2.@tld@" { - type primary; - file "step1.csk-roll2.@tld@.db"; - dnssec-policy "csk-roll2-@tld@"; -}; -zone "step2.csk-roll2.@tld@" { - type primary; - file "step2.csk-roll2.@tld@.db"; - dnssec-policy "csk-roll2-@tld@"; -}; -zone "step3.csk-roll2.@tld@" { - type primary; - file "step3.csk-roll2.@tld@.db"; - dnssec-policy "csk-roll2-@tld@"; -}; -zone "step4.csk-roll2.@tld@" { - type primary; - file "step4.csk-roll2.@tld@.db"; - dnssec-policy "csk-roll2-@tld@"; -}; -zone "step5.csk-roll2.@tld@" { - type primary; - file "step5.csk-roll2.@tld@.db"; - dnssec-policy "csk-roll2-@tld@"; -}; -zone "step6.csk-roll2.@tld@" { - type primary; - file "step6.csk-roll2.@tld@.db"; - dnssec-policy "csk-roll2-@tld@"; -}; -zone "step7.csk-roll2.@tld@" { - type primary; - file "step7.csk-roll2.@tld@.db"; - dnssec-policy "csk-roll2-@tld@"; -}; - -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_csk_roll2/tests_rollover_csk_roll2.py bind9-9.20.29/bin/tests/system/rollover_csk_roll2/tests_rollover_csk_roll2.py --- bind9-9.20.26/bin/tests/system/rollover_csk_roll2/tests_rollover_csk_roll2.py 2026-07-20 14:47:53.864846864 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_csk_roll2/tests_rollover_csk_roll2.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,429 +0,0 @@ -# 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. - -from datetime import timedelta - -import pytest - -from isctest.kasp import Ipub, Iret -from isctest.util import param -from rollover.common import ROLLOVER_MARK, TIMEDELTA -from rollover.setup import configure_cskroll2, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - -CDSS = ["CDNSKEY", "CDS (SHA-256)", "CDS (SHA-384)"] -CONFIG = { - "dnskey-ttl": TIMEDELTA["PT1H"], - "ds-ttl": TIMEDELTA["PT1H"], - "max-zone-ttl": TIMEDELTA["P1D"], - "parent-propagation-delay": TIMEDELTA["P7D"], - "publish-safety": TIMEDELTA["PT1H"], - "purge-keys": TIMEDELTA[0], - "retire-safety": TIMEDELTA["PT1H"], - "signatures-refresh": TIMEDELTA["PT12H"], - "signatures-validity": TIMEDELTA["P1D"], - "zone-propagation-delay": TIMEDELTA["PT1H"], -} -POLICY = "csk-roll2" -CSK_LIFETIME = timedelta(days=31 * 6) -LIFETIME_POLICY = int(CSK_LIFETIME.total_seconds()) - -IPUB = Ipub(CONFIG) -IRET = Iret(CONFIG, zsk=True, ksk=True) -IRETZSK = Iret(CONFIG) -IRETKSK = Iret(CONFIG, ksk=True) -KEYTTLPROP = CONFIG["dnskey-ttl"] + CONFIG["zone-propagation-delay"] -OFFSETS = {} -OFFSETS["step1-p"] = -int(timedelta(days=7).total_seconds()) -OFFSETS["step2-p"] = -int(CSK_LIFETIME.total_seconds() - IPUB.total_seconds()) -OFFSETS["step2-s"] = 0 -OFFSETS["step3-p"] = -int(CSK_LIFETIME.total_seconds()) -OFFSETS["step3-s"] = -int(IPUB.total_seconds()) -OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(IRETZSK.total_seconds()) -OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(IRETZSK.total_seconds()) -OFFSETS["step5-p"] = OFFSETS["step4-p"] - int( - IRETKSK.total_seconds() - IRETZSK.total_seconds() -) -OFFSETS["step5-s"] = OFFSETS["step4-s"] - int( - IRETKSK.total_seconds() - IRETZSK.total_seconds() -) -OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step7-p"] = OFFSETS["step6-p"] - int(timedelta(days=90).total_seconds()) -OFFSETS["step7-s"] = OFFSETS["step6-s"] - int(timedelta(days=90).total_seconds()) - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "autosign", - "manual", - ]: - delegations = configure_cskroll2(tld_name, f"{POLICY}-{tld_name}") - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll2_step1(tld, ns3, default_algorithm): - zone = f"step1.csk-roll2.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - # Note that the key was already generated during setup. - - step = { - # Introduce the first key. This will immediately be active. - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", - ], - # Next key event is when the successor CSK needs to be published - # minus time already elapsed. This is Lcsk - Ipub + Dreg (we ignore - # registration delay). - "nextev": CSK_LIFETIME - IPUB - TIMEDELTA["P7D"], - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll2_step2(tld, ns3, default_algorithm): - zone = f"step2.csk-roll2.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 1. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block CSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # Successor CSK is prepublished (signs DNSKEY RRset, but not yet - # other RRsets). - # CSK1 goal: omnipresent -> hidden - # CSK2 goal: hidden -> omnipresent - # CSK2 dnskey: hidden -> rumoured - # CSK2 krrsig: hidden -> rumoured - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:hidden ds:hidden offset:{OFFSETS['step2-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the successor CSK becomes OMNIPRESENT. - "nextev": IPUB, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll2_step3(tld, ns3, default_algorithm): - zone = f"step3.csk-roll2.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 2, but DNSKEY has become OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step3-s']}", - ], - "keyrelationships": [0, 1], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[1].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" - if msg in ns3.log: - # Force step. - isctest.log.debug( - f"keymgr-manual-mode blocking transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" - ) - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # Successor CSK becomes omnipresent, meaning we can start signing - # the remainder of the zone with the successor CSK, and we can - # submit the DS. - "zone": zone, - "cdss": CDSS, - # Predecessor CSK will be removed, so moving to UNRETENTIVE. - # CSK1 zrrsig: omnipresent -> unretentive - # Successor CSK DNSKEY is OMNIPRESENT, so moving ZRRSIG to RUMOURED. - # CSK2 dnskey: rumoured -> omnipresent - # CSK2 krrsig: rumoured -> omnipresent - # CSK2 zrrsig: hidden -> rumoured - # The predecessor DS can be withdrawn and the successor DS can be - # introduced. - # CSK1 ds: omnipresent -> unretentive - # CSK2 ds: hidden -> rumoured - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:unretentive offset:{OFFSETS['step3-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:rumoured offset:{OFFSETS['step3-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the predecessor DS has been replaced with - # the successor DS and enough time has passed such that the all - # validators that have this DS RRset cached only know about the - # successor DS. This is the the retire interval. - "nextev": IRETZSK, - # Set 'smooth' to true so expected signatures of subdomain are - # from the predecessor ZSK. - "smooth": True, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll2_step4(tld, ns3, default_algorithm): - zone = f"step4.csk-roll2.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - # The predecessor ZRRSIG is HIDDEN. The successor ZRRSIG is - # OMNIPRESENT. - # CSK1 zrrsig: unretentive -> hidden - # CSK2 zrrsig: rumoured -> omnipresent - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:unretentive offset:{OFFSETS['step4-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:rumoured offset:{OFFSETS['step4-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the predecessor DS has been replaced with - # the successor DS and enough time has passed such that the all - # validators that have this DS RRset cached only know about the - # successor DS. This is the retire interval of the KSK part (minus) - # time already elapsed). - "nextev": IRET - IRETZSK, - # We already swapped the DS in the previous step, so disable ds-swap. - "ds-swap": False, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll2_step5(tld, ns3, default_algorithm): - zone = f"step5.csk-roll2.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 4, but DS has become HIDDEN/OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", - ], - "keyrelationships": [0, 1], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[0].key.tag - msg1 = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" - msg2 = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" - assert msg1 in ns3.log - assert msg2 in ns3.log - - # Force step. - tag = keys[1].key.tag - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - "zone": zone, - "cdss": CDSS, - # The predecessor DNSKEY can be removed. - # CSK1 dnskey: omnipresent -> unretentive - # CSK1 krrsig: omnipresent -> unretentive - # CSK1 ds: unretentive -> hidden - # The successor key is now fully OMNIPRESENT. - # CSK2 ds: rumoured -> omnipresent - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive krrsig:unretentive zrrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the DNSKEY enters the HIDDEN state. - # This is the DNSKEY TTL plus zone propagation delay. - "nextev": KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll2_step6(tld, ns3, default_algorithm): - zone = f"step6.csk-roll2.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - # The predecessor CSK is now completely HIDDEN. - # CSK1 dnskey: unretentive -> hidden - # CSK1 krrsig: unretentive -> hidden - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step6-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}", - ], - "keyrelationships": [0, 1], - # Next key event is when the new successor needs to be published. - # This is the Lcsk, minus time passed since the key was published. - "nextev": CSK_LIFETIME - IRET - IPUB - KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_csk_roll2_step7(tld, ns3, default_algorithm): - zone = f"step7.csk-roll2.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - # The predecessor CSK is now completely HIDDEN. - "keyprops": [ - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden krrsig:hidden zrrsig:hidden ds:hidden offset:{OFFSETS['step7-p']}", - f"csk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step7-s']}", - ], - "keyrelationships": [0, 1], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_dynamic2inline/ns3/dynamic2inline.kasp.db bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/dynamic2inline.kasp.db --- bind9-9.20.26/bin/tests/system/rollover_dynamic2inline/ns3/dynamic2inline.kasp.db 2026-07-20 14:47:53.864846864 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/dynamic2inline.kasp.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -; 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. - -$TTL 300 -@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - diff -Nru bind9-9.20.26/bin/tests/system/rollover_dynamic2inline/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_dynamic2inline/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_dynamic2inline/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_dynamic2inline/ns3/named.conf.j2 2026-07-20 14:47:53.864846864 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -/* - * 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. - */ - -include "named.common.conf"; - -zone "dynamic2inline.kasp" { - type primary; - file "dynamic2inline.kasp.db"; - allow-update { any; }; - dnssec-policy "default"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_dynamic2inline/tests_rollover_dynamic2inline.py bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/tests_rollover_dynamic2inline.py --- bind9-9.20.26/bin/tests/system/rollover_dynamic2inline/tests_rollover_dynamic2inline.py 2026-07-20 14:47:53.864846864 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_dynamic2inline/tests_rollover_dynamic2inline.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -# 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. - -from rollover.common import CDSS, DEFAULT_CONFIG, ROLLOVER_MARK - -import isctest - -pytestmark = ROLLOVER_MARK - - -def test_dynamic2inline(ns3, default_algorithm, templates): - config = DEFAULT_CONFIG - policy = "default" - zone = "dynamic2inline.kasp" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden", - ], - "nextev": None, - } - - isctest.kasp.check_rollover_step(ns3, config, policy, step) - - templates.render("ns3/named.conf", {"change_lifetime": True}) - ns3.reconfigure() - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/kasp.conf 2026-07-20 14:47:53.864846864 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "enable-dnssec-autosign" { - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 300; - max-zone-ttl PT12H; - zone-propagation-delay PT5M; - retire-safety PT20M; - publish-safety PT5M; - - parent-propagation-delay 1h; - parent-ds-ttl 2h; - - keys { - csk lifetime unlimited algorithm 13; - }; -}; - -dnssec-policy "enable-dnssec-manual" { - manual-mode yes; - - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 300; - max-zone-ttl PT12H; - zone-propagation-delay PT5M; - retire-safety PT20M; - publish-safety PT5M; - - parent-propagation-delay 1h; - parent-ds-ttl 2h; - - keys { - csk lifetime unlimited algorithm 13; - }; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/named.conf.j2 2026-07-20 14:47:53.864846864 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - * 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 zones = ["autosign", "manual"] %} - -include "kasp.conf"; -include "named.common.conf"; - -{% for tld in zones %} -zone "step1.enable-dnssec.@tld@" { - type primary; - file "step1.enable-dnssec.@tld@.db"; - dnssec-policy "enable-dnssec-@tld@"; -}; -zone "step2.enable-dnssec.@tld@" { - type primary; - file "step2.enable-dnssec.@tld@.db"; - dnssec-policy "enable-dnssec-@tld@"; -}; -zone "step3.enable-dnssec.@tld@" { - type primary; - file "step3.enable-dnssec.@tld@.db"; - dnssec-policy "enable-dnssec-@tld@"; -}; -zone "step4.enable-dnssec.@tld@" { - type primary; - file "step4.enable-dnssec.@tld@.db"; - dnssec-policy "enable-dnssec-@tld@"; -}; - -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/tests_rollover_enable_dnssec.py bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/tests_rollover_enable_dnssec.py --- bind9-9.20.26/bin/tests/system/rollover_enable_dnssec/tests_rollover_enable_dnssec.py 2026-07-20 14:47:53.864846864 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_enable_dnssec/tests_rollover_enable_dnssec.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,230 +0,0 @@ -# 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. - -import pytest - -from isctest.kasp import Ipub, IpubC, Iret -from isctest.util import param -from rollover.common import CDSS, ROLLOVER_MARK, TIMEDELTA -from rollover.setup import configure_enable_dnssec, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - -CONFIG = { - "dnskey-ttl": TIMEDELTA["PT5M"], - "ds-ttl": TIMEDELTA["PT2H"], - "max-zone-ttl": TIMEDELTA["PT12H"], - "parent-propagation-delay": TIMEDELTA["PT1H"], - "publish-safety": TIMEDELTA["PT5M"], - "retire-safety": TIMEDELTA["PT20M"], - "signatures-refresh": TIMEDELTA["P7D"], - "signatures-validity": TIMEDELTA["P14D"], - "zone-propagation-delay": TIMEDELTA["PT5M"], -} -POLICY = "enable-dnssec" -IPUB = Ipub(CONFIG) -IPUBC = IpubC(CONFIG, rollover=False) -IRETZSK = Iret(CONFIG, rollover=False) -IRETKSK = Iret(CONFIG, zsk=False, ksk=True, rollover=False) -OFFSETS = {} -OFFSETS["step1"] = 0 -OFFSETS["step2"] = -int(IPUB.total_seconds()) -OFFSETS["step3"] = -int(IRETZSK.total_seconds()) -OFFSETS["step4"] = -int(IPUBC.total_seconds() + IRETKSK.total_seconds()) - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "autosign", - "manual", - ]: - delegations = configure_enable_dnssec(tld_name, f"{POLICY}-{tld_name}") - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_rollover_enable_dnssec_step1(tld, default_algorithm, ns3): - zone = f"step1.enable-dnssec.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as insecure. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [], - "manual-mode": True, - "zone-signed": False, - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - msg = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line(f"keymgr: {zone} done") - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden offset:{OFFSETS['step1']}", - ], - # Next key event is when the DNSKEY RRset becomes OMNIPRESENT, - # after the publication interval. - "nextev": IPUB, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_rollover_enable_dnssec_step2(tld, default_algorithm, ns3): - zone = f"step2.enable-dnssec.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - # The DNSKEY is omnipresent, but the zone signatures not yet. - # Thus, the DS remains hidden. - # dnskey: rumoured -> omnipresent - # krrsig: rumoured -> omnipresent - "keyprops": [ - f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:hidden offset:{OFFSETS['step2']}", - ], - # Next key event is when the zone signatures become OMNIPRESENT, - # Minus the time already elapsed. - "nextev": IRETZSK - IPUB, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_rollover_enable_dnssec_step3(tld, default_algorithm, ns3): - zone = f"step3.enable-dnssec.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 2, but zone signatures have become OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{OFFSETS['step3']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[0].key.tag - msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - "zone": zone, - "cdss": CDSS, - # All signatures should be omnipresent, so the DS can be submitted. - # zrrsig: rumoured -> omnipresent - # ds: hidden -> rumoured - "keyprops": [ - f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:rumoured offset:{OFFSETS['step3']}", - ], - # Next key event is when the DS can move to the OMNIPRESENT state. - # This is after the retire interval. - "nextev": IRETKSK, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_rollover_enable_dnssec_step4(tld, default_algorithm, ns3): - zone = f"step4.enable-dnssec.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - "zone": zone, - "cdss": CDSS, - # DS has been published long enough. - # ds: rumoured -> omnipresent - "keyprops": [ - f"csk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4']}", - ], - # Next key event is never, the zone dnssec-policy has been - # established. So we fall back to the default loadkeys interval. - "nextev": TIMEDELTA["PT1H"], - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/kasp.conf 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "unsigning" { - dnskey-ttl 7200; - - keys { - ksk key-directory lifetime unlimited algorithm ecdsa256; - zsk key-directory lifetime P60D algorithm ecdsa256; - }; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/named.conf.j2 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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 policy = policy | default("unsigning") %} - -include "kasp.conf"; -include "named.common.conf"; - -zone "step1.going-insecure.kasp" { - type primary; - file "step1.going-insecure.kasp.db"; - dnssec-policy @policy@; -}; - -{% if policy == "insecure" %} -zone "step2.going-insecure.kasp" { - type primary; - file "step2.going-insecure.kasp.db"; - dnssec-policy insecure; -}; -{% endif %} - -zone "step1.going-insecure-dynamic.kasp" { - type primary; - file "step1.going-insecure-dynamic.kasp.db"; - dnssec-policy @policy@; - inline-signing no; - allow-update { any; }; -}; - -{% if policy == "insecure" %} -zone "step2.going-insecure-dynamic.kasp" { - type primary; - file "step2.going-insecure-dynamic.kasp.db"; - dnssec-policy insecure; - inline-signing no; - allow-update { any; }; -}; -{% endif %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_initial.py bind9-9.20.29/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_initial.py --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_initial.py 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_initial.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -# 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. - -import pytest - -from rollover.common import CDSS, DURATION, ROLLOVER_MARK, UNSIGNING_CONFIG -from rollover.setup import configure_going_insecure, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - tld_name = "kasp" - delegations = configure_going_insecure(tld_name, reconfig=False) - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - data["tlds"].append(tld_name) - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - return data - - -@pytest.mark.parametrize( - "zone", - [ - "going-insecure.kasp", - "going-insecure-dynamic.kasp", - ], -) -def test_going_insecure_initial(zone, ns3, default_algorithm): - config = UNSIGNING_CONFIG - policy = "unsigning" - zone = f"step1.{zone}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P10D']}", - f"zsk {DURATION['P60D']} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P10D']}", - ], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_reconfig.py bind9-9.20.29/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_reconfig.py 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_going_insecure/tests_rollover_going_insecure_reconfig.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -# 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. - -import pytest - -from rollover.common import ( - CDSS, - DEFAULT_CONFIG, - DURATION, - ROLLOVER_MARK, - UNSIGNING_CONFIG, -) -from rollover.setup import configure_going_insecure, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - tld_name = "kasp" - delegations = configure_going_insecure(tld_name, reconfig=True) - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - data["tlds"].append(tld_name) - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - return data - - -@pytest.fixture(scope="module", autouse=True) -def after_servers_start(ns3, templates): - templates.render("ns3/named.conf", {"policy": "insecure"}) - ns3.reconfigure() # move from "unsigning" to "insecure" - - -@pytest.mark.parametrize( - "zone", - [ - "going-insecure.kasp", - "going-insecure-dynamic.kasp", - ], -) -def test_going_insecure_reconfig_step1(zone, ns3, default_algorithm): - config = DEFAULT_CONFIG - policy = "insecure" - zone = f"step1.{zone}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # Key goal states should be HIDDEN. - # The DS may be removed if we are going insecure. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{-DURATION['P10D']}", - f"zsk {DURATION['P60D']} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P10D']}", - ], - # Next key event is when the DS becomes HIDDEN. This - # happens after the# parent propagation delay plus DS TTL. - "nextev": DEFAULT_CONFIG["ds-ttl"] + DEFAULT_CONFIG["parent-propagation-delay"], - # Going insecure, check for CDS/CDNSKEY DELETE, and skip key timing checks. - "cds-delete": True, - "check-keytimes": False, - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) - - -@pytest.mark.parametrize( - "zone", - [ - "going-insecure.kasp", - "going-insecure-dynamic.kasp", - ], -) -def test_going_insecure_reconfig_step2(zone, ns3, default_algorithm): - config = DEFAULT_CONFIG - policy = "insecure" - zone = f"step2.{zone}" - - isctest.kasp.wait_keymgr_done(ns3, zone, reconfig=True) - - # The DS is long enough removed from the zone to be considered - # HIDDEN. This means the DNSKEY and the KSK signatures can be - # removed. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{-DURATION['P10D']}", - f"zsk {DURATION['P60D']} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive zrrsig:unretentive offset:{-DURATION['P10D']}", - ], - # Next key event is when the DNSKEY becomes HIDDEN. - # This happens after the propagation delay, plus DNSKEY TTL. - "nextev": UNSIGNING_CONFIG["dnskey-ttl"] - + DEFAULT_CONFIG["zone-propagation-delay"], - # Zone is no longer signed. - "zone-signed": False, - "check-keytimes": False, - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/kasp.conf 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "ksk-doubleksk-autosign" { - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 2h; - publish-safety P1D; - retire-safety P2D; - purge-keys PT1H; - - cdnskey no; - keys { - ksk key-directory lifetime P60D algorithm ecdsa256; - zsk key-directory lifetime unlimited algorithm ecdsa256; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; - - parent-ds-ttl 3600; - parent-propagation-delay PT1H; -}; - -dnssec-policy "ksk-doubleksk-manual" { - manual-mode yes; - - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 2h; - publish-safety P1D; - retire-safety P2D; - purge-keys PT1H; - - cdnskey no; - keys { - ksk key-directory lifetime P60D algorithm ecdsa256; - zsk key-directory lifetime unlimited algorithm ecdsa256; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; - - parent-ds-ttl 3600; - parent-propagation-delay PT1H; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/named.conf.j2 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * 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. - */ - -include "kasp.conf"; -include "named.common.conf"; - -zone "three-is-a-crowd.kasp" { - type primary; - file "three-is-a-crowd.kasp.db"; - inline-signing yes; - /* Use same policy as KSK rollover test zones. */ - dnssec-policy "ksk-doubleksk-autosign"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/tests_rollover_three_is_a_crowd.py bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/tests_rollover_three_is_a_crowd.py --- bind9-9.20.26/bin/tests/system/rollover_ksk_3crowd/tests_rollover_three_is_a_crowd.py 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_3crowd/tests_rollover_three_is_a_crowd.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -# 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. - -from datetime import timedelta - -from isctest.kasp import KeyTimingMetadata -from rollover.common import ( - KSK_CONFIG, - KSK_IPUB, - KSK_IRET, - KSK_LIFETIME_POLICY, - ROLLOVER_MARK, -) -from rollover.setup import configure_ksk_3crowd, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - -CDSS = ["CDS (SHA-256)"] -POLICY = "ksk-doubleksk-autosign" -OFFSET1 = -int(timedelta(days=60).total_seconds()) -OFFSET2 = -int(timedelta(hours=27).total_seconds()) -TTL = int(KSK_CONFIG["dnskey-ttl"].total_seconds()) - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - tld_name = "kasp" - delegations = configure_ksk_3crowd(tld_name) - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - data["tlds"].append(tld_name) - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - return data - - -def test_rollover_ksk_three_is_a_crowd(ns3, default_algorithm): - """Test #2375: Scheduled rollovers are happening faster than they can finish.""" - zone = "three-is-a-crowd.kasp" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSET1}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSET2}", - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSET1}", - ], - "keyrelationships": [0, 1], - } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) - - # Rollover successor KSK (with DS in rumoured state). - expected = isctest.kasp.policy_to_properties(TTL, step["keyprops"]) - keys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier) - isctest.kasp.check_keys(zone, keys, expected) - key = expected[1].key - now = KeyTimingMetadata.now() - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -rollover -key {key.tag} -when {now} {zone}") - watcher.wait_for_line(f"keymgr: {zone} done") - - # We now expect four keys (3x KSK, 1x ZSK). - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSET1}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSET2}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:0", - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSET1}", - ], - "check-keytimes": False, # checked manually with modified values - } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) - - expected = isctest.kasp.policy_to_properties(TTL, step["keyprops"]) - keys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier) - isctest.kasp.check_keys(zone, keys, expected) - - expected[0].metadata["Successor"] = expected[1].key.tag - expected[1].metadata["Predecessor"] = expected[0].key.tag - # Three is a crowd scenario. - expected[1].metadata["Successor"] = expected[2].key.tag - expected[2].metadata["Predecessor"] = expected[1].key.tag - isctest.kasp.check_keyrelationships(keys, expected) - for kp in expected: - kp.set_expected_keytimes(KSK_CONFIG) - - # The first successor KSK is already being retired. - expected[1].timing["Retired"] = now + KSK_IPUB - expected[1].timing["Removed"] = now + KSK_IPUB + KSK_IRET - - isctest.kasp.check_keytimes(keys, expected) diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/kasp.conf 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "ksk-doubleksk-autosign" { - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 2h; - publish-safety P1D; - retire-safety P2D; - purge-keys PT1H; - - cdnskey no; - keys { - ksk key-directory lifetime P60D algorithm ecdsa256; - zsk key-directory lifetime unlimited algorithm ecdsa256; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; - - parent-ds-ttl 3600; - parent-propagation-delay PT1H; -}; - -dnssec-policy "ksk-doubleksk-manual" { - manual-mode yes; - - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 2h; - publish-safety P1D; - retire-safety P2D; - purge-keys PT1H; - - cdnskey no; - keys { - ksk key-directory lifetime P60D algorithm ecdsa256; - zsk key-directory lifetime unlimited algorithm ecdsa256; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; - - parent-ds-ttl 3600; - parent-propagation-delay PT1H; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/named.conf.j2 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - * 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 zones = ["autosign", "manual"] %} - -include "kasp.conf"; -include "named.common.conf"; - -{% for tld in zones %} -zone "step1.ksk-doubleksk.@tld@" { - type primary; - file "step1.ksk-doubleksk.@tld@.db"; - dnssec-policy "ksk-doubleksk-@tld@"; -}; -zone "step2.ksk-doubleksk.@tld@" { - type primary; - file "step2.ksk-doubleksk.@tld@.db"; - dnssec-policy "ksk-doubleksk-@tld@"; -}; -zone "step3.ksk-doubleksk.@tld@" { - type primary; - file "step3.ksk-doubleksk.@tld@.db"; - dnssec-policy "ksk-doubleksk-@tld@"; -}; -zone "step4.ksk-doubleksk.@tld@" { - type primary; - file "step4.ksk-doubleksk.@tld@.db"; - dnssec-policy "ksk-doubleksk-@tld@"; -}; -zone "step5.ksk-doubleksk.@tld@" { - type primary; - file "step5.ksk-doubleksk.@tld@.db"; - dnssec-policy "ksk-doubleksk-@tld@"; -}; -zone "step6.ksk-doubleksk.@tld@" { - type primary; - file "step6.ksk-doubleksk.@tld@.db"; - dnssec-policy "ksk-doubleksk-@tld@"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/tests_rollover_ksk_doubleksk.py bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/tests_rollover_ksk_doubleksk.py --- bind9-9.20.26/bin/tests/system/rollover_ksk_doubleksk/tests_rollover_ksk_doubleksk.py 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_ksk_doubleksk/tests_rollover_ksk_doubleksk.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,371 +0,0 @@ -# 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. - -from datetime import timedelta - -import pytest - -from isctest.util import param -from rollover.common import ( - KSK_CONFIG, - KSK_IPUB, - KSK_IPUBC, - KSK_IRET, - KSK_KEYTTLPROP, - KSK_LIFETIME, - KSK_LIFETIME_POLICY, - ROLLOVER_MARK, - TIMEDELTA, -) -from rollover.setup import configure_ksk_doubleksk, configure_root, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - -CDSS = ["CDS (SHA-256)"] -POLICY = "ksk-doubleksk" -OFFSETS = {} -OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds()) -OFFSETS["step2-p"] = -int(KSK_LIFETIME.total_seconds() - KSK_IPUBC.total_seconds()) -OFFSETS["step2-s"] = 0 -OFFSETS["step3-p"] = -int(KSK_LIFETIME.total_seconds()) -OFFSETS["step3-s"] = -int(KSK_IPUBC.total_seconds()) -OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(KSK_IRET.total_seconds()) -OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(KSK_IRET.total_seconds()) -OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KSK_KEYTTLPROP.total_seconds()) -OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KSK_KEYTTLPROP.total_seconds()) -OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(KSK_CONFIG["purge-keys"].total_seconds()) -OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KSK_CONFIG["purge-keys"].total_seconds()) - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "autosign", - "manual", - ]: - delegations = configure_ksk_doubleksk(tld_name) - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_ksk_doubleksk_step1(tld, ns3, default_algorithm): - zone = f"step1.ksk-doubleksk.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - # Note that the key was already generated during setup. - - step = { - # Introduce the first key. This will immediately be active. - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step1-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", - ], - # Next key event is when the successor KSK needs to be published. - # That is the KSK lifetime - prepublication time (minus time - # already passed). - "nextev": KSK_LIFETIME - KSK_IPUB - timedelta(days=7), - } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_ksk_doubleksk_step2(tld, ns3, default_algorithm): - zone = f"step2.ksk-doubleksk.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 1. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) - - # Check logs. - tag = keys[1].key.tag - msg = f"keymgr-manual-mode: block KSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # Successor KSK is prepublished (and signs DNSKEY RRset). - # KSK1 goal: omnipresent -> hidden - # KSK2 goal: hidden -> omnipresent - # KSK2 dnskey: hidden -> rumoured - # KSK2 krrsig: hidden -> rumoured - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden offset:{OFFSETS['step2-s']}", - ], - "keyrelationships": [1, 2], - # Next key event is when the successor KSK becomes OMNIPRESENT. - "nextev": KSK_IPUB, - } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_ksk_doubleksk_step3(tld, ns3, default_algorithm): - zone = f"step3.ksk-doubleksk.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 2, but DNSKEY has become OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step3-s']}", - ], - "keyrelationships": [1, 2], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) - - # Check logs. - tag = keys[2].key.tag - msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - # Check logs. - tag = keys[1].key.tag - msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" - if msg in ns3.log: - # Force step. - isctest.log.debug( - f"keymgr-manual-mode blocking transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" - ) - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # The successor DNSKEY RRset has become omnipresent. The - # predecessor DS can be withdrawn and the successor DS can be - # introduced. - # KSK1 ds: omnipresent -> unretentive - # KSK2 dnskey: rumoured -> omnipresent - # KSK2 krrsig: rumoured -> omnipresent - # KSK2 ds: hidden -> rumoured - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:unretentive offset:{OFFSETS['step3-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:rumoured offset:{OFFSETS['step3-s']}", - ], - "keyrelationships": [1, 2], - # Next key event is when the predecessor DS has been replaced with - # the successor DS and enough time has passed such that the all - # validators that have this DS RRset cached only know about the - # successor DS. This is the the retire interval. - "nextev": KSK_IRET, - } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_ksk_doubleksk_step4(tld, ns3, default_algorithm): - zone = f"step4.ksk-doubleksk.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 3, but DS has become HIDDEN/OMNIPRESENT. - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step4-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}", - ], - "keyrelationships": [1, 2], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) - - # Check logs. - tag = keys[1].key.tag - msg1 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" - msg2 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" - assert msg1 in ns3.log - assert msg2 in ns3.log - - # Force step. - tag = keys[2].key.tag - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # The predecessor DNSKEY may be removed, the successor DS is - # omnipresent. - # KSK1 dnskey: omnipresent -> unretentive - # KSK1 krrsig: omnipresent -> unretentive - # KSK1 ds: unretentive -> hidden - # KSK2 ds: rumoured -> omnipresent - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive krrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}", - ], - "keyrelationships": [1, 2], - # Next key event is when the DNSKEY enters the HIDDEN state. - # This is the DNSKEY TTL plus zone propagation delay. - "nextev": KSK_KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_ksk_doubleksk_step5(tld, ns3, default_algorithm): - zone = f"step5.ksk-doubleksk.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - # The predecessor DNSKEY is long enough removed from the zone it - # has become hidden. - # KSK1 dnskey: unretentive -> hidden - # KSK1 krrsig: unretentive -> hidden - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step5-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden krrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", - ], - "keyrelationships": [1, 2], - # Next key event is when the new successor needs to be published. - # This is the KSK lifetime minus Ipub minus Iret minus time elapsed. - "nextev": KSK_LIFETIME - KSK_IPUB - KSK_IRET - KSK_KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_ksk_doubleksk_step6(tld, ns3, default_algorithm): - zone = f"step6.ksk-doubleksk.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - # Predecessor KSK is now purged. - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step6-p']}", - f"ksk {KSK_LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-s']}", - ], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/kasp.conf.j2 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/kasp.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/kasp.conf.j2 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/kasp.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "unlimited-lifetime" { - keys { - csk lifetime unlimited algorithm @DEFAULT_ALGORITHM@; - }; -}; -dnssec-policy "short-lifetime" { - keys { - csk lifetime P6M algorithm @DEFAULT_ALGORITHM@; - }; -}; - -dnssec-policy "long-lifetime" { - keys { - csk lifetime P1Y algorithm @DEFAULT_ALGORITHM@; - }; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/limit-lifetime.db bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/limit-lifetime.db --- bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/limit-lifetime.db 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/limit-lifetime.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -; 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. - -$TTL 300 -@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/longer-lifetime.db bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/longer-lifetime.db --- bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/longer-lifetime.db 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/longer-lifetime.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -; 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. - -$TTL 300 -@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/named.conf.j2 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* - * 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 change_lifetime = change_lifetime | default(False) %} -{% set longer = "short-lifetime" if not change_lifetime else "long-lifetime" %} -{% set shorter = "long-lifetime" if not change_lifetime else "short-lifetime" %} -{% set limit = "unlimited-lifetime" if not change_lifetime else "short-lifetime" %} -{% set unlimit = "short-lifetime" if not change_lifetime else "unlimited-lifetime" %} - -include "kasp.conf"; -include "named.common.conf"; - -zone longer-lifetime.kasp { - type primary; - file "longer-lifetime.db"; - dnssec-policy @longer@; -}; - -zone shorter-lifetime.kasp { - type primary; - file "shorter-lifetime.db"; - dnssec-policy @shorter@; -}; - -zone limit-lifetime.kasp { - type primary; - file "limit-lifetime.db"; - dnssec-policy @limit@; -}; - -zone unlimit-lifetime.kasp { - type primary; - file "unlimit-lifetime.db"; - dnssec-policy @unlimit@; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/shorter-lifetime.db bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/shorter-lifetime.db --- bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/shorter-lifetime.db 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/shorter-lifetime.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -; 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. - -$TTL 300 -@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/template.db.in bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/template.db.in --- bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/template.db.in 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/template.db.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -; 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. - -$TTL 300 -@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/unlimit-lifetime.db bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/unlimit-lifetime.db --- bind9-9.20.26/bin/tests/system/rollover_lifetime/ns3/unlimit-lifetime.db 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/ns3/unlimit-lifetime.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -; 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. - -$TTL 300 -@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_initial.py bind9-9.20.29/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_initial.py --- bind9-9.20.26/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_initial.py 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_initial.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -# 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. - -import pytest - -from isctest.util import param -from rollover.common import CDSS, DEFAULT_CONFIG, DURATION, ROLLOVER_MARK - -import isctest - -pytestmark = ROLLOVER_MARK - - -@pytest.mark.parametrize( - "zone, policy, lifetime", - [ - param("shorter-lifetime", "long-lifetime", "P1Y"), - param("longer-lifetime", "short-lifetime", "P6M"), - param("limit-lifetime", "unlimited-lifetime", 0), - param("unlimit-lifetime", "short-lifetime", "P6M"), - ], -) -def test_lifetime_initial(zone, policy, lifetime, ns3, default_algorithm): - config = DEFAULT_CONFIG - - isctest.kasp.wait_keymgr_done(ns3, f"{zone}.kasp") - - step = { - "zone": f"{zone}.kasp", - "cdss": CDSS, - "keyprops": [ - f"csk {DURATION[lifetime]} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden", - ], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_reconfig.py bind9-9.20.29/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_reconfig.py 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_lifetime/tests_rollover_lifetime_reconfig.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -# 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. - -import pytest - -from isctest.util import param -from rollover.common import CDSS, DEFAULT_CONFIG, DURATION, ROLLOVER_MARK - -import isctest - -pytestmark = ROLLOVER_MARK - - -@pytest.fixture(scope="module", autouse=True) -def after_servers_start(ns3, templates): - isctest.kasp.wait_keymgr_done(ns3, "shorter-lifetime.kasp") - isctest.kasp.wait_keymgr_done(ns3, "longer-lifetime.kasp") - isctest.kasp.wait_keymgr_done(ns3, "limit-lifetime.kasp") - isctest.kasp.wait_keymgr_done(ns3, "unlimit-lifetime.kasp") - - templates.render("ns3/named.conf", {"change_lifetime": True}) - ns3.reconfigure() - - -@pytest.mark.parametrize( - "zone, policy, lifetime", - [ - param("shorter-lifetime", "short-lifetime", "P6M"), - param("longer-lifetime", "long-lifetime", "P1Y"), - param( - "limit-lifetime", - "short-lifetime", - "P6M", - ), - param("unlimit-lifetime", "unlimited-lifetime", 0), - ], -) -def test_lifetime_reconfig(zone, policy, lifetime, ns3, default_algorithm): - config = DEFAULT_CONFIG - - isctest.kasp.wait_keymgr_done(ns3, f"{zone}.kasp", reconfig=True) - - step = { - "zone": f"{zone}.kasp", - "cdss": CDSS, - "keyprops": [ - f"csk {DURATION[lifetime]} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden", - ], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/kasp.conf.j2 bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/kasp.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/kasp.conf.j2 2026-07-20 14:47:53.866846896 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/kasp.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "multisigner-model2" { - dnskey-ttl 3600; - inline-signing no; - - keys { - ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; - zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535; - }; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/named.conf.j2 2026-07-20 14:47:53.867846911 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - * 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. - */ - -include "kasp.conf"; -include "named.common.conf"; - -/* RFC 8901 Multi-signer Model 2. */ -zone "multisigner-model2.kasp" { - type primary; - file "multisigner-model2.kasp.db"; - dnssec-policy "multisigner-model2"; - allow-update { any; }; -}; - -/* - * A zone that starts with keys that have tags that are - * outside of the desired multi-signer key tag range. - */ -zone "single-to-multisigner.kasp" { - type primary; - file "single-to-multisigner.kasp.db"; - dnssec-policy "multisigner-model2"; - allow-update { any; }; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/template.db.in bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/template.db.in --- bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/template.db.in 2026-07-20 14:47:53.867846911 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/template.db.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -; 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. - -$TTL 300 -@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - diff -Nru bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_multisigner/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_multisigner/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_multisigner/tests_rollover_multisigner.py bind9-9.20.29/bin/tests/system/rollover_multisigner/tests_rollover_multisigner.py --- bind9-9.20.26/bin/tests/system/rollover_multisigner/tests_rollover_multisigner.py 2026-07-20 14:47:53.867846911 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_multisigner/tests_rollover_multisigner.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,238 +0,0 @@ -# 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. - -from datetime import timedelta - -import os - -import dns.update - -from isctest.kasp import Iret -from isctest.run import EnvCmd -from rollover.common import ROLLOVER_MARK -from rollover.setup import fake_lifetime, render_and_sign_zone - -import isctest - -pytestmark = ROLLOVER_MARK - - -def bootstrap(): - templates = isctest.template.TemplateEngine(".") - - # Multi-signer zones. - keygen = EnvCmd("KEYGEN", "-a ECDSA256 -L 3600") - settime = EnvCmd("SETTIME", "-s") - - # Model 2. - zonename = "multisigner-model2.kasp" - isctest.log.info(f"setup {zonename}") - # Key generation. - ksk_name = keygen(f"-M 32768:65535 -f KSK {zonename}", cwd="ns3").out.strip() - zsk_name = keygen(f"-M 32768:65535 {zonename}", cwd="ns3").out.strip() - # Signing. - dnskeys = [] - for key_name in [ksk_name, zsk_name]: - key = isctest.kasp.Key(key_name, keydir="ns3") - dnskeys.append(key.dnskey) - # Import a ZSK of another provider into the DNSKEY RRset. - zsk_extra = keygen(f"-M 0:32767 {zonename}").out.strip() - key = isctest.kasp.Key(zsk_extra) - dnskeys.append(key.dnskey) - # Render zone file. - outfile = f"{zonename}.db" - templates = isctest.template.TemplateEngine(".") - template = "template.db.j2.manual" - tdata = { - "fqdn": f"{zonename}.", - "dnskeys": dnskeys, - "privaterrs": [], - } - templates.render(f"ns3/{outfile}", tdata, template=f"ns3/{template}") - - # We are changing an existing single-signed zone to multi-signed - # zone where the key tags do not match the dnssec-policy key tag range - zonename = "single-to-multisigner.kasp" - isctest.log.info(f"setup {zonename}") - # Timing metadata. - TpubN = "now-7d" - TsbmN = "now-8635mi" # T - 1d5m - keytimes = f"-P {TpubN} -A {TpubN}" - cdstimes = f"-P sync {TsbmN}" - # Key generation. - ksk_name = keygen( - f"-M 0:32767 -f KSK {keytimes} {cdstimes} {zonename}", cwd="ns3" - ).out.strip() - zsk_name = keygen(f"-M 0:32767 {keytimes} {zonename}", cwd="ns3").out.strip() - settime( - f"-g OMNIPRESENT -d OMNIPRESENT {TpubN} -k OMNIPRESENT {TpubN} -r OMNIPRESENT {TpubN} {ksk_name}", - cwd="ns3", - ) - settime( - f"-g OMNIPRESENT -k OMNIPRESENT {TpubN} -z OMNIPRESENT {TpubN} {zsk_name}", - cwd="ns3", - ) - # Signing. - fake_lifetime(ksk_name, 0) - fake_lifetime(zsk_name, 0) - render_and_sign_zone(zonename, [ksk_name, zsk_name]) - - return {} - - -def test_rollover_multisigner(ns3, default_algorithm): - policy = "multisigner-model2" - config = { - "dnskey-ttl": timedelta(hours=1), - "ds-ttl": timedelta(days=1), - "max-zone-ttl": timedelta(days=1), - "parent-propagation-delay": timedelta(hours=1), - "publish-safety": timedelta(hours=1), - "retire-safety": timedelta(hours=1), - "signatures-refresh": timedelta(days=5), - "signatures-validity": timedelta(days=14), - "zone-propagation-delay": timedelta(minutes=5), - } - ttl = int(config["dnskey-ttl"].total_seconds()) - - offset = -timedelta(days=7) - offval = int(offset.total_seconds()) - - def keygen(zone): - keygen_command = [ - os.environ.get("KEYGEN"), - "-a", - default_algorithm.name, - "-L", - "3600", - "-M", - "0:32767", - zone, - ] - - return isctest.run.cmd(keygen_command).out - - zone = "multisigner-model2.kasp" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - isctest.kasp.check_dnssec_verify(ns3, zone) - - key_properties = [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden tag-range:32768-65535", - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured zrrsig:rumoured tag-range:32768-65535", - ] - expected = isctest.kasp.policy_to_properties(ttl, key_properties) - - newprops = [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} tag-range:0-32767" - ] - expected2 = isctest.kasp.policy_to_properties(ttl, newprops) - expected2[0].private = False - expected2[0].legacy = True - expected = expected + expected2 - - ownkeys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier) - extkeys = isctest.kasp.keydir_to_keylist(zone) - keys = ownkeys + extkeys - ksks = [k for k in ownkeys if k.is_ksk()] - zsks = [k for k in ownkeys if not k.is_ksk()] - zsks = zsks + extkeys - - isctest.kasp.check_keys(zone, keys, expected) - for kp in expected: - kp.set_expected_keytimes(config) - isctest.kasp.check_keytimes(keys, expected) - isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=policy) - isctest.kasp.check_apex(ns3, zone, ksks, zsks) - isctest.kasp.check_subdomain(ns3, zone, ksks, zsks) - - # Update zone with ZSK from another provider for zone. - out = keygen(zone) - newkeys = isctest.kasp.keystr_to_keylist(out) - newprops = [ - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} tag-range:0-32767" - ] - expected2 = isctest.kasp.policy_to_properties(ttl, newprops) - expected2[0].private = False - expected2[0].legacy = True - expected = expected + expected2 - - dnskey = newkeys[0].dnskey - - update_msg = dns.update.UpdateMessage(zone) - update_msg.add(dnskey.name, dnskey.ttl, dnskey[0]) - ns3.nsupdate(update_msg) - - isctest.kasp.check_dnssec_verify(ns3, zone) - - keys = keys + newkeys - zsks = zsks + newkeys - isctest.kasp.check_keys(zone, keys, expected) - isctest.kasp.check_apex(ns3, zone, ksks, zsks) - isctest.kasp.check_subdomain(ns3, zone, ksks, zsks) - - # Remove ZSKs from the other providers for zone. - dnskey2 = extkeys[0].dnskey - update_msg = dns.update.UpdateMessage(zone) - update_msg.delete(dnskey.name, dnskey[0]) - update_msg.delete(dnskey2.name, dnskey2[0]) - ns3.nsupdate(update_msg) - - isctest.kasp.check_dnssec_verify(ns3, zone) - - expected = isctest.kasp.policy_to_properties(ttl, key_properties) - keys = ownkeys - ksks = [k for k in ownkeys if k.is_ksk()] - zsks = [k for k in ownkeys if not k.is_ksk()] - isctest.kasp.check_keys(zone, keys, expected) - isctest.kasp.check_apex(ns3, zone, ksks, zsks) - isctest.kasp.check_subdomain(ns3, zone, ksks, zsks) - - # A zone transitioning from single-signed to multi-signed. We should have - # the old omnipresent keys outside of the desired key range and the new - # keys in the desired key range. - zone = "single-to-multisigner.kasp" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - isctest.kasp.check_dnssec_verify(ns3, zone) - - key_properties = [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden tag-range:32768-65535", - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured zrrsig:hidden tag-range:32768-65535", - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent tag-range:0-32767 offset:{offval}", - f"zsk unlimited {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:omnipresent tag-range:0-32767 offset:{offval}", - ] - expected = isctest.kasp.policy_to_properties(ttl, key_properties) - keys = isctest.kasp.keydir_to_keylist(zone, ns3.identifier) - ksks = [k for k in keys if k.is_ksk()] - zsks = [k for k in keys if not k.is_ksk()] - - isctest.kasp.check_keys(zone, keys, expected) - - for kp in expected: - kp.set_expected_keytimes(config) - - start = expected[0].key.get_timing("Created") - expected[2].timing["Retired"] = start - expected[2].timing["Removed"] = expected[2].timing["Retired"] + Iret( - config, zsk=False, ksk=True - ) - expected[3].timing["Retired"] = start - expected[3].timing["Removed"] = expected[3].timing["Retired"] + Iret( - config, zsk=True, ksk=False - ) - - isctest.kasp.check_keytimes(keys, expected) - isctest.kasp.check_dnssecstatus(ns3, zone, keys, policy=policy) - isctest.kasp.check_apex(ns3, zone, ksks, zsks) - isctest.kasp.check_subdomain(ns3, zone, ksks, zsks) diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_straight2none/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_straight2none/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/kasp.conf 2026-07-20 14:47:53.865846880 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "unsigning" { - dnskey-ttl 7200; - - keys { - ksk key-directory lifetime unlimited algorithm ecdsa256; - zsk key-directory lifetime P60D algorithm ecdsa256; - }; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/named.conf.j2 2026-07-20 14:47:53.867846911 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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 policy = policy | default("default") %} - -include "kasp.conf"; -include "named.common.conf"; - -zone "going-straight-to-none.kasp" { - type primary; - file "going-straight-to-none.kasp.db"; - dnssec-policy @policy@; -}; - -zone "going-straight-to-none-dynamic.kasp" { - type primary; - file "going-straight-to-none-dynamic.kasp.db.signed"; - inline-signing no; - dnssec-policy @policy@; - allow-update { any; }; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_straight2none/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_initial.py bind9-9.20.29/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_initial.py --- bind9-9.20.26/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_initial.py 2026-07-20 14:47:53.867846911 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_initial.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -# 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. - -import pytest - -from rollover.common import CDSS, DEFAULT_CONFIG, DURATION, ROLLOVER_MARK -from rollover.setup import configure_root, configure_straight2none, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - tld_name = "kasp" - delegations = configure_straight2none(tld_name) - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - data["tlds"].append(tld_name) - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - return data - - -@pytest.mark.parametrize( - "zone", - [ - "going-straight-to-none.kasp", - "going-straight-to-none-dynamic.kasp", - ], -) -def test_straight2none_initial(zone, ns3, default_algorithm): - config = DEFAULT_CONFIG - policy = "default" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - step = { - "zone": zone, - "cdss": CDSS, - "keyprops": [ - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P10D']}", - ], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_reconfig.py bind9-9.20.29/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_reconfig.py --- bind9-9.20.26/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_reconfig.py 2026-07-20 14:47:53.867846911 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_straight2none/tests_rollover_straight2none_reconfig.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -# 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. - -import pytest - -from rollover.common import CDSS, DEFAULT_CONFIG, DURATION, ROLLOVER_MARK -from rollover.setup import configure_root, configure_straight2none, configure_tld - -import isctest - -pytestmark = ROLLOVER_MARK - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - tld_name = "kasp" - delegations = configure_straight2none(tld_name) - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - data["tlds"].append(tld_name) - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - return data - - -@pytest.fixture(scope="module", autouse=True) -def after_servers_start(ns3, templates): - isctest.kasp.wait_keymgr_done(ns3, "going-straight-to-none.kasp") - isctest.kasp.wait_keymgr_done(ns3, "going-straight-to-none-dynamic.kasp") - - templates.render("ns3/named.conf", {"policy": "none"}) - ns3.reconfigure() - - -@pytest.mark.parametrize( - "zone", - [ - "going-straight-to-none.kasp", - "going-straight-to-none-dynamic.kasp", - ], -) -def test_straight2none_reconfig(zone, ns3, default_algorithm): - config = DEFAULT_CONFIG - policy = None - - step = { - "zone": zone, - "cdss": CDSS, - # These zones will go bogus after signatures expire, but - # remain validly signed for now. - "keyprops": [ - f"csk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P10D']}", - ], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, config, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns1/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * 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. - */ - -// NS1 - -options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion no; - notify yes; -}; - -zone "." { - type primary; - file "root.db.signed"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns1/root.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns1/root.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns1/root.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns1/root.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -; 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. - -$TTL 300 -. IN SOA . a.root.servers.nil. ( - 2000042100 ; serial - 600 ; refresh - 600 ; retry - 1200 ; expire - 600 ; minimum - ) -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@ NS @ns_name@ -@ns_name@ A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns2/named.conf.j2 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * 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. - */ - -// NS2 - -options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - allow-notify { 10.53.0.3; }; - recursion no; - dnssec-validation no; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; - -{% for zone in tlds %} -zone "@zone@" { - type primary; - file "@zone@.db.signed"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns2/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns2/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns2/template.db.j2.manual 2026-07-20 14:47:53.860846802 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns2/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -; 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. - -$TTL 300 -$ORIGIN @fqdn@ - -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns2 - -ns2 A 10.53.0.2 -ns3 A 10.53.0.3 - -scanner A 10.53.0.2 - -*._dsync DSYNC CDS NOTIFY @PORT@ scanner - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for zone in delegations %} -{% set ns_name = zone.ns.name + "." + zone.name %} -@zone.name@. NS @ns_name@. -@ns_name@. A @zone.ns.ip@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/kasp.conf bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/kasp.conf --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/kasp.conf 2026-07-20 14:47:53.867846911 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/kasp.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * 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. - */ - -dnssec-policy "zsk-prepub-autosign" { - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 3600; - publish-safety P1D; - retire-safety P2D; - purge-keys PT1H; - - keys { - ksk key-directory lifetime unlimited algorithm ecdsa256; - zsk key-directory lifetime P30D algorithm ecdsa256; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; -}; - -dnssec-policy "zsk-prepub-manual" { - manual-mode yes; - - signatures-refresh P1W; - signatures-validity P2W; - signatures-validity-dnskey P2W; - - dnskey-ttl 3600; - publish-safety P1D; - retire-safety P2D; - purge-keys PT1H; - - keys { - ksk key-directory lifetime unlimited algorithm ecdsa256; - zsk key-directory lifetime P30D algorithm ecdsa256; - }; - - zone-propagation-delay PT1H; - max-zone-ttl 1d; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/named.common.conf.j2 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/named.common.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/named.common.conf.j2 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/named.common.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * 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. - */ - -{% if trust_anchors is defined %} -include "trusted.conf"; -{% set dnssec_validation = "yes" %} -{% else %} -{% set dnssec_validation = "auto" %} -{% endif %} - - -options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - allow-transfer { any; }; - recursion yes; - dnssec-validation @dnssec_validation@; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; - -zone "." { - type hint; - file "../../_common/root.hint"; -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/named.conf.j2 2026-07-20 14:47:53.867846911 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - * 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 zones = ["autosign", "manual"] %} - -include "kasp.conf"; -include "named.common.conf"; - -{% for tld in zones %} -zone "step1.zsk-prepub.@tld@" { - type primary; - file "step1.zsk-prepub.@tld@.db"; - dnssec-policy "zsk-prepub-@tld@"; -}; -zone "step2.zsk-prepub.@tld@" { - type primary; - file "step2.zsk-prepub.@tld@.db"; - dnssec-policy "zsk-prepub-@tld@"; -}; -zone "step3.zsk-prepub.@tld@" { - type primary; - file "step3.zsk-prepub.@tld@.db"; - dnssec-policy "zsk-prepub-@tld@"; -}; -zone "step4.zsk-prepub.@tld@" { - type primary; - file "step4.zsk-prepub.@tld@.db"; - dnssec-policy "zsk-prepub-@tld@"; -}; -zone "step5.zsk-prepub.@tld@" { - type primary; - file "step5.zsk-prepub.@tld@.db"; - dnssec-policy "zsk-prepub-@tld@"; -}; -zone "step6.zsk-prepub.@tld@" { - type primary; - file "step6.zsk-prepub.@tld@.db"; - dnssec-policy "zsk-prepub-@tld@"; -}; -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/template.db.j2.manual bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/template.db.j2.manual --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/template.db.j2.manual 2026-07-20 14:47:53.861846818 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/template.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -; 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. - -$TTL 300 -@fqdn@ IN SOA mname1. . ( - 1 ; serial - 20 ; refresh (20 seconds) - 20 ; retry (20 seconds) - 1814400 ; expire (3 weeks) - 3600 ; minimum (1 hour) - ) - - NS ns3 -ns3 A 10.53.0.3 - -a A 10.0.0.1 -b A 10.0.0.2 -c A 10.0.0.3 - -{% for dnskey in dnskeys %} -@dnskey@ -{% endfor %} - -{% for privaterr in privaterrs %} -@privaterr@ -{% endfor %} diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/trusted.conf.j2 bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/trusted.conf.j2 --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/ns3/trusted.conf.j2 2026-07-20 14:47:53.585841141 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/ns3/trusted.conf.j2 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -trust-anchors { -{% for ta in trust_anchors %} - "@ta.domain@" @ta.type@ @ta.contents@; -{% endfor %} -}; diff -Nru bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/tests_rollover_zsk_prepublication.py bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/tests_rollover_zsk_prepublication.py --- bind9-9.20.26/bin/tests/system/rollover_zsk_prepub/tests_rollover_zsk_prepublication.py 2026-07-20 14:47:53.868846927 +0000 +++ bind9-9.20.29/bin/tests/system/rollover_zsk_prepub/tests_rollover_zsk_prepublication.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,374 +0,0 @@ -# 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. - -from datetime import timedelta - -import pytest - -from isctest.kasp import Ipub, Iret -from isctest.util import param -from rollover.common import ROLLOVER_MARK, TIMEDELTA -from rollover.setup import configure_root, configure_tld, configure_zsk_prepub - -import isctest - -pytestmark = ROLLOVER_MARK - -CONFIG = { - "dnskey-ttl": TIMEDELTA["PT1H"], - "ds-ttl": TIMEDELTA["P1D"], - "max-zone-ttl": TIMEDELTA["P1D"], - "parent-propagation-delay": TIMEDELTA["PT1H"], - "publish-safety": TIMEDELTA["P1D"], - "purge-keys": TIMEDELTA["PT1H"], - "retire-safety": TIMEDELTA["P2D"], - "signatures-refresh": TIMEDELTA["P7D"], - "signatures-validity": TIMEDELTA["P14D"], - "zone-propagation-delay": TIMEDELTA["PT1H"], -} -POLICY = "zsk-prepub" -ZSK_LIFETIME = TIMEDELTA["P30D"] -LIFETIME_POLICY = int(ZSK_LIFETIME.total_seconds()) -IPUB = Ipub(CONFIG) -IRET = Iret(CONFIG) -KEYTTLPROP = CONFIG["dnskey-ttl"] + CONFIG["zone-propagation-delay"] -OFFSETS = {} -OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds()) -OFFSETS["step2-p"] = -int(ZSK_LIFETIME.total_seconds() - IPUB.total_seconds()) -OFFSETS["step2-s"] = 0 -OFFSETS["step3-p"] = -int(ZSK_LIFETIME.total_seconds()) -OFFSETS["step3-s"] = -int(IPUB.total_seconds()) -OFFSETS["step4-p"] = OFFSETS["step3-p"] - int(IRET.total_seconds()) -OFFSETS["step4-s"] = OFFSETS["step3-s"] - int(IRET.total_seconds()) -OFFSETS["step5-p"] = OFFSETS["step4-p"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step5-s"] = OFFSETS["step4-s"] - int(KEYTTLPROP.total_seconds()) -OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(CONFIG["purge-keys"].total_seconds()) -OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(CONFIG["purge-keys"].total_seconds()) - - -def bootstrap(): - data = { - "tlds": [], - "trust_anchors": [], - } - - tlds = [] - for tld_name in [ - "autosign", - "manual", - ]: - delegations = configure_zsk_prepub(tld_name) - - tld = configure_tld(tld_name, delegations) - tlds.append(tld) - - data["tlds"].append(tld_name) - - ta = configure_root(tlds) - data["trust_anchors"].append(ta) - - return data - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_zsk_prepub_step1(tld, ns3, default_algorithm): - zone = f"step1.zsk-prepub.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - # Note that the key was already generated during setup. - - step = { - # Introduce the first key. This will immediately be active. - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step1-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step1-p']}", - ], - # Next key event is when the successor ZSK needs to be published. - # That is the ZSK lifetime - prepublication time (minus time - # already passed). - "nextev": ZSK_LIFETIME - IPUB - timedelta(days=7), - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_zsk_prepub_step2(tld, ns3, default_algorithm): - zone = f"step2.zsk-prepub.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 1. - step = { - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", - ], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[1].key.tag - msg = f"keymgr-manual-mode: block ZSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # it is time to pre-publish the successor zsk. - # zsk1 goal: omnipresent -> hidden - # zsk2 goal: hidden -> omnipresent - # zsk2 dnskey: hidden -> rumoured - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:rumoured zrrsig:hidden offset:{OFFSETS['step2-s']}", - ], - "keyrelationships": [1, 2], - # next key event is when the successor zsk becomes omnipresent. - # that is the dnskey ttl plus the zone propagation delay - "nextev": IPUB, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_zsk_prepub_step3(tld, ns3, default_algorithm): - zone = f"step3.zsk-prepub.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 2, but DNSKEY has become OMNIPRESENT. - step = { - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:hidden offset:{OFFSETS['step3-s']}", - ], - "keyrelationships": [1, 2], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[2].key.tag - msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" - assert msg in ns3.log - - # Force step. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - # Check logs. - tag = keys[1].key.tag - msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" - if msg in ns3.log: - # Force step. - isctest.log.debug( - f"keymgr-manual-mode blocking transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" - ) - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # predecessor zsk is no longer actively signing. successor zsk is - # now actively signing. - # zsk1 zrrsig: omnipresent -> unretentive - # zsk2 dnskey: rumoured -> omnipresent - # zsk2 zrrsig: hidden -> rumoured - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:unretentive offset:{OFFSETS['step3-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:rumoured offset:{OFFSETS['step3-s']}", - ], - "keyrelationships": [1, 2], - # next key event is when all the rrsig records have been replaced - # with signatures of the new zsk, in other words when zrrsig - # becomes omnipresent. - "nextev": IRET, - # set 'smooth' to true so expected signatures of subdomain are - # from the predecessor zsk. - "smooth": True, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Force full resign and check all signatures have been replaced. - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"sign {zone}") - watcher.wait_for_line(f"zone {zone}/IN (signed): sending notifies") - - step["smooth"] = False - step["nextev"] = Iret(CONFIG, smooth=False) - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_zsk_prepub_step4(tld, ns3, default_algorithm): - zone = f"step4.zsk-prepub.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - if tld == "manual": - # Same as step 3, but zone signatures have become HIDDEN/OMNIPRESENT. - step = { - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:omnipresent zrrsig:hidden offset:{OFFSETS['step4-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-s']}", - ], - "keyrelationships": [1, 2], - "manual-mode": True, - "nextev": None, - } - keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - # Check logs. - tag = keys[1].key.tag - msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" - assert msg in ns3.log - - # Force step. - tag = keys[2].key.tag - with ns3.watch_log_from_here() as watcher: - ns3.rndc(f"dnssec -step {zone}") - watcher.wait_for_line( - f"zone {zone}/IN (signed): zone_rekey done: key {tag}/ECDSAP256SHA256" - ) - - step = { - # predecessor zsk is no longer needed. all rrsets are signed with - # the successor zsk. - # zsk1 dnskey: omnipresent -> unretentive - # zsk1 zrrsig: unretentive -> hidden - # zsk2 zrrsig: rumoured -> omnipresent - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:unretentive zrrsig:hidden offset:{OFFSETS['step4-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-s']}", - ], - "keyrelationships": [1, 2], - # next key event is when the dnskey enters the hidden state. - # this is the dnskey ttl plus zone propagation delay. - "nextev": KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_zsk_prepub_step5(tld, ns3, default_algorithm): - zone = f"step5.zsk-prepub.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - # predecessor zsk is now removed. - # zsk1 dnskey: unretentive -> hidden - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:hidden dnskey:hidden zrrsig:hidden offset:{OFFSETS['step5-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step5-s']}", - ], - "keyrelationships": [1, 2], - # next key event is when the new successor needs to be published. - # this is the zsk lifetime minus IRET minus IPUB minus time - # elapsed. - "nextev": ZSK_LIFETIME - IRET - IPUB - KEYTTLPROP, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) - - -@pytest.mark.parametrize( - "tld", - [ - param("autosign"), - param("manual"), - ], -) -def test_zsk_prepub_step6(tld, ns3, default_algorithm): - zone = f"step6.zsk-prepub.{tld}" - policy = f"{POLICY}-{tld}" - - isctest.kasp.wait_keymgr_done(ns3, zone) - - # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. - - step = { - # predecessor zsk is now purged. - "zone": zone, - "keyprops": [ - f"ksk unlimited {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step6-p']}", - f"zsk {LIFETIME_POLICY} {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step6-s']}", - ], - "nextev": None, - } - isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) diff -Nru bind9-9.20.26/bin/tests/system/rootkeysentinel/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rootkeysentinel/ns1/named.conf.j2 2026-07-20 14:47:53.868846927 +0000 +++ bind9-9.20.29/bin/tests/system/rootkeysentinel/ns1/named.conf.j2 2026-09-11 19:41:01.336327046 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/rootkeysentinel/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rootkeysentinel/ns2/named.conf.j2 2026-07-20 14:47:53.868846927 +0000 +++ bind9-9.20.29/bin/tests/system/rootkeysentinel/ns2/named.conf.j2 2026-09-11 19:41:01.336327046 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type primary; file "example.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/rootkeysentinel/ns3/hint.db bind9-9.20.29/bin/tests/system/rootkeysentinel/ns3/hint.db --- bind9-9.20.26/bin/tests/system/rootkeysentinel/ns3/hint.db 2026-07-20 14:47:53.868846927 +0000 +++ bind9-9.20.29/bin/tests/system/rootkeysentinel/ns3/hint.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -; 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. - -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/rootkeysentinel/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rootkeysentinel/ns3/named.conf.j2 2026-07-20 14:47:53.868846927 +0000 +++ bind9-9.20.29/bin/tests/system/rootkeysentinel/ns3/named.conf.j2 2026-09-11 19:41:01.336327046 +0000 @@ -12,22 +12,13 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; root-key-sentinel yes; }; -zone "." { - type hint; - file "hint.db"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/rootkeysentinel/ns4/hint.db bind9-9.20.29/bin/tests/system/rootkeysentinel/ns4/hint.db --- bind9-9.20.26/bin/tests/system/rootkeysentinel/ns4/hint.db 2026-07-20 14:47:53.868846927 +0000 +++ bind9-9.20.29/bin/tests/system/rootkeysentinel/ns4/hint.db 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -; 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. - -. NS a.root-servers.nil. -a.root-servers.nil. A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/rootkeysentinel/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/rootkeysentinel/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rootkeysentinel/ns4/named.conf.j2 2026-07-20 14:47:53.868846927 +0000 +++ bind9-9.20.29/bin/tests/system/rootkeysentinel/ns4/named.conf.j2 2026-09-11 19:41:01.337327070 +0000 @@ -12,22 +12,13 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; root-key-sentinel no; }; -zone "." { - type hint; - file "hint.db"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns1/named.conf.j2 2026-07-20 14:47:53.869846942 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns1/named.conf.j2 2026-09-11 19:41:01.337327070 +0000 @@ -12,27 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; allow-transfer { any; }; notify no; minimal-responses no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." {type primary; file "root.db";}; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns10/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns10/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns10/named.conf.j2 2026-07-20 14:47:53.870846958 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns10/named.conf.j2 2026-09-11 19:41:01.338327094 +0000 @@ -12,28 +12,14 @@ */ options { - query-source address 10.53.0.10; - notify-source 10.53.0.10; - transfer-source 10.53.0.10; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.10; }; - listen-on-v6 { none; }; allow-transfer { any; }; notify no; minimal-responses no; - recursion yes; dnssec-validation yes; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.10 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "../trusted.conf"; zone "." { type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns11/0.0.127.in-addr.arpa.db bind9-9.20.29/bin/tests/system/rpz/ns11/0.0.127.in-addr.arpa.db --- bind9-9.20.26/bin/tests/system/rpz/ns11/0.0.127.in-addr.arpa.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns11/0.0.127.in-addr.arpa.db 2026-09-11 19:41:01.338327094 +0000 @@ -0,0 +1,3 @@ +0.0.127.in-addr.arpa. 60 IN SOA localhost. localhost.localdomain. 1 60 60 60 60 + 60 IN NS . +1 60 IN PTR localhost. diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns11/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns11/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns11/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns11/named.conf.j2 2026-09-11 19:41:01.338327094 +0000 @@ -0,0 +1,27 @@ +options { + {% include_indented "_common/options.conf.j2" %} + dnssec-validation no; + response-policy { + zone "nsdname."; + }; + + /* + * This is the default, but this config covers a crash fix + * where a parent zone and a child zone are on the same auth. + * Here, 127.IN-ADDR.ARPA (parent of the "0.0.127.in-addr.arpa" below) + * is implicitly created. + */ + empty-zones-enable yes; +}; + +{% include "_common/controls.conf.j2" %} + +zone "0.0.127.in-addr.arpa" { + type primary; + file "0.0.127.in-addr.arpa.db"; +}; + +zone "nsdname." { + type primary; + file "nsdname.db"; +}; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns11/nsdname.db bind9-9.20.29/bin/tests/system/rpz/ns11/nsdname.db --- bind9-9.20.26/bin/tests/system/rpz/ns11/nsdname.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns11/nsdname.db 2026-09-11 19:41:01.338327094 +0000 @@ -0,0 +1,6 @@ +nsdname. 60 IN SOA localhost. localhost.localdomain. 1 60 60 60 60 + 60 IN NS . +$ORIGIN nsdname. +ns.0xc0f1c3a5.com.rpz-nsdname 60 IN CNAME *.walled-garden.example.com. +ns.0xc0f1c3a5.net.rpz-nsdname 60 IN CNAME *.walled-garden.example.com. +ns.0xc0f1c3a5.org.rpz-nsdname 60 IN CNAME *.walled-garden.example.com. diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns2/named.conf.j2 2026-07-20 14:47:53.870846958 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns2/named.conf.j2 2026-09-11 19:41:01.338327094 +0000 @@ -12,28 +12,14 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; allow-transfer { any; }; notify no; minimal-responses no; - recursion yes; dnssec-validation yes; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "../trusted.conf"; zone "." { type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns3/named.conf.j2 2026-07-20 14:47:53.871846973 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns3/named.conf.j2 2026-09-11 19:41:01.340327142 +0000 @@ -18,45 +18,38 @@ {% set bad_dlz = bad_dlz | default(False) %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} statistics-file "named.stats"; session-keyfile "session.key"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; allow-transfer { any; }; - notify yes; minimal-responses no; - recursion yes; dnssec-validation no; min-refresh-time 1; min-retry-time 1; response-policy { - zone "fast-expire"; - zone "bl" max-policy-ttl 100; - zone "bl-2"; - zone "bl-given" policy given recursive-only yes; - zone "bl-passthru" policy passthru; - zone "bl-no-op" policy no-op; # obsolete for passthru - zone "bl-disabled" policy disabled; - zone "bl-nodata" policy nodata recursive-only no; - zone "bl-nxdomain" policy nxdomain; - zone "bl-cname" policy cname txt-only.tld2.; - zone "bl-wildcname" policy cname *.tld4.; - zone "bl-garden" policy cname a12.tld2.; - zone "bl-drop" policy drop; - zone "bl-tcp-only" policy tcp-only; - zone "bl.tld2"; - zone "manual-update-rpz" ede forged; - zone "mixed-case-rpz"; - zone "include-rpz"; - zone "evil-cname" policy cname a12.tld2. ede blocked; - zone "wild-cname" ede blocked; - zone "slow-rpz"; + zone "fast-expire"; + zone "bl" max-policy-ttl 100; + zone "bl-2"; + zone "bl-given" policy given recursive-only yes; + zone "bl-passthru" policy passthru; + zone "bl-no-op" policy no-op; # obsolete for passthru + zone "bl-disabled" policy disabled; + zone "bl-nodata" policy nodata recursive-only no; + zone "bl-nxdomain" policy nxdomain; + zone "bl-cname" policy cname txt-only.tld2.; + zone "bl-wildcname" policy cname *.tld4.; + zone "bl-garden" policy cname a12.tld2.; + zone "bl-drop" policy drop; + zone "bl-tcp-only" policy tcp-only; + zone "bl.tld2"; + zone "manual-update-rpz" ede forged; + zone "mixed-case-rpz"; + zone "include-rpz"; + zone "evil-cname" policy cname a12.tld2. ede blocked; + zone "wild-cname" ede blocked; + zone "slow-rpz"; + zone "outofzone.tld2"; } add-soa yes min-ns-dots 0 @@ -68,20 +61,13 @@ ; include "../dnsrps.conf"; - also-notify { 10.53.0.3 port @EXTRAPORT1@; }; + also-notify { @ns.ip@ port @EXTRAPORT1@; }; notify-delay 0; }; logging { category rpz { default_debug; }; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints"; }; @@ -138,9 +124,9 @@ }; zone "slow-rpz." { - type primary; - file "slow-rpz.db"; - notify no; + type primary; + file "slow-rpz.db"; + notify no; }; zone "fast-expire." { @@ -150,6 +136,18 @@ notify no; }; +/* + * A policy zone holding a record from outside the zone. ns2 does not + * serve it, so "outofzone.db" is never replaced by a transfer. + */ +zone "outofzone.tld2." { + type secondary; + file "outofzone.db"; + masterfile-format text; + primaries { 10.53.0.2; }; + notify no; +}; + zone "stub." { type stub; primaries { 10.53.0.2; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns3/named1.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns3/named1.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns3/named1.conf.j2 2026-07-20 14:47:53.871846973 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns3/named1.conf.j2 2026-09-11 19:41:01.340327142 +0000 @@ -18,45 +18,38 @@ {% set bad_dlz = bad_dlz | default(False) %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} statistics-file "named.stats"; session-keyfile "session.key"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; allow-transfer { any; }; - notify yes; minimal-responses no; - recursion yes; dnssec-validation no; min-refresh-time 1; min-retry-time 1; response-policy { - zone "fast-expire"; - zone "bl" max-policy-ttl 100; - zone "bl-2"; - zone "bl-given" policy given recursive-only yes; - zone "bl-passthru" policy passthru; - zone "bl-no-op" policy no-op; # obsolete for passthru - zone "bl-disabled" policy disabled; - zone "bl-nodata" policy nodata recursive-only no; - zone "bl-nxdomain" policy nxdomain; - zone "bl-cname" policy cname txt-only.tld2.; - zone "bl-wildcname" policy cname *.tld4.; - zone "bl-garden" policy cname a12.tld2.; - zone "bl-drop" policy drop; - zone "bl-tcp-only" policy tcp-only; - zone "bl.tld2"; - zone "manual-update-rpz" ede forged; - zone "mixed-case-rpz"; - zone "include-rpz"; - zone "evil-cname" policy cname a12.tld2. ede blocked; - zone "wild-cname" ede blocked; - zone "slow-rpz"; + zone "fast-expire"; + zone "bl" max-policy-ttl 100; + zone "bl-2"; + zone "bl-given" policy given recursive-only yes; + zone "bl-passthru" policy passthru; + zone "bl-no-op" policy no-op; # obsolete for passthru + zone "bl-disabled" policy disabled; + zone "bl-nodata" policy nodata recursive-only no; + zone "bl-nxdomain" policy nxdomain; + zone "bl-cname" policy cname txt-only.tld2.; + zone "bl-wildcname" policy cname *.tld4.; + zone "bl-garden" policy cname a12.tld2.; + zone "bl-drop" policy drop; + zone "bl-tcp-only" policy tcp-only; + zone "bl.tld2"; + zone "manual-update-rpz" ede forged; + zone "mixed-case-rpz"; + zone "include-rpz"; + zone "evil-cname" policy cname a12.tld2. ede blocked; + zone "wild-cname" ede blocked; + zone "slow-rpz"; + zone "outofzone.tld2"; } add-soa yes min-ns-dots 0 @@ -68,20 +61,13 @@ ; include "../dnsrps.conf"; - also-notify { 10.53.0.3 port @EXTRAPORT1@; }; + also-notify { @ns.ip@ port @EXTRAPORT1@; }; notify-delay 0; }; logging { category rpz { default_debug; }; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints"; }; @@ -138,9 +124,9 @@ }; zone "slow-rpz." { - type primary; - file "slow-rpz.db"; - notify no; + type primary; + file "slow-rpz.db"; + notify no; }; zone "fast-expire." { @@ -150,6 +136,18 @@ notify no; }; +/* + * A policy zone holding a record from outside the zone. ns2 does not + * serve it, so "outofzone.db" is never replaced by a transfer. + */ +zone "outofzone.tld2." { + type secondary; + file "outofzone.db"; + masterfile-format text; + primaries { 10.53.0.2; }; + notify no; +}; + zone "stub." { type stub; primaries { 10.53.0.2; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns3/outofzone.db.in bind9-9.20.29/bin/tests/system/rpz/ns3/outofzone.db.in --- bind9-9.20.26/bin/tests/system/rpz/ns3/outofzone.db.in 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns3/outofzone.db.in 2026-09-11 19:41:01.340327142 +0000 @@ -0,0 +1,29 @@ +; 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. + +; A policy zone as a secondary would have written it out after a transfer +; that carried a record from outside the zone. The zone is a secondary so +; that this file is loaded the way a secondary loads its own copy of a +; transferred zone; the out-of-zone check in lib/dns/master.c only applies +; to primaries. + +$TTL 300 +@ SOA ns.tld3. hostmaster.ns.tld3. ( 1 3600 1200 2419200 60 ) + NS ns.tld3. + +; Two labels, fewer than the three of the origin, so stripping the origin +; from it used to underflow an unsigned label count in name2data(). +com. CNAME . + +; An ordinary trigger, so the test can tell that the rest of the zone is +; still loaded after the record above has been rejected. It is never +; queried, so it cannot disturb the other checks in this test. +never-queried.example CNAME . diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns4/named.conf.j2 2026-07-20 14:47:53.872846989 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns4/named.conf.j2 2026-09-11 19:41:01.340327142 +0000 @@ -12,29 +12,15 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; allow-transfer { any; }; notify no; minimal-responses no; - recursion yes; dnssec-validation yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "../trusted.conf"; zone "." { type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns5/named.conf.j2 2026-07-20 14:47:53.872846989 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns5/named.conf.j2 2026-09-11 19:41:01.341327166 +0000 @@ -16,21 +16,13 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} statistics-file "named.stats"; session-keyfile "session.key"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; allow-transfer { any; }; ixfr-from-differences yes; notify-delay 0; - notify yes; minimal-responses no; - recursion yes; dnssec-validation yes; # turn rpz on or off @@ -38,14 +30,7 @@ include "../dnsrps.conf"; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "../trusted.conf"; zone "." {type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns6/named.conf.j2 2026-07-20 14:47:53.873847004 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns6/named.conf.j2 2026-09-11 19:41:01.341327166 +0000 @@ -12,26 +12,19 @@ */ options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} statistics-file "named.stats"; session-keyfile "session.key"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; allow-transfer { any; }; forward only; forwarders { 10.53.0.3; }; minimal-responses no; - recursion yes; dnssec-validation yes; qname-minimization disabled; response-policy { - zone "policy1" min-update-interval 0; - zone "bl.tld2s" policy given; + zone "policy1" min-update-interval 0; + zone "bl.tld2s" policy given; } qname-wait-recurse yes // add-soa yes # leave add-soa as default for unset test nsip-enable yes @@ -42,14 +35,7 @@ logging { category rpz { default_debug; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "../trusted.conf"; @@ -63,6 +49,6 @@ }; zone "bl.tld2s." { - type primary; - file "bl.tld2s.db"; + type primary; + file "bl.tld2s.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns7/named.conf.j2 2026-07-20 14:47:53.873847004 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns7/named.conf.j2 2026-09-11 19:41:01.341327166 +0000 @@ -12,22 +12,15 @@ */ options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} statistics-file "named.stats"; session-keyfile "session.key"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; allow-transfer { any; }; minimal-responses no; - recursion yes; dnssec-validation yes; response-policy { - zone "policy2" add-soa no ede none; + zone "policy2" add-soa no ede none; } qname-wait-recurse no nsip-enable yes nsdname-enable yes @@ -38,14 +31,7 @@ logging { category rpz { default_debug; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "../trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns8/named.conf.j2 2026-07-20 14:47:53.873847004 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns8/named.conf.j2 2026-09-11 19:41:01.342327189 +0000 @@ -16,23 +16,15 @@ */ options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} statistics-file "named.stats"; session-keyfile "session.key"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; allow-transfer { any; }; - notify yes; minimal-responses no; - recursion yes; dnssec-validation no; response-policy { - zone "manual-update-rpz"; + zone "manual-update-rpz"; } // add-soa yes // do not set testing default mode min-ns-dots 0 @@ -43,20 +35,13 @@ ; include "../dnsrps.conf"; - also-notify { 10.53.0.8 port @EXTRAPORT1@; }; + also-notify { @ns.ip@ port @EXTRAPORT1@; }; notify-delay 0; }; logging { category rpz { default_debug; }; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/ns9/named.conf.j2 bind9-9.20.29/bin/tests/system/rpz/ns9/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpz/ns9/named.conf.j2 2026-07-20 14:47:53.873847004 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/ns9/named.conf.j2 2026-09-11 19:41:01.342327189 +0000 @@ -16,24 +16,16 @@ */ options { - query-source address 10.53.0.9; - notify-source 10.53.0.9; - transfer-source 10.53.0.9; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} statistics-file "named.stats"; session-keyfile "session.key"; - listen-on { 10.53.0.9; }; - listen-on-v6 { none; }; allow-transfer { any; }; - notify yes; minimal-responses no; - recursion yes; dnssec-validation no; dns64-server "example.localdomain."; dns64 64:ff9b::/96 { }; response-policy { - zone "rpz"; + zone "rpz"; } qname-wait-recurse no ; @@ -43,14 +35,7 @@ logging { category rpz { default_debug; }; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpz/setup.sh bind9-9.20.29/bin/tests/system/rpz/setup.sh --- bind9-9.20.26/bin/tests/system/rpz/setup.sh 2026-07-20 14:47:53.874847020 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/setup.sh 2026-09-11 19:41:01.342327189 +0000 @@ -53,6 +53,9 @@ cp ns5/fast-expire.db.in ns5/fast-expire.db cp ns5/expire.conf.in ns5/expire.conf +# a policy zone holding a record from outside the zone +cp ns3/outofzone.db.in ns3/outofzone.db + # $1=directory # $2=domain name # $3=input zone file diff -Nru bind9-9.20.26/bin/tests/system/rpz/testlib/Makefile.in bind9-9.20.29/bin/tests/system/rpz/testlib/Makefile.in --- bind9-9.20.26/bin/tests/system/rpz/testlib/Makefile.in 2026-07-20 14:49:10.470578886 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/testlib/Makefile.in 2026-09-11 19:42:18.442185926 +0000 @@ -272,6 +272,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/tests/system/rpz/tests.sh bind9-9.20.29/bin/tests/system/rpz/tests.sh --- bind9-9.20.26/bin/tests/system/rpz/tests.sh 2026-07-20 14:47:53.875847035 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/tests.sh 2026-09-11 19:41:01.343327214 +0000 @@ -581,8 +581,8 @@ ckstats $ns6 test1 ns6 0 start_group "IP rewrites" test2 -msg='rpz IP address "128.2.0.0.0.0.3.2.2001" is not the canonical "128.2.zz.3.2.2001"' -grep "$msg" ns3/named.run >/dev/null || setret "expected 'is not the canonical' message not logged" +msg='invalid rpz IP address "128.2.0.0.0.0.3.2.2001.rpz-ip.bl" is not in canonical form 128.2.zz.3.2.2001.rpz-nsdname.bl' +grep "$msg" ns3/named.run >/dev/null || setret "expected 'not in canonical form' message not logged" nodata a3-1.tld2 # 1 NODATA nochange a3-2.tld2 # 2 no policy record so no change nochange a4-1.tld2 # 3 obsolete PASSTHRU record style @@ -752,12 +752,15 @@ test -z "$HAVE_CORE" || setret "found $HAVE_CORE; memory leak?" fi -# look for complaints from lib/dns/rpz.c and bin/name/query.c +# look for complaints from lib/dns/rpz.c and bin/name/query.c, except the +# one the outofzone.tld2 policy zone is there to provoke +EXPECTED='invalid rpz owner name "com"' for runfile in ns*/named.run; do - EMSGS=$(nextpart $runfile | grep -E -l 'invalid rpz|rpz.*failed' || true) + EMSGS=$(nextpart $runfile | grep -Fv "$EXPECTED" \ + | grep -E -l 'invalid rpz|rpz.*failed' || true) if test -n "$EMSGS"; then setret "error messages in $runfile starting with:" - grep -E 'invalid rpz|rpz.*failed' ns*/named.run \ + grep -E 'invalid rpz|rpz.*failed' ns*/named.run | grep -Fv "$EXPECTED" \ | sed -e '10,$d' -e 's/^//' | cat_i fi done diff -Nru bind9-9.20.26/bin/tests/system/rpz/tests_rpz_6407.py bind9-9.20.29/bin/tests/system/rpz/tests_rpz_6407.py --- bind9-9.20.26/bin/tests/system/rpz/tests_rpz_6407.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/tests_rpz_6407.py 2026-09-11 19:41:01.344327238 +0000 @@ -0,0 +1,20 @@ +# 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. + +import isctest + + +# This tests ensures the server does not crash during this query. +# See issue B#6407 +def test_rpz_6407(ns11): + msg = isctest.query.create("1.0.0.127.in-addr.arpa.", "PTR") + res = isctest.query.tcp(msg, ns11.ip) + isctest.check.noerror(res) diff -Nru bind9-9.20.26/bin/tests/system/rpz/tests_rpz_outofzone.py bind9-9.20.29/bin/tests/system/rpz/tests_rpz_outofzone.py --- bind9-9.20.26/bin/tests/system/rpz/tests_rpz_outofzone.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/tests_rpz_outofzone.py 2026-09-11 19:41:01.344327238 +0000 @@ -0,0 +1,32 @@ +#!/usr/bin/python3 + +# 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. + +from isctest.instance import NamedInstance + + +def test_rpz_out_of_zone_owner_name(ns3: NamedInstance) -> None: + """ + ns3 loads a policy zone holding "com.", whose two labels are fewer than + the three of the "outofzone.tld2." origin that gets stripped from an + owner name to build the trigger name. That used to underflow an + unsigned label count and fail an assertion, taking named down as the + policy zone was loaded - so reaching this test at all is most of the + check. + """ + assert 'invalid rpz owner name "com"; not within the policy zone' in ns3.log + + # Only the record above was dropped; the rest of the zone still loads. + assert ( + "rpz: outofzone.tld2: adding node never-queried.example.outofzone.tld2" + in ns3.log + ) diff -Nru bind9-9.20.26/bin/tests/system/rpz/tests_sh_rpz.py bind9-9.20.29/bin/tests/system/rpz/tests_sh_rpz.py --- bind9-9.20.26/bin/tests/system/rpz/tests_sh_rpz.py 2026-07-20 14:47:53.875847035 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/tests_sh_rpz.py 2026-09-11 19:41:01.344327238 +0000 @@ -45,6 +45,7 @@ "ns3/mixed-case-rpz.db", "ns3/named.conf.tmp", "ns3/named.stats", + "ns3/outofzone.db", "ns3/slow-rpz.db", "ns3/wild-cname.db", "ns5/bl.db", diff -Nru bind9-9.20.26/bin/tests/system/rpz/tests_sh_rpz_dnsrps.py bind9-9.20.29/bin/tests/system/rpz/tests_sh_rpz_dnsrps.py --- bind9-9.20.26/bin/tests/system/rpz/tests_sh_rpz_dnsrps.py 2026-07-20 14:47:53.875847035 +0000 +++ bind9-9.20.29/bin/tests/system/rpz/tests_sh_rpz_dnsrps.py 2026-09-11 19:41:01.344327238 +0000 @@ -49,6 +49,7 @@ "ns3/mixed-case-rpz.db", "ns3/named.conf.tmp", "ns3/named.stats", + "ns3/outofzone.db", "ns3/slow-rpz.db", "ns3/wild-cname.db", "ns5/bl.db", diff -Nru bind9-9.20.26/bin/tests/system/rpzextra/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rpzextra/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzextra/ns2/named.conf.j2 2026-07-20 14:47:53.876847051 +0000 +++ bind9-9.20.29/bin/tests/system/rpzextra/ns2/named.conf.j2 2026-09-11 19:41:01.344327238 +0000 @@ -11,47 +11,35 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - listen-on { 10.53.0.2; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation no; allow-query { any; }; }; zone "allowed" { - type primary; + type primary; file "allowed.db"; allow-transfer { none; }; }; zone "baddomain" { - type primary; - file "baddomain.db"; - allow-transfer { none; }; + type primary; + file "baddomain.db"; + allow-transfer { none; }; }; zone "gooddomain" { - type primary; - file "gooddomain.db"; - allow-transfer { none; }; + type primary; + file "gooddomain.db"; + allow-transfer { none; }; }; zone "rpz-external.local" { - type primary; - file "rpz-external.local.db"; - allow-transfer { any; }; + type primary; + file "rpz-external.local.db"; + allow-transfer { any; }; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzextra/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rpzextra/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzextra/ns3/named.conf.j2 2026-07-20 14:47:53.876847051 +0000 +++ bind9-9.20.29/bin/tests/system/rpzextra/ns3/named.conf.j2 2026-09-11 19:41:01.345327261 +0000 @@ -11,26 +11,13 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - listen-on { 10.53.0.3; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation no; allow-query { any; }; - recursion yes; allow-recursion { any; }; empty-zones-enable false; response-policy { @@ -94,7 +81,7 @@ }; view "third" { - match-clients { 10.53.0.3; }; + match-clients { @ns.ip@; }; zone "." { type hint; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rpzrecurse/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns1/named.conf.j2 2026-07-20 14:47:53.877847067 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns1/named.conf.j2 2026-09-11 19:41:01.346327285 +0000 @@ -12,27 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; recursion no; dnssec-validation no; querylog yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.clientip.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.clientip.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.clientip.conf 2026-07-20 14:47:53.878847082 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.clientip.conf 2026-09-11 19:41:01.347327309 +0000 @@ -15,22 +15,22 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - # policy configuration to be tested - response-policy { + # policy configuration to be tested + response-policy { zone "clientip1"; zone "clientip2"; - } qname-wait-recurse no + } qname-wait-recurse no nsdname-enable yes nsip-enable yes; - # policy zones to be tested - zone "clientip1" { type primary; file "db.clientip1"; }; - zone "clientip2" { type primary; file "db.clientip2"; }; + # policy zones to be tested + zone "clientip1" { type primary; file "db.clientip1"; }; + zone "clientip2" { type primary; file "db.clientip2"; }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.clientip2.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.clientip2.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.clientip2.conf 2026-07-20 14:47:53.878847082 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.clientip2.conf 2026-09-11 19:41:01.347327309 +0000 @@ -15,22 +15,22 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - servfail-ttl 0; + servfail-ttl 0; - # policy configuration to be tested - response-policy { + # policy configuration to be tested + response-policy { zone "clientip21"; - } qname-wait-recurse no + } qname-wait-recurse no nsdname-enable yes nsip-enable yes; - # policy zones to be tested - zone "clientip21" { type primary; file "db.clientip21"; }; + # policy zones to be tested + zone "clientip21" { type primary; file "db.clientip21"; }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.conf.header.j2 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.conf.header.j2 --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.conf.header.j2 2026-07-20 14:47:53.878847082 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.conf.header.j2 2026-09-11 19:41:01.347327309 +0000 @@ -11,18 +11,9 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; - options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; dnssec-validation no; querylog yes; @@ -30,13 +21,5 @@ include "../dnsrps.conf"; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.conf.j2 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.conf.j2 2026-09-11 19:41:01.347327309 +0000 @@ -15,10 +15,10 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.default.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.default.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.default.conf 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.default.conf 2026-09-11 19:41:01.347327309 +0000 @@ -15,10 +15,10 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.invalidprefixlength.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.invalidprefixlength.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.invalidprefixlength.conf 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.invalidprefixlength.conf 2026-09-11 19:41:01.348327333 +0000 @@ -15,16 +15,16 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - # policy configuration to be tested - response-policy { + # policy configuration to be tested + response-policy { zone "invalidprefixlength"; - }; + }; - # policy zones to be tested - zone "invalidprefixlength" { type primary; file "db.invalidprefixlength"; }; + # policy zones to be tested + zone "invalidprefixlength" { type primary; file "db.invalidprefixlength"; }; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.log.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.log.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.log.conf 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.log.conf 2026-09-11 19:41:01.348327333 +0000 @@ -15,24 +15,24 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - # policy configuration to be tested - response-policy { + # policy configuration to be tested + response-policy { zone "log1" log no; zone "log2" log yes; zone "log3"; # missing log clause - } qname-wait-recurse no + } qname-wait-recurse no nsdname-enable yes nsip-enable yes; - # policy zones to be tested - zone "log1" { type primary; file "db.log1"; }; - zone "log2" { type primary; file "db.log2"; }; - zone "log3" { type primary; file "db.log3"; }; + # policy zones to be tested + zone "log1" { type primary; file "db.log1"; }; + zone "log2" { type primary; file "db.log2"; }; + zone "log3" { type primary; file "db.log3"; }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.max.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.max.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.max.conf 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.max.conf 2026-09-11 19:41:01.348327333 +0000 @@ -15,13 +15,13 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - # policy configuration to be tested - response-policy { + # policy configuration to be tested + response-policy { zone "max1"; zone "max2"; zone "max3"; @@ -86,75 +86,75 @@ zone "max62"; zone "max63"; zone "max64"; - } qname-wait-recurse no + } qname-wait-recurse no nsdname-enable yes nsip-enable yes; - # policy zones to be tested - zone "max1" { type primary; file "db.max1.local"; }; - zone "max2" { type primary; file "db.max2.local"; }; - zone "max3" { type primary; file "db.max3.local"; }; - zone "max4" { type primary; file "db.max4.local"; }; - zone "max5" { type primary; file "db.max5.local"; }; - zone "max6" { type primary; file "db.max6.local"; }; - zone "max7" { type primary; file "db.max7.local"; }; - zone "max8" { type primary; file "db.max8.local"; }; - zone "max9" { type primary; file "db.max9.local"; }; - zone "max10" { type primary; file "db.max10.local"; }; - zone "max11" { type primary; file "db.max11.local"; }; - zone "max12" { type primary; file "db.max12.local"; }; - zone "max13" { type primary; file "db.max13.local"; }; - zone "max14" { type primary; file "db.max14.local"; }; - zone "max15" { type primary; file "db.max15.local"; }; - zone "max16" { type primary; file "db.max16.local"; }; - zone "max17" { type primary; file "db.max17.local"; }; - zone "max18" { type primary; file "db.max18.local"; }; - zone "max19" { type primary; file "db.max19.local"; }; - zone "max20" { type primary; file "db.max20.local"; }; - zone "max21" { type primary; file "db.max21.local"; }; - zone "max22" { type primary; file "db.max22.local"; }; - zone "max23" { type primary; file "db.max23.local"; }; - zone "max24" { type primary; file "db.max24.local"; }; - zone "max25" { type primary; file "db.max25.local"; }; - zone "max26" { type primary; file "db.max26.local"; }; - zone "max27" { type primary; file "db.max27.local"; }; - zone "max28" { type primary; file "db.max28.local"; }; - zone "max29" { type primary; file "db.max29.local"; }; - zone "max30" { type primary; file "db.max30.local"; }; - zone "max31" { type primary; file "db.max31.local"; }; - zone "max32" { type primary; file "db.max32.local"; }; - zone "max33" { type primary; file "db.max33.local"; }; - zone "max34" { type primary; file "db.max34.local"; }; - zone "max35" { type primary; file "db.max35.local"; }; - zone "max36" { type primary; file "db.max36.local"; }; - zone "max37" { type primary; file "db.max37.local"; }; - zone "max38" { type primary; file "db.max38.local"; }; - zone "max39" { type primary; file "db.max39.local"; }; - zone "max40" { type primary; file "db.max40.local"; }; - zone "max41" { type primary; file "db.max41.local"; }; - zone "max42" { type primary; file "db.max42.local"; }; - zone "max43" { type primary; file "db.max43.local"; }; - zone "max44" { type primary; file "db.max44.local"; }; - zone "max45" { type primary; file "db.max45.local"; }; - zone "max46" { type primary; file "db.max46.local"; }; - zone "max47" { type primary; file "db.max47.local"; }; - zone "max48" { type primary; file "db.max48.local"; }; - zone "max49" { type primary; file "db.max49.local"; }; - zone "max50" { type primary; file "db.max50.local"; }; - zone "max51" { type primary; file "db.max51.local"; }; - zone "max52" { type primary; file "db.max52.local"; }; - zone "max53" { type primary; file "db.max53.local"; }; - zone "max54" { type primary; file "db.max54.local"; }; - zone "max55" { type primary; file "db.max55.local"; }; - zone "max56" { type primary; file "db.max56.local"; }; - zone "max57" { type primary; file "db.max57.local"; }; - zone "max58" { type primary; file "db.max58.local"; }; - zone "max59" { type primary; file "db.max59.local"; }; - zone "max60" { type primary; file "db.max60.local"; }; - zone "max61" { type primary; file "db.max61.local"; }; - zone "max62" { type primary; file "db.max62.local"; }; - zone "max63" { type primary; file "db.max63.local"; }; - zone "max64" { type primary; file "db.max64.local"; }; + # policy zones to be tested + zone "max1" { type primary; file "db.max1.local"; }; + zone "max2" { type primary; file "db.max2.local"; }; + zone "max3" { type primary; file "db.max3.local"; }; + zone "max4" { type primary; file "db.max4.local"; }; + zone "max5" { type primary; file "db.max5.local"; }; + zone "max6" { type primary; file "db.max6.local"; }; + zone "max7" { type primary; file "db.max7.local"; }; + zone "max8" { type primary; file "db.max8.local"; }; + zone "max9" { type primary; file "db.max9.local"; }; + zone "max10" { type primary; file "db.max10.local"; }; + zone "max11" { type primary; file "db.max11.local"; }; + zone "max12" { type primary; file "db.max12.local"; }; + zone "max13" { type primary; file "db.max13.local"; }; + zone "max14" { type primary; file "db.max14.local"; }; + zone "max15" { type primary; file "db.max15.local"; }; + zone "max16" { type primary; file "db.max16.local"; }; + zone "max17" { type primary; file "db.max17.local"; }; + zone "max18" { type primary; file "db.max18.local"; }; + zone "max19" { type primary; file "db.max19.local"; }; + zone "max20" { type primary; file "db.max20.local"; }; + zone "max21" { type primary; file "db.max21.local"; }; + zone "max22" { type primary; file "db.max22.local"; }; + zone "max23" { type primary; file "db.max23.local"; }; + zone "max24" { type primary; file "db.max24.local"; }; + zone "max25" { type primary; file "db.max25.local"; }; + zone "max26" { type primary; file "db.max26.local"; }; + zone "max27" { type primary; file "db.max27.local"; }; + zone "max28" { type primary; file "db.max28.local"; }; + zone "max29" { type primary; file "db.max29.local"; }; + zone "max30" { type primary; file "db.max30.local"; }; + zone "max31" { type primary; file "db.max31.local"; }; + zone "max32" { type primary; file "db.max32.local"; }; + zone "max33" { type primary; file "db.max33.local"; }; + zone "max34" { type primary; file "db.max34.local"; }; + zone "max35" { type primary; file "db.max35.local"; }; + zone "max36" { type primary; file "db.max36.local"; }; + zone "max37" { type primary; file "db.max37.local"; }; + zone "max38" { type primary; file "db.max38.local"; }; + zone "max39" { type primary; file "db.max39.local"; }; + zone "max40" { type primary; file "db.max40.local"; }; + zone "max41" { type primary; file "db.max41.local"; }; + zone "max42" { type primary; file "db.max42.local"; }; + zone "max43" { type primary; file "db.max43.local"; }; + zone "max44" { type primary; file "db.max44.local"; }; + zone "max45" { type primary; file "db.max45.local"; }; + zone "max46" { type primary; file "db.max46.local"; }; + zone "max47" { type primary; file "db.max47.local"; }; + zone "max48" { type primary; file "db.max48.local"; }; + zone "max49" { type primary; file "db.max49.local"; }; + zone "max50" { type primary; file "db.max50.local"; }; + zone "max51" { type primary; file "db.max51.local"; }; + zone "max52" { type primary; file "db.max52.local"; }; + zone "max53" { type primary; file "db.max53.local"; }; + zone "max54" { type primary; file "db.max54.local"; }; + zone "max55" { type primary; file "db.max55.local"; }; + zone "max56" { type primary; file "db.max56.local"; }; + zone "max57" { type primary; file "db.max57.local"; }; + zone "max58" { type primary; file "db.max58.local"; }; + zone "max59" { type primary; file "db.max59.local"; }; + zone "max60" { type primary; file "db.max60.local"; }; + zone "max61" { type primary; file "db.max61.local"; }; + zone "max62" { type primary; file "db.max62.local"; }; + zone "max63" { type primary; file "db.max63.local"; }; + zone "max64" { type primary; file "db.max64.local"; }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.wildcard1.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard1.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.wildcard1.conf 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard1.conf 2026-09-11 19:41:01.348327333 +0000 @@ -15,20 +15,20 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - # policy configuration to be tested - response-policy { + # policy configuration to be tested + response-policy { zone "wildcard1" policy NXDOMAIN; - } qname-wait-recurse yes + } qname-wait-recurse yes nsdname-enable yes nsip-enable yes; - # policy zones to be tested - zone "wildcard1" { type primary; file "db.wildcard1"; }; + # policy zones to be tested + zone "wildcard1" { type primary; file "db.wildcard1"; }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.wildcard2.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard2.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.wildcard2.conf 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard2.conf 2026-09-11 19:41:01.348327333 +0000 @@ -15,22 +15,22 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - # policy configuration to be tested - response-policy { + # policy configuration to be tested + response-policy { zone "wildcard2a" policy NXDOMAIN; zone "wildcard2b" policy NXDOMAIN; - } qname-wait-recurse yes + } qname-wait-recurse yes nsdname-enable yes nsip-enable yes; - # policy zones to be tested - zone "wildcard2a" { type primary; file "db.wildcard2a"; }; - zone "wildcard2b" { type primary; file "db.wildcard2b"; }; + # policy zones to be tested + zone "wildcard2a" { type primary; file "db.wildcard2a"; }; + zone "wildcard2b" { type primary; file "db.wildcard2b"; }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.wildcard3.conf bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard3.conf --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns2/named.wildcard3.conf 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns2/named.wildcard3.conf 2026-09-11 19:41:01.348327333 +0000 @@ -15,20 +15,20 @@ include "named.conf.header"; view "recursive" { - zone "." { + zone "." { type hint; file "root.hint"; - }; + }; - # policy configuration to be tested - response-policy { + # policy configuration to be tested + response-policy { zone "wildcard3" policy NXDOMAIN; - } qname-wait-recurse yes + } qname-wait-recurse yes nsdname-enable yes nsip-enable yes; - # policy zones to be tested - zone "wildcard3" { type primary; file "db.wildcard3"; }; + # policy zones to be tested + zone "wildcard3" { type primary; file "db.wildcard3"; }; - recursion yes; + recursion yes; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns3/named.conf.j2 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named.conf.j2 2026-09-11 19:41:01.348327333 +0000 @@ -11,22 +11,11 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; dnssec-validation no; response-policy { zone "policy"; } qname-wait-recurse yes @@ -36,7 +25,6 @@ include "../dnsrps.conf"; }; - zone "policy" { type primary; file "policy.db"; }; zone "example.tld" { type primary; file "example.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns3/named1.conf.j2 bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named1.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns3/named1.conf.j2 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named1.conf.j2 2026-09-11 19:41:01.348327333 +0000 @@ -11,22 +11,11 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; dnssec-validation no; response-policy { zone "policy"; } qname-wait-recurse yes @@ -36,7 +25,6 @@ include "../dnsrps.conf"; }; - zone "policy" { type primary; file "policy.db"; }; zone "example.tld" { type primary; file "example.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns3/named2.conf.j2 2026-07-20 14:47:53.879847098 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named2.conf.j2 2026-09-11 19:41:01.348327333 +0000 @@ -11,31 +11,19 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; response-policy { zone "policy"; } nsip-wait-recurse no - qname-wait-recurse yes - nsip-enable yes - nsdname-enable yes; + qname-wait-recurse yes + nsip-enable yes + nsdname-enable yes; include "../dnsrps.conf"; }; - zone "policy" { type primary; file "policy.db"; }; zone "example.tld" { type primary; file "example.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns3/named3.conf.j2 bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns3/named3.conf.j2 2026-07-20 14:47:53.880847113 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns3/named3.conf.j2 2026-09-11 19:41:01.348327333 +0000 @@ -11,29 +11,17 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; response-policy { zone "policy"; } nsdname-wait-recurse no - nsdname-enable yes; + nsdname-enable yes; include "../dnsrps.conf"; }; - zone "policy" { type primary; file "policy.db"; }; zone "example.tld" { type primary; file "example.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/rpzrecurse/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rpzrecurse/ns4/named.conf.j2 2026-07-20 14:47:53.880847113 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/ns4/named.conf.j2 2026-09-11 19:41:01.349327357 +0000 @@ -11,28 +11,13 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; - options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "child.example.tld" { type primary; file "child.example.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/rpzrecurse/prereq.sh bind9-9.20.29/bin/tests/system/rpzrecurse/prereq.sh --- bind9-9.20.26/bin/tests/system/rpzrecurse/prereq.sh 2026-07-20 14:47:53.880847113 +0000 +++ bind9-9.20.29/bin/tests/system/rpzrecurse/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/rrl/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rrl/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrl/ns1/named.conf.j2 2026-07-20 14:47:53.881847129 +0000 +++ bind9-9.20.29/bin/tests/system/rrl/ns1/named.conf.j2 2026-09-11 19:41:01.350327381 +0000 @@ -12,18 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; notify no; - recursion yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} zone "." {type primary; file "root.db";}; diff -Nru bind9-9.20.26/bin/tests/system/rrl/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rrl/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrl/ns2/named.conf.j2 2026-07-20 14:47:53.881847129 +0000 +++ bind9-9.20.29/bin/tests/system/rrl/ns2/named.conf.j2 2026-09-11 19:41:01.350327381 +0000 @@ -12,50 +12,36 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; statistics-file "named.stats"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; notify no; - recursion yes; dnssec-validation no; rate-limit { - responses-per-second 2; - all-per-second 50; - slip 3; - exempt-clients { 10.53.0.7; }; + responses-per-second 2; + all-per-second 50; + slip 3; + exempt-clients { 10.53.0.7; }; - // small enough to force a table expansion - min-table-size 75; + // small enough to force a table expansion + min-table-size 75; }; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} /* * These log settings have no effect unless "-g" is removed from ../../start.pl */ logging { channel debug { - file "log-debug"; - print-category yes; print-severity yes; severity debug 10; + file "log-debug"; + print-category yes; print-severity yes; severity debug 10; }; channel queries { - file "log-queries"; - print-category yes; print-severity yes; severity info; + file "log-queries"; + print-category yes; print-severity yes; severity info; }; category rate-limit { debug; queries; }; category queries { debug; queries; }; diff -Nru bind9-9.20.26/bin/tests/system/rrl/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rrl/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrl/ns3/named.conf.j2 2026-07-20 14:47:53.881847129 +0000 +++ bind9-9.20.29/bin/tests/system/rrl/ns3/named.conf.j2 2026-09-11 19:41:01.350327381 +0000 @@ -12,37 +12,31 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; notify no; - recursion yes; dnssec-validation no; // check that all of the options are parsed without limiting anything rate-limit { - responses-per-second 200; - referrals-per-second 220; - nodata-per-second 230; - nxdomains-per-second 240; - errors-per-second 250; - all-per-second 700; - ipv4-prefix-length 24; - ipv6-prefix-length 64; - qps-scale 10; - window 1; - max-table-size 1000; - log-only no; - min-table-size 0; + responses-per-second 200; + referrals-per-second 220; + nodata-per-second 230; + nxdomains-per-second 240; + errors-per-second 250; + all-per-second 700; + ipv4-prefix-length 24; + ipv6-prefix-length 64; + qps-scale 10; + window 1; + max-table-size 1000; + log-only no; + min-table-size 0; }; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints"; }; diff -Nru bind9-9.20.26/bin/tests/system/rrl/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/rrl/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrl/ns4/named.conf.j2 2026-07-20 14:47:53.882847144 +0000 +++ bind9-9.20.29/bin/tests/system/rrl/ns4/named.conf.j2 2026-09-11 19:41:01.350327381 +0000 @@ -12,52 +12,38 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} session-keyfile "session.key"; - pid-file "named.pid"; statistics-file "named.stats"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; notify no; - recursion yes; dnssec-validation no; max-udp-size 4096; rate-limit { - responses-per-second 2; - all-per-second 50; - slip 3; - exempt-clients { 10.53.0.7; }; - log-only yes; + responses-per-second 2; + all-per-second 50; + slip 3; + exempt-clients { 10.53.0.7; }; + log-only yes; - // small enough to force a table expansion - min-table-size 75; + // small enough to force a table expansion + min-table-size 75; }; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} /* * These log settings have no effect unless "-g" is removed from ../../start.pl */ logging { channel debug { - file "log-debug"; - print-category yes; print-severity yes; severity debug 10; + file "log-debug"; + print-category yes; print-severity yes; severity debug 10; }; channel queries { - file "log-queries"; - print-category yes; print-severity yes; severity info; + file "log-queries"; + print-category yes; print-severity yes; severity info; }; category rate-limit { debug; queries; }; category queries { debug; queries; }; diff -Nru bind9-9.20.26/bin/tests/system/rrsetorder/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rrsetorder/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrsetorder/ns1/named.conf.j2 2026-07-20 14:47:53.882847144 +0000 +++ bind9-9.20.29/bin/tests/system/rrsetorder/ns1/named.conf.j2 2026-09-11 19:41:01.351327405 +0000 @@ -12,13 +12,7 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; @@ -33,6 +27,8 @@ }; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/rrsetorder/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rrsetorder/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrsetorder/ns2/named.conf.j2 2026-07-20 14:47:53.882847144 +0000 +++ bind9-9.20.29/bin/tests/system/rrsetorder/ns2/named.conf.j2 2026-09-11 19:41:01.351327405 +0000 @@ -12,16 +12,9 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; rrset-order { name "fixed.example" order fixed; name "random.example" order random; @@ -32,6 +25,8 @@ }; }; +{% include "_common/controls.conf.j2" %} + zone "." { type secondary; primaries { 10.53.0.1; }; diff -Nru bind9-9.20.26/bin/tests/system/rrsetorder/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rrsetorder/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrsetorder/ns3/named.conf.j2 2026-07-20 14:47:53.882847144 +0000 +++ bind9-9.20.29/bin/tests/system/rrsetorder/ns3/named.conf.j2 2026-09-11 19:41:01.351327405 +0000 @@ -12,16 +12,8 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; rrset-order { name "fixed.example" order fixed; name "random.example" order random; @@ -32,8 +24,6 @@ }; }; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/rrsetorder/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/rrsetorder/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrsetorder/ns4/named.conf.j2 2026-07-20 14:47:53.882847144 +0000 +++ bind9-9.20.29/bin/tests/system/rrsetorder/ns4/named.conf.j2 2026-09-11 19:41:01.351327405 +0000 @@ -12,24 +12,14 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; rrset-order { class IN type A name "host.example.com" order random; }; }; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/rrsetorder/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/rrsetorder/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rrsetorder/ns5/named.conf.j2 2026-07-20 14:47:53.883847160 +0000 +++ bind9-9.20.29/bin/tests/system/rrsetorder/ns5/named.conf.j2 2026-09-11 19:41:01.351327405 +0000 @@ -12,20 +12,10 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/rsabigexponent/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/rsabigexponent/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rsabigexponent/ns1/named.conf.j2 2026-07-20 14:47:53.885847191 +0000 +++ bind9-9.20.29/bin/tests/system/rsabigexponent/ns1/named.conf.j2 2026-09-11 19:41:01.354327477 +0000 @@ -14,18 +14,13 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/rsabigexponent/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/rsabigexponent/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rsabigexponent/ns2/named.conf.j2 2026-07-20 14:47:53.886847207 +0000 +++ bind9-9.20.29/bin/tests/system/rsabigexponent/ns2/named.conf.j2 2026-09-11 19:41:01.354327477 +0000 @@ -14,22 +14,14 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/rsabigexponent/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/rsabigexponent/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/rsabigexponent/ns3/named.conf.j2 2026-07-20 14:47:53.886847207 +0000 +++ bind9-9.20.29/bin/tests/system/rsabigexponent/ns3/named.conf.j2 2026-09-11 19:41:01.355327501 +0000 @@ -14,22 +14,13 @@ // NS3 options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; - notify yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; max-rsa-exponent-size 35; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named.conf.j2 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named.conf.j2 2026-09-11 19:41:01.355327501 +0000 @@ -14,21 +14,9 @@ // NS2 options { - query-source address 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named1.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named1.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named1.conf.j2 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named1.conf.j2 2026-09-11 19:41:01.355327501 +0000 @@ -14,21 +14,9 @@ // NS2 options { - query-source address 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named2.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named2.conf.j2 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named2.conf.j2 2026-09-11 19:41:01.355327501 +0000 @@ -12,11 +12,10 @@ */ options { + {% include_indented "_common/options.conf.j2" %} directory "./nope"; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; recursion no; dnssec-validation no; }; + +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named3.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named3.conf.j2 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named3.conf.j2 2026-09-11 19:41:01.355327501 +0000 @@ -12,11 +12,10 @@ */ options { + {% include_indented "_common/options.conf.j2" %} managed-keys-directory "./nope"; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; recursion no; dnssec-validation no; }; + +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named4.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named4.conf.j2 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named4.conf.j2 2026-09-11 19:41:01.356327525 +0000 @@ -12,11 +12,10 @@ */ options { + {% include_indented "_common/options.conf.j2" %} new-zones-directory "./nope"; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; recursion no; dnssec-validation no; }; + +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named5.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named5.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named5.conf.j2 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named5.conf.j2 2026-09-11 19:41:01.356327525 +0000 @@ -12,9 +12,8 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation no; }; + +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named6.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named6.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named6.conf.j2 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named6.conf.j2 2026-09-11 19:41:01.356327525 +0000 @@ -12,13 +12,12 @@ */ options { - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { fd92:7065:b8e:ffff::2; }; + {% include_indented "_common/options-dual.conf.j2" %} dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "ipv4-only-servers" { type secondary; primaries { 10.53.0.3; }; @@ -26,5 +25,5 @@ zone "ipv6-only-servers" { type secondary; - primaries { fd92:7065:b8e:ffff::2; }; + primaries { @ns.ip6@; }; }; diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named7.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named7.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named7.conf.j2 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named7.conf.j2 2026-09-11 19:41:01.356327525 +0000 @@ -12,10 +12,12 @@ */ options { + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/listen.conf.j2" %} port @PORT@; pid-file "named7.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; recursion no; dnssec-validation no; }; + +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/runtime/ns2/named8.conf.j2 bind9-9.20.29/bin/tests/system/runtime/ns2/named8.conf.j2 --- bind9-9.20.26/bin/tests/system/runtime/ns2/named8.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/ns2/named8.conf.j2 2026-09-11 19:41:01.356327525 +0000 @@ -0,0 +1,53 @@ +options { + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; + listen-on-v6 { none; }; + dnssec-validation no; +}; + +key "a" { + algorithm hmac-sha256; + secret "FrSt77yPTFx6hTs4i2tKLB9LmE0="; +}; + +key "b" { + algorithm hmac-sha256; + secret "hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA=="; +}; + +/* + * Reference cycles in remote-servers lists must be skipped, not + * followed: named used to recurse into them endlessly and crash on + * startup (GL #6287). + */ +primaries "loop-direct" { "loop-direct"; 10.53.0.99 port @PORT@; }; +primaries "loop-tail" { 10.53.0.99 port @PORT@; "loop-tail"; }; +primaries "loop-a" { "loop-b"; }; +primaries "loop-b" { "loop-a"; 10.53.0.99 port @PORT@; }; + +/* Reusing a list outside the active recursion path is not a cycle. */ +primaries "common" { 192.0.2.1; }; + +zone "cycle-direct" { + type secondary; + primaries { "loop-direct"; }; +}; + +zone "cycle-tail" { + type secondary; + primaries { "loop-tail"; }; +}; + +zone "cycle-mutual" { + type secondary; + primaries { "loop-a"; }; +}; + +zone "repeated-list-references" { + type secondary; + primaries { + "common" key "a"; + "common" key "b"; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/runtime/tests.sh bind9-9.20.29/bin/tests/system/runtime/tests.sh --- bind9-9.20.26/bin/tests/system/runtime/tests.sh 2026-07-20 14:47:53.887847222 +0000 +++ bind9-9.20.29/bin/tests/system/runtime/tests.sh 2026-09-11 19:41:01.356327525 +0000 @@ -223,6 +223,20 @@ status=$((status + ret)) n=$((n + 1)) +echo_i "checking cyclic and repeated remote-servers lists (GL #6287) ($n)" +ret=0 +testpid=$(run_named ns2 named$n.run -c named8.conf -D runtime-ns2-remote-servers-loop) +test -n "$testpid" || ret=1 +retry_quiet 60 check_named_log "running$" ns2/named$n.run || ret=1 +retry_quiet 60 check_named_log \ + "zone repeated-list-references/IN: soa_query: remote server current address index 0 count 2" \ + ns2/named$n.run || ret=1 +kill_named ns2/named.pid || ret=1 +test -n "$testpid" && retry_quiet 10 check_pid $testpid || ret=1 +if [ $ret -ne 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + +n=$((n + 1)) echo_i "verifying that named switches UID ($n)" if [ "$(id -u)" -eq 0 ]; then ret=0 diff -Nru bind9-9.20.26/bin/tests/system/selfpointedglue/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/selfpointedglue/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/selfpointedglue/ns1/named.conf.j2 2026-07-20 14:47:53.888847238 +0000 +++ bind9-9.20.29/bin/tests/system/selfpointedglue/ns1/named.conf.j2 2026-09-11 19:41:01.356327525 +0000 @@ -12,16 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/selfpointedglue/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/selfpointedglue/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/selfpointedglue/ns2/named.conf.j2 2026-07-20 14:47:53.888847238 +0000 +++ bind9-9.20.29/bin/tests/system/selfpointedglue/ns2/named.conf.j2 2026-09-11 19:41:01.356327525 +0000 @@ -12,16 +12,13 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "tld." { type primary; file "tld.db"; diff -Nru bind9-9.20.26/bin/tests/system/selfpointedglue/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/selfpointedglue/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/selfpointedglue/ns3/named.conf.j2 2026-07-20 14:47:53.888847238 +0000 +++ bind9-9.20.29/bin/tests/system/selfpointedglue/ns3/named.conf.j2 2026-09-11 19:41:01.357327549 +0000 @@ -12,13 +12,10 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} listen-on { - 10.53.0.3; + @ns.ip@; 10.53.0.5; 10.53.0.6; 10.53.0.7; @@ -29,10 +26,13 @@ 10.53.1.2; 10.53.2.1; }; + listen-on-v6 { none; }; recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "example.tld." { type primary; file "example.tld.db"; diff -Nru bind9-9.20.26/bin/tests/system/selfpointedglue/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/selfpointedglue/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/selfpointedglue/ns4/named.conf.j2 2026-07-20 14:47:53.888847238 +0000 +++ bind9-9.20.29/bin/tests/system/selfpointedglue/ns4/named.conf.j2 2026-09-11 19:41:01.357327549 +0000 @@ -13,18 +13,12 @@ {% set maxdelegationservers = maxdelegationservers | default(None) %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; dnstap { resolver query; }; dnstap-output file "dnstap.out"; {% if maxdelegationservers %} - @maxdelegationservers@ + @maxdelegationservers@ {% endif %} }; @@ -44,16 +38,6 @@ server 10.53.1.2 { tcp-only true; }; server 10.53.2.1 { tcp-only true; }; -zone "." { - type hint; - file "root.hint"; -}; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; +{% include "_common/root.hint.conf" %} -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/selfpointedglue/ns4/root.hint bind9-9.20.29/bin/tests/system/selfpointedglue/ns4/root.hint --- bind9-9.20.26/bin/tests/system/selfpointedglue/ns4/root.hint 2026-07-20 14:47:53.888847238 +0000 +++ bind9-9.20.29/bin/tests/system/selfpointedglue/ns4/root.hint 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -; 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. - -$TTL 999999 -. IN NS a.root-servers.nil. -a.root-servers.nil. IN A 10.53.0.1 diff -Nru bind9-9.20.26/bin/tests/system/selftest/tests_template.py bind9-9.20.29/bin/tests/system/selftest/tests_template.py --- bind9-9.20.26/bin/tests/system/selftest/tests_template.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/selftest/tests_template.py 2026-09-11 19:41:01.357327549 +0000 @@ -0,0 +1,90 @@ +# 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. +""" +isctest.template self-test +Check the {% include_indented %} tag of the TemplateEngine. +""" + +import jinja2 +import pytest + + +def render(templates, system_test_dir, name, source, data=None): + (system_test_dir / f"{name}.j2").write_text(source) + templates.render(name, data) + return (system_test_dir / name).read_text() + + +def test_include_indented(templates, system_test_dir): + (system_test_dir / "inc.conf.j2").write_text("first @word@;\nsecond;\n") + output = render( + templates, + system_test_dir, + "main.conf", + 'block {\n\t{% include_indented "inc.conf.j2" %}\n};\n', + {"word": "value"}, + ) + assert output == "block {\n\tfirst value;\n\tsecond;\n};\n" + + +def test_include_indented_depth_follows_tag(templates, system_test_dir): + (system_test_dir / "inc.conf.j2").write_text("a;\nb;\n") + output = render( + templates, + system_test_dir, + "nested.conf", + 'one {\n\ttwo {\n\t\t{% include_indented "inc.conf.j2" %}\n\t};\n};\n', + ) + assert output == "one {\n\ttwo {\n\t\ta;\n\t\tb;\n\t};\n};\n" + + +def test_include_indented_keeps_blank_lines_blank(templates, system_test_dir): + (system_test_dir / "inc.conf.j2").write_text("a;\n\nb;\n") + output = render( + templates, + system_test_dir, + "blank.conf", + '\t{% include_indented "inc.conf.j2" %}\n', + ) + assert output == "\ta;\n\n\tb;\n" + + +def test_include_indented_must_follow_indentation_only(templates, system_test_dir): + (system_test_dir / "inc.conf.j2").write_text("a;\n") + with pytest.raises(jinja2.TemplateSyntaxError, match="indentation only"): + render( + templates, + system_test_dir, + "inline.conf", + 'block { {% include_indented "inc.conf.j2" %}\n};\n', + ) + + +def test_include_indented_requires_loaded_template(templates): + with pytest.raises(jinja2.TemplateSyntaxError, match="loader-backed"): + templates.j2env.from_string('\t{% include_indented "inc.conf.j2" %}\n') + + +def test_include_indented_common_prefix(templates, system_test_dir): + output = render( + templates, + system_test_dir, + "hint.conf", + 'view v {\n\t{% include_indented "_common/root.hint.conf" %}\n};\n', + ) + assert output == ( + "view v {\n" + '\tzone "." {\n' + "\t\ttype hint;\n" + '\t\tfile "../../_common/root.hint";\n' + "\t};\n" + "};\n" + ) diff -Nru bind9-9.20.26/bin/tests/system/send.pl bind9-9.20.29/bin/tests/system/send.pl --- bind9-9.20.26/bin/tests/system/send.pl 2026-07-20 14:47:53.889847253 +0000 +++ bind9-9.20.29/bin/tests/system/send.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -#!/usr/bin/perl - -# 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. - -# -# Send a file to a given address and port using TCP. Used for -# configuring the test server in ans.pl. -# - -use IO::File; -use IO::Socket; - -@ARGV == 2 or die "usage: send.pl host port [file ...]\n"; - -my $host = shift @ARGV; -my $port = shift @ARGV; - -my $sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, - Proto => "tcp",) or die "$!"; -while (<>) { - $sock->syswrite($_, length $_); -} - -$sock->close; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ans2/ans.pl bind9-9.20.29/bin/tests/system/serve_stale/ans2/ans.pl --- bind9-9.20.26/bin/tests/system/serve_stale/ans2/ans.pl 2026-07-20 14:47:53.889847253 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ans2/ans.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,408 +0,0 @@ -#!/usr/bin/env perl - -# 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. - -use strict; -use warnings; - -use IO::File; -use IO::Socket; -use Getopt::Long; -use Net::DNS; -use Time::HiRes qw(usleep nanosleep); - -my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; -print $pidf "$$\n" or die "cannot write pid file: $!"; -$pidf->close or die "cannot close pid file: $!"; -sub rmpid { unlink "ans.pid"; exit 1; }; - -$SIG{INT} = \&rmpid; -$SIG{TERM} = \&rmpid; - -# If send_response is set, the server will respond, otherwise the query will -# be dropped. -my $send_response = 1; -# If slow_response is set, a lookup for the CNAME target (target.example) is -# delayed. Other lookups will not be delayed. -my $slow_response = 0; - -my $localaddr = "10.53.0.2"; - -my $localport = int($ENV{'PORT'}); -if (!$localport) { $localport = 5300; } - -my $udpsock = IO::Socket::INET->new(LocalAddr => "$localaddr", - LocalPort => $localport, Proto => "udp", Reuse => 1) or die "$!"; - -# -# Delegations -# -my $SOA = "example 300 IN SOA . . 0 0 0 0 300"; -my $NS = "example 300 IN NS ns.example"; -my $A = "ns.example 300 IN A $localaddr"; -my $ssSOA = "delegated.serve.stale 300 IN SOA . . 0 0 0 0 300"; -my $ssNS = "delegated.serve.stale 300 IN NS ns.delegated.serve.stale"; -my $ssA = "ns.delegated.serve.stale 300 IN A $localaddr"; - -# -# Slow delegation -# -my $slowSOA = "slow 300 IN SOA . . 0 0 0 0 300"; -my $slowNS = "slow 300 IN NS ns.slow"; -my $slowA = "ns.slow 300 IN A $localaddr"; -my $slowTXT = "data.slow 2 IN TXT \"A slow text record with a 2 second ttl\""; -my $slownegSOA = "slow 2 IN SOA . . 0 0 0 0 300"; - -# -# Records to be TTL stretched -# -my $TXT = "data.example 2 IN TXT \"A text record with a 2 second ttl\""; -my $LONGTXT = "longttl.example 600 IN TXT \"A text record with a 600 second ttl\""; -my $CAA = "othertype.example 2 IN CAA 0 issue \"ca1.example.net\""; -my $negSOA = "example 2 IN SOA . . 0 0 0 0 300"; -my $ssnegSOA = "delegated.serve.stale 2 IN SOA . . 0 0 0 0 300"; -my $CNAME = "cname.example 7 IN CNAME target.example"; -my $TARGET = "target.example 9 IN A $localaddr"; -my $SHORTCNAME = "shortttl.cname.example 1 IN CNAME longttl.target.example"; -my $LONGTARGET = "longttl.target.example 600 IN A $localaddr"; - -# -# YWH records -# -my $ywhSOA = "source.stale 300 IN SOA . . 0 0 0 0 300"; -my $ywhNS = "source.stale 300 IN NS ns.source.stale"; -my $ywhA = "ns.source.stale 300 IN A $localaddr"; -my $ywhCNAME = "alias.source.stale 2 IN CNAME www.target.stale"; -my $ywhCNAMENX = "aliasnx.source.stale 2 IN CNAME nonexist.target.stale"; - -sub reply_handler { - my ($qname, $qclass, $qtype) = @_; - my ($rcode, @ans, @auth, @add); - - print ("request: $qname/$qtype\n"); - STDOUT->flush(); - - # Control whether we send a response or not. - # We always respond to control commands. - if ($qname eq "enable" ) { - if ($qtype eq "TXT") { - $send_response = 1; - my $rr = new Net::DNS::RR("$qname 0 $qclass TXT \"$send_response\""); - push @ans, $rr; - } - $rcode = "NOERROR"; - return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); - } elsif ($qname eq "disable" ) { - if ($qtype eq "TXT") { - $send_response = 0; - my $rr = new Net::DNS::RR("$qname 0 $qclass TXT \"$send_response\""); - push @ans, $rr; - } - $rcode = "NOERROR"; - return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); - } elsif ($qname eq "slowdown" ) { - if ($qtype eq "TXT") { - $send_response = 1; - $slow_response = 1; - my $rr = new Net::DNS::RR("$qname 0 $qclass TXT \"$send_response\""); - push @ans, $rr; - } - $rcode = "NOERROR"; - return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); - } - - # If we are not responding to queries we are done. - return if (!$send_response); - - if (index($qname, "latency") == 0) { - # simulate network latency before answering - print " Sleeping 50 milliseconds\n"; - select(undef, undef, undef, 0.05); - } - - # Construct the response and send it. - if ($qname eq "ns.example" ) { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($A); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($SOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "example") { - if ($qtype eq "NS") { - my $rr = new Net::DNS::RR($NS); - push @auth, $rr; - $rr = new Net::DNS::RR($A); - push @add, $rr; - } elsif ($qtype eq "SOA") { - my $rr = new Net::DNS::RR($SOA); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($SOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "nodata.example") { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - $rcode = "NOERROR"; - } elsif ($qname eq "data.example") { - if ($qtype eq "TXT") { - my $rr = new Net::DNS::RR($TXT); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "a-only.example") { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR("a-only.example 2 IN A $localaddr"); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "cname.example") { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($CNAME); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "target.example") { - if ($slow_response) { - print " Sleeping 3 seconds\n"; - sleep(3); - } - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($TARGET); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "shortttl.cname.example") { - my $rr = new Net::DNS::RR($SHORTCNAME); - push @ans, $rr; - $rcode = "NOERROR"; - } elsif ($qname eq "longttl.target.example") { - if ($slow_response) { - print " Sleeping 3 seconds\n"; - sleep(3); - } - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($LONGTARGET); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "longttl.example") { - if ($qtype eq "TXT") { - my $rr = new Net::DNS::RR($LONGTXT); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "nxdomain.example") { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - $rcode = "NXDOMAIN"; - } elsif ($qname eq "othertype.example") { - if ($qtype eq "CAA") { - my $rr = new Net::DNS::RR($CAA); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($negSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "ns.delegated.serve.stale" ) { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($ssA); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($ssSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "delegated.serve.stale") { - if ($qtype eq "NS") { - my $rr = new Net::DNS::RR($ssNS); - push @auth, $rr; - $rr = new Net::DNS::RR($ssA); - push @add, $rr; - } elsif ($qtype eq "SOA") { - my $rr = new Net::DNS::RR($ssSOA); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($ssSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "www.delegated.serve.stale") { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR("www.delegated.serve.stale 2 IN A 10.53.0.99"); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($ssnegSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "cname.delegated.serve.stale") { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR("cname.delegated.serve.stale 2 IN CNAME cname-target.serve.stale."); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($ssnegSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "ns.slow" ) { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($slowA); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($slowSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "slow") { - if ($qtype eq "NS") { - my $rr = new Net::DNS::RR($slowNS); - push @auth, $rr; - $rr = new Net::DNS::RR($slowA); - push @add, $rr; - } elsif ($qtype eq "SOA") { - my $rr = new Net::DNS::RR($slowSOA); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($slowSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "data.slow") { - if ($slow_response) { - print " Sleeping 3 seconds\n"; - sleep(3); - # only one time - $slow_response = 0; - } - if ($qtype eq "TXT") { - my $rr = new Net::DNS::RR($slowTXT); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($slownegSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "source.stale") { - if ($qtype eq "SOA") { - my $rr = new Net::DNS::RR($ywhSOA); - push @ans, $rr; - } elsif ($qtype eq "NS") { - my $rr = new Net::DNS::RR($ywhNS); - push @ans, $rr; - $rr = new Net::DNS::RR($ywhA); - push @add, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "ns.source.stale") { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($ywhA); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($ywhSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "alias.source.stale") { - my $rr = new Net::DNS::RR($ywhCNAME); - push @ans, $rr; - $rcode = "NOERROR"; - } elsif ($qname eq "aliasnx.source.stale") { - my $rr = new Net::DNS::RR($ywhCNAMENX); - push @ans, $rr; - $rcode = "NOERROR"; - } else { - my $rr = new Net::DNS::RR($SOA); - push @auth, $rr; - $rcode = "NXDOMAIN"; - } - - # mark the answer as authoritative (by setting the 'aa' flag) - return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); -} - -GetOptions( - 'port=i' => \$localport, -); - -my $rin; -my $rout; - -for (;;) { - $rin = ''; - vec($rin, fileno($udpsock), 1) = 1; - - select($rout = $rin, undef, undef, undef); - - if (vec($rout, fileno($udpsock), 1)) { - my ($buf, $request, $err); - $udpsock->recv($buf, 512); - - if ($Net::DNS::VERSION > 0.68) { - $request = new Net::DNS::Packet(\$buf, 0); - $@ and die $@; - } else { - my $err; - ($request, $err) = new Net::DNS::Packet(\$buf, 0); - $err and die $err; - } - - my @questions = $request->question; - my $qname = $questions[0]->qname; - my $qclass = $questions[0]->qclass; - my $qtype = $questions[0]->qtype; - my $id = $request->header->id; - - my ($rcode, $ans, $auth, $add, $headermask) = reply_handler($qname, $qclass, $qtype); - - if (!defined($rcode)) { - print " Silently ignoring query\n"; - next; - } - - my $reply = Net::DNS::Packet->new(); - $reply->header->qr(1); - $reply->header->aa(1) if $headermask->{'aa'}; - $reply->header->id($id); - $reply->header->rcode($rcode); - $reply->push("question", @questions); - $reply->push("answer", @$ans) if $ans; - $reply->push("authority", @$auth) if $auth; - $reply->push("additional", @$add) if $add; - - my $num_chars = $udpsock->send($reply->data); - print " Sent $num_chars bytes via UDP\n"; - } -} diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ans2/ans.py bind9-9.20.29/bin/tests/system/serve_stale/ans2/ans.py --- bind9-9.20.26/bin/tests/system/serve_stale/ans2/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ans2/ans.py 2026-09-11 19:41:01.358327573 +0000 @@ -0,0 +1,193 @@ +""" +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. +""" + +import dns.rcode +import dns.rdatatype + +from isctest.asyncserver import ( + ControllableAsyncDnsServer, + QnameHandler, + QnameQtypeHandler, + ResponseHandler, + StaticResponseHandler, + ToggleResponsesCommand, +) + +from ..serve_stale_ans import ( + a_handler, + cname_a_handler, + cname_handler, + fallback_handler, + ns_handler, + other_types_handler, + rrset, + soa, + soa_handler, + txt_handler, +) + + +class NxdomainExampleHandler(QnameHandler, StaticResponseHandler): + qnames = ["nxdomain.example."] + rcode = dns.rcode.NXDOMAIN + authority = [soa("example.", ttl=2)] + + +# A negative answer that stays fresh for the whole run of a test, so that a +# resolver refreshing it can only be doing so because it wrongly considers +# the cached entry stale. +class LongttlNodataExampleHandler(QnameHandler, StaticResponseHandler): + qnames = ["longttl-nodata.example."] + authority = [soa("example.", ttl=600, minimum=600)] + + +class LongttlNxdomainExampleHandler(QnameHandler, StaticResponseHandler): + qnames = ["longttl-nxdomain.example."] + rcode = dns.rcode.NXDOMAIN + authority = [soa("example.", ttl=600, minimum=600)] + + +class OthertypeExampleCaaHandler(QnameQtypeHandler, StaticResponseHandler): + qnames = ["othertype.example."] + qtypes = [dns.rdatatype.CAA] + answer = [ + rrset( + "othertype.example.", + 2, + dns.rdatatype.CAA, + '0 issue "ca1.example.net"', + ) + ] + + +class SourceStaleFallbackHandler(QnameHandler, StaticResponseHandler): + qnames = ["source.stale."] + + +def handlers() -> list[ResponseHandler]: + return [ + a_handler("NsExample", "ns.example."), + ns_handler("Example", "example.", "ns.example."), + soa_handler("Example", "example."), + other_types_handler("Example", ["example.", "ns.example."], "example."), + other_types_handler("NodataExample", "nodata.example.", "example.", ttl=2), + LongttlNodataExampleHandler(), + LongttlNxdomainExampleHandler(), + txt_handler( + "DataExample", + "data.example.", + "A text record with a 2 second ttl", + ttl=2, + ), + other_types_handler("DataExample", "data.example.", "example.", ttl=2), + a_handler("AOnlyExample", "a-only.example.", ttl=2), + other_types_handler("AOnlyExample", "a-only.example.", "example.", ttl=2), + cname_a_handler("CnameExample", "cname.example.", "target.example.", ttl=7), + other_types_handler("CnameExample", "cname.example.", "example.", ttl=2), + a_handler("TargetExample", "target.example.", ttl=9), + other_types_handler("TargetExample", "target.example.", "example.", ttl=2), + cname_handler( + "ShortTtlCnameExample", + "shortttl.cname.example.", + "longttl.target.example.", + ttl=1, + ), + a_handler("LongTtlTargetExample", "longttl.target.example.", ttl=600), + other_types_handler( + "LongTtlTargetExample", "longttl.target.example.", "example.", ttl=2 + ), + txt_handler( + "LongTtlExample", + "longttl.example.", + "A text record with a 600 second ttl", + ttl=600, + ), + other_types_handler("LongTtlExample", "longttl.example.", "example.", ttl=2), + NxdomainExampleHandler(), + OthertypeExampleCaaHandler(), + other_types_handler( + "OthertypeExample", "othertype.example.", "example.", ttl=2 + ), + a_handler("NsDelegatedServeStale", "ns.delegated.serve.stale."), + other_types_handler( + "NsDelegatedServeStale", + "ns.delegated.serve.stale.", + "delegated.serve.stale.", + ), + ns_handler( + "DelegatedServeStaleZone", + "delegated.serve.stale.", + "ns.delegated.serve.stale.", + ), + soa_handler("DelegatedServeStaleZone", "delegated.serve.stale."), + other_types_handler( + "DelegatedServeStaleZone", + "delegated.serve.stale.", + "delegated.serve.stale.", + ), + a_handler( + "WwwDelegatedServeStale", + "www.delegated.serve.stale.", + ttl=2, + address="10.53.0.99", + ), + other_types_handler( + "WwwDelegatedServeStale", + "www.delegated.serve.stale.", + "delegated.serve.stale.", + ttl=2, + ), + cname_a_handler( + "CnameDelegatedServeStale", + "cname.delegated.serve.stale.", + "cname-target.serve.stale.", + ttl=2, + ), + other_types_handler( + "CnameDelegatedServeStale", + "cname.delegated.serve.stale.", + "delegated.serve.stale.", + ttl=2, + ), + soa_handler("SourceStale", "source.stale."), + ns_handler("SourceStale", "source.stale.", "ns.source.stale.", in_answer=True), + SourceStaleFallbackHandler(), + a_handler("NsSourceStale", "ns.source.stale."), + other_types_handler("NsSourceStale", "ns.source.stale.", "source.stale."), + cname_handler( + "AliasSourceStale", + "alias.source.stale.", + "www.target.stale.", + ttl=2, + ), + cname_handler( + "AliasNxSourceStale", + "aliasnx.source.stale.", + "nonexist.target.stale.", + ttl=2, + ), + fallback_handler("example."), + ] + + +def main() -> None: + server = ControllableAsyncDnsServer( + default_aa=True, default_rcode=dns.rcode.NOERROR + ) + server.install_response_handlers(*handlers()) + server.install_control_command(ToggleResponsesCommand()) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ans8/ans.pl bind9-9.20.29/bin/tests/system/serve_stale/ans8/ans.pl --- bind9-9.20.26/bin/tests/system/serve_stale/ans8/ans.pl 2026-07-20 14:47:53.889847253 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ans8/ans.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -#!/usr/bin/env perl - -# 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. - -use strict; -use warnings; - -use IO::File; -use IO::Socket; -use Getopt::Long; -use Net::DNS; -use Time::HiRes qw(usleep nanosleep); - -my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; -print $pidf "$$\n" or die "cannot write pid file: $!"; -$pidf->close or die "cannot close pid file: $!"; -sub rmpid { unlink "ans.pid"; exit 1; }; - -$SIG{INT} = \&rmpid; -$SIG{TERM} = \&rmpid; - -my $localaddr = "10.53.0.8"; - -my $localport = int($ENV{'PORT'}); -if (!$localport) { $localport = 5300; } - -my $udpsock = IO::Socket::INET->new(LocalAddr => "$localaddr", - LocalPort => $localport, Proto => "udp", Reuse => 1) or die "$!"; - -# -# YWH records -# -my $ywhSOA = "target.stale 300 IN SOA . . 0 0 0 0 300"; -my $ywhNS = "target.stale 300 IN NS ns.target.stale"; -my $ywhA = "ns.target.stale 300 IN A $localaddr"; -my $ywhWWW = "www.target.stale 2 IN A 10.0.0.1"; - -sub reply_handler { - my ($qname, $qclass, $qtype) = @_; - my ($rcode, @ans, @auth, @add); - - print ("request: $qname/$qtype\n"); - STDOUT->flush(); - - # Control what response we send. - if ($qname eq "update" ) { - if ($qtype eq "TXT") { - $ywhWWW = "www.target.stale 2 IN A 10.0.0.2"; - my $rr = new Net::DNS::RR("$qname 0 $qclass TXT \"update\""); - push @ans, $rr; - } - $rcode = "NOERROR"; - return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); - } elsif ($qname eq "restore" ) { - if ($qtype eq "TXT") { - $ywhWWW = "www.target.stale 2 IN A 10.0.0.1"; - my $rr = new Net::DNS::RR("$qname 0 $qclass TXT \"restore\""); - push @ans, $rr; - } - $rcode = "NOERROR"; - return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); - } - - if ($qname eq "target.stale") { - if ($qtype eq "SOA") { - my $rr = new Net::DNS::RR($ywhSOA); - push @ans, $rr; - } elsif ($qtype eq "NS") { - my $rr = new Net::DNS::RR($ywhNS); - push @ans, $rr; - $rr = new Net::DNS::RR($ywhA); - push @add, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "ns.target.stale") { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($ywhA); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($ywhSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } elsif ($qname eq "www.target.stale") { - if ($qtype eq "A") { - my $rr = new Net::DNS::RR($ywhWWW); - push @ans, $rr; - } else { - my $rr = new Net::DNS::RR($ywhSOA); - push @auth, $rr; - } - $rcode = "NOERROR"; - } else { - my $rr = new Net::DNS::RR($ywhSOA); - push @auth, $rr; - $rcode = "NXDOMAIN"; - } - - # mark the answer as authoritative (by setting the 'aa' flag) - return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); -} - -GetOptions( - 'port=i' => \$localport, -); - -my $rin; -my $rout; - -for (;;) { - $rin = ''; - vec($rin, fileno($udpsock), 1) = 1; - - select($rout = $rin, undef, undef, undef); - - if (vec($rout, fileno($udpsock), 1)) { - my ($buf, $request, $err); - $udpsock->recv($buf, 512); - - if ($Net::DNS::VERSION > 0.68) { - $request = new Net::DNS::Packet(\$buf, 0); - $@ and die $@; - } else { - my $err; - ($request, $err) = new Net::DNS::Packet(\$buf, 0); - $err and die $err; - } - - my @questions = $request->question; - my $qname = $questions[0]->qname; - my $qclass = $questions[0]->qclass; - my $qtype = $questions[0]->qtype; - my $id = $request->header->id; - - my ($rcode, $ans, $auth, $add, $headermask) = reply_handler($qname, $qclass, $qtype); - - if (!defined($rcode)) { - print " Silently ignoring query\n"; - next; - } - - my $reply = Net::DNS::Packet->new(); - $reply->header->qr(1); - $reply->header->aa(1) if $headermask->{'aa'}; - $reply->header->id($id); - $reply->header->rcode($rcode); - $reply->push("question", @questions); - $reply->push("answer", @$ans) if $ans; - $reply->push("authority", @$auth) if $auth; - $reply->push("additional", @$add) if $add; - - my $num_chars = $udpsock->send($reply->data); - print " Sent $num_chars bytes via UDP\n"; - } -} diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ans8/ans.py bind9-9.20.29/bin/tests/system/serve_stale/ans8/ans.py --- bind9-9.20.26/bin/tests/system/serve_stale/ans8/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ans8/ans.py 2026-09-11 19:41:01.358327573 +0000 @@ -0,0 +1,88 @@ +""" +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. +""" + +import dns.rcode + +from isctest.asyncserver import ( + ControllableAsyncDnsServer, + QnameHandler, + ResponseHandler, + StaticResponseHandler, + SwitchControlCommand, +) + +from ..serve_stale_ans import ( + a_handler, + fallback_handler, + ns_handler, + other_types_handler, + soa_handler, +) + +ANS8_ADDR = "10.53.0.8" + + +class TargetStaleFallbackHandler(QnameHandler, StaticResponseHandler): + qnames = ["target.stale."] + + +def handlers(www_address: str) -> list[ResponseHandler]: + return [ + soa_handler("TargetStale", "target.stale."), + ns_handler( + "TargetStale", + "target.stale.", + "ns.target.stale.", + address=ANS8_ADDR, + in_answer=True, + ), + TargetStaleFallbackHandler(), + a_handler( + "NsTargetStale", + "ns.target.stale.", + address=ANS8_ADDR, + ), + a_handler( + "WwwTargetStale", + "www.target.stale.", + ttl=2, + address=www_address, + ), + other_types_handler( + "TargetStaleNodata", + ["ns.target.stale.", "www.target.stale."], + "target.stale.", + ), + fallback_handler("target.stale."), + ] + + +def main() -> None: + server = ControllableAsyncDnsServer( + default_aa=True, default_rcode=dns.rcode.NOERROR + ) + + restored = handlers("10.0.0.1") + server.install_response_handlers(*restored) + switch_command = SwitchControlCommand( + { + "restore": restored, + "update": handlers("10.0.0.2"), + } + ) + server.install_control_command(switch_command) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ans9/ans.py bind9-9.20.29/bin/tests/system/serve_stale/ans9/ans.py --- bind9-9.20.26/bin/tests/system/serve_stale/ans9/ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ans9/ans.py 2026-09-11 19:41:01.358327573 +0000 @@ -0,0 +1,146 @@ +""" +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. +""" + +from collections.abc import AsyncGenerator + +import asyncio + +import dns.rcode +import dns.rdatatype + +from isctest.asyncserver import ( + ControlCommand, + ControllableAsyncDnsServer, + QueryContext, + ResponseAction, + ResponseHandler, +) + +from ..serve_stale_ans import ( + StaticHandler, + a_handler, + fallback_handler, + ns_handler, + other_types_handler, + soa, + soa_handler, + txt, +) + +ANS9_ADDR = "10.53.0.9" + + +class SlowdownState: + """ + One-shot slowdown flag, armed by the "slowdown" control query. + + The first data.slow query consumes it: the response to that query is + delayed by three seconds and the slowdown is turned off again. + """ + + def __init__(self) -> None: + self.armed = False + + def consume(self) -> float: + delay = 3.0 if self.armed else 0.0 + self.armed = False + return delay + + +class SlowdownControlCommand(ControlCommand): + control_subdomain = "slowdown" + + def __init__(self, slowdown: SlowdownState) -> None: + self._slowdown = slowdown + super().__init__() + + def handle( + self, args: list[str], server: ControllableAsyncDnsServer, qctx: QueryContext + ) -> str | None: + if args: + return "Expected no extra labels" + + self._slowdown.armed = True + return "slowdown armed" + + +class SerializedHandler(ResponseHandler): + """ + Answer queries one at a time. + + All handlers of this server share one lock which is held until the + response is sent, so a response delayed by the slowdown holds back the + responses to all queries which arrive in the meantime. + """ + + def __init__(self, inner: ResponseHandler, lock: asyncio.Lock) -> None: + self._inner = inner + self._lock = lock + super().__init__() + + def match(self, qctx: QueryContext) -> bool: + return self._inner.match(qctx) + + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[ResponseAction, None]: + # This generator is suspended at the yield below while the response + # is being delayed and sent, so the lock is held until the send + # completes. + async with self._lock: + async for action in self._inner.get_responses(qctx): + yield action + + def __str__(self) -> str: + return f"Serialized({self._inner})" + + +def handlers(slowdown: SlowdownState) -> list[ResponseHandler]: + return [ + a_handler("NsSlow", "ns.slow.", address=ANS9_ADDR), + other_types_handler("NsSlow", "ns.slow.", "slow."), + ns_handler("SlowZone", "slow.", "ns.slow.", address=ANS9_ADDR), + soa_handler("SlowZone", "slow."), + other_types_handler("SlowZone", "slow.", "slow."), + StaticHandler( + "DataSlowTxtHandler", + "data.slow.", + [dns.rdatatype.TXT], + answer=[txt("data.slow.", "A slow text record with a 2 second ttl", ttl=2)], + delay=slowdown.consume, + ), + StaticHandler( + "DataSlowFallbackHandler", + "data.slow.", + authority=[soa("slow.", ttl=2)], + delay=slowdown.consume, + ), + fallback_handler("slow."), + ] + + +def main() -> None: + server = ControllableAsyncDnsServer( + default_aa=True, default_rcode=dns.rcode.NOERROR + ) + slowdown = SlowdownState() + lock = asyncio.Lock() + server.install_response_handlers( + *(SerializedHandler(handler, lock) for handler in handlers(slowdown)) + ) + server.install_control_command(SlowdownControlCommand(slowdown)) + server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns1/named.conf.j2 2026-07-20 14:47:53.889847253 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns1/named.conf.j2 2026-09-11 19:41:01.358327573 +0000 @@ -16,25 +16,11 @@ {% set stale_refresh_time = stale_refresh_time | default(30) %} {% set stale_test_zone = stale_test_zone | default(False) %} -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; dnssec-validation no; max-stale-ttl @max_stale_ttl@; stale-answer-ttl @stale_answer_ttl@; @@ -43,6 +29,10 @@ {% if stale_refresh_time is not none %} stale-refresh-time @stale_refresh_time@; {% endif %} + # The auth is local; with the default 'off' client-timeout the test + # blocks on the full resolver-query-timeout whenever it forces a + # resolver failure, so cap it low to keep those waits short. + resolver-query-timeout 2000; servfail-ttl 0; }; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns1/named1.conf.in bind9-9.20.29/bin/tests/system/serve_stale/ns1/named1.conf.in --- bind9-9.20.26/bin/tests/system/serve_stale/ns1/named1.conf.in 2026-07-20 14:47:53.889847253 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns1/named1.conf.in 2026-09-11 19:41:01.358327573 +0000 @@ -29,7 +29,6 @@ listen-on { 10.53.0.1; }; listen-on-v6 { none; }; allow-transfer { any; }; - recursion yes; dnssec-validation no; max-stale-ttl 3600; stale-answer-ttl 4; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns1/named2.conf.in bind9-9.20.29/bin/tests/system/serve_stale/ns1/named2.conf.in --- bind9-9.20.26/bin/tests/system/serve_stale/ns1/named2.conf.in 2026-07-20 14:47:53.889847253 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns1/named2.conf.in 2026-09-11 19:41:01.358327573 +0000 @@ -29,7 +29,6 @@ listen-on { 10.53.0.1; }; listen-on-v6 { none; }; allow-transfer { any; }; - recursion yes; dnssec-validation no; max-stale-ttl 3600; stale-answer-ttl 4; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns1/named3.conf.in bind9-9.20.29/bin/tests/system/serve_stale/ns1/named3.conf.in --- bind9-9.20.26/bin/tests/system/serve_stale/ns1/named3.conf.in 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns1/named3.conf.in 2026-09-11 19:41:01.358327573 +0000 @@ -29,9 +29,8 @@ listen-on { 10.53.0.1; }; listen-on-v6 { none; }; allow-transfer { any; }; - recursion yes; dnssec-validation no; - max-stale-ttl 20; + max-stale-ttl 8; stale-answer-ttl 3; stale-answer-enable yes; stale-cache-enable yes; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns1/named3.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns1/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns1/named3.conf.j2 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns1/named3.conf.j2 2026-09-11 19:41:01.358327573 +0000 @@ -11,7 +11,7 @@ * information regarding copyright ownership. */ -{% set max_stale_ttl = 20 %} +{% set max_stale_ttl = 8 %} {% set stale_answer_ttl = 3 %} {% set stale_refresh_time = None %} diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns1/named4.conf.in bind9-9.20.29/bin/tests/system/serve_stale/ns1/named4.conf.in --- bind9-9.20.26/bin/tests/system/serve_stale/ns1/named4.conf.in 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns1/named4.conf.in 2026-09-11 19:41:01.358327573 +0000 @@ -29,7 +29,6 @@ listen-on { 10.53.0.1; }; listen-on-v6 { none; }; allow-transfer { any; }; - recursion yes; dnssec-validation no; max-stale-ttl 20; stale-answer-ttl 3; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns1/root.db bind9-9.20.29/bin/tests/system/serve_stale/ns1/root.db --- bind9-9.20.26/bin/tests/system/serve_stale/ns1/root.db 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns1/root.db 2026-09-11 19:41:01.358327573 +0000 @@ -15,6 +15,6 @@ example. 300 NS ns.example. ns.example. 300 A 10.53.0.2 slow. 300 NS ns.slow. -ns.slow. 300 A 10.53.0.2 +ns.slow. 300 A 10.53.0.9 stale. 300 NS ns.stale. ns.stale. 300 A 10.53.0.6 diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named.conf.j2 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; qname-minimization off; prefetch 0; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named1.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named1.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named1.conf.j2 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named1.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dump-file "named_dump3.db"; stale-cache-enable yes; dnssec-validation no; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named2.conf.j2 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named2.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -15,25 +15,11 @@ * Test default stale-answer-client-timeout value */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - recursion yes; stale-answer-enable yes; stale-cache-enable yes; stale-answer-ttl 3; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named3.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named3.conf.j2 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named3.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -15,31 +15,19 @@ * Test disable of stale-answer-client-timeout. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - recursion yes; stale-answer-enable yes; stale-cache-enable yes; stale-answer-ttl 3; stale-refresh-time 0; max-stale-ttl 3600; - resolver-query-timeout 10000; # 10 seconds + # Client-timeout defaults to 'off', so the stale shortttl.cname.example + # checks block on this timeout when the auth is down; keep it short. + resolver-query-timeout 2000; # 2 seconds prefetch 0; }; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named4.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named4.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named4.conf.j2 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named4.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -15,25 +15,11 @@ * Test stale-answer-client-timeout 0. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - recursion yes; stale-answer-enable yes; stale-cache-enable yes; stale-answer-ttl 3; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named5.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named5.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named5.conf.j2 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named5.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -15,31 +15,17 @@ * Test stale-answer-client-timeout 0. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - recursion yes; stale-answer-enable yes; stale-cache-enable yes; stale-answer-ttl 3; stale-answer-client-timeout 0; stale-refresh-time 4; - resolver-query-timeout 10000; # 10 seconds + resolver-query-timeout 2000; # 2 seconds max-stale-ttl 3600; prefetch 0; }; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named6.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named6.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named6.conf.j2 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named6.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -11,25 +11,11 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - recursion yes; stale-answer-enable no; stale-cache-enable yes; stale-answer-ttl 3; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named7.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named7.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named7.conf.j2 2026-07-20 14:47:53.891847284 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named7.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -15,25 +15,11 @@ * Test serve-stale interaction with fetch-limits (dual-mode). */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - recursion yes; /* * stale-answer-enable is not strictly required because serving * stale answers is enabled in the test via rndc. diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named8.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named8.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named8.conf.j2 2026-07-20 14:47:53.891847284 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named8.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; stale-answer-enable yes; stale-cache-enable yes; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns3/named9.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns3/named9.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns3/named9.conf.j2 2026-07-20 14:47:53.891847284 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns3/named9.conf.j2 2026-09-11 19:41:01.359327597 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; stale-answer-enable yes; stale-cache-enable yes; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns4/named.conf.j2 2026-07-20 14:47:53.891847284 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns4/named.conf.j2 2026-09-11 19:41:01.360327621 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; dump-file "named_dump.db"; stale-answer-enable no; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns5/named.conf.j2 2026-07-20 14:47:53.891847284 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns5/named.conf.j2 2026-09-11 19:41:01.360327621 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; dump-file "named_dump.db"; stale-answer-enable yes; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns6/named.conf.j2 2026-07-20 14:47:53.891847284 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns6/named.conf.j2 2026-09-11 19:41:01.360327621 +0000 @@ -11,23 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; recursion no; }; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns7/named.conf.j2 2026-07-20 14:47:53.891847284 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns7/named.conf.j2 2026-09-11 19:41:01.360327621 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; qname-minimization off; @@ -39,6 +25,10 @@ stale-answer-client-timeout off; stale-refresh-time 30; + # Cap the resolver timeout so the stale-CNAME checks that force a + # resolver failure do not each block for the 10s default. + resolver-query-timeout 2000; + max-cache-ttl 300; max-ncache-ttl 300; }; @@ -50,13 +40,13 @@ // Authoritative zone: nonexist.target.stale -> NXDOMAIN zone "target.stale" { - type primary; - file "target.stale.db"; + type primary; + file "target.stale.db"; }; // Forward source.stale queries to ans2 zone "source.stale" { - type forward; - forward only; - forwarders { 10.53.0.2 port @PORT@; }; + type forward; + forward only; + forwarders { 10.53.0.2 port @PORT@; }; }; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns7/named1.conf.j2 bind9-9.20.29/bin/tests/system/serve_stale/ns7/named1.conf.j2 --- bind9-9.20.26/bin/tests/system/serve_stale/ns7/named1.conf.j2 2026-07-20 14:47:53.892847300 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns7/named1.conf.j2 2026-09-11 19:41:01.360327621 +0000 @@ -11,24 +11,10 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; qname-minimization off; @@ -39,6 +25,10 @@ stale-answer-client-timeout off; stale-refresh-time 30; + # Cap the resolver timeout so the stale-CNAME checks that force a + # resolver failure do not each block for the 10s default. + resolver-query-timeout 2000; + max-cache-ttl 300; max-ncache-ttl 300; }; @@ -50,14 +40,14 @@ // Forward source.stale queries to ans2 zone "source.stale" { - type forward; - forward only; - forwarders { 10.53.0.2 port @PORT@; }; + type forward; + forward only; + forwarders { 10.53.0.2 port @PORT@; }; }; // Forward target.stale queries to ans8 zone "target.stale" { - type forward; - forward only; - forwarders { 10.53.0.8 port @PORT@; }; + type forward; + forward only; + forwarders { 10.53.0.8 port @PORT@; }; }; diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/ns7/root.db bind9-9.20.29/bin/tests/system/serve_stale/ns7/root.db --- bind9-9.20.26/bin/tests/system/serve_stale/ns7/root.db 2026-07-20 14:47:53.890847269 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/ns7/root.db 2026-09-11 19:41:01.358327573 +0000 @@ -15,6 +15,6 @@ example. 300 NS ns.example. ns.example. 300 A 10.53.0.2 slow. 300 NS ns.slow. -ns.slow. 300 A 10.53.0.2 +ns.slow. 300 A 10.53.0.9 stale. 300 NS ns.stale. ns.stale. 300 A 10.53.0.6 diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/prereq.sh bind9-9.20.29/bin/tests/system/serve_stale/prereq.sh --- bind9-9.20.26/bin/tests/system/serve_stale/prereq.sh 2026-07-20 14:47:53.892847300 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MTime::HiRes -e ''; then - echo_i "perl Time::HiRes module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/serve_stale_ans.py bind9-9.20.29/bin/tests/system/serve_stale/serve_stale_ans.py --- bind9-9.20.26/bin/tests/system/serve_stale/serve_stale_ans.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/serve_stale_ans.py 2026-09-11 19:41:01.360327621 +0000 @@ -0,0 +1,223 @@ +""" +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. +""" + +from collections.abc import Callable, Sequence + +import dns.name +import dns.rcode +import dns.rdataclass +import dns.rdatatype +import dns.rrset + +from isctest.asyncserver import QueryContext, ResponseHandler, StaticResponseHandler + + +def rrset( + owner: str, + ttl: int, + rdtype: dns.rdatatype.RdataType, + rdata: str, +) -> dns.rrset.RRset: + return dns.rrset.from_text(owner, ttl, dns.rdataclass.IN, rdtype, rdata) + + +def soa(owner: str, ttl: int = 300, minimum: int = 300) -> dns.rrset.RRset: + return rrset(owner, ttl, dns.rdatatype.SOA, f". . 0 0 0 0 {minimum}") + + +def ns(owner: str, target: str, ttl: int = 300) -> dns.rrset.RRset: + return rrset(owner, ttl, dns.rdatatype.NS, target) + + +def a(owner: str, address: str, ttl: int = 300) -> dns.rrset.RRset: + return rrset(owner, ttl, dns.rdatatype.A, address) + + +def txt(owner: str, data: str, ttl: int = 2) -> dns.rrset.RRset: + return rrset(owner, ttl, dns.rdatatype.TXT, f'"{data}"') + + +def cname(owner: str, target: str, ttl: int) -> dns.rrset.RRset: + return rrset(owner, ttl, dns.rdatatype.CNAME, target) + + +# The delay before sending a response may either be fixed or determined at +# response time by a callable. +Delay = float | Callable[[], float] + + +class StaticHandler(StaticResponseHandler): + """ + A response handler answering with statically configured content. + + Matches queries by QNAME (any QNAME when `qnames` is None) and optionally + by QTYPE, and responds with the RRsets/RCODE/delay given to the + constructor. `name` is only used for logging. + """ + + def __init__( + self, + name: str, + qnames: str | list[str] | None, + qtypes: list[dns.rdatatype.RdataType] | None = None, + *, + answer: Sequence[dns.rrset.RRset] = (), + authority: Sequence[dns.rrset.RRset] = (), + additional: Sequence[dns.rrset.RRset] = (), + rcode: dns.rcode.Rcode | None = None, + delay: Delay = 0.0, + ) -> None: + if isinstance(qnames, str): + qnames = [qnames] + self._name = name + self._qnames = ( + None if qnames is None else [dns.name.from_text(q) for q in qnames] + ) + self._qtypes = qtypes + self._answer = list(answer) + self._authority = list(authority) + self._additional = list(additional) + self._rcode = rcode + self._delay = delay + + def match(self, qctx: QueryContext) -> bool: + if self._qnames is not None and qctx.qname not in self._qnames: + return False + if self._qtypes is not None and qctx.qtype not in self._qtypes: + return False + return True + + @property + def answer(self) -> Sequence[dns.rrset.RRset]: + return self._answer + + @property + def authority(self) -> Sequence[dns.rrset.RRset]: + return self._authority + + @property + def additional(self) -> Sequence[dns.rrset.RRset]: + return self._additional + + @property + def rcode(self) -> dns.rcode.Rcode | None: + return self._rcode + + @property + def delay(self) -> float: + if callable(self._delay): + return self._delay() + return self._delay + + def __str__(self) -> str: + if self._qnames is None: + return self._name + qnames = ", ".join(n.to_text() for n in self._qnames) + return f"{self._name}(QNAMEs: {qnames})" + + +def a_handler( + name_prefix: str, + owner: str, + ttl: int = 300, + address: str = "10.53.0.2", +) -> ResponseHandler: + return StaticHandler( + f"{name_prefix}AHandler", + owner, + [dns.rdatatype.A], + answer=[a(owner, ttl=ttl, address=address)], + ) + + +def ns_handler( + name_prefix: str, + owner: str, + target: str, + ttl: int = 300, + glue_ttl: int = 300, + address: str = "10.53.0.2", + in_answer: bool = False, +) -> ResponseHandler: + ns_rrsets = [ns(owner, target, ttl=ttl)] + return StaticHandler( + f"{name_prefix}NsHandler", + owner, + [dns.rdatatype.NS], + answer=ns_rrsets if in_answer else (), + authority=() if in_answer else ns_rrsets, + additional=[a(target, address=address, ttl=glue_ttl)], + ) + + +def soa_handler(name_prefix: str, owner: str, ttl: int = 300) -> ResponseHandler: + return StaticHandler( + f"{name_prefix}SoaHandler", + owner, + [dns.rdatatype.SOA], + answer=[soa(owner, ttl=ttl)], + ) + + +def other_types_handler( + name_prefix: str, + qname_or_qnames: str | list[str], + zone: str, + ttl: int = 300, +) -> ResponseHandler: + return StaticHandler( + f"{name_prefix}OtherTypesHandler", + qname_or_qnames, + authority=[soa(zone, ttl=ttl)], + ) + + +def cname_handler( + name_prefix: str, owner: str, target: str, ttl: int = 300 +) -> ResponseHandler: + return StaticHandler( + f"{name_prefix}CnameHandler", + owner, + answer=[cname(owner, target, ttl=ttl)], + ) + + +def cname_a_handler( + name_prefix: str, owner: str, target: str, ttl: int = 300 +) -> ResponseHandler: + return StaticHandler( + f"{name_prefix}CnameAHandler", + owner, + [dns.rdatatype.A], + answer=[cname(owner, target, ttl=ttl)], + ) + + +def txt_handler( + name_prefix: str, owner: str, text: str, ttl: int = 300 +) -> ResponseHandler: + return StaticHandler( + f"{name_prefix}TxtHandler", + owner, + [dns.rdatatype.TXT], + answer=[txt(owner, text, ttl=ttl)], + ) + + +def fallback_handler(zone: str, ttl: int = 300) -> ResponseHandler: + return StaticHandler( + "FallbackHandler", + None, + rcode=dns.rcode.NXDOMAIN, + authority=[soa(zone, ttl=ttl)], + ) diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/tests.sh bind9-9.20.29/bin/tests/system/serve_stale/tests.sh --- bind9-9.20.26/bin/tests/system/serve_stale/tests.sh 2026-07-20 14:47:53.892847300 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/tests.sh 2026-09-11 19:41:01.361327645 +0000 @@ -18,6 +18,27 @@ RNDCCMD="$RNDC -c ../_common/rndc.conf -p ${CONTROLPORT} -s" DIG="$DIG +time=12 +tries=1" +ans2_control() { + control_name=$1 + shift + $DIG -p "${PORT}" @10.53.0.2 "${control_name}.send-responses._control" TXT "$@" >dig.out.ans2_control || return 1 + grep "status: NOERROR" dig.out.ans2_control >/dev/null || return 1 +} + +ans8_control() { + control_name=$1 + shift + $DIG -p "${PORT}" @10.53.0.8 "${control_name}.switch._control" TXT "$@" >dig.out.ans8_control || return 1 + grep "status: NOERROR" dig.out.ans8_control >/dev/null || return 1 +} + +ans9_control() { + control_name=$1 + shift + $DIG -p "${PORT}" @10.53.0.9 "${control_name}._control" TXT "$@" >dig.out.ans9_control || return 1 + grep "status: NOERROR" dig.out.ans9_control >/dev/null || return 1 +} + max_stale_ttl=$(sed -ne 's,^[[:space:]]*max-stale-ttl \([[:digit:]]*\).*,\1,p' $TOP_SRCDIR/bin/named/config.c) stale_answer_ttl=$(sed -ne 's,^[[:space:]]*stale-answer-ttl \([[:digit:]]*\).*,\1,p' $TOP_SRCDIR/bin/named/config.c) @@ -49,9 +70,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) # Query via stale CNAME — triggers the bug @@ -67,9 +86,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -106,18 +123,14 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) # Kill target auth, restart with NEW IP (10.0.0.2) n=$((n + 1)) echo_i "update target authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.8 txt update >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"update\"" dig.out.test$n >/dev/null || ret=1 +ans8_control update || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) # Query via stale CNAME — triggers the bug @@ -145,18 +158,14 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) n=$((n + 1)) echo_i "update target authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.8 txt restore >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"restore\"" dig.out.test$n >/dev/null || ret=1 +ans8_control restore || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -188,9 +197,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) # Flush target's negative cache entry (simulates cache eviction/pressure) @@ -224,9 +231,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -300,9 +305,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -444,9 +447,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -517,9 +518,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -756,7 +755,7 @@ echo_i "check 'rndc serve-stale status' ($n)" ret=0 $RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1 -grep '_default: stale cache enabled; stale answers disabled (stale-answer-ttl=3 max-stale-ttl=20 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1 +grep '_default: stale cache enabled; stale answers disabled (stale-answer-ttl=3 max-stale-ttl=8 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -775,16 +774,14 @@ echo_i "check 'rndc serve-stale status' ($n)" ret=0 $RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1 -grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=20 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1 +grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=8 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -857,9 +854,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1010,9 +1005,7 @@ echo_i "flush cache, enable responses from authoritative server ($n)" ret=0 $RNDCCMD 10.53.0.1 flushtree example >rndc.out.test$n.1 2>&1 || ret=1 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1020,7 +1013,7 @@ echo_i "check 'rndc serve-stale status' ($n)" ret=0 $RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1 -grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=20 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1 +grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=8 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1039,9 +1032,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1067,9 +1058,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1124,9 +1113,7 @@ echo_i "flush cache, enable responses from authoritative server ($n)" ret=0 $RNDCCMD 10.53.0.1 flushtree example >rndc.out.test$n.1 2>&1 || ret=1 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1146,9 +1133,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1174,9 +1159,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1214,9 +1197,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1289,9 +1270,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1392,23 +1371,15 @@ sleep 2 -# Check that if we don't have stale data for a domain name, we will -# not answer anything until the resolver query timeout. -n=$((n + 1)) -echo_i "check notincache.example TXT times out (max-stale-ttl default) ($n)" -ret=0 -$DIG -p ${PORT} +tries=1 +timeout=3 @10.53.0.3 notfound.example TXT >dig.out.test$n 2>&1 && ret=1 -grep "timed out" dig.out.test$n >/dev/null || ret=1 -grep ";; no servers could be reached" dig.out.test$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) +# Note: the "notincache.example TXT times out" step (the original test +# 120) has been moved to the pytest suite in tests_serve_stale_tcp.py, +# together with the two steps below which depend on it. echo_i "sending queries for tests $((n + 1))-$((n + 4))..." $DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$((n + 1)) & $DIG -p ${PORT} @10.53.0.3 othertype.example CAA >dig.out.test$((n + 2)) & $DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$((n + 3)) & $DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT >dig.out.test$((n + 4)) & -$DIG -p ${PORT} @10.53.0.3 notfound.example TXT >dig.out.test$((n + 5)) & wait @@ -1450,18 +1421,9 @@ if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) -# The notfound.example check is different than nxdomain.example because -# we didn't send a prime query to add notfound.example to the cache. -# Independently, EDE 22 is sent as the authoritative server doesn't respond. -n=$((n + 1)) -echo_i "check notfound.example TXT (max-stale-ttl default) ($n)" -ret=0 -grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1 -grep "EDE: 22 (No Reachable Authority)" dig.out.test$n >/dev/null || ret=1 -grep "EDE: 3 (Stale Answer)" dig.out.test$n >/dev/null && ret=1 -grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) +# Note: the "notfound.example TXT" SERVFAIL+EDE 22 step (the original +# test 125) has been moved to the pytest suite in tests_serve_stale_tcp.py; +# see the comment above where test 120 was removed. # # Now test server with serve-stale answers disabled. @@ -1471,9 +1433,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1546,9 +1506,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1686,9 +1644,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1761,9 +1717,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -1921,10 +1875,19 @@ status=$((status + ret)) if [ $ret != 0 ]; then echo_i "failed"; fi -############################################# -# Test for stale-answer-client-timeout off. # -############################################# -echo_i "test stale-answer-client-timeout (off)" +check_server_responds() { + $DIG -p ${PORT} @10.53.0.3 version.bind txt ch >dig.out.test$n || return 1 + grep "status: NOERROR" dig.out.test$n >/dev/null || return 1 +} + +############################################################## +# Test for stale-answer-client-timeout off and CNAME record. # +############################################################## +# The standalone "stale-answer-client-timeout off" test (the original +# test 163) has been moved to the pytest suite in tests_serve_stale_tcp.py; +# see the comment where test 120 was removed. Its configuration +# (named3.conf) is still used as the base for the CNAME case below. +echo_i "test stale-answer-client-timeout (0) and CNAME record" n=$((n + 1)) echo_i "updating ns3/named.conf ($n)" @@ -1940,45 +1903,13 @@ if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) -# Send a query, auth server is disabled, we will enable it after a while in -# order to receive an answer before resolver-query-timeout expires. Since -# stale-answer-client-timeout is disabled we must receive an answer from -# authoritative server. -echo_i "sending query for test $((n + 2))" -$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$((n + 2)) & -sleep 3 - n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) -# Wait until dig is done. -wait - -n=$((n + 1)) -echo_i "check data.example TXT comes from authoritative server (stale-answer-client-timeout off) ($n)" -grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 -grep "EDE" dig.out.test$n >/dev/null && ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "data\.example\..*[12].*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -check_server_responds() { - $DIG -p ${PORT} @10.53.0.3 version.bind txt ch >dig.out.test$n || return 1 - grep "status: NOERROR" dig.out.test$n >/dev/null || return 1 -} - -############################################################## -# Test for stale-answer-client-timeout off and CNAME record. # -############################################################## -echo_i "test stale-answer-client-timeout (0) and CNAME record" - n=$((n + 1)) echo_i "prime cache shortttl.cname.example (stale-answer-client-timeout off) ($n)" ret=0 @@ -1996,9 +1927,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2020,9 +1949,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2074,9 +2001,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2112,9 +2037,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2173,9 +2096,7 @@ n=$((n + 1)) echo_i "slow down response from authoritative server ($n)" ret=0 - $DIG -p ${PORT} @10.53.0.2 slowdown TXT >dig.out.test$n || ret=1 - grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 - grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 + ans9_control slowdown || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2468,9 +2389,7 @@ echo_i "flush cache, enable responses from authoritative server ($n)" ret=0 $RNDCCMD 10.53.0.3 flushtree example >rndc.out.test$n.1 2>&1 || ret=1 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2490,9 +2409,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2512,9 +2429,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2534,9 +2449,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2577,9 +2490,7 @@ n=$((n + 1)) echo_i "enable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2654,9 +2565,7 @@ n=$((n + 1)) echo_i "disable responses from authoritative server ($n)" ret=0 -$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n || ret=1 -grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1 -grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1 +ans2_control disable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2834,21 +2743,21 @@ rndc_reload ns3 10.53.0.3 # flush cache, enable ans2 responses, make sure serve-stale is on $RNDCCMD 10.53.0.3 flush >rndc.out.test$n.1 2>&1 || ret=1 -$DIG -p ${PORT} @10.53.0.2 txt enable >/dev/null || ret=1 +ans2_control enable || ret=1 $RNDCCMD 10.53.0.3 serve-stale on >rndc.out.test$n.2 2>&1 || ret=1 # prime the cache with an AAAA NXRRSET response $DIG -p ${PORT} @10.53.0.3 a-only.example AAAA >dig.out.1.test$n || ret=1 grep "status: NOERROR" dig.out.1.test$n >/dev/null || ret=1 grep "2001:aaaa" dig.out.1.test$n >/dev/null || ret=1 # disable responses from the auth server -$DIG -p ${PORT} @10.53.0.2 txt disable >/dev/null || ret=1 +ans2_control disable || ret=1 # wait two seconds for the previous answer to become stale sleep 2 # resend the query and wait in the background; we should get a stale answer $DIG -p ${PORT} @10.53.0.3 a-only.example AAAA >dig.out.2.test$n & # re-enable queries after a pause, so the server gets a real answer too sleep 2 -$DIG -p ${PORT} @10.53.0.2 txt enable >/dev/null || ret=1 +ans2_control enable || ret=1 wait grep "status: NOERROR" dig.out.2.test$n >/dev/null || ret=1 grep "2001:aaaa" dig.out.2.test$n >/dev/null || ret=1 @@ -2864,14 +2773,14 @@ ret=0 # flush cache, enable ans2 responses, make sure serve-stale is on $RNDCCMD 10.53.0.3 flush >rndc.out.test$n.1 2>&1 || ret=1 -$DIG -p ${PORT} @10.53.0.2 txt enable >/dev/null || ret=1 +ans2_control enable || ret=1 $RNDCCMD 10.53.0.3 serve-stale on >rndc.out.test$n.2 2>&1 || ret=1 # prime the cache with the A response $DIG -p ${PORT} @10.53.0.3 www.delegated.serve.stale >dig.out.1.test$n || ret=1 grep -F "status: NOERROR" dig.out.1.test$n >/dev/null || ret=1 grep -F "10.53.0.99" dig.out.1.test$n >/dev/null || ret=1 # disable responses from the auth server -$DIG -p ${PORT} @10.53.0.2 txt disable >/dev/null || ret=1 +ans2_control disable || ret=1 # wait two seconds for the previous answer to become stale sleep 2 # resend the query; we should immediately get a stale answer @@ -2880,7 +2789,7 @@ grep -F "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.2.test$n >/dev/null || ret=1 grep -F "10.53.0.99" dig.out.2.test$n >/dev/null || ret=1 # re-enable responses -$DIG -p ${PORT} @10.53.0.2 txt enable >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) @@ -2889,14 +2798,14 @@ ret=0 # flush cache, enable ans2 responses, make sure serve-stale is on $RNDCCMD 10.53.0.3 flush >rndc.out.test$n.1 2>&1 || ret=1 -$DIG -p ${PORT} @10.53.0.2 txt enable >/dev/null || ret=1 +ans2_control enable || ret=1 $RNDCCMD 10.53.0.3 serve-stale on >rndc.out.test$n.2 2>&1 || ret=1 # prime the cache with the A response $DIG -p ${PORT} @10.53.0.3 cname.delegated.serve.stale >dig.out.1.test$n || ret=1 grep -F "status: NOERROR" dig.out.1.test$n >/dev/null || ret=1 grep -F "10.53.0.99" dig.out.1.test$n >/dev/null || ret=1 # disable responses from the auth server -$DIG -p ${PORT} @10.53.0.2 txt disable >/dev/null || ret=1 +ans2_control disable || ret=1 # wait two seconds for the previous answer to become stale sleep 2 # resend the query; we should immediately get a stale answer @@ -2905,7 +2814,7 @@ grep -F "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.2.test$n >/dev/null || ret=1 grep -F "10.53.0.99" dig.out.2.test$n >/dev/null || ret=1 # re-enable responses -$DIG -p ${PORT} @10.53.0.2 txt enable >/dev/null || ret=1 +ans2_control enable || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/tests_serve_stale_ncache.py bind9-9.20.29/bin/tests/system/serve_stale/tests_serve_stale_ncache.py --- bind9-9.20.26/bin/tests/system/serve_stale/tests_serve_stale_ncache.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/tests_serve_stale_ncache.py 2026-09-11 19:41:01.361327645 +0000 @@ -0,0 +1,97 @@ +# 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. + +""" +With "stale-answer-client-timeout 0" a negative cache entry which is still +within its TTL must be answered straight from the cache. Only a stale entry +may trigger a refresh of the RRset. +""" + +import time + +import dns.message +import dns.rcode +import pytest + +from isctest.instance import AnsInstance, NamedInstance + +import isctest + +pytestmark = pytest.mark.extra_artifacts( + [ + "ans*/ans.run", + "ns*/root.bk", + ] +) + +# ans2 answers both of these from a SOA with a 600 second TTL and a 600 +# second MINIMUM, so the negative answer stays fresh for the whole test. +NODATA_NAME = "longttl-nodata.example." +NXDOMAIN_NAME = "longttl-nxdomain.example." + + +def upstream_queries(ans2: AnsInstance, qname: str) -> int: + """Number of TXT queries for `qname` which reached the authoritative server.""" + return len(ans2.log.grep(f"Received {qname.rstrip('.')}/IN/TXT ")) + + +@pytest.fixture(scope="module", autouse=True) +def after_servers_start(ns3: NamedInstance) -> None: + ns3.rndc("serve-stale on") + ns3.rndc("flush") + + +@pytest.mark.parametrize( + "qname,expected_rcode", + [ + pytest.param(NODATA_NAME, dns.rcode.NOERROR, id="nodata"), + pytest.param(NXDOMAIN_NAME, dns.rcode.NXDOMAIN, id="nxdomain"), + ], +) +def test_fresh_ncache_entry_is_not_refreshed( + servers: dict[str, NamedInstance], + ns3: NamedInstance, + qname: str, + expected_rcode: dns.rcode.Rcode, +) -> None: + ans2 = servers["ans2"] + msg = dns.message.make_query(qname, "TXT") + + # Prime the cache; this is the one query the authoritative server is + # allowed to see. + res = isctest.query.udp(msg, ns3.ip) + isctest.check.rcode(res, expected_rcode) + assert not res.answer + + primed = upstream_queries(ans2, qname) + assert primed == 1, "priming the cache should send exactly one upstream query" + + # Repeat the query. The negative answer is nowhere near its expiry, so + # every one of these has to be a cache hit, and none of them may mark the + # answer as stale. + for _ in range(3): + res = isctest.query.udp(msg, ns3.ip) + isctest.check.rcode(res, expected_rcode) + isctest.check.noede(res) + + # Refreshing stale data is detached from the client query, so give it a + # moment to attempt to reach ans2 before concluding it never happened. + time.sleep(1) + + assert ( + upstream_queries(ans2, qname) == primed + ), "a negative cache entry within its TTL was refreshed upstream" + + prohibited_log = ( + f"{qname.rstrip('.')} TXT stale answer used, " + "an attempt to refresh the RRset will still be made" + ) + assert prohibited_log not in ns3.log diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/tests_serve_stale_tcp.py bind9-9.20.29/bin/tests/system/serve_stale/tests_serve_stale_tcp.py --- bind9-9.20.26/bin/tests/system/serve_stale/tests_serve_stale_tcp.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/tests_serve_stale_tcp.py 2026-09-11 19:41:01.361327645 +0000 @@ -0,0 +1,129 @@ +# 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. + +import concurrent.futures +import shutil +import time + +import dns.edns +import dns.exception +import dns.name +import dns.rdataclass +import dns.rdatatype +import pytest + +from isctest.instance import NamedInstance + +import isctest + +pytestmark = pytest.mark.extra_artifacts( + [ + "ans*/ans.run", + "ns*/root.bk", + ] +) + + +def _toggle(mode: str) -> None: + msg = isctest.query.create(f"{mode}.send-responses._control.", "TXT", dnssec=False) + res = isctest.query.udp(msg, "10.53.0.2", attempts=1) + isctest.check.noerror(res) + + +def _toggle_after(delay: float, mode: str) -> None: + time.sleep(delay) + _toggle(mode) + + +@pytest.fixture(scope="module", autouse=True) +def after_servers_start(ns3: NamedInstance) -> None: + """ + Run ns3 with stale answers enabled and stale-answer-client-timeout + disabled (its default value). + """ + shutil.copyfile("ns3/named3.conf", "ns3/named.conf") + ns3.reconfigure() + ns3.rndc("flush") + + +def test_no_stale_data_times_out(): + """Verify the resolver does not answer until the query timeout. + + With the authoritative server unresponsive and the queried name + absent from the cache, the client must not receive a fast SERVFAIL + (the original test 120 in tests.sh); the resolver holds the query + until its own resolver-query-timeout expires, which is longer than + the second this client waits. + """ + + _toggle("disable") + msg = isctest.query.create("notincache.example.", "TXT", dnssec=False) + start = time.monotonic() + with pytest.raises(dns.exception.Timeout): + isctest.query.udp(msg, "10.53.0.3", timeout=1, attempts=1) + assert time.monotonic() - start >= 1 + + +def test_servfail_with_ede22(): + """Verify SERVFAIL carries EDE 22 (and not EDE 3) when auth is unreachable. + + With the authoritative server unresponsive and no cached data to + serve stale, the resolver must return SERVFAIL with EDE 22 (No + Reachable Authority) and must not attach EDE 3 (Stale Answer) + (the original test 125 in tests.sh). + """ + + _toggle("disable") + msg = isctest.query.create("notfound.example.", "TXT", dnssec=False) + res = isctest.query.udp(msg, "10.53.0.3", timeout=15, attempts=1) + isctest.check.servfail(res) + isctest.check.ede(res, dns.edns.EDECode.NO_REACHABLE_AUTHORITY) + assert not any( + opt.otype == dns.edns.OptionType.EDE + and opt.code == dns.edns.EDECode.STALE_ANSWER + for opt in res.options + ), "unexpected stale-answer EDE in SERVFAIL response" + assert len(res.answer) == 0 + + +def test_authoritative_answer_after_reenable(): + """Verify the resolver waits for auth to recover instead of failing fast. + + Prime the cache, let the TTL expire, disable the authoritative + server, issue a query, and re-enable the authoritative server + while the query is still in flight. The resolver must return an + authoritative NOERROR answer with no EDE attached, not a stale + answer or SERVFAIL (the original test 163 in tests.sh). + """ + + _toggle("enable") + msg = isctest.query.create("data.example.", "TXT", dnssec=False) + isctest.check.noerror(isctest.query.udp(msg, "10.53.0.3", timeout=5)) + + # allow the 2s TTL to expire + time.sleep(3) + + _toggle("disable") + + with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool: + reenable = pool.submit(_toggle_after, 1.0, "enable") + res = isctest.query.udp(msg, "10.53.0.3", timeout=15, attempts=1) + reenable.result() + + isctest.check.noerror(res) + isctest.check.noede(res) + answer = res.find_rrset( + res.answer, + dns.name.from_text("data.example."), + dns.rdataclass.IN, + dns.rdatatype.TXT, + ) + assert "A text record with a 2 second ttl" in str(answer[0]) diff -Nru bind9-9.20.26/bin/tests/system/serve_stale/tests_sh_serve_stale.py bind9-9.20.29/bin/tests/system/serve_stale/tests_sh_serve_stale.py --- bind9-9.20.26/bin/tests/system/serve_stale/tests_sh_serve_stale.py 2026-07-20 14:47:53.892847300 +0000 +++ bind9-9.20.29/bin/tests/system/serve_stale/tests_sh_serve_stale.py 2026-09-11 19:41:01.361327645 +0000 @@ -11,19 +11,20 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "rndc.out.*", "ans*/ans.run", "ns*/named.stats*", "ns*/named_dump*", - "ns*/named.stats*", "ns*/root.bk", "ns1/stale.test.db.jnl", ] ) +pytestmark = EXTRA_ARTIFACTS + @pytest.mark.flaky(max_runs=2) def test_serve_stale(run_tests_sh): diff -Nru bind9-9.20.26/bin/tests/system/sfcache/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/sfcache/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/sfcache/ns1/named.conf.j2 2026-07-20 14:47:53.892847300 +0000 +++ bind9-9.20.29/bin/tests/system/sfcache/ns1/named.conf.j2 2026-09-11 19:41:01.361327645 +0000 @@ -14,18 +14,13 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; diff -Nru bind9-9.20.26/bin/tests/system/sfcache/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/sfcache/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/sfcache/ns2/named.conf.j2 2026-07-20 14:47:53.893847316 +0000 +++ bind9-9.20.29/bin/tests/system/sfcache/ns2/named.conf.j2 2026-09-11 19:41:01.362327668 +0000 @@ -14,31 +14,14 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/sfcache/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/sfcache/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/sfcache/ns5/named.conf.j2 2026-07-20 14:47:53.893847316 +0000 +++ bind9-9.20.29/bin/tests/system/sfcache/ns5/named.conf.j2 2026-09-11 19:41:01.362327668 +0000 @@ -14,30 +14,13 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; servfail-ttl 30; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} include "trusted.conf"; diff -Nru bind9-9.20.26/bin/tests/system/sfcache_cname/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/sfcache_cname/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/sfcache_cname/ns1/named.conf.j2 2026-07-20 14:47:53.893847316 +0000 +++ bind9-9.20.29/bin/tests/system/sfcache_cname/ns1/named.conf.j2 2026-09-11 19:41:01.362327668 +0000 @@ -1,16 +1,12 @@ options { - query-source address @ns.ip@; - notify-source @ns.ip@; - transfer-source @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; - recursion no; - dnssec-validation no; + {% include_indented "_common/options.conf.j2" %} + recursion no; + dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { - type primary; - file "root.db"; + type primary; + file "root.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/sfcache_cname/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/sfcache_cname/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/sfcache_cname/ns2/named.conf.j2 2026-07-20 14:47:53.894847331 +0000 +++ bind9-9.20.29/bin/tests/system/sfcache_cname/ns2/named.conf.j2 2026-09-11 19:41:01.362327668 +0000 @@ -1,16 +1,13 @@ options { - query-source address @ns.ip@; - port @PORT@; - pid-file "named.pid"; - listen-on { @ns.ip@; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; qname-minimization off; servfail-ttl 5; max-query-count 2; }; +{% include "_common/controls.conf.j2" %} + zone "tld1." { type static-stub; server-addresses { 10.53.0.1; }; diff -Nru bind9-9.20.26/bin/tests/system/shutdown/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/shutdown/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/shutdown/ns1/named.conf.j2 2026-07-20 14:47:53.894847331 +0000 +++ bind9-9.20.29/bin/tests/system/shutdown/ns1/named.conf.j2 2026-09-11 19:41:01.363327693 +0000 @@ -11,32 +11,19 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - listen-on { 10.53.0.1; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation no; allow-query { any; }; - recursion yes; allow-recursion { any; }; }; # Delegate .test domain to 10.53.0.2 zone "." { - type primary; - file "root.db"; - allow-transfer { none; }; + type primary; + file "root.db"; + allow-transfer { none; }; }; diff -Nru bind9-9.20.26/bin/tests/system/shutdown/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/shutdown/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/shutdown/ns2/named.conf.j2 2026-07-20 14:47:53.894847331 +0000 +++ bind9-9.20.29/bin/tests/system/shutdown/ns2/named.conf.j2 2026-09-11 19:41:01.363327693 +0000 @@ -11,28 +11,16 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - listen-on { 10.53.0.2; }; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation no; allow-query { any; }; }; -# 10.53.0.2 is authoritative for .test domain +# @ns.ip@ is authoritative for .test domain zone "test" { type primary; file "test.db"; diff -Nru bind9-9.20.26/bin/tests/system/shutdown/resolver/named.conf.j2 bind9-9.20.29/bin/tests/system/shutdown/resolver/named.conf.j2 --- bind9-9.20.26/bin/tests/system/shutdown/resolver/named.conf.j2 2026-07-20 14:47:53.894847331 +0000 +++ bind9-9.20.29/bin/tests/system/shutdown/resolver/named.conf.j2 2026-09-11 19:41:01.363327693 +0000 @@ -21,10 +21,11 @@ }; key rndc_key { - secret "1234abcd8765"; + secret "1234abcd8765"; algorithm @DEFAULT_HMAC@; }; +/* deliberately not _common/controls.conf.j2: non-ns directory without the ns.ip template variable */ controls { inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; }; @@ -35,6 +36,7 @@ transfer-source 10.53.0.3; port @PORT@; listen-on { 10.53.0.3; }; + listen-on-v6 { none; }; pid-file "named.pid"; notify no; dnssec-validation no; diff -Nru bind9-9.20.26/bin/tests/system/sig0/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/sig0/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/sig0/ns1/named.conf.j2 2026-07-20 14:47:53.895847347 +0000 +++ bind9-9.20.29/bin/tests/system/sig0/ns1/named.conf.j2 2026-09-11 19:41:01.363327693 +0000 @@ -12,25 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; notify no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} view "v1" { match-clients { any; }; diff -Nru bind9-9.20.26/bin/tests/system/sig0_https/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/sig0_https/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/sig0_https/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/sig0_https/ns1/named.conf.j2 2026-09-11 19:41:01.364327717 +0000 @@ -0,0 +1,7 @@ +options { + {% include_indented "_common/options.conf.j2" %} + https-port @HTTPSPORT@; + listen-on tls ephemeral http default { @ns.ip@; }; +}; + +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/sig0_https/tests_sig0_https.py bind9-9.20.29/bin/tests/system/sig0_https/tests_sig0_https.py --- bind9-9.20.26/bin/tests/system/sig0_https/tests_sig0_https.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/sig0_https/tests_sig0_https.py 2026-09-11 19:41:01.364327717 +0000 @@ -0,0 +1,111 @@ +# 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. + +import socket +import ssl +import struct +import time + +from h2.connection import H2Connection + +import dns.message +import dns.name +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.rrset + +import isctest.mark + +pytestmark = [isctest.mark.with_libnghttp2] + + +def sig0_wire(): + now = int(time.time()) + + # dnspython doesn't seems to have a way to put this in a higher level way, + # so let's construct the SIG(0) rdata "manually". + # `!` means network byte order, `H` 2 bytes, `B` 1 byte, `I` 4 bytes. + sig_rdata = ( + struct.pack( + "!HBBIIIH", + 0, # 0 as SIG(0) doesn't sign a specific RR type, but the whole message. + 8, # RSA/SHA-256 (but it could by anything for this attack) + 0, # Labels: SIG(0) does not describe a DNS name, so this is zero + 0, # TTL + now + 300, # Expiration + now - 300, # Inception + 123, # Key tag (could also be anything for this attack) + ) + + (dns.name.from_text("sig0.invalid.").to_wire()) + + (b"\x00" * 256) # The invalid signature + ) + + sig = dns.rdata.from_wire( + dns.rdataclass.ANY, + dns.rdatatype.SIG, + sig_rdata, + 0, + len(sig_rdata), + ) + + msg = dns.message.make_query( + ".", + dns.rdatatype.SOA, + dns.rdataclass.IN, + ) + + msg.additional.append( + dns.rrset.from_rdata( + dns.name.root, + 0, + sig, + ) + ) + + return msg.to_wire() + + +def test_sig0_doh(ns1, named_httpsport): + msg = sig0_wire() + + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + + with socket.create_connection((ns1.ip, named_httpsport)) as sock: + with ctx.wrap_socket(sock) as conn: + h2 = H2Connection() + h2.initiate_connection() + + stream = h2.get_next_available_stream_id() + h2.send_headers( + stream, + [ + (":method", "POST"), + (":scheme", "https"), + (":authority", f"{ns1.ip}:{named_httpsport}"), + (":path", "/dns-query"), + ("content-type", "application/dns-message"), + ("content-length", str(len(msg))), + ], + ) + h2.send_data(stream, msg, end_stream=True) + + # Send the query and immediately close the connection. + # named should gracefully handle the fact the connection is + # now closed after it checked the message signature. + conn.sendall(h2.data_to_send()) + + # If the server succesfully restarted, it means it didn't crash. + with ns1.watch_log_from_here() as watcher: + ns1.rndc("reload") + watcher.wait_for_line("running") diff -Nru bind9-9.20.26/bin/tests/system/sortlist/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/sortlist/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/sortlist/ns1/named.conf.j2 2026-07-20 14:47:53.895847347 +0000 +++ bind9-9.20.29/bin/tests/system/sortlist/ns1/named.conf.j2 2026-09-11 19:41:01.364327717 +0000 @@ -12,16 +12,9 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; sortlist { { 10.53.0.1; // IF 10.53.0.1 @@ -35,6 +28,8 @@ }; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/spf/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/spf/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/spf/ns1/named.conf.j2 2026-07-20 14:47:53.896847362 +0000 +++ bind9-9.20.29/bin/tests/system/spf/ns1/named.conf.j2 2026-09-11 19:41:01.365327740 +0000 @@ -12,19 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; ixfr-from-differences yes; }; +{% include "_common/controls.conf.j2" %} + zone "spf" { type primary; file "spf.db"; diff -Nru bind9-9.20.26/bin/tests/system/srtt/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/srtt/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/srtt/ns1/named.conf.j2 2026-07-20 14:47:53.897847378 +0000 +++ bind9-9.20.29/bin/tests/system/srtt/ns1/named.conf.j2 2026-09-11 19:41:01.366327764 +0000 @@ -12,17 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/srtt/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/srtt/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/srtt/ns6/named.conf.j2 2026-07-20 14:47:53.897847378 +0000 +++ bind9-9.20.29/bin/tests/system/srtt/ns6/named.conf.j2 2026-09-11 19:41:01.366327764 +0000 @@ -13,29 +13,12 @@ options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; dnstap { resolver query; }; dnstap-output file "dnstap.out"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/ssumaxtype/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/ssumaxtype/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ssumaxtype/ns1/named.conf.j2 2026-07-20 14:47:53.898847393 +0000 +++ bind9-9.20.29/bin/tests/system/ssumaxtype/ns1/named.conf.j2 2026-09-11 19:41:01.366327764 +0000 @@ -12,25 +12,12 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key "ddns-key" { algorithm @DEFAULT_HMAC@; diff -Nru bind9-9.20.26/bin/tests/system/ssutoctou/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/ssutoctou/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ssutoctou/ns1/named.conf.j2 2026-07-20 14:47:53.898847393 +0000 +++ bind9-9.20.29/bin/tests/system/ssutoctou/ns1/named.conf.j2 2026-09-11 19:41:01.367327788 +0000 @@ -14,25 +14,12 @@ {% set use_ssu = use_ssu | default(False) %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/staticstub/conf/bad02.conf bind9-9.20.29/bin/tests/system/staticstub/conf/bad02.conf --- bind9-9.20.26/bin/tests/system/staticstub/conf/bad02.conf 2026-07-20 14:47:53.899847409 +0000 +++ bind9-9.20.29/bin/tests/system/staticstub/conf/bad02.conf 2026-09-11 19:41:01.367327788 +0000 @@ -27,6 +27,6 @@ # server-names must be valid domain names. zone "example.com" { - type static-stub; - server-names { "\11.example.net"; }; + type static-stub; + server-names { "\11.example.net"; }; }; diff -Nru bind9-9.20.26/bin/tests/system/staticstub/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/staticstub/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/staticstub/ns1/named.conf.j2 2026-07-20 14:47:53.900847424 +0000 +++ bind9-9.20.29/bin/tests/system/staticstub/ns1/named.conf.j2 2026-09-11 19:41:01.369327836 +0000 @@ -12,14 +12,12 @@ */ options { - query-source address 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/staticstub/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/staticstub/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/staticstub/ns2/named.conf.j2 2026-07-20 14:47:53.901847440 +0000 +++ bind9-9.20.29/bin/tests/system/staticstub/ns2/named.conf.j2 2026-09-11 19:41:01.369327836 +0000 @@ -13,35 +13,18 @@ {% set server_config_use_addr = server_config_use_addr | default(False) %} -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "trusted.conf"; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; notify no; minimal-responses no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type static-stub; diff -Nru bind9-9.20.26/bin/tests/system/staticstub/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/staticstub/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/staticstub/ns3/named.conf.j2 2026-07-20 14:47:53.901847440 +0000 +++ bind9-9.20.29/bin/tests/system/staticstub/ns3/named.conf.j2 2026-09-11 19:41:01.369327836 +0000 @@ -13,23 +13,10 @@ {% set example_zone = example_zone | default(True) %} -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; diff -Nru bind9-9.20.26/bin/tests/system/staticstub/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/staticstub/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/staticstub/ns4/named.conf.j2 2026-07-20 14:47:53.902847456 +0000 +++ bind9-9.20.29/bin/tests/system/staticstub/ns4/named.conf.j2 2026-09-11 19:41:01.370327860 +0000 @@ -12,18 +12,17 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + listen-on { @ns.ip@; }; listen-on-v6 { ::1; }; recursion no; dnssec-validation no; notify no; }; +{% include "_common/controls.conf.j2" %} + zone "example.com" { type primary; file "example.com.db"; diff -Nru bind9-9.20.26/bin/tests/system/statistics/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/statistics/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/statistics/ns1/named.conf.j2 2026-07-20 14:47:53.902847456 +0000 +++ bind9-9.20.29/bin/tests/system/statistics/ns1/named.conf.j2 2026-09-11 19:41:01.371327884 +0000 @@ -12,21 +12,16 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.1 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/statistics/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/statistics/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/statistics/ns2/named.conf.j2 2026-07-20 14:47:53.903847471 +0000 +++ bind9-9.20.29/bin/tests/system/statistics/ns2/named.conf.j2 2026-09-11 19:41:01.371327884 +0000 @@ -12,38 +12,20 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.2 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/statistics/ns2/named1.conf.j2 bind9-9.20.29/bin/tests/system/statistics/ns2/named1.conf.j2 --- bind9-9.20.26/bin/tests/system/statistics/ns2/named1.conf.j2 2026-07-20 14:47:53.903847471 +0000 +++ bind9-9.20.29/bin/tests/system/statistics/ns2/named1.conf.j2 2026-09-11 19:41:01.371327884 +0000 @@ -12,38 +12,20 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.2 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/statistics/ns2/named2.conf.j2 bind9-9.20.29/bin/tests/system/statistics/ns2/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/statistics/ns2/named2.conf.j2 2026-07-20 14:47:53.903847471 +0000 +++ bind9-9.20.29/bin/tests/system/statistics/ns2/named2.conf.j2 2026-09-11 19:41:01.371327884 +0000 @@ -12,38 +12,20 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.2 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/statistics/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/statistics/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/statistics/ns3/named.conf.j2 2026-07-20 14:47:53.903847471 +0000 +++ bind9-9.20.29/bin/tests/system/statistics/ns3/named.conf.j2 2026-09-11 19:41:01.371327884 +0000 @@ -12,35 +12,19 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; qname-minimization disabled; zone-statistics yes; }; {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.3 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/statistics/prereq.sh bind9-9.20.29/bin/tests/system/statistics/prereq.sh --- bind9-9.20.26/bin/tests/system/statistics/prereq.sh 2026-07-20 14:47:53.903847471 +0000 +++ bind9-9.20.29/bin/tests/system/statistics/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/statschannel/generic.py bind9-9.20.29/bin/tests/system/statschannel/generic.py --- bind9-9.20.26/bin/tests/system/statschannel/generic.py 2026-07-20 14:47:53.904847487 +0000 +++ bind9-9.20.29/bin/tests/system/statschannel/generic.py 2026-09-11 19:41:01.372327908 +0000 @@ -10,7 +10,7 @@ # information regarding copyright ownership. from collections import defaultdict -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from time import sleep import os @@ -19,13 +19,14 @@ import isctest -# ISO datetime format without msec -FMT = "%Y-%m-%dT%H:%M:%SZ" +# ISO datetime format without msec (the %z directive parses the trailing "Z" +# as UTC, yielding timezone-aware datetimes) +FMT = "%Y-%m-%dT%H:%M:%S%z" # The constants were taken from BIND 9 source code (lib/dns/zone.c) max_refresh = timedelta(seconds=2419200) # 4 weeks max_expires = timedelta(seconds=14515200) # 24 weeks -dayzero = datetime.utcfromtimestamp(0).replace(microsecond=0) +dayzero = datetime.fromtimestamp(0, timezone.utc).replace(microsecond=0) # Wait for the secondary zone files to appear to extract their mtime MAX_SECONDARY_ZONE_WAITTIME_SEC = 5 @@ -49,7 +50,7 @@ def check_zone_timers(loaded, expires, refresh, loaded_exp): - now = datetime.utcnow().replace(microsecond=0) + now = datetime.now(timezone.utc).replace(microsecond=0) # Sanity checks the zone timers values if expires is not None: check_expires(expires, now, now + max_expires) @@ -72,7 +73,7 @@ except FileNotFoundError: return dayzero - mtime = datetime.utcfromtimestamp(si.st_mtime).replace(microsecond=0) + mtime = datetime.fromtimestamp(si.st_mtime, timezone.utc).replace(microsecond=0) return mtime diff -Nru bind9-9.20.26/bin/tests/system/statschannel/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/statschannel/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/statschannel/ns1/named.conf.j2 2026-07-20 14:47:53.904847487 +0000 +++ bind9-9.20.29/bin/tests/system/statschannel/ns1/named.conf.j2 2026-09-11 19:41:01.373327932 +0000 @@ -12,18 +12,9 @@ */ options { - query-source address 10.53.0.1; - query-source-v6 address fd92:7065:b8e:ffff::1; - notify-source 10.53.0.1; - notify-source-v6 fd92:7065:b8e:ffff::1; - transfer-source 10.53.0.1; - transfer-source-v6 fd92:7065:b8e:ffff::1; - port @PORT@; + {% include_indented "_common/options-dual.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { fd92:7065:b8e:ffff::1; }; - listen-on-v6 tls ephemeral { fd92:7065:b8e:ffff::1; }; + listen-on-v6 tls ephemeral { @ns.ip6@; }; recursion no; dnssec-validation no; notify explicit; @@ -31,16 +22,9 @@ version none; // make statistics independent of the version number }; -statistics-channels { inet 10.53.0.1 port @EXTRAPORT1@ allow { localhost; }; }; +statistics-channels { inet @ns.ip@ port @EXTRAPORT1@ allow { localhost; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} server 10.53.0.3 { transfer-format one-answer; diff -Nru bind9-9.20.26/bin/tests/system/statschannel/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/statschannel/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/statschannel/ns2/named.conf.j2 2026-07-20 14:47:53.905847502 +0000 +++ bind9-9.20.29/bin/tests/system/statschannel/ns2/named.conf.j2 2026-09-11 19:41:01.373327932 +0000 @@ -12,13 +12,7 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; @@ -27,16 +21,9 @@ sig-signing-signatures 100; }; -statistics-channels { inet 10.53.0.2 port @EXTRAPORT1@ allow { localhost; }; }; +statistics-channels { inet @ns.ip@ port @EXTRAPORT1@ allow { localhost; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "dnssec" { inline-signing no; diff -Nru bind9-9.20.26/bin/tests/system/statschannel/ns2/named2.conf.j2 bind9-9.20.29/bin/tests/system/statschannel/ns2/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/statschannel/ns2/named2.conf.j2 2026-07-20 14:47:53.905847502 +0000 +++ bind9-9.20.29/bin/tests/system/statschannel/ns2/named2.conf.j2 2026-09-11 19:41:01.373327932 +0000 @@ -12,13 +12,7 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; @@ -27,16 +21,9 @@ sig-signing-signatures 100; }; -statistics-channels { inet 10.53.0.2 port @EXTRAPORT1@ allow { localhost; }; }; +statistics-channels { inet @ns.ip@ port @EXTRAPORT1@ allow { localhost; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "dnssec" { keys { diff -Nru bind9-9.20.26/bin/tests/system/statschannel/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/statschannel/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/statschannel/ns3/named.conf.j2 2026-07-20 14:47:53.905847502 +0000 +++ bind9-9.20.29/bin/tests/system/statschannel/ns3/named.conf.j2 2026-09-11 19:41:01.373327932 +0000 @@ -12,17 +12,10 @@ */ options { - query-source address 10.53.0.3; - query-source-v6 fd92:7065:b8e:ffff::3; - notify-source 10.53.0.3; - notify-source-v6 fd92:7065:b8e:ffff::3; - transfer-source 10.53.0.3; - transfer-source-v6 fd92:7065:b8e:ffff::3; - port @PORT@; + {% include_indented "_common/options/sources-dual.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + {% include_indented "_common/options/listen.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; recursion no; dnssec-validation no; notify no; @@ -31,16 +24,9 @@ allow-new-zones yes; }; -statistics-channels { inet 10.53.0.3 port @EXTRAPORT1@ allow { localhost; }; }; +statistics-channels { inet @ns.ip@ port @EXTRAPORT1@ allow { localhost; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} server fd92:7065:b8e:ffff::1 { tcp-only yes; diff -Nru bind9-9.20.26/bin/tests/system/statschannel/prereq.sh bind9-9.20.29/bin/tests/system/statschannel/prereq.sh --- bind9-9.20.26/bin/tests/system/statschannel/prereq.sh 2026-07-20 14:47:53.905847502 +0000 +++ bind9-9.20.29/bin/tests/system/statschannel/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -if ! ${PERL} -MFile::Fetch -e ''; then - echo_i "perl File::Fetch module is required" - exit 1 -fi - -if ! $FEATURETEST --have-libxml2 && ! $FEATURETEST --have-json-c; then - echo_i "skip: one or both of --with-libxml2 and --with-json-c required" - exit 255 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/statschannel/tests_sh_statschannel.py bind9-9.20.29/bin/tests/system/statschannel/tests_sh_statschannel.py --- bind9-9.20.26/bin/tests/system/statschannel/tests_sh_statschannel.py 2026-07-20 14:47:53.906847518 +0000 +++ bind9-9.20.29/bin/tests/system/statschannel/tests_sh_statschannel.py 2026-09-11 19:41:01.374327956 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "K*", "bind9.xsl.1", @@ -50,6 +52,11 @@ ] ) +pytestmark = [ + isctest.mark.with_libxml2_or_json_c, + EXTRA_ARTIFACTS, +] + def test_statschannel(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/stress/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/stress/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/stress/ns2/named.conf.j2 2026-07-20 14:47:53.907847533 +0000 +++ bind9-9.20.29/bin/tests/system/stress/ns2/named.conf.j2 2026-09-11 19:41:01.375327980 +0000 @@ -11,19 +11,12 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; zone "zone000000.example" { diff -Nru bind9-9.20.26/bin/tests/system/stress/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/stress/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/stress/ns3/named.conf.j2 2026-07-20 14:47:53.907847533 +0000 +++ bind9-9.20.29/bin/tests/system/stress/ns3/named.conf.j2 2026-09-11 19:41:01.375327980 +0000 @@ -11,30 +11,12 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; - options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; - -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} server 10.53.0.4 { provide-ixfr no; diff -Nru bind9-9.20.26/bin/tests/system/stress/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/stress/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/stress/ns4/named.conf.j2 2026-07-20 14:47:53.907847533 +0000 +++ bind9-9.20.29/bin/tests/system/stress/ns4/named.conf.j2 2026-09-11 19:41:01.375327980 +0000 @@ -11,19 +11,11 @@ * information regarding copyright ownership. */ -controls { /* empty */ }; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; diff -Nru bind9-9.20.26/bin/tests/system/stress/prereq.sh bind9-9.20.29/bin/tests/system/stress/prereq.sh --- bind9-9.20.26/bin/tests/system/stress/prereq.sh 2026-07-20 14:47:53.907847533 +0000 +++ bind9-9.20.29/bin/tests/system/stress/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/stub/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/stub/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/stub/ns1/named.conf.j2 2026-07-20 14:47:53.907847533 +0000 +++ bind9-9.20.29/bin/tests/system/stub/ns1/named.conf.j2 2026-09-11 19:41:01.376328004 +0000 @@ -12,19 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; minimal-responses no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/stub/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/stub/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/stub/ns2/named.conf.j2 2026-07-20 14:47:53.908847549 +0000 +++ bind9-9.20.29/bin/tests/system/stub/ns2/named.conf.j2 2026-09-11 19:41:01.376328004 +0000 @@ -12,23 +12,15 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; minimal-responses no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "child.example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/stub/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/stub/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/stub/ns3/named.conf.j2 2026-07-20 14:47:53.908847549 +0000 +++ bind9-9.20.29/bin/tests/system/stub/ns3/named.conf.j2 2026-09-11 19:41:01.376328004 +0000 @@ -12,32 +12,14 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; minimal-responses no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/stub/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/stub/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/stub/ns4/named.conf.j2 2026-07-20 14:47:53.908847549 +0000 +++ bind9-9.20.29/bin/tests/system/stub/ns4/named.conf.j2 2026-09-11 19:41:01.376328004 +0000 @@ -12,19 +12,14 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; minimal-responses yes; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/stub/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/stub/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/stub/ns5/named.conf.j2 2026-07-20 14:47:53.908847549 +0000 +++ bind9-9.20.29/bin/tests/system/stub/ns5/named.conf.j2 2026-09-11 19:41:01.376328004 +0000 @@ -12,20 +12,13 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "example" { type stub; diff -Nru bind9-9.20.26/bin/tests/system/svcb_alias/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/svcb_alias/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/svcb_alias/ns1/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/svcb_alias/ns1/named.conf.j2 2026-09-11 19:41:01.377328028 +0000 @@ -0,0 +1,14 @@ +{% include "_common/controls.conf.j2" %} +options { + {% include_indented "_common/options.conf.j2" %} + recursion yes; + dnssec-validation no; + allow-query { any; }; + allow-recursion { any; }; + // minimal-responses defaults to no-auth-recursive, the affected setting +}; + +zone "." { + type hint; + file "root.hint"; +}; diff -Nru bind9-9.20.26/bin/tests/system/svcb_alias/ns1/root.hint bind9-9.20.29/bin/tests/system/svcb_alias/ns1/root.hint --- bind9-9.20.26/bin/tests/system/svcb_alias/ns1/root.hint 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/svcb_alias/ns1/root.hint 2026-09-11 19:41:01.377328028 +0000 @@ -0,0 +1,2 @@ +. IN NS ns2. +ns2. IN A 10.53.0.2 diff -Nru bind9-9.20.26/bin/tests/system/svcb_alias/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/svcb_alias/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/svcb_alias/ns2/named.conf.j2 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/svcb_alias/ns2/named.conf.j2 2026-09-11 19:41:01.377328028 +0000 @@ -0,0 +1,16 @@ +{% include "_common/controls.conf.j2" %} +options { + {% include_indented "_common/options.conf.j2" %} + recursion no; + dnssec-validation no; +}; + +zone "." { + type primary; + file "root.db"; +}; + +zone "tree.example" { + type primary; + file "tree.db"; +}; diff -Nru bind9-9.20.26/bin/tests/system/svcb_alias/ns2/root.db bind9-9.20.29/bin/tests/system/svcb_alias/ns2/root.db --- bind9-9.20.26/bin/tests/system/svcb_alias/ns2/root.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/svcb_alias/ns2/root.db 2026-09-11 19:41:01.377328028 +0000 @@ -0,0 +1,5 @@ +$TTL 86400 +. IN SOA ns2. hostmaster.ns2. ( 1 3600 1800 604800 86400 ) +. IN NS ns2. +ns2. IN A 10.53.0.2 +tree.example. IN NS ns2. diff -Nru bind9-9.20.26/bin/tests/system/svcb_alias/setup.sh bind9-9.20.29/bin/tests/system/svcb_alias/setup.sh --- bind9-9.20.26/bin/tests/system/svcb_alias/setup.sh 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/svcb_alias/setup.sh 2026-09-11 19:41:01.377328028 +0000 @@ -0,0 +1,36 @@ +#!/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 + +# Branching factor equals DNS_RDATASET_MAXADDITIONAL so every RRset passes +# the per-RRset additional-processing limit. PARENTS is the highest node +# index that still owns an HTTPS RRset; its children are empty leaves. +BRANCHES=13 +PARENTS=182 + +{ + echo "\$TTL 43200" + echo "@ IN SOA ns2. hostmaster.ns2. ( 1 3600 1800 604800 86400 )" + echo "@ IN NS ns2." +} >ns2/tree.db + +awk -v b="$BRANCHES" -v p="$PARENTS" 'END { + for (i = 0; i <= p; i++) { + for (j = 1; j <= b; j++) { + printf "n%d\tIN HTTPS\t0 n%d\n", i, b * i + j + } + } +}' >ns2/tree.db diff -Nru bind9-9.20.26/bin/tests/system/svcb_alias/tests_svcb_alias.py bind9-9.20.29/bin/tests/system/svcb_alias/tests_svcb_alias.py --- bind9-9.20.26/bin/tests/system/svcb_alias/tests_svcb_alias.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/svcb_alias/tests_svcb_alias.py 2026-09-11 19:41:01.377328028 +0000 @@ -0,0 +1,88 @@ +# 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. + +import dns.rcode +import pytest + +import isctest + +pytestmark = pytest.mark.extra_artifacts( + [ + "ns2/tree.db", + ] +) + +# Highest node index that owns an HTTPS RRset in ns2/tree.db (setup.sh). Its +# children are empty leaves, so the tree served from cache is three levels +# deep: n0 (root), n1..n13, n14..n182. +PARENTS = 182 + +# DNS_RDATASET_MAXADDITIONAL from lib/dns/include/dns/rdataset.h: the most +# records one RRset contributes to a single level of additional processing. +MAXADDITIONAL = 13 + + +def _additional_rrs(res): + return sum(len(rrset) for rrset in res.additional) + + +def _query_tcp(ns, index): + msg = isctest.query.create(f"n{index}.tree.example.", "HTTPS") + # Query over TCP so the additional section is not capped by the UDP buffer. + res = isctest.query.tcp(msg, ns.ip) + isctest.check.noerror(res) + return res + + +def test_svcb_alias_tree_additional_is_bounded(ns1): + """ + A cached tree of HTTPS AliasMode records must not let a single query walk + the whole tree while building the additional section. + + ns2 serves a 13-way HTTPS AliasMode tree. Priming the resolver cache + top-down (ascending index, so every node's children are still cache misses + while it is being cached) plants the tree without any single response + walking it. A query for the root then follows every cached descendant: + the per-RRset limit (DNS_RDATASET_MAXADDITIONAL) and the per-path depth + limit (max-restarts) each bound one path, but neither bounds the aggregate + number of records visited across the sibling paths. + """ + # Prime the cache with every node that owns an HTTPS RRset. + for i in range(PARENTS + 1): + res = isctest.query.udp( + isctest.query.create(f"n{i}.tree.example.", "HTTPS"), + ns1.ip, + expected_rcode=dns.rcode.NOERROR, + ) + isctest.check.noerror(res) + + # Root of the full three-level tree. + root = _query_tcp(ns1, 0) + # A node one level down: its grandchildren are empty leaves, so following + # it touches only a single level of the tree. This is roughly the amount + # of additional data a bounded resolver should also produce for the root. + shallow = _query_tcp(ns1, 1) + + isctest.log.info( + "additional records: root=%d (names=%d) shallow=%d (names=%d)", + _additional_rrs(root), + len(root.additional), + _additional_rrs(shallow), + len(shallow.additional), + ) + + # Without an aggregate limit, the root walk visits the whole planted tree + # and its additional section grows with the tree. With the limit in place + # the walk is cut to roughly one level, so the root must not carry more + # than about one extra RRset's worth of additional names beyond a node + # whose own subtree is a single level. This pins the behaviour without + # depending on the limit's exact value. + assert len(root.additional) <= len(shallow.additional) + MAXADDITIONAL diff -Nru bind9-9.20.26/bin/tests/system/synthfromdnssec/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/synthfromdnssec/ns1/named.conf.j2 2026-07-20 14:47:53.909847564 +0000 +++ bind9-9.20.29/bin/tests/system/synthfromdnssec/ns1/named.conf.j2 2026-09-11 19:41:01.378328052 +0000 @@ -14,30 +14,16 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.1 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/synthfromdnssec/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/synthfromdnssec/ns2/named.conf.j2 2026-07-20 14:47:53.909847564 +0000 +++ bind9-9.20.29/bin/tests/system/synthfromdnssec/ns2/named.conf.j2 2026-09-11 19:41:01.378328052 +0000 @@ -14,30 +14,16 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.2 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/synthfromdnssec/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/synthfromdnssec/ns3/named.conf.j2 2026-07-20 14:47:53.909847564 +0000 +++ bind9-9.20.29/bin/tests/system/synthfromdnssec/ns3/named.conf.j2 2026-09-11 19:41:01.378328052 +0000 @@ -14,30 +14,16 @@ // NS3 options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.3 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/synthfromdnssec/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/synthfromdnssec/ns4/named.conf.j2 2026-07-20 14:47:53.910847580 +0000 +++ bind9-9.20.29/bin/tests/system/synthfromdnssec/ns4/named.conf.j2 2026-09-11 19:41:01.378328052 +0000 @@ -14,31 +14,17 @@ // NS4 options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation yes; synth-from-dnssec no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.4 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/synthfromdnssec/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/synthfromdnssec/ns5/named.conf.j2 2026-07-20 14:47:53.910847580 +0000 +++ bind9-9.20.29/bin/tests/system/synthfromdnssec/ns5/named.conf.j2 2026-09-11 19:41:01.379328076 +0000 @@ -14,32 +14,18 @@ // NS5 options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation yes; synth-from-dnssec yes; validate-except { example.internal; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.5 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/synthfromdnssec/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/synthfromdnssec/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/synthfromdnssec/ns6/named.conf.j2 2026-07-20 14:47:53.910847580 +0000 +++ bind9-9.20.29/bin/tests/system/synthfromdnssec/ns6/named.conf.j2 2026-09-11 19:41:01.379328076 +0000 @@ -14,31 +14,17 @@ // NS6 options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} notify no; dnssec-validation no; synth-from-dnssec yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} {% if FEATURE_LIBXML2 == "1" or FEATURE_JSON_C == "1" %} statistics-channels { - inet 10.53.0.6 port @EXTRAPORT1@ allow { any; }; + inet @ns.ip@ port @EXTRAPORT1@ allow { any; }; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/tcp/1996-alloc_dnsbuf-crash-test.pkt bind9-9.20.29/bin/tests/system/tcp/1996-alloc_dnsbuf-crash-test.pkt --- bind9-9.20.26/bin/tests/system/tcp/1996-alloc_dnsbuf-crash-test.pkt 2026-07-20 14:47:53.910847580 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/1996-alloc_dnsbuf-crash-test.pkt 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -# Transaction ID -0001 -# Standard query -0000 -# Questions: 1, Additional: 1 -0001 0000 0000 0000 -# QNAME: www.isc.org -03 697363 03 6F7267 00 -# Type: AXFR -00fc -# Class: IN -0001 diff -Nru bind9-9.20.26/bin/tests/system/tcp/ans6/ans.py bind9-9.20.29/bin/tests/system/tcp/ans6/ans.py --- bind9-9.20.26/bin/tests/system/tcp/ans6/ans.py 2026-07-20 14:47:53.911847596 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/ans6/ans.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -# 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. - -############################################################################ -# -# This tool allows an arbitrary number of TCP connections to be made to the -# specified service and to keep them open until told otherwise. It is -# controlled by writing text commands to a TCP socket (default port: 5309). -# -# Currently supported commands: -# -# - open -# -# Opens TCP connections to : and keeps them open. -# must be an IP address (IPv4 or IPv6). -# -# - close -# -# Close the oldest previously established connections. -# -############################################################################ - -from __future__ import print_function - -import datetime -import errno -import os -import select -import signal -import socket -import sys -import time - -# Timeout for establishing all connections requested by a single 'open' command. -OPEN_TIMEOUT = 2 -VERSION_QUERY = b"\x00\x1e\xaf\xb8\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07version\x04bind\x00\x00\x10\x00\x03" - - -def log(msg): - print(datetime.datetime.now().strftime("%d-%b-%Y %H:%M:%S.%f ") + msg) - - -def open_connections(active_conns, count, host, port): - queued = [] - errors = [] - - try: - socket.inet_aton(host) - family = socket.AF_INET - except socket.error: - family = socket.AF_INET6 - - log(f"Opening {count} connections...") - - for _ in range(count): - sock = socket.socket(family, socket.SOCK_STREAM) - sock.setblocking(0) - err = sock.connect_ex((host, port)) - if err not in (0, errno.EINPROGRESS): - log(f"{errno.errorcode[err]} on connect for socket {sock}") - errors.append(sock) - else: - queued.append(sock) - - start = time.monotonic() - while queued: - now = time.monotonic() - time_left = OPEN_TIMEOUT - (now - start) - if time_left <= 0: - break - _, wsocks, _ = select.select([], queued, [], time_left) - for sock in wsocks: - queued.remove(sock) - err = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err: - log(f"{errno.errorcode[err]} for socket {sock}") - errors.append(sock) - else: - sock.send(VERSION_QUERY) - active_conns.append(sock) - - if errors: - log(f"result=FAIL: {len(errors)} connection(s) failed") - elif queued: - log(f"result=FAIL: Timed out, aborting {len(queued)} pending connections") - for sock in queued: - sock.close() - else: - log(f"result=OK: Successfully opened {count} connections") - - -def close_connections(active_conns, count): - log(f"Closing {'all' if count == 0 else count} connections...") - if count == 0: - count = len(active_conns) - for _ in range(count): - sock = active_conns.pop(0) - sock.close() - log(f"result=OK: Successfully closed {count} connections") - - -def sigterm(*_): - log("SIGTERM received, shutting down") - os.remove("ans.pid") - sys.exit(0) - - -def main(): - active_conns = [] - - signal.signal(signal.SIGTERM, sigterm) - - with open("ans.pid", "w", encoding="utf-8") as pidfile: - print(os.getpid(), file=pidfile) - - listenip = "10.53.0.6" - try: - port = int(os.environ["CONTROLPORT"]) - except KeyError: - port = 5309 - - log(f"Listening on {listenip}:{port}") - - ctlsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ctlsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - ctlsock.bind((listenip, port)) - ctlsock.listen(1) - - while True: - clientsock, _ = ctlsock.accept() - log(f"Accepted control connection from {clientsock}") - cmdline = clientsock.recv(512).decode("ascii").strip() - if cmdline: - log(f"Received command: {cmdline}") - cmd = cmdline.split() - if cmd[0] == "open": - count, host, port = cmd[1:] - open_connections(active_conns, int(count), host, int(port)) - elif cmd[0] == "close": - (count,) = cmd[1:] - close_connections(active_conns, int(count)) - else: - log("result=FAIL: Unknown command") - clientsock.close() - - -if __name__ == "__main__": - main() diff -Nru bind9-9.20.26/bin/tests/system/tcp/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/tcp/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tcp/ns1/named.conf.j2 2026-07-20 14:47:53.911847596 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/ns1/named.conf.j2 2026-09-11 19:41:01.379328076 +0000 @@ -12,27 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; statistics-file "named.stats"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/tcp/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/tcp/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tcp/ns2/named.conf.j2 2026-07-20 14:47:53.911847596 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/ns2/named.conf.j2 2026-09-11 19:41:01.380328100 +0000 @@ -12,33 +12,15 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; statistics-file "named.stats"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/tcp/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/tcp/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tcp/ns3/named.conf.j2 2026-07-20 14:47:53.911847596 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/ns3/named.conf.j2 2026-09-11 19:41:01.380328100 +0000 @@ -12,31 +12,12 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; server 10.53.0.1 { tcp-only yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/tcp/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/tcp/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tcp/ns4/named.conf.j2 2026-07-20 14:47:53.911847596 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/ns4/named.conf.j2 2026-09-11 19:41:01.380328100 +0000 @@ -12,33 +12,14 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; forwarders { 10.53.0.2; }; forward only; }; server 10.53.0.2 { tcp-only yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/tcp/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/tcp/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tcp/ns5/named.conf.j2 2026-07-20 14:47:53.912847611 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/ns5/named.conf.j2 2026-09-11 19:41:01.380328100 +0000 @@ -13,33 +13,14 @@ // NS5 -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - tcp-listen-queue 32; - recursion yes; - notify yes; - tcp-clients 17; + {% include_indented "_common/options.conf.j2" %} + tcp-listen-queue 32; + tcp-clients 17; dnssec-validation no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/tcp/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/tcp/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tcp/ns7/named.conf.j2 2026-07-20 14:47:53.912847611 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/ns7/named.conf.j2 2026-09-11 19:41:01.380328100 +0000 @@ -12,28 +12,14 @@ */ options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; statistics-file "named.stats"; tcp-clients 1; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/tcp/tests.sh bind9-9.20.29/bin/tests/system/tcp/tests.sh --- bind9-9.20.26/bin/tests/system/tcp/tests.sh 2026-07-20 14:47:53.912847611 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/tests.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,228 +0,0 @@ -#!/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 - -# shellcheck source=../conf.sh -. ../conf.sh - -dig_with_opts() { - "${DIG}" -p "${PORT}" "$@" -} - -rndccmd() { - "${RNDC}" -p "${CONTROLPORT}" -c ../_common/rndc.conf -s "$@" -} - -status=0 -n=0 - -n=$((n + 1)) -echo_i "initializing TCP statistics ($n)" -ret=0 -rndccmd 10.53.0.1 stats || ret=1 -rndccmd 10.53.0.2 stats || ret=1 -mv ns1/named.stats ns1/named.stats.test$n -mv ns2/named.stats ns2/named.stats.test$n -ntcp10="$(grep "TCP requests received" ns1/named.stats.test$n | tail -1 | awk '{print $1}')" -ntcp20="$(grep "TCP requests received" ns2/named.stats.test$n | tail -1 | awk '{print $1}')" -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -n=$((n + 1)) -echo_i "checking TCP request statistics (resolver) ($n)" -ret=0 -dig_with_opts @10.53.0.3 txt.example. >dig.out.test$n -sleep 1 -rndccmd 10.53.0.1 stats || ret=1 -rndccmd 10.53.0.2 stats || ret=1 -mv ns1/named.stats ns1/named.stats.test$n -mv ns2/named.stats ns2/named.stats.test$n -ntcp11="$(grep "TCP requests received" ns1/named.stats.test$n | tail -1 | awk '{print $1}')" -ntcp21="$(grep "TCP requests received" ns2/named.stats.test$n | tail -1 | awk '{print $1}')" -if [ "$ntcp10" -ge "$ntcp11" ]; then ret=1; fi -if [ "$ntcp20" -ne "$ntcp21" ]; then ret=1; fi -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -n=$((n + 1)) -echo_i "checking TCP request statistics (forwarder) ($n)" -ret=0 -dig_with_opts @10.53.0.4 txt.example. >dig.out.test$n -sleep 1 -rndccmd 10.53.0.1 stats || ret=1 -rndccmd 10.53.0.2 stats || ret=1 -mv ns1/named.stats ns1/named.stats.test$n -mv ns2/named.stats ns2/named.stats.test$n -ntcp12="$(grep "TCP requests received" ns1/named.stats.test$n | tail -1 | awk '{print $1}')" -ntcp22="$(grep "TCP requests received" ns2/named.stats.test$n | tail -1 | awk '{print $1}')" -if [ "$ntcp11" -ne "$ntcp12" ]; then ret=1; fi -if [ "$ntcp21" -ge "$ntcp22" ]; then ret=1; fi -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# -------- TCP high-water tests ---------- -refresh_tcp_stats() { - rndccmd 10.53.0.5 status >rndc.out.$n || ret=1 - TCP_CUR="$(sed -n "s/^tcp clients: \([0-9][0-9]*\).*/\1/p" rndc.out.$n)" - TCP_LIMIT="$(sed -n "s/^tcp clients: .*\/\([0-9][0-9]*\)/\1/p" rndc.out.$n)" - TCP_HIGH="$(sed -n "s/^TCP high-water: \([0-9][0-9]*\)/\1/p" rndc.out.$n)" - REC_HIGH="$(sed -n "s/^recursive high-water: \([0-9][0-9]*\)/\1/p" rndc.out.$n)" -} - -# Send a command to the tool script listening on 10.53.0.6. -send_command() { - nextpart ans6/ans.run >/dev/null - echo "$*" | send 10.53.0.6 "${CONTROLPORT}" - wait_for_log_peek 10 "result=" ans6/ans.run || ret=1 - if ! nextpartpeek ans6/ans.run | grep -qF "result=OK"; then - return 1 - fi -} - -# Instructs ans6 to open $1 TCP connections to 10.53.0.5. -open_connections() { - send_command "open" "${1}" 10.53.0.5 "${PORT}" || return 1 -} - -# Instructs ans6 to close $1 TCP connections to 10.53.0.5. -close_connections() { - send_command "close" "${1}" || return 1 -} - -# Check TCP connections are working normally before opening -# multiple connections -n=$((n + 1)) -echo_i "checking TCP query repsonse ($n)" -ret=0 -dig_with_opts +tcp @10.53.0.5 txt.example >dig.out.test$n -grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Check TCP statistics after server startup before using them as a baseline for -# subsequent checks. -n=$((n + 1)) -echo_i "TCP and recursive high-water: check initial statistics ($n)" -ret=0 -refresh_tcp_stats -assert_int_equal "${TCP_CUR}" 0 "current TCP clients count" || ret=1 -# We compare initial tcp-highwater value with 1 because as part of the -# system test startup, the script start.pl executes dig to check if target -# named is running, and that increments tcp-quota by one. -assert_int_equal "${TCP_HIGH}" 1 "tcp-highwater count" || ret=1 -assert_int_equal "${REC_HIGH}" 1 "recursive-highwater count" || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Reset TCP high-water statistics -n=$((n + 1)) -echo_i "TCP and recursive high-water: reset ($n)" -ret=0 -rndccmd 10.53.0.5 reset-stats tcp-high-water recursive-high-water || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Check TCP statistics after reset -n=$((n + 1)) -echo_i "TCP and recursive high-water: check statistics after reset ($n)" -ret=0 -refresh_tcp_stats -assert_int_equal "${TCP_CUR}" 0 "current TCP clients count" || ret=1 -assert_int_equal "${TCP_HIGH}" 0 "tcp-highwater count" || ret=1 -assert_int_equal "${REC_HIGH}" 0 "recursive-highwater count" || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Ensure the TCP high-water statistic gets updated after some TCP connections -# are established, and recursive high-water is unchanged. -n=$((n + 1)) -echo_i "TCP and recursive high-water: check values after some TCP and UDP connections are established ($n)" -ret=0 -OLD_TCP_CUR="${TCP_CUR}" -OLD_REC_HIGH="${REC_HIGH}" -TCP_ADDED=9 -REC_ADDED=1 -dig_with_opts +udp @10.53.0.5 recurse.example >dig.out.test$n -open_connections "${TCP_ADDED}" || ret=1 -check_stats_added() { - refresh_tcp_stats - assert_int_equal "${TCP_CUR}" $((OLD_TCP_CUR + TCP_ADDED)) "current TCP clients count" || return 1 - assert_int_equal "${TCP_HIGH}" $((OLD_TCP_CUR + TCP_ADDED)) "TCP high-water value" || return 1 - assert_int_equal "${REC_HIGH}" $((OLD_REC_HIGH + REC_ADDED)) "recursive high-water value" || return 1 -} -retry 2 check_stats_added || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Ensure the TCP high-water statistic remains unchanged after some TCP -# connections are closed. -n=$((n + 1)) -echo_i "TCP high-water: check value after some TCP connections are closed ($n)" -ret=0 -OLD_TCP_CUR="${TCP_CUR}" -OLD_TCP_HIGH="${TCP_HIGH}" -TCP_REMOVED=5 -close_connections "${TCP_REMOVED}" || ret=1 -check_stats_removed() { - refresh_tcp_stats - assert_int_equal "${TCP_CUR}" $((OLD_TCP_CUR - TCP_REMOVED)) "current TCP clients count" || return 1 - assert_int_equal "${TCP_HIGH}" "${OLD_TCP_HIGH}" "TCP high-water value" || return 1 -} -retry 2 check_stats_removed || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Ensure the TCP high-water statistic never exceeds the configured TCP clients -# limit. -n=$((n + 1)) -echo_i "TCP high-water: ensure tcp-clients is an upper bound ($n)" -ret=0 -open_connections $((TCP_LIMIT + 1)) || ret=1 -check_stats_limit() { - refresh_tcp_stats - assert_int_equal "${TCP_CUR}" "${TCP_LIMIT}" "current TCP clients count" || return 1 - assert_int_equal "${TCP_HIGH}" "${TCP_LIMIT}" "TCP high-water value" || return 1 -} -retry 2 check_stats_limit || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -# Check TCP connections are working normally before opening -# multiple connections -n=$((n + 1)) -echo_i "checking TCP response recovery ($n)" -ret=0 -# "0" closes all connections -close_connections 0 || ret=1 -dig_with_opts +tcp @10.53.0.5 txt.example >dig.out.test$n || ret=1 -grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -#################################################### -# NOTE: The next test resets the debug level to 1. # -#################################################### - -n=$((n + 1)) -echo_i "checking that BIND 9 doesn't crash on long TCP messages ($n)" -ret=0 -# Avoid logging useless information. -rndccmd 10.53.0.1 trace 1 || ret=1 -{ $PERL ../packet.pl -a "10.53.0.1" -p "${PORT}" -t tcp -r 300000 1996-alloc_dnsbuf-crash-test.pkt || ret=1; } | cat_i -dig_with_opts +tcp @10.53.0.1 txt.example >dig.out.test$n || ret=1 -if [ $ret != 0 ]; then echo_i "failed"; fi -status=$((status + ret)) - -echo_i "exit status: $status" -[ $status -eq 0 ] || exit 1 diff -Nru bind9-9.20.26/bin/tests/system/tcp/tests_sh_tcp.py bind9-9.20.29/bin/tests/system/tcp/tests_sh_tcp.py --- bind9-9.20.26/bin/tests/system/tcp/tests_sh_tcp.py 2026-07-20 14:47:53.912847611 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/tests_sh_tcp.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -# 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. - -import pytest - -pytestmark = pytest.mark.extra_artifacts( - [ - "dig.out.*", - "rndc.out.*", - "ans*/ans.run", - "ans*/ans.run.prev", - "ns*/named.stats.*", - ] -) - - -def test_tcp(run_tests_sh): - run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/tcp/tests_tcp.py bind9-9.20.29/bin/tests/system/tcp/tests_tcp.py --- bind9-9.20.26/bin/tests/system/tcp/tests_tcp.py 2026-07-20 14:47:53.912847611 +0000 +++ bind9-9.20.29/bin/tests/system/tcp/tests_tcp.py 2026-09-11 19:41:01.381328124 +0000 @@ -11,49 +11,282 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. +from collections.abc import Iterable, Iterator +from types import TracebackType +from typing import NamedTuple + +import asyncio +import contextlib import socket import struct import time -import dns.flags import dns.message import dns.name import dns.query +import dns.rcode import dns.rrset import pytest -pytestmark = pytest.mark.extra_artifacts( - [ - "ans*/ans.run", - ] -) +from isctest.instance import NamedInstance + +import isctest + +pytestmark = pytest.mark.extra_artifacts(["ns*/named.stats"]) -TIMEOUT = 10 +TIMEOUT: int = 10 -def create_msg(qname, qtype, edns=-1): - msg = dns.message.make_query(qname, qtype, use_edns=edns) - return msg +class TcpStatus(NamedTuple): + current: int + limit: int + high_water: int + recursive_high_water: int + + def check( + self, + *, + current: int | None = None, + limit: int | None = None, + high_water: int | None = None, + recursive_high_water: int | None = None, + ) -> None: + if current is not None: + assert ( + self.current == current + ), f"current TCP clients count: expected {current}, got {self.current}" + if limit is not None: + assert ( + self.limit == limit + ), f"TCP clients limit: expected {limit}, got {self.limit}" + if high_water is not None: + assert ( + self.high_water == high_water + ), f"TCP high-water value: expected {high_water}, got {self.high_water}" + if recursive_high_water is not None: + assert self.recursive_high_water == recursive_high_water, ( + "recursive high-water value: " + f"expected {recursive_high_water}, got {self.recursive_high_water}" + ) + + @classmethod + def of(cls, ns: NamedInstance) -> "TcpStatus": + status = ns.rndc("status").out + + def value(label: str) -> str: + matches = status.grep(f"{label}:") + assert matches, f"'{label}' not found in rndc status:\n{status}" + line = matches[0].string.strip() + _, _, result = line.partition(":") + return result.strip() + + current, limit = value("tcp clients").split("/", maxsplit=1) + + return cls( + current=int(current), + limit=int(limit), + high_water=int(value("TCP high-water")), + recursive_high_water=int(value("recursive high-water")), + ) + @classmethod + def wait_for( + cls, + ns: NamedInstance, + *, + current: int | None = None, + limit: int | None = None, + high_water: int | None = None, + recursive_high_water: int | None = None, + timeout: int = 2, + delay: int = 1, + ) -> "TcpStatus": + status: TcpStatus | None = None + + def check() -> bool: + nonlocal status + status = cls.of(ns) + status.check( + current=current, + limit=limit, + high_water=high_water, + recursive_high_water=recursive_high_water, + ) + return True + + isctest.run.retry_with_timeout(check, timeout=timeout, delay=delay) + assert status is not None + return status + + +class TcpConnectionPool: + OPEN_TIMEOUT = 2 + + def __init__(self) -> None: + self.connections: list[socket.socket] = [] + + async def __aenter__(self) -> "TcpConnectionPool": + return self + + async def __aexit__( + self, + _exc_type: type[BaseException] | None, + _exc: BaseException | None, + _tb: TracebackType | None, + ) -> None: + await self.close() + + async def open(self, count: int, host: str, port: int) -> None: + tasks = [ + asyncio.create_task(open_tcp_query_connection(host, port)) + for _ in range(count) + ] -def timeout(): - return time.time() + TIMEOUT + try: + results = await asyncio.wait_for( + asyncio.gather(*tasks, return_exceptions=True), + timeout=self.OPEN_TIMEOUT, + ) + except asyncio.TimeoutError as exc: + for task in tasks: + task.cancel() + results = await asyncio.gather(*tasks, return_exceptions=True) + close_tcp_connections( + result for result in results if isinstance(result, socket.socket) + ) + raise AssertionError(f"timed out opening {count} TCP connections") from exc + + connections = [ + result for result in results if isinstance(result, socket.socket) + ] + errors = [result for result in results if isinstance(result, BaseException)] + if errors: + close_tcp_connections(connections) + raise AssertionError( + f"{len(errors)} TCP connection(s) failed: {errors[0]!r}" + ) + + self.connections.extend(connections) + + async def close(self, count: int = 0) -> None: + if count == 0: + count = len(self.connections) + + assert count <= len( + self.connections + ), f"cannot close {count} of {len(self.connections)} active connection(s)" + + closing = self.connections[:count] + del self.connections[:count] + close_tcp_connections(closing) -def create_socket(host, port): +def create_socket(host: str, port: int) -> socket.socket: sock = socket.create_connection((host, port), timeout=10) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True) return sock -def test_tcp_garbage(named_port): - with create_socket("10.53.0.7", named_port) as sock: - msg = create_msg("a.example.", "A") - dns.query.send_tcp(sock, msg, timeout()) - dns.query.receive_tcp(sock, timeout()) +def tcp_requests_received(ns: NamedInstance) -> int: + ns.rndc("stats") + stats = isctest.text.TextFile(str(ns.directory / "named.stats")) + matches = stats.grep("TCP requests received") + assert matches, f"'TCP requests received' not found in {stats}" + # `rndc stats` appends to the file; only the last occurrence is current + return int(matches[-1].string.split()[0]) + + +def check_tcp_response(server_ip: str) -> None: + msg = isctest.query.create("txt.example.", "A") + response = isctest.query.tcp(msg, server_ip) + isctest.check.nxdomain(response) + + +def tcp_round_trip( + sock: socket.socket, msg: dns.message.Message +) -> dns.message.Message: + expiration = time.time() + TIMEOUT + dns.query.send_tcp(sock, msg, expiration) + response, _ = dns.query.receive_tcp(sock, expiration) + return response + + +async def open_tcp_query_connection(host: str, port: int) -> socket.socket: + try: + socket.inet_pton(socket.AF_INET, host) + family = socket.AF_INET + except OSError: + family = socket.AF_INET6 + + sock = socket.socket(family, socket.SOCK_STREAM) + sock.setblocking(False) + + try: + loop = asyncio.get_running_loop() + await loop.sock_connect(sock, (host, port)) + msg = isctest.query.create( + "version.bind.", "TXT", "CH", dnssec=False, use_edns=False, ad=False + ) + await loop.sock_sendall(sock, msg.to_wire(prepend_length=True)) + except BaseException: + # BaseException so the socket is also closed when the task is + # cancelled at one of the awaits, not just on connection errors + sock.close() + raise - wire = msg.to_wire() - assert len(wire) > 0 + return sock + + +def close_tcp_connections(connections: Iterable[socket.socket]) -> None: + for sock in connections: + sock.close() + + +async def send_long_tcp_stream( + host: str, port: int, message: dns.message.Message, min_bytes: int +) -> None: + frame = message.to_wire(prepend_length=True) + chunk_frames = max(1, 65536 // len(frame)) + frames_remaining = (min_bytes + len(frame) - 1) // len(frame) + + async def discard_stream(reader: asyncio.StreamReader) -> None: + with contextlib.suppress(OSError): + while await reader.read(65535): + pass + + async def run() -> None: + reader, writer = await asyncio.open_connection(host, port) + discard_task = asyncio.create_task(discard_stream(reader)) + try: + with contextlib.suppress(ConnectionError): + remaining = frames_remaining + while remaining > 0: + frames = min(chunk_frames, remaining) + writer.write(frame * frames) + await writer.drain() + remaining -= frames + writer.write_eof() + await writer.drain() + writer.close() + with contextlib.suppress(ConnectionError, OSError): + await writer.wait_closed() + await discard_task + finally: + writer.close() + if not discard_task.done(): + discard_task.cancel() + with contextlib.suppress(asyncio.CancelledError): + await discard_task + + await asyncio.wait_for(run(), timeout=10 * TIMEOUT) + + +def test_tcp_garbage(ns7: NamedInstance, named_port: int) -> None: + with create_socket(ns7.ip, named_port) as sock: + msg = isctest.query.create( + "a.example.", "A", dnssec=False, use_edns=-1, ad=False + ) + tcp_round_trip(sock, msg) # Send DNS message shorter than DNS message header (12), # this should cause the connection to be terminated @@ -62,43 +295,42 @@ with pytest.raises(EOFError): try: - dns.query.send_tcp(sock, msg, timeout()) - dns.query.receive_tcp(sock, timeout()) + tcp_round_trip(sock, msg) except ConnectionError as e: raise EOFError from e -def test_tcp_garbage_response(named_port): - with create_socket("10.53.0.7", named_port) as sock: - msg = create_msg("a.example.", "A") - dns.query.send_tcp(sock, msg, timeout()) - dns.query.receive_tcp(sock, timeout()) - - wire = msg.to_wire() - assert len(wire) > 0 +def test_tcp_garbage_response(ns7: NamedInstance, named_port: int) -> None: + with create_socket(ns7.ip, named_port) as sock: + msg = isctest.query.create( + "a.example.", "A", dnssec=False, use_edns=-1, ad=False + ) + tcp_round_trip(sock, msg) # Send DNS response instead of DNS query, this should cause # the connection to be terminated rmsg = dns.message.make_response(msg) - dns.query.send_tcp(sock, rmsg, timeout()) with pytest.raises(EOFError): try: - dns.query.receive_tcp(sock, timeout()) + tcp_round_trip(sock, rmsg) except ConnectionError as e: raise EOFError from e # Regression test for CVE-2022-0396 -def test_close_wait(named_port): - with create_socket("10.53.0.7", named_port) as sock: - msg = create_msg("a.example.", "A") - dns.query.send_tcp(sock, msg, timeout()) - dns.query.receive_tcp(sock, timeout()) +def test_close_wait(ns7: NamedInstance, named_port: int) -> None: + with create_socket(ns7.ip, named_port) as sock: + msg = isctest.query.create( + "a.example.", "A", dnssec=False, use_edns=-1, ad=False + ) + tcp_round_trip(sock, msg) - msg = dns.message.make_query("a.example.", "A", use_edns=0, payload=1232) - dns.query.send_tcp(sock, msg, timeout()) + msg = isctest.query.create( + "a.example.", "A", dnssec=False, use_edns=0, payload=1232, ad=False + ) + dns.query.send_tcp(sock, msg, time.time() + TIMEOUT) # Shutdown the socket, but ignore the other side closing the socket # first because we sent DNS message with EDNS0 @@ -114,25 +346,167 @@ # ns7/named.dropedns and close the socket, making room for the next # request. If it gets stuck in CLOSE_WAIT state, there is no connection # available for the query below and it will time out. - with create_socket("10.53.0.7", named_port) as sock: - msg = create_msg("a.example.", "A") - dns.query.send_tcp(sock, msg, timeout()) - dns.query.receive_tcp(sock, timeout()) + with create_socket(ns7.ip, named_port) as sock: + msg = isctest.query.create( + "a.example.", "A", dnssec=False, use_edns=-1, ad=False + ) + tcp_round_trip(sock, msg) # GL #4273 -def test_tcp_big(named_port): - with create_socket("10.53.0.7", named_port) as sock: - msg = dns.message.Message(id=0) - msg.flags = dns.flags.RD - msg.question.append(dns.rrset.from_text(dns.name.root, 0, 1, "URI")) +def test_tcp_big(ns7: NamedInstance, named_port: int) -> None: + with create_socket(ns7.ip, named_port) as sock: + msg = isctest.query.create( + dns.name.root, "URI", dnssec=False, use_edns=-1, ad=False, message_id=0 + ) msg.additional.append( dns.rrset.from_text(dns.name.root, 0, 1, "URI", "0 0 " + "b" * 65503) ) - dns.query.send_tcp(sock, msg, timeout()) - dns.query.receive_tcp(sock, timeout()) + tcp_round_trip(sock, msg) # Now check that the server is alive and well - msg = create_msg("a.example.", "A") - dns.query.send_tcp(sock, msg, timeout()) - dns.query.receive_tcp(sock, timeout()) + msg = isctest.query.create( + "a.example.", "A", dnssec=False, use_edns=-1, ad=False + ) + tcp_round_trip(sock, msg) + + +def wait_for_stable_tcp_requests(ns: NamedInstance, timeout: int = 10) -> int: + """Read the TCP request counter until it stops changing. + + The counter is incremented on request receipt, so a client response + implies its upstream queries are already counted; this only needs to + absorb unsynchronized traffic such as the resolver's root priming query. + """ + last = -1 + + def stable() -> bool: + nonlocal last + previous, last = last, tcp_requests_received(ns) + return previous == last + + isctest.run.retry_with_timeout(stable, timeout=timeout) + return last + + +def test_tcp_request_statistics( + ns1: NamedInstance, ns2: NamedInstance, ns3: NamedInstance, ns4: NamedInstance +) -> None: + isctest.log.info("initializing TCP statistics") + ns1_tcp = tcp_requests_received(ns1) + ns2_tcp = tcp_requests_received(ns2) + + isctest.log.info("checking TCP request statistics (resolver)") + msg = isctest.query.create("txt.example.", "A") + isctest.query.udp(msg, ns3.ip, expected_rcode=dns.rcode.NXDOMAIN) + + ns1_tcp_after_resolver = wait_for_stable_tcp_requests(ns1) + ns2_tcp_after_resolver = wait_for_stable_tcp_requests(ns2) + assert ns1_tcp < ns1_tcp_after_resolver + assert ns2_tcp == ns2_tcp_after_resolver + + isctest.log.info("checking TCP request statistics (forwarder)") + msg = isctest.query.create("txt.example.", "A") + isctest.query.udp(msg, ns4.ip, expected_rcode=dns.rcode.NXDOMAIN) + + ns1_tcp_after_forwarder = wait_for_stable_tcp_requests(ns1) + ns2_tcp_after_forwarder = wait_for_stable_tcp_requests(ns2) + assert ns1_tcp_after_resolver == ns1_tcp_after_forwarder + assert ns2_tcp_after_resolver < ns2_tcp_after_forwarder + + +def test_tcp_high_water(ns5: NamedInstance, named_port: int) -> None: + async def run() -> None: + async with TcpConnectionPool() as pool: + isctest.log.info("checking TCP query response") + check_tcp_response(ns5.ip) + + ns5.rndc("reset-stats tcp-high-water recursive-high-water") + isctest.log.info( + "TCP and recursive high-water: check statistics after reset" + ) + status = TcpStatus.of(ns5) + status.check(current=0, high_water=0, recursive_high_water=0) + + isctest.log.info( + "TCP and recursive high-water: check values after some TCP " + "and UDP connections are established" + ) + old_status = status + tcp_added = 9 + rec_added = 1 + msg = isctest.query.create("recurse.example.", "A") + isctest.query.udp(msg, ns5.ip) + await pool.open(tcp_added, ns5.ip, named_port) + status = TcpStatus.wait_for( + ns5, + current=old_status.current + tcp_added, + high_water=old_status.current + tcp_added, + recursive_high_water=old_status.recursive_high_water + rec_added, + ) + + isctest.log.info( + "TCP high-water: check value after some TCP connections are closed" + ) + old_status = status + tcp_removed = 5 + await pool.close(tcp_removed) + status = TcpStatus.wait_for( + ns5, + current=old_status.current - tcp_removed, + high_water=old_status.high_water, + ) + + isctest.log.info("TCP high-water: ensure tcp-clients is an upper bound") + await pool.open(status.limit + 1, ns5.ip, named_port) + TcpStatus.wait_for( + ns5, + current=status.limit, + high_water=status.limit, + ) + + isctest.log.info("checking TCP response recovery") + await pool.close() + check_tcp_response(ns5.ip) + + asyncio.run(run()) + + +def debug_level(ns: NamedInstance) -> int: + status = ns.rndc("status").out + matches = status.grep("debug level:") + assert matches, f"'debug level' not found in rndc status:\n{status}" + return int(matches[0].string.partition(":")[2]) + + +@contextlib.contextmanager +def temporary_trace_level(ns: NamedInstance, level: int) -> Iterator[None]: + """Lower the debug level for a noisy section, then restore the default.""" + prev_level = debug_level(ns) + ns.rndc(f"trace {level}") + try: + yield + finally: + # Don't mask an in-flight test failure if named has died. + ns.rndc(f"trace {prev_level}", raise_on_exception=False) + + +def test_long_tcp_messages(ns1: NamedInstance, named_port: int) -> None: + isctest.log.info("checking that BIND 9 doesn't crash on long TCP messages") + stream_bytes = 6 * 1024 * 1024 + msg = isctest.query.create( + "isc.org.", + "AXFR", + dnssec=False, + use_edns=False, + rd=False, + ad=False, + message_id=1, + ) + + # Avoid logging the huge query stream at the default debug level. + with temporary_trace_level(ns1, 1): + asyncio.run(send_long_tcp_stream(ns1.ip, named_port, msg, stream_bytes)) + + msg = isctest.query.create("txt.example.", "A") + isctest.query.tcp(msg, ns1.ip) diff -Nru bind9-9.20.26/bin/tests/system/timeouts/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/timeouts/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/timeouts/ns1/named.conf.j2 2026-07-20 14:47:53.913847627 +0000 +++ bind9-9.20.29/bin/tests/system/timeouts/ns1/named.conf.j2 2026-09-11 19:41:01.381328124 +0000 @@ -11,20 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; dnssec-validation no; recursion no; diff -Nru bind9-9.20.26/bin/tests/system/timeouts/tests_tcp_timeouts.py bind9-9.20.29/bin/tests/system/timeouts/tests_tcp_timeouts.py --- bind9-9.20.26/bin/tests/system/timeouts/tests_tcp_timeouts.py 2026-07-20 14:47:53.913847627 +0000 +++ bind9-9.20.29/bin/tests/system/timeouts/tests_tcp_timeouts.py 2026-09-11 19:41:01.382328147 +0000 @@ -64,7 +64,6 @@ raise EOFError from e -@pytest.mark.flaky(max_runs=2, rerun_filter=isctest.mark.is_host_freebsd_13) def test_idle_timeout(named_port): # # The idle timeout is 5 seconds, so the third message should fail diff -Nru bind9-9.20.26/bin/tests/system/tkey/nooptions/example.db bind9-9.20.29/bin/tests/system/tkey/nooptions/example.db --- bind9-9.20.26/bin/tests/system/tkey/nooptions/example.db 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/tkey/nooptions/example.db 2026-09-11 19:41:01.382328147 +0000 @@ -0,0 +1,5 @@ +$TTL 300 +@ IN SOA ns.example.nil. hostmaster.example.nil. ( 1 300 300 604800 300 ) + IN NS ns.example.nil. +ns IN A 10.53.0.1 +a IN A 192.0.2.1 diff -Nru bind9-9.20.26/bin/tests/system/tkey/nooptions/named.conf bind9-9.20.29/bin/tests/system/tkey/nooptions/named.conf --- bind9-9.20.26/bin/tests/system/tkey/nooptions/named.conf 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/tkey/nooptions/named.conf 2026-09-11 19:41:01.382328147 +0000 @@ -0,0 +1,13 @@ +controls { +}; + +view "test" { + recursion no; + dnssec-validation no; + + zone "example.nil" { + type primary; + file "example.db"; + notify no; + }; +}; diff -Nru bind9-9.20.26/bin/tests/system/tkey/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/tkey/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tkey/ns1/named.conf.j2 2026-07-20 14:47:53.913847627 +0000 +++ bind9-9.20.29/bin/tests/system/tkey/ns1/named.conf.j2 2026-09-11 19:41:01.382328147 +0000 @@ -12,18 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; }; +{% include "_common/controls.conf.j2" %} + key "test-key" { algorithm "hmac-sha256"; secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY="; diff -Nru bind9-9.20.26/bin/tests/system/tkey/tests_no_options.py bind9-9.20.29/bin/tests/system/tkey/tests_no_options.py --- bind9-9.20.26/bin/tests/system/tkey/tests_no_options.py 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/tkey/tests_no_options.py 2026-09-11 19:41:01.382328147 +0000 @@ -0,0 +1,109 @@ +#!/usr/bin/python3 + +# 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. + +import os +import subprocess + +import dns.exception +import dns.rcode +import dns.rdatatype +import pytest + +import isctest + +pytestmark = pytest.mark.extra_artifacts(["nooptions/named.run"]) + +SERVER_IP = "10.53.0.1" + + +def terminate_named(named_proc): + if named_proc.poll() is None: + named_proc.terminate() + try: + named_proc.wait(timeout=10) + except subprocess.TimeoutExpired: + named_proc.kill() + named_proc.wait(timeout=10) + + +def wait_until_ready(named_proc, port): + # isctest.check.named_alive() cannot be used because it always uses PORT. + query = isctest.query.create("a.example.nil", "A", dnssec=False, use_edns=False) + + def check_server(): + assert named_proc.poll() is None, "named exited during startup" + isctest.query.udp( + query, + SERVER_IP, + port=port, + timeout=1, + attempts=1, + expected_rcode=dns.rcode.NOERROR, + ) + return True + + isctest.run.retry_with_timeout(check_server, timeout=10) + + +def test_tkey_query_without_options(): + """A TKEY query must not crash named when global options are omitted.""" + port = int(os.environ["EXTRAPORT1"]) + named_cmdline = isctest.run.get_named_cmdline("nooptions") + named_cmdline.extend(["-p", str(port), "-T", "maxcachesize=2097152"]) + + # Do not add an options block: on affected branches, even an empty one + # creates the TKEY context and masks the bug. This makes named listen on + # all local addresses and use its compiled-in runtime-file paths. The + # extra port avoids clashes; runtime files may be created in root-run test + # environments, while failures to create them as an unprivileged user are + # expected. + + query = isctest.query.create( + ".", + dns.rdatatype.TKEY, + dnssec=False, + use_edns=False, + rd=False, + ad=False, + message_id=0x1234, + ) + assert query.to_wire() == bytes.fromhex("1234000000010000000000000000f90001") + + with open("nooptions/named.run", "wb") as named_log: + named_proc = subprocess.Popen( # pylint: disable=consider-using-with + named_cmdline, + cwd="nooptions", + stdout=named_log, + stderr=subprocess.STDOUT, + ) + try: + wait_until_ready(named_proc, port) + try: + isctest.query.udp( + query, + SERVER_IP, + port=port, + timeout=1, + attempts=1, + expected_rcode=dns.rcode.FORMERR, + ) + except dns.exception.Timeout: + returncode = named_proc.poll() + if returncode is not None: + pytest.fail(f"TKEY query crashed named (exit code {returncode})") + raise + assert named_proc.poll() is None, "TKEY query crashed named" + finally: + terminate_named(named_proc) + + assert named_proc.returncode == 0, "named did not shut down cleanly" diff -Nru bind9-9.20.26/bin/tests/system/tkeyleak/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/tkeyleak/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tkeyleak/ns1/named.conf.j2 2026-07-20 14:47:53.913847627 +0000 +++ bind9-9.20.29/bin/tests/system/tkeyleak/ns1/named.conf.j2 2026-09-11 19:41:01.382328147 +0000 @@ -12,26 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; tkey-gssapi-keytab "dns.keytab"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/tkeyleak/prereq.sh bind9-9.20.29/bin/tests/system/tkeyleak/prereq.sh --- bind9-9.20.26/bin/tests/system/tkeyleak/prereq.sh 2026-07-20 14:47:53.914847642 +0000 +++ bind9-9.20.29/bin/tests/system/tkeyleak/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -$FEATURETEST --gssapi || { - echo_i "gssapi not supported - skipping tkeyleak test" - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/tkeyleak/tests_tkeyleak.py bind9-9.20.29/bin/tests/system/tkeyleak/tests_tkeyleak.py --- bind9-9.20.26/bin/tests/system/tkeyleak/tests_tkeyleak.py 2026-07-20 14:47:53.914847642 +0000 +++ bind9-9.20.29/bin/tests/system/tkeyleak/tests_tkeyleak.py 2026-09-11 19:41:01.383328172 +0000 @@ -38,13 +38,19 @@ import pytest import isctest +import isctest.mark -pytestmark = pytest.mark.extra_artifacts( +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "*/*.db", ] ) +pytestmark = [ + isctest.mark.with_gssapi, + EXTRA_ARTIFACTS, +] + TKEY_NAME = dns.name.from_text("test.key.") GSSAPI_ALGORITHM = dns.name.from_text("gss-tsig.") TKEY_MODE_GSSAPI = 3 diff -Nru bind9-9.20.26/bin/tests/system/transport_acl/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/transport_acl/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_acl/ns1/named.conf.j2 2026-07-20 14:47:53.914847642 +0000 +++ bind9-9.20.29/bin/tests/system/transport_acl/ns1/named.conf.j2 2026-09-11 19:41:01.383328172 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,15 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} ## # generic test - listen-on port @PORT@ { 10.53.0.1; }; - listen-on port @TLSPORT@ tls self-signed { 10.53.0.1; }; + listen-on port @TLSPORT@ tls self-signed { @ns.ip@; }; # test #1 - listen-on port @EXTRAPORT1@ { 10.53.0.1; }; + listen-on port @EXTRAPORT1@ { @ns.ip@; }; listen-on port @EXTRAPORT1@ tls self-signed { 10.53.0.2; }; - listen-on port @EXTRAPORT2@ { 10.53.0.1; }; + listen-on port @EXTRAPORT2@ { @ns.ip@; }; listen-on port @EXTRAPORT2@ tls self-signed { 10.53.0.2; }; # test #2 listen-on port @EXTRAPORT1@ { 10.53.0.3; }; @@ -48,19 +43,18 @@ listen-on port @EXTRAPORT2@ { 10.53.0.5; }; listen-on port @EXTRAPORT1@ tls self-signed { 10.53.0.6; }; # test #5 - listen-on port @EXTRAPORT3@ tls self-signed { 10.53.0.1; }; - listen-on port @EXTRAPORT4@ tls self-signed { 10.53.0.1; }; + listen-on port @EXTRAPORT3@ tls self-signed { @ns.ip@; }; + listen-on port @EXTRAPORT4@ tls self-signed { @ns.ip@; }; listen-on port @EXTRAPORT3@ { 10.53.0.2; }; # test #6 - listen-on port @EXTRAPORT5@ { 10.53.0.1; }; + listen-on port @EXTRAPORT5@ { @ns.ip@; }; # test #7 - listen-on port @EXTRAPORT6@ tls self-signed { 10.53.0.1; }; + listen-on port @EXTRAPORT6@ tls self-signed { @ns.ip@; }; # test #7 - listen-on port @EXTRAPORT7@ tls self-signed { 10.53.0.1; }; + listen-on port @EXTRAPORT7@ tls self-signed { @ns.ip@; }; # test #8 - listen-on port @EXTRAPORT8@ { 10.53.0.1; }; + listen-on port @EXTRAPORT8@ { @ns.ip@; }; ## - listen-on-v6 { none; }; recursion no; notify explicit; statistics-file "named.stats"; @@ -68,7 +62,6 @@ tcp-initial-timeout 1200; }; - zone "example0" { type primary; file "example.db"; @@ -120,7 +113,7 @@ zone "example8" { type primary; file "example.db"; - allow-transfer port @EXTRAPORT7@ transport tls { 10.53.0.1; 10.53.0.2; 10.53.0.3; }; + allow-transfer port @EXTRAPORT7@ transport tls { @ns.ip@; 10.53.0.2; 10.53.0.3; }; }; zone "example9" { diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-http-plain-proxy.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-http-plain-proxy.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-http-plain-proxy.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-http-plain-proxy.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test TLS - listen-on port @EXTRAPORT1@ proxy plain tls none http default { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ proxy plain tls none http default { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ proxy plain tls none http default { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ proxy plain tls none http default { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-http-plain.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-http-plain.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-http-plain.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-http-plain.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test TLS - listen-on port @EXTRAPORT1@ tls none http default { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ tls none http default { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ tls none http default { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ tls none http default { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-https-proxy-encrypted.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https-proxy-encrypted.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-https-proxy-encrypted.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https-proxy-encrypted.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test TLS - listen-on port @EXTRAPORT1@ proxy encrypted tls self-signed http default { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ proxy encrypted tls self-signed http default { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ proxy encrypted tls self-signed http default { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ proxy encrypted tls self-signed http default { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-https-proxy-plain.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https-proxy-plain.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-https-proxy-plain.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https-proxy-plain.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test TLS - listen-on port @EXTRAPORT1@ proxy plain tls self-signed http default { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ proxy plain tls self-signed http default { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ proxy plain tls self-signed http default { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ proxy plain tls self-signed http default { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-https.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-https.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-https.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test TLS - listen-on port @EXTRAPORT1@ tls self-signed http default { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ tls self-signed http default { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ tls self-signed http default { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ tls self-signed http default { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-proxy.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-proxy.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-proxy.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-proxy.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test - listen-on port @EXTRAPORT1@ proxy plain { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ proxy plain { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ proxy plain { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ proxy plain { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-tls-proxy-encrypted.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls-proxy-encrypted.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-tls-proxy-encrypted.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls-proxy-encrypted.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test TLS - listen-on port @EXTRAPORT1@ proxy encrypted tls self-signed { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ proxy encrypted tls self-signed { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ proxy encrypted tls self-signed { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ proxy encrypted tls self-signed { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-tls-proxy-plain.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls-proxy-plain.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-tls-proxy-plain.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls-proxy-plain.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test TLS - listen-on port @EXTRAPORT1@ proxy plain tls self-signed { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ proxy plain tls self-signed { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ proxy plain tls self-signed { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ proxy plain tls self-signed { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named-tls.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named-tls.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named-tls.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test TLS - listen-on port @EXTRAPORT1@ tls self-signed { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ tls self-signed { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ tls self-signed { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ tls self-signed { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/transport_change/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/transport_change/ns1/named.conf.j2 2026-07-20 14:47:53.915847658 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/ns1/named.conf.j2 2026-09-11 19:41:01.384328195 +0000 @@ -11,11 +11,7 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls self-signed { cert-file "../self-signed-cert.pem"; @@ -23,13 +19,14 @@ }; options { - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} ## # generic - listen-on port @PORT@ { 10.53.0.1; }; + listen-on { @ns.ip@; }; # test - listen-on port @EXTRAPORT1@ { 10.53.0.1; }; - listen-on-v6 port @EXTRAPORT1@ { fd92:7065:b8e:ffff::1; }; + listen-on port @EXTRAPORT1@ { @ns.ip@; }; + listen-on-v6 port @EXTRAPORT1@ { @ns.ip6@; }; ## recursion no; notify explicit; @@ -37,10 +34,9 @@ dnssec-validation no; tcp-initial-timeout 1200; allow-proxy { any; }; - allow-proxy-on { 10.53.0.1; fd92:7065:b8e:ffff::1; }; + allow-proxy-on { @ns.ip@; @ns.ip6@; }; }; - zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/transport_change/prereq.sh bind9-9.20.29/bin/tests/system/transport_change/prereq.sh --- bind9-9.20.26/bin/tests/system/transport_change/prereq.sh 2026-07-20 14:47:53.916847673 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -#!/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. - -# shellcheck disable=SC1091 -. ../conf.sh - -$FEATURETEST --with-libnghttp2 || { - echo_i "This test requires libnghttp2 support." >&2 - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/transport_change/tests_sh_transport_change.py bind9-9.20.29/bin/tests/system/transport_change/tests_sh_transport_change.py --- bind9-9.20.26/bin/tests/system/transport_change/tests_sh_transport_change.py 2026-07-20 14:47:53.916847673 +0000 +++ bind9-9.20.29/bin/tests/system/transport_change/tests_sh_transport_change.py 2026-09-11 19:41:01.385328219 +0000 @@ -11,13 +11,20 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "dig.out.*", "ns1/example.db", ] ) +pytestmark = [ + isctest.mark.with_libnghttp2, + EXTRA_ARTIFACTS, +] + def test_transport_change(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/tsig/ns1/named-md5.conf.j2 bind9-9.20.29/bin/tests/system/tsig/ns1/named-md5.conf.j2 --- bind9-9.20.26/bin/tests/system/tsig/ns1/named-md5.conf.j2 2026-07-20 14:47:53.917847689 +0000 +++ bind9-9.20.29/bin/tests/system/tsig/ns1/named-md5.conf.j2 2026-09-11 19:41:01.386328243 +0000 @@ -22,6 +22,6 @@ }; key "hmac-md5-legacy" { - algorithm "hmac-md5"; - secret "B7HCXJs0XnSPzypG5oHuGw=="; + algorithm "hmac-md5"; + secret "B7HCXJs0XnSPzypG5oHuGw=="; }; diff -Nru bind9-9.20.26/bin/tests/system/tsig/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/tsig/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tsig/ns1/named.conf.j2 2026-07-20 14:47:53.917847689 +0000 +++ bind9-9.20.29/bin/tests/system/tsig/ns1/named.conf.j2 2026-09-11 19:41:01.386328243 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; notify no; }; +{% include "_common/controls.conf.j2" %} + {% if FEATURE_MD5 == "1" %} include "named-md5.conf"; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/tsig/tests.sh bind9-9.20.29/bin/tests/system/tsig/tests.sh --- bind9-9.20.26/bin/tests/system/tsig/tests.sh 2026-07-20 14:47:53.917847689 +0000 +++ bind9-9.20.29/bin/tests/system/tsig/tests.sh 2026-09-11 19:41:01.386328243 +0000 @@ -271,7 +271,7 @@ echo_i "check that a malformed truncated response to a TSIG query is handled" ret=0 -$DIG -p $PORT @10.53.0.1 bad-tsig >dig.out.bad-tsig || ret=1 +$DIG +timeout=15 -p $PORT @10.53.0.1 bad-tsig >dig.out.bad-tsig || ret=1 grep "status: SERVFAIL" dig.out.bad-tsig >/dev/null || ret=1 if [ $ret -eq 1 ]; then echo_i "failed" diff -Nru bind9-9.20.26/bin/tests/system/tsiggss/authsock.pl bind9-9.20.29/bin/tests/system/tsiggss/authsock.pl --- bind9-9.20.26/bin/tests/system/tsiggss/authsock.pl 2026-07-20 14:47:53.918847704 +0000 +++ bind9-9.20.29/bin/tests/system/tsiggss/authsock.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -#!/usr/bin/env perl - -# 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. - -# test the update-policy external protocol - -require 5.6.0; - -use IO::Socket::UNIX; -use Getopt::Long; - -my $path; -my $typeallowed = "A"; -my $pidfile = "authsock.pid"; -my $timeout = 0; - -GetOptions("path=s" => \$path, - "type=s" => \$typeallowed, - "pidfile=s" => \$pidfile, - "timeout=i" => \$timeout); - -if (!defined($path)) { - print("Usage: authsock.pl --path= --type=type --pidfile=pidfile\n"); - exit(1); -} - -unlink($path); -my $server = IO::Socket::UNIX->new(Local => $path, Type => SOCK_STREAM, Listen => 8) or - die "unable to create socket $path"; -chmod 0777, $path; - -# setup our pidfile -open(my $pid,">",$pidfile) - or die "unable to open pidfile $pidfile"; -print $pid "$$\n"; -close($pid); - -if ($timeout != 0) { - # die after the given timeout - alarm($timeout); -} - -while (my $client = $server->accept()) { - $client->recv(my $buf, 8, 0); - my ($version, $req_len) = unpack('N N', $buf); - - if ($version != 1 || $req_len < 17) { - printf("Badly formatted request\n"); - $client->send(pack('N', 2)); - next; - } - - $client->recv(my $buf, $req_len - 8, 0); - - my ($signer, - $name, - $addr, - $type, - $key, - $key_data) = unpack('Z* Z* Z* Z* Z* N/a', $buf); - - if ($req_len != length($buf)+8) { - printf("Length mismatch %u %u\n", $req_len, length($buf)+8); - $client->send(pack('N', 2)); - next; - } - - printf("version=%u signer=%s name=%s addr=%s type=%s key=%s key_data_len=%u\n", - $version, $signer, $name, $addr, $type, $key, length($key_data)); - - my $result; - if ($typeallowed eq $type) { - $result = 1; - printf("allowed type %s == %s\n", $type, $typeallowed); - } else { - printf("disallowed type %s != %s\n", $type, $typeallowed); - $result = 0; - } - - $reply = pack('N', $result); - $client->send($reply); -} diff -Nru bind9-9.20.26/bin/tests/system/tsiggss/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/tsiggss/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/tsiggss/ns1/named.conf.j2 2026-07-20 14:47:53.918847704 +0000 +++ bind9-9.20.29/bin/tests/system/tsiggss/ns1/named.conf.j2 2026-09-11 19:41:01.387328267 +0000 @@ -12,28 +12,17 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} session-keyfile "session.key"; - listen-on { 10.53.0.1; 127.0.0.1; }; + listen-on { @ns.ip@; 127.0.0.1; }; listen-on-v6 { none; }; recursion no; dnssec-validation no; - notify yes; tkey-gssapi-keytab "dns.keytab"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example.nil." IN { type primary; diff -Nru bind9-9.20.26/bin/tests/system/tsiggss/prereq.sh bind9-9.20.29/bin/tests/system/tsiggss/prereq.sh --- bind9-9.20.26/bin/tests/system/tsiggss/prereq.sh 2026-07-20 14:47:53.918847704 +0000 +++ bind9-9.20.29/bin/tests/system/tsiggss/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#!/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. - -. ../conf.sh - -# enable the tsiggss test only if gssapi was enabled -$FEATURETEST --gssapi || { - echo_i "gssapi and krb5 not supported - skipping tsiggss test" - exit 255 -} - -$FEATURETEST --have-fips-dh || { - echo_i "FIPS mode Diffie-Hellman not working - skipping tsiggss test" - exit 255 -} - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/tsiggss/tests.sh bind9-9.20.29/bin/tests/system/tsiggss/tests.sh --- bind9-9.20.26/bin/tests/system/tsiggss/tests.sh 2026-07-20 14:47:53.919847720 +0000 +++ bind9-9.20.29/bin/tests/system/tsiggss/tests.sh 2026-09-11 19:41:01.388328291 +0000 @@ -120,7 +120,7 @@ echo_i "testing external update policy (CNAME) with auth sock ($n)" ret=0 -$PERL ./authsock.pl --type=CNAME --path=ns1/auth.sock --pidfile=authsock.pid --timeout=120 >/dev/null 2>&1 & +($PERL "${TOP_SRCDIR}/bin/tests/system/authsock.pl" --type=CNAME --path=ns1/auth.sock --pidfile=authsock.pid --timeout=120 >/dev/null 2>&1 &) & sleep 1 test_update $n testcname.example.nil. CNAME "86400 CNAME testdenied.example.nil" "testdenied" || ret=1 n=$((n + 1)) diff -Nru bind9-9.20.26/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py bind9-9.20.29/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py --- bind9-9.20.26/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py 2026-07-20 14:47:53.919847720 +0000 +++ bind9-9.20.29/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py 2026-09-11 19:41:01.388328291 +0000 @@ -28,14 +28,21 @@ import pytest import isctest +import isctest.mark -pytestmark = pytest.mark.extra_artifacts( +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "ns1/K*", "ns1/example.nil.db", ] ) +pytestmark = [ + isctest.mark.with_gssapi, + isctest.mark.with_fips_dh, + EXTRA_ARTIFACTS, +] + class CraftedTKEYQuery: """ diff -Nru bind9-9.20.26/bin/tests/system/tsiggss/tests_sh_tsiggss.py bind9-9.20.29/bin/tests/system/tsiggss/tests_sh_tsiggss.py --- bind9-9.20.26/bin/tests/system/tsiggss/tests_sh_tsiggss.py 2026-07-20 14:47:53.919847720 +0000 +++ bind9-9.20.29/bin/tests/system/tsiggss/tests_sh_tsiggss.py 2026-09-11 19:41:01.388328291 +0000 @@ -11,7 +11,9 @@ import pytest -pytestmark = pytest.mark.extra_artifacts( +import isctest.mark + +EXTRA_ARTIFACTS = pytest.mark.extra_artifacts( [ "authsock.pid", "nsupdate.out*", @@ -24,6 +26,12 @@ ] ) +pytestmark = [ + isctest.mark.with_gssapi, + isctest.mark.with_fips_dh, + EXTRA_ARTIFACTS, +] + def test_tsiggss(run_tests_sh): run_tests_sh() diff -Nru bind9-9.20.26/bin/tests/system/ttl/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/ttl/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ttl/ns1/named.conf.j2 2026-07-20 14:47:53.919847720 +0000 +++ bind9-9.20.29/bin/tests/system/ttl/ns1/named.conf.j2 2026-09-11 19:41:01.388328291 +0000 @@ -11,32 +11,16 @@ * information regarding copyright ownership. */ -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; check-integrity no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "min-example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/ttl/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/ttl/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/ttl/ns2/named.conf.j2 2026-07-20 14:47:53.919847720 +0000 +++ bind9-9.20.29/bin/tests/system/ttl/ns2/named.conf.j2 2026-09-11 19:41:01.388328291 +0000 @@ -12,17 +12,9 @@ */ options { - directory "."; - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} servfail-ttl 0; max-recursion-depth 12; - recursion yes; dnssec-validation no; min-cache-ttl 60; min-ncache-ttl 30; @@ -30,13 +22,6 @@ max-ncache-ttl 60; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type hint; file "hints.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/unknown/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/unknown/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/unknown/ns1/named.conf.j2 2026-07-20 14:47:53.921847751 +0000 +++ bind9-9.20.29/bin/tests/system/unknown/ns1/named.conf.j2 2026-09-11 19:41:01.391328363 +0000 @@ -12,18 +12,14 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; }; +{% include "_common/controls.conf.j2" %} + view "in" { allow-transfer { any; }; diff -Nru bind9-9.20.26/bin/tests/system/unknown/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/unknown/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/unknown/ns2/named.conf.j2 2026-07-20 14:47:53.922847767 +0000 +++ bind9-9.20.29/bin/tests/system/unknown/ns2/named.conf.j2 2026-09-11 19:41:01.391328363 +0000 @@ -12,18 +12,14 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; }; +{% include "_common/controls.conf.j2" %} + view "in" { zone "example." { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/unknown/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/unknown/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/unknown/ns3/named.conf.j2 2026-07-20 14:47:53.922847767 +0000 +++ bind9-9.20.29/bin/tests/system/unknown/ns3/named.conf.j2 2026-09-11 19:41:01.391328363 +0000 @@ -12,18 +12,14 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; notify no; }; +{% include "_common/controls.conf.j2" %} + dnssec-policy unknown { keys { ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; diff -Nru bind9-9.20.26/bin/tests/system/upforwd/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/upforwd/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/upforwd/ns1/named.conf.j2 2026-07-20 14:47:53.923847782 +0000 +++ bind9-9.20.29/bin/tests/system/upforwd/ns1/named.conf.j2 2026-09-11 19:41:01.392328387 +0000 @@ -17,21 +17,15 @@ }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on tls ephemeral { 10.53.0.1; }; - listen-on-v6 { none; }; + listen-on tls ephemeral { @ns.ip@; }; allow-transfer { any; }; - recursion yes; dnssec-validation no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/upforwd/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/upforwd/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/upforwd/ns2/named.conf.j2 2026-07-20 14:47:53.923847782 +0000 +++ bind9-9.20.29/bin/tests/system/upforwd/ns2/named.conf.j2 2026-09-11 19:41:01.392328387 +0000 @@ -12,19 +12,13 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; dnssec-validation no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type secondary; file "example.bk"; diff -Nru bind9-9.20.26/bin/tests/system/upforwd/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/upforwd/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/upforwd/ns3/named.conf.j2 2026-07-20 14:47:53.923847782 +0000 +++ bind9-9.20.29/bin/tests/system/upforwd/ns3/named.conf.j2 2026-09-11 19:41:01.392328387 +0000 @@ -12,30 +12,16 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on tls ephemeral { 10.53.0.3; }; - listen-on-v6 { none; }; + listen-on tls ephemeral { @ns.ip@; }; allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; include "dnstap.conf"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} tls tls-example-primary { remote-hostname "srv01.crt01.example.com"; // enable Strict TLS diff -Nru bind9-9.20.26/bin/tests/system/upforwd/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/upforwd/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/upforwd/ns3/named2.conf.j2 2026-07-20 14:47:53.923847782 +0000 +++ bind9-9.20.29/bin/tests/system/upforwd/ns3/named2.conf.j2 2026-09-11 19:41:01.392328387 +0000 @@ -12,30 +12,16 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; + {% include_indented "_common/options.conf.j2" %} tls-port @TLSPORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on tls ephemeral { 10.53.0.3; }; - listen-on-v6 { none; }; + listen-on tls ephemeral { @ns.ip@; }; allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; update-quota 1; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "example" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/upforwd/prereq.sh bind9-9.20.29/bin/tests/system/upforwd/prereq.sh --- bind9-9.20.26/bin/tests/system/upforwd/prereq.sh 2026-07-20 14:47:53.923847782 +0000 +++ bind9-9.20.29/bin/tests/system/upforwd/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/verify/tests_verify.py bind9-9.20.29/bin/tests/system/verify/tests_verify.py --- bind9-9.20.26/bin/tests/system/verify/tests_verify.py 2026-07-20 14:47:53.924847798 +0000 +++ bind9-9.20.29/bin/tests/system/verify/tests_verify.py 2026-09-11 19:41:01.393328411 +0000 @@ -9,13 +9,28 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. +from pathlib import Path from re import compile as Re import os import re +import time +from cryptography.hazmat.primitives.asymmetric import rsa +from dns.dnssectypes import NSEC3Hash +from dns.rdtypes.dnskeybase import Flag + +import dns.dnssec +import dns.name +import dns.rdata +import dns.rdataclass +import dns.rdatatype +import dns.zone import pytest +from isctest.template import NO_NS, zones +from isctest.zone import Zone + import isctest pytestmark = pytest.mark.extra_artifacts( @@ -28,12 +43,114 @@ "zones/*.out*", "zones/*.tmp", "zones/updated*", + "zones/bad-nsec3param-hash*", + "zones/nsec-bad-nsec3param-hash*", + "zones/good-bad-nsec3param-hash*", + "zones/nsec+non-zero-nsec3param-flags*", + "zones/no-nsec+non-zero-nsec3param-flags*", + "zones/nseconly-nsec3param*", ] ) VERIFY = os.environ.get("VERIFY") +def bootstrap(): + + def generate_keys(): + algorithm = dns.dnssec.Algorithm.RSASHA256 + ksk_private_key = rsa.generate_private_key(public_exponent=65537, key_size=1024) + try: + ksk_dnskey = dns.dnssec.make_dnskey( + public_key=ksk_private_key.public_key(), + algorithm=algorithm, + flags=Flag.ZONE | Flag.SEP, + ) + except ImportError as exc: + # if the cryptography package is too old, the make_dnskey() function + # will raise ImportError at runtime + pytest.skip(f"{exc}") + return ksk_private_key, ksk_dnskey + + def gen_and_sign(name, nsec3=False): + zone = Zone(name, NO_NS, signed=True) + ksk_private_key, ksk_dnskey = generate_keys() + keys = [(ksk_private_key, ksk_dnskey)] + zone.render() + + # read the rendered zone + unsigned_path = str(Path(zone.ns.name) / zone.filepath_unsigned) + signed_path = str(Path(zone.ns.name) / zone.filepath_signed) + zoneobj = dns.zone.from_file(unsigned_path, origin=f"{name}.") + lifetime = 30 * 86400 + + # sign the zone + with zoneobj.writer() as txn: + dns.dnssec.sign_zone( + zone=zoneobj, + txn=txn, + keys=keys, + lifetime=lifetime, + add_dnskey=True, + deterministic=False, # for OpenSSL<3.2.0 compat + ) + + # This generates an NSEC3 record for the apex, so that we can + # verify a zone with both a valid and invalid NSEC3PARAM record. + if nsec3: + origin = dns.name.from_text(f"{name}.") + hashname = dns.dnssec.nsec3_hash( + origin, salt=b"", iterations=0, algorithm=NSEC3Hash.SHA1 + ) + nsec3rdata = dns.rdata.from_text( + rdclass=dns.rdataclass.IN, + rdtype=dns.rdatatype.NSEC3, + tok=f"1 0 0 - {hashname} SOA NS A NSEC3PARAM DNSKEY RRSIG", + ) + nsec3_owner = dns.name.from_text(f"{hashname}.{name}.") + node = zoneobj.find_node(nsec3_owner, create=True) + nsec3_rrset = node.find_rdataset( + rdclass=dns.rdataclass.IN, rdtype=dns.rdatatype.NSEC3, create=True + ) + nsec3_rrset.ttl = 300 + nsec3_rrset.add(nsec3rdata) + + inception = int(time.time()) - 30 + nsec3_sigdata = dns.dnssec.sign( + rrset=(nsec3_owner, nsec3_rrset), + private_key=ksk_private_key, + signer=origin, + dnskey=ksk_dnskey, + inception=inception, + lifetime=lifetime, + ) + nsec3_rrsig = node.find_rdataset( + rdclass=dns.rdataclass.IN, + rdtype=dns.rdatatype.RRSIG, + covers=dns.rdatatype.NSEC3, + create=True, + ) + nsec3_rrsig.ttl = 300 + nsec3_rrsig.add(nsec3_sigdata) + + zoneobj.to_file(signed_path) + + return zone + + return { + "zones": zones( + [ + gen_and_sign("bad-nsec3param-hash"), + gen_and_sign("nsec-bad-nsec3param-hash"), + gen_and_sign("good-bad-nsec3param-hash", True), + gen_and_sign("nsec+non-zero-nsec3param-flags"), + gen_and_sign("no-nsec+non-zero-nsec3param-flags"), + gen_and_sign("nseconly-nsec3param", True), + ] + ), + } + + @pytest.mark.parametrize( "zone", [ @@ -46,6 +163,7 @@ "ksk+zsk.optout", "zsk-only.nsec3", "zsk-only.nsec", + "no-nsec3-at-insecure-delegation", ], ) def test_verify_good_zone_files(zone): @@ -142,6 +260,11 @@ assert "Expected and found NSEC3 chains not equal" in cmd.err +def test_verify_bad_zone_files_missing_nsec3_at_insecure_delegation(): + cmd = verify_bad_zone("missing-nsec3-at-insecure-delegation") + assert "Missing NSEC3 record for" in cmd.err + + # checking error message when -o is not used # and a SOA record not at top of zone is found def test_verify_soa_not_at_top_error(): @@ -176,3 +299,86 @@ ] ) assert "Loading zone 'updated' from file 'zones/updated.other'" in cmd.out + + +# checking that unknown hash is detected +def test_verify_rejects_bad_nsec3param_hash(): + cmd = isctest.run.cmd( + [ + VERIFY, + "-z", + "-o", + "bad-nsec3param-hash", + "zones/bad-nsec3param-hash.db.signed", + ], + raise_on_exception=False, + ) + assert cmd.rc != 0 + assert "No usable NSEC/NSEC3 chain for testing" in cmd.err + + +def test_verify_ignores_bad_nsec3param_hash_with_nsec(): + isctest.run.cmd( + [ + VERIFY, + "-z", + "-o", + "nsec-bad-nsec3param-hash", + "zones/nsec-bad-nsec3param-hash.db.signed", + ] + ) + + +def test_verify_ignores_bad_nsec3param_hash_with_good_nsec3param(): + isctest.run.cmd( + [ + VERIFY, + "-z", + "-o", + "good-bad-nsec3param-hash", + "zones/good-bad-nsec3param-hash.db.signed", + ] + ) + + +def test_verify_rejects_no_nsec_and_all_nsec3param_with_non_zero_flags(): + cmd = isctest.run.cmd( + [ + VERIFY, + "-z", + "-o", + "no-nsec+non-zero-nsec3param-flags", + "zones/no-nsec+non-zero-nsec3param-flags.db.signed", + ], + raise_on_exception=False, + ) + assert cmd.rc != 0 + assert "No usable NSEC/NSEC3 chain for testing" in cmd.err + + +def test_verify_ignores_nsec3param_non_zero_flags(): + isctest.run.cmd( + [ + VERIFY, + "-z", + "-o", + "nsec+non-zero-nsec3param-flags", + "zones/nsec+non-zero-nsec3param-flags.db.signed", + ], + ) + + +def test_verify_rejects_nsec3param_with_nsec_only_key(): + cmd = isctest.run.cmd( + [ + VERIFY, + "-z", + "-o", + "nseconly-nsec3param", + "zones/nseconly-nsec3param.db.signed", + ], + raise_on_exception=False, + ) + assert cmd.rc != 0 + isctest.log.debug(cmd.err) + assert "cannot use NSEC3 with key algorithm" in cmd.out diff -Nru bind9-9.20.26/bin/tests/system/verify/zones/bad-nsec3param-hash.db.j2.manual bind9-9.20.29/bin/tests/system/verify/zones/bad-nsec3param-hash.db.j2.manual --- bind9-9.20.26/bin/tests/system/verify/zones/bad-nsec3param-hash.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/verify/zones/bad-nsec3param-hash.db.j2.manual 2026-09-11 19:41:01.393328411 +0000 @@ -0,0 +1,7 @@ +{% include '_common/zones/soa.partial.db.j2' %} +{% include '_common/zones/ns.partial.db.j2' %} + +; This NSEC3PARAM record is unusable and should cause verification failure. +{% raw %} +@ NSEC3PARAM 2 0 0 - +{% endraw %} diff -Nru bind9-9.20.26/bin/tests/system/verify/zones/genzones.sh bind9-9.20.29/bin/tests/system/verify/zones/genzones.sh --- bind9-9.20.26/bin/tests/system/verify/zones/genzones.sh 2026-07-20 14:47:53.924847798 +0000 +++ bind9-9.20.29/bin/tests/system/verify/zones/genzones.sh 2026-09-11 19:41:01.393328411 +0000 @@ -244,6 +244,22 @@ rm -f ${file}.tmp $SIGNER -3 - -Px -Z nonsecify -O full -o ${zone} -f ${file} ${file} $zsk >s.out$n || dumpit s.out$n +# An non OPTOUT NSEC3 zone with a insecure delegation without a NSEC3 record +setup missing-nsec3-at-insecure-delegation bad +zsk=$($KEYGEN -a ${DEFAULT_ALGORITHM} ${zone} 2>kg1.out$n) || dumpit kg1.out$n +ksk=$($KEYGEN -a ${DEFAULT_ALGORITHM} -fK ${zone} 2>kg2.out$n) || dumpit kg2.out$n +cat unsigned.db $ksk.key $zsk.key >$file +$SIGNER -3 - -P -O full -o ${zone} -f ${file} ${file} >s.out$n || dumpit s.out$n +echo "insecure.${zone}. 3600 IN NS a.name.server." >>$file + +# An OPTOUT NSEC3 zone with a insecure delegation without a NSEC3 record +setup no-nsec3-at-insecure-delegation good +zsk=$($KEYGEN -a ${DEFAULT_ALGORITHM} ${zone} 2>kg1.out$n) || dumpit kg1.out$n +ksk=$($KEYGEN -a ${DEFAULT_ALGORITHM} -fK ${zone} 2>kg2.out$n) || dumpit kg2.out$n +cat unsigned.db $ksk.key $zsk.key >$file +$SIGNER -3 - -P -A -O full -o ${zone} -f ${file} ${file} >s.out$n || dumpit s.out$n +echo "insecure.${zone}. 3600 IN NS a.name.server." >>$file + # sign and verify with journal file setup updated other $KEYGEN -a ${DEFAULT_ALGORITHM} ${zone} >kg1.out$n 2>&1 || dumpit kg1.out$n diff -Nru bind9-9.20.26/bin/tests/system/verify/zones/good-bad-nsec3param-hash.db.j2.manual bind9-9.20.29/bin/tests/system/verify/zones/good-bad-nsec3param-hash.db.j2.manual --- bind9-9.20.26/bin/tests/system/verify/zones/good-bad-nsec3param-hash.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/verify/zones/good-bad-nsec3param-hash.db.j2.manual 2026-09-11 19:41:01.393328411 +0000 @@ -0,0 +1,8 @@ +{% include '_common/zones/soa.partial.db.j2' %} +{% include '_common/zones/ns.partial.db.j2' %} + +; This NSEC3PARAM record is unusable and should cause verification failure. +{% raw %} +@ NSEC3PARAM 1 0 0 - +@ NSEC3PARAM 2 0 0 - +{% endraw %} diff -Nru bind9-9.20.26/bin/tests/system/verify/zones/no-nsec+non-zero-nsec3param-flags.db.j2.manual bind9-9.20.29/bin/tests/system/verify/zones/no-nsec+non-zero-nsec3param-flags.db.j2.manual --- bind9-9.20.26/bin/tests/system/verify/zones/no-nsec+non-zero-nsec3param-flags.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/verify/zones/no-nsec+non-zero-nsec3param-flags.db.j2.manual 2026-09-11 19:41:01.393328411 +0000 @@ -0,0 +1,10 @@ +{% include '_common/zones/soa.partial.db.j2' %} +{% include '_common/zones/ns.partial.db.j2' %} + +; This NSEC3PARAM record should be ignored. It does not +; indicate that there is a valid NSEC3 chain. As there +; isn't another NSEC3PARAM record with zero flags nor a +; NSEC record this zone should be rejected. +{% raw %} +@ NSEC3PARAM 1 1 0 - +{% endraw %} diff -Nru bind9-9.20.26/bin/tests/system/verify/zones/nsec+non-zero-nsec3param-flags.db.j2.manual bind9-9.20.29/bin/tests/system/verify/zones/nsec+non-zero-nsec3param-flags.db.j2.manual --- bind9-9.20.26/bin/tests/system/verify/zones/nsec+non-zero-nsec3param-flags.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/verify/zones/nsec+non-zero-nsec3param-flags.db.j2.manual 2026-09-11 19:41:01.394328435 +0000 @@ -0,0 +1,9 @@ +{% include '_common/zones/soa.partial.db.j2' %} +{% include '_common/zones/ns.partial.db.j2' %} + +; This NSEC3PARAM record should be ignored. It does not +; indicate that there is a valid NSEC3 chain. +{% raw %} +@ NSEC @ SOA NS A NSEC3PARAM DNSKEY NSEC RRSIG +@ NSEC3PARAM 1 1 0 - +{% endraw %} diff -Nru bind9-9.20.26/bin/tests/system/verify/zones/nsec-badnsec3param-hash.db.j2.manual bind9-9.20.29/bin/tests/system/verify/zones/nsec-badnsec3param-hash.db.j2.manual --- bind9-9.20.26/bin/tests/system/verify/zones/nsec-badnsec3param-hash.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/verify/zones/nsec-badnsec3param-hash.db.j2.manual 2026-09-11 19:41:01.394328435 +0000 @@ -0,0 +1,8 @@ +{% include '_common/zones/soa.partial.db.j2' %} +{% include '_common/zones/ns.partial.db.j2' %} + +; This NSEC3PARAM record is unusable but should be ignored since NSEC works. +{% raw %} +@ NSEC @ SOA NS A NSEC3PARAM DNSKEY NSEC RRSIG +@ NSEC3PARAM 2 0 0 - +{% endraw %} diff -Nru bind9-9.20.26/bin/tests/system/verify/zones/nseconly-nsec3param.db.j2.manual bind9-9.20.29/bin/tests/system/verify/zones/nseconly-nsec3param.db.j2.manual --- bind9-9.20.26/bin/tests/system/verify/zones/nseconly-nsec3param.db.j2.manual 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/bin/tests/system/verify/zones/nseconly-nsec3param.db.j2.manual 2026-09-11 19:41:01.394328435 +0000 @@ -0,0 +1,8 @@ +{% include '_common/zones/soa.partial.db.j2' %} +{% include '_common/zones/ns.partial.db.j2' %} + +; This NSEC3PARAM record is valid but the DNSKEY has an NSEC-only algorithm +{% raw %} +@ NSEC3PARAM 1 0 0 - +@ DNSKEY 257 3 5 BEAAAAOlYGw53D+f01yCL5JsP0SB6EjYrnd0JYRBooAaGPT+Q0kpiN+7GviFh+nIazoB8e2Yv7mupgqkmIjObdcbGstYpUltdECdNpNmBvASKB9SBdtGeRvXXpORi3Qyxb9kHGG7SpzyYbc+KDVKnzYHB94pvqu3ZZpPFPBFtCibp/mkhw== +{% endraw %} diff -Nru bind9-9.20.26/bin/tests/system/views/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/views/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/views/ns1/named.conf.j2 2026-07-20 14:47:53.924847798 +0000 +++ bind9-9.20.29/bin/tests/system/views/ns1/named.conf.j2 2026-09-11 19:41:01.394328435 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/views/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/views/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/views/ns2/named.conf.j2 2026-07-20 14:47:53.925847813 +0000 +++ bind9-9.20.29/bin/tests/system/views/ns2/named.conf.j2 2026-09-11 19:41:01.395328459 +0000 @@ -12,27 +12,12 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "views" { keys { @@ -41,10 +26,7 @@ }; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/views/ns2/named2.conf.j2 bind9-9.20.29/bin/tests/system/views/ns2/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/views/ns2/named2.conf.j2 2026-07-20 14:47:53.925847813 +0000 +++ bind9-9.20.29/bin/tests/system/views/ns2/named2.conf.j2 2026-09-11 19:41:01.395328459 +0000 @@ -12,27 +12,15 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; 10.53.0.4; }; + {% include_indented "_common/options/sources.conf.j2" %} + {% include_indented "_common/options/server.conf.j2" %} + listen-on { @ns.ip@; 10.53.0.4; }; listen-on-v6 { none; }; allow-transfer { any; }; - recursion yes; dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "views" { keys { @@ -42,13 +30,10 @@ }; view "internal" { - match-clients { 10.53.0.2; + match-clients { @ns.ip@; 10.53.0.3; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "example" { type primary; @@ -79,10 +64,7 @@ view "external" { match-clients { any; }; - zone "." { - type hint; - file "../../_common/root.hint"; - }; + {% include_indented "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/views/ns2/named3.conf.j2 bind9-9.20.29/bin/tests/system/views/ns2/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/views/ns2/named3.conf.j2 2026-07-20 14:47:53.925847813 +0000 +++ bind9-9.20.29/bin/tests/system/views/ns2/named3.conf.j2 2026-09-11 19:41:01.395328459 +0000 @@ -12,26 +12,13 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; notify no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} include "zones.conf"; diff -Nru bind9-9.20.26/bin/tests/system/views/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/views/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/views/ns3/named.conf.j2 2026-07-20 14:47:53.926847829 +0000 +++ bind9-9.20.29/bin/tests/system/views/ns3/named.conf.j2 2026-09-11 19:41:01.395328459 +0000 @@ -12,32 +12,13 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/views/ns3/named2.conf.j2 bind9-9.20.29/bin/tests/system/views/ns3/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/views/ns3/named2.conf.j2 2026-07-20 14:47:53.926847829 +0000 +++ bind9-9.20.29/bin/tests/system/views/ns3/named2.conf.j2 2026-09-11 19:41:01.395328459 +0000 @@ -12,32 +12,13 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/views/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/views/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/views/ns5/named.conf.j2 2026-07-20 14:47:53.926847829 +0000 +++ bind9-9.20.29/bin/tests/system/views/ns5/named.conf.j2 2026-09-11 19:41:01.395328459 +0000 @@ -12,32 +12,13 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - directory "."; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "child.clone" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/wildcard/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/wildcard/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/wildcard/ns1/named.conf.j2 2026-07-20 14:47:53.927847845 +0000 +++ bind9-9.20.29/bin/tests/system/wildcard/ns1/named.conf.j2 2026-09-11 19:41:01.396328483 +0000 @@ -12,18 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; - notify yes; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db.signed"; }; /* @@ -35,9 +30,9 @@ zone "private.nsec" { type primary; file "private.nsec.db.signed"; }; zone "nestedwild.test" { - type primary; - file "nestedwild.db"; - check-names ignore; + type primary; + file "nestedwild.db"; + check-names ignore; }; /* @@ -45,9 +40,9 @@ * also has a wildcard, used to abort named when served from RBTDB. */ zone "entwild.test" { - type primary; - file "entwild.db.signed"; - check-names ignore; + type primary; + file "entwild.db.signed"; + check-names ignore; }; /* diff -Nru bind9-9.20.26/bin/tests/system/wildcard/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/wildcard/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/wildcard/ns2/named.conf.j2 2026-07-20 14:47:53.927847845 +0000 +++ bind9-9.20.29/bin/tests/system/wildcard/ns2/named.conf.j2 2026-09-11 19:41:01.397328507 +0000 @@ -12,19 +12,10 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; - notify yes; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/wildcard/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/wildcard/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/wildcard/ns3/named.conf.j2 2026-07-20 14:47:53.927847845 +0000 +++ bind9-9.20.29/bin/tests/system/wildcard/ns3/named.conf.j2 2026-09-11 19:41:01.397328507 +0000 @@ -12,21 +12,12 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; - notify yes; }; +{% include "_common/controls.conf.j2" %} + include "../ns1/trusted.conf"; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/wildcard/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/wildcard/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/wildcard/ns4/named.conf.j2 2026-07-20 14:47:53.927847845 +0000 +++ bind9-9.20.29/bin/tests/system/wildcard/ns4/named.conf.j2 2026-09-11 19:41:01.397328507 +0000 @@ -12,20 +12,14 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; - notify yes; forward only; forwarders { 10.53.0.2; }; }; +{% include "_common/controls.conf.j2" %} + include "../ns1/trusted.conf"; include "../ns1/private.nsec.conf"; include "../ns1/private.nsec3.conf"; diff -Nru bind9-9.20.26/bin/tests/system/wildcard/ns5/named.conf.j2 bind9-9.20.29/bin/tests/system/wildcard/ns5/named.conf.j2 --- bind9-9.20.26/bin/tests/system/wildcard/ns5/named.conf.j2 2026-07-20 14:47:53.928847860 +0000 +++ bind9-9.20.29/bin/tests/system/wildcard/ns5/named.conf.j2 2026-09-11 19:41:01.397328507 +0000 @@ -12,21 +12,12 @@ */ options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.5; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation yes; - notify yes; }; +{% include "_common/controls.conf.j2" %} + include "../ns1/trusted.conf"; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} diff -Nru bind9-9.20.26/bin/tests/system/xfer/ans11/ans.py bind9-9.20.29/bin/tests/system/xfer/ans11/ans.py --- bind9-9.20.26/bin/tests/system/xfer/ans11/ans.py 2026-07-20 14:47:53.928847860 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ans11/ans.py 2026-09-11 19:41:01.398328531 +0000 @@ -13,285 +13,180 @@ from collections.abc import AsyncGenerator -import struct - import dns.flags import dns.rcode +import dns.rdataclass import dns.rdatatype +import dns.rrset from isctest.asyncserver import ( AsyncDnsServer, - BytesResponseSend, + AxfrHandler, DnsProtocol, DnsResponseSend, QueryContext, - ResponseAction, ResponseHandler, + StaticResponseHandler, ) -# DNS constants used by raw wire builder functions below -DNS_TYPE_SOA = 6 -DNS_TYPE_A = 1 -DNS_TYPE_NS = 2 -DNS_TYPE_AXFR = 252 -DNS_TYPE_IXFR = 251 -DNS_CLASS_IN = 1 -DNS_FLAG_QR = 0x8000 -DNS_FLAG_AA = 0x0400 -DNS_RCODE_NOERROR = 0 -DNS_RCODE_SERVFAIL = 2 - -ZONE_NAME = "ixfr-race." -NUM_RECORDS = 400 - - -def encode_name(name): - """Encode a DNS name in wire format (no compression).""" - parts = name.rstrip(".").split(".") - result = b"" - for part in parts: - encoded = part.encode("ascii") - result += struct.pack("B", len(encoded)) + encoded - result += b"\x00" - return result - - -def build_soa_rdata( - mname, rname, serial, refresh=3600, retry=900, expire=604800, minimum=86400 -): - """Build SOA record rdata.""" - rdata = encode_name(mname) - rdata += encode_name(rname) - rdata += struct.pack("!IIIII", serial, refresh, retry, expire, minimum) - return rdata - - -def build_a_rdata(ip_str): - """Build A record rdata from dotted-quad string.""" - parts = ip_str.split(".") - return struct.pack("4B", *[int(p) for p in parts]) - - -def build_rr(name_bytes, rtype, rclass, ttl, rdata): - """Build a complete resource record.""" - rr = name_bytes - rr += struct.pack("!HHIH", rtype, rclass, ttl, len(rdata)) - rr += rdata - return rr - - -def build_dns_header(qid, flags, qdcount, ancount, nscount=0, arcount=0): - """Build DNS message header.""" - return struct.pack("!HHHHHH", qid, flags, qdcount, ancount, nscount, arcount) - - -def build_ixfr_message1(qid, zone_name, num_records): - """ - Build IXFR Message 1: A valid IXFR diff that triggers ixfr_commit(). - - This message contains a complete diff 1 (large, many records) which - triggers ixfr_commit() -> isc_work_enqueue() -> worker thread starts. - - The message ends with a boundary SOA that starts diff 2, so the state - machine is in XFRST_IXFR_DEL waiting for more records. - - Answer section structure: - 1. Initial SOA (end_serial=3) -- XFRST_ZONEXFRREQUEST - 2. Old SOA (serial=1) -- XFRST_FIRSTDATA -> IXFR -> DELSOA - 3. DEL A records (num_records) -- XFRST_IXFR_DEL (diffs++) - 4. Mid SOA (serial=2) -- XFRST_IXFR_ADDSOA (diffs++) - 5. ADD A records (num_records) -- XFRST_IXFR_ADD (diffs++) - 6. Boundary SOA (serial=2) -- ixfr_commit()! Worker enqueued. - Then goto redo -> DELSOA of diff 2 - """ - zone_wire = encode_name(zone_name) - question = zone_wire + struct.pack("!HH", DNS_TYPE_IXFR, DNS_CLASS_IN) +ZONE = "ixfr-race." +NS_NAME = f"ns.{ZONE}" +FIRST_DIFF_RECORDS = 50 +SECOND_DIFF_RECORDS = 200 + + +def rrset( + owner: str, ttl: int, rdtype: dns.rdatatype.RdataType, rdata: str +) -> dns.rrset.RRset: + return dns.rrset.from_text(owner, ttl, dns.rdataclass.IN, rdtype, rdata) + + +def soa(serial: int) -> dns.rrset.RRset: + return rrset( + ZONE, + 3600, + dns.rdatatype.SOA, + f"{NS_NAME} admin.{ZONE} {serial} 3600 900 604800 86400", + ) - mname = "ns." + zone_name - rname = "admin." + zone_name - end_serial = 3 - old_serial = 1 - mid_serial = 2 - - soa_end = build_soa_rdata(mname, rname, end_serial) - soa_old = build_soa_rdata(mname, rname, old_serial) - soa_mid = build_soa_rdata(mname, rname, mid_serial) - - records = [] - - # 1. Initial SOA (end serial) - records.append(build_rr(zone_wire, DNS_TYPE_SOA, DNS_CLASS_IN, 3600, soa_end)) - - # 2. Old SOA (serial 1) - triggers IXFR detection - records.append(build_rr(zone_wire, DNS_TYPE_SOA, DNS_CLASS_IN, 3600, soa_old)) - - # 3. DEL A records - for i in range(num_records): - name = encode_name(f"host-{i}.{zone_name}") - ip = f"10.0.{(i >> 8) & 0xFF}.{i & 0xFF}" - records.append( - build_rr(name, DNS_TYPE_A, DNS_CLASS_IN, 3600, build_a_rdata(ip)) - ) - # 4. Mid SOA (serial 2) - end of DEL, start of ADD - records.append(build_rr(zone_wire, DNS_TYPE_SOA, DNS_CLASS_IN, 3600, soa_mid)) +def a(owner: str, address: str) -> dns.rrset.RRset: + return rrset(owner, 3600, dns.rdatatype.A, address) - # 5. ADD A records - for i in range(num_records): - name = encode_name(f"host-{i}.{zone_name}") - ip = f"10.1.{(i >> 8) & 0xFF}.{i & 0xFF}" - records.append( - build_rr(name, DNS_TYPE_A, DNS_CLASS_IN, 3600, build_a_rdata(ip)) - ) - # 6. Boundary SOA (serial=2 == current_serial) -> ixfr_commit()! - # This triggers the worker thread via isc_work_enqueue(). - # Then goto redo processes it as DELSOA of diff 2. - records.append(build_rr(zone_wire, DNS_TYPE_SOA, DNS_CLASS_IN, 3600, soa_mid)) +def ns() -> dns.rrset.RRset: + return rrset(ZONE, 3600, dns.rdatatype.NS, NS_NAME) - ancount = len(records) - answer = b"".join(records) - flags = DNS_FLAG_QR | DNS_FLAG_AA | DNS_RCODE_NOERROR - header = build_dns_header(qid, flags, 1, ancount) - msg = header + question + answer - return msg +def host_a_records(prefix: str, second_octet: int, count: int) -> list[dns.rrset.RRset]: + return [ + a(f"{prefix}-{i}.{ZONE}", f"10.{second_octet}.{(i >> 8) & 0xFF}.{i & 0xFF}") + for i in range(count) + ] -def build_bad_rcode_message2(qid, zone_name): +def ixfr_diffs() -> list[dns.rrset.RRset]: """ - Build Message 2 - - A DNS response with rcode=SERVFAIL. When BIND receives this during an - active IXFR transfer: + Craft two complete IXFR diffs, but omit the terminating SOA. - xfrin_recv_done(): - msg->rcode != dns_rcode_noerror (SERVFAIL != NOERROR) -> - result = dns_result_fromrcode(msg->rcode) -> - reqtype == dns_rdatatype_ixfr (not axfr/soa) -> - falls through to try_axfr: -> - xfrin_reset() -> destroys journal/version + Committing the first diff starts the apply worker. Parsing the second, + larger diff gives that worker time to splice the first chunk from the + shared queue before the second chunk is committed. The second chunk is + then left on xfr->diff_head for the following SERVFAIL to expose GL#6114. + """ + return [ + soa(4), + soa(1), + soa(2), + *host_a_records("first", 1, FIRST_DIFF_RECORDS), + soa(2), + soa(3), + *host_a_records("second", 2, SECOND_DIFF_RECORDS), + soa(3), + ] - Meanwhile ixfr_apply worker from Message 1 is still running -> UAF. - This works with DEFAULT secondary configuration (no special options). +class TransferState: + """ + Flag toggled once the initial AXFR (serial 1) has been served. The SOA + handlers read it to advertise serial 1 before the transfer and serial 4 + after it, so the secondary's next refresh switches from AXFR to IXFR. """ - zone_wire = encode_name(zone_name) - question = zone_wire + struct.pack("!HH", DNS_TYPE_IXFR, DNS_CLASS_IN) - flags = DNS_FLAG_QR | DNS_FLAG_AA | DNS_RCODE_SERVFAIL - header = build_dns_header(qid, flags, 1, 0) - msg = header + question + def __init__(self) -> None: + self.initial_axfr_served = False - return msg +class TransferHandler(ResponseHandler): + """Base for the handlers that share a single TransferState.""" -def build_soa_response(qid, zone_name, serial): - """Build a SOA response for the zone.""" - zone_wire = encode_name(zone_name) - question = zone_wire + struct.pack("!HH", DNS_TYPE_SOA, DNS_CLASS_IN) + def __init__(self, progress: TransferState) -> None: + super().__init__() + self._progress = progress - mname = "ns." + zone_name - rname = "admin." + zone_name - soa_rdata = build_soa_rdata(mname, rname, serial) - answer = build_rr(zone_wire, DNS_TYPE_SOA, DNS_CLASS_IN, 3600, soa_rdata) - flags = DNS_FLAG_QR | DNS_FLAG_AA | DNS_RCODE_NOERROR - header = build_dns_header(qid, flags, 1, 1) - return header + question + answer +class InitialSoaHandler(TransferHandler, StaticResponseHandler): + answer = [soa(1)] + def match(self, qctx: QueryContext) -> bool: + return ( + qctx.qtype == dns.rdatatype.SOA and not self._progress.initial_axfr_served + ) -def build_axfr_response(qid, zone_name, serial, num_records): - """ - Build a complete AXFR response for initial zone load. - AXFR format: SOA, NS, A records, ..., SOA (trailing SOA marks end). - """ - zone_wire = encode_name(zone_name) - question = zone_wire + struct.pack("!HH", DNS_TYPE_AXFR, DNS_CLASS_IN) +class RefreshSoaHandler(TransferHandler, StaticResponseHandler): + answer = [soa(4)] - mname = "ns." + zone_name - rname = "admin." + zone_name - soa_rdata = build_soa_rdata(mname, rname, serial) + def match(self, qctx: QueryContext) -> bool: + return qctx.qtype == dns.rdatatype.SOA and self._progress.initial_axfr_served - records = [] - # Opening SOA - records.append(build_rr(zone_wire, DNS_TYPE_SOA, DNS_CLASS_IN, 3600, soa_rdata)) +class InitialAxfrHandler(TransferHandler, AxfrHandler): + """Serve the initial zone (serial 1) and mark the transfer as done.""" - # NS record - ns_wire = encode_name("ns." + zone_name) - records.append(build_rr(zone_wire, DNS_TYPE_NS, DNS_CLASS_IN, 3600, ns_wire)) + initial_soa = soa(1) + zone_contents = [ + ns(), + a(NS_NAME, "127.0.0.1"), + ] + final_soa = soa(1) - # NS A record - records.append( - build_rr(ns_wire, DNS_TYPE_A, DNS_CLASS_IN, 3600, build_a_rdata("127.0.0.1")) - ) + def match(self, qctx: QueryContext) -> bool: + matched = super().match(qctx) + if matched: + self._progress.initial_axfr_served = True + return matched - # A records (matching gen_zone.py output) - for i in range(num_records): - name = encode_name(f"host-{i}.{zone_name}") - ip = f"10.0.{(i >> 8) & 0xFF}.{i & 0xFF}" - records.append( - build_rr(name, DNS_TYPE_A, DNS_CLASS_IN, 3600, build_a_rdata(ip)) - ) - # Trailing SOA (marks end of AXFR) - records.append(build_rr(zone_wire, DNS_TYPE_SOA, DNS_CLASS_IN, 3600, soa_rdata)) +class TruncatedIxfrHandler(ResponseHandler): + """Set TC on an IXFR received over UDP to force the secondary to retry over TCP.""" - ancount = len(records) - answer = b"".join(records) - flags = DNS_FLAG_QR | DNS_FLAG_AA | DNS_RCODE_NOERROR - header = build_dns_header(qid, flags, 1, ancount) - msg = header + question + answer + def match(self, qctx: QueryContext) -> bool: + return qctx.qtype == dns.rdatatype.IXFR and qctx.protocol == DnsProtocol.UDP - return msg + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + qctx.response.flags |= dns.flags.TC + yield DnsResponseSend(qctx.response) -class IxfrRaceHandler(ResponseHandler): +class RaceIxfrHandler(ResponseHandler): """ - Handle SOA, AXFR, and IXFR queries to trigger the IXFR->AXFR race condition. + Reproduce the IXFR->AXFR use-after-free races (GL#5767 and GL#6114). - Phase 1: Respond to SOA with serial=1 and serve an AXFR to load the zone. - Phase 2: After AXFR, respond to SOA with serial=3 to trigger IXFR. - On IXFR, send a valid large diff (msg1) followed immediately by a - SERVFAIL response (msg2) to race ixfr_commit() against xfrin_reset(). + Over TCP, send two valid IXFR diffs. The first starts the apply worker and + the second remains queued after that worker splices the first chunk. + Immediately follow them with a SERVFAIL response that makes + xfrin_recv_done() defer the AXFR retry until the worker finishes. Cleanup + then has to detach the queued second chunk before freeing it. """ - def __init__(self) -> None: - self._axfr_done = False + def match(self, qctx: QueryContext) -> bool: + return qctx.qtype == dns.rdatatype.IXFR and qctx.protocol == DnsProtocol.TCP async def get_responses( self, qctx: QueryContext - ) -> AsyncGenerator[ResponseAction, None]: - qid = qctx.query.id - - if qctx.qtype == dns.rdatatype.SOA: - serial = 3 if self._axfr_done else 1 - yield BytesResponseSend(build_soa_response(qid, ZONE_NAME, serial)) - - elif qctx.qtype == dns.rdatatype.AXFR: - yield BytesResponseSend(build_axfr_response(qid, ZONE_NAME, 1, NUM_RECORDS)) - self._axfr_done = True - - elif qctx.qtype == dns.rdatatype.IXFR: - if qctx.protocol == DnsProtocol.UDP: - # Force TCP retry by setting the TC bit - qctx.response.flags |= dns.flags.TC - yield DnsResponseSend(qctx.response) - else: - # Message 1: Valid IXFR diff -> triggers ixfr_commit() - yield BytesResponseSend( - build_ixfr_message1(qid, ZONE_NAME, NUM_RECORDS) - ) - # Message 2: SERVFAIL -> triggers xfrin_reset() while - # ixfr_apply worker from Message 1 is still running -> UAF - yield BytesResponseSend(build_bad_rcode_message2(qid, ZONE_NAME)) + ) -> AsyncGenerator[DnsResponseSend, None]: + for rrset_ in ixfr_diffs(): + qctx.response.answer.append(rrset_) + yield DnsResponseSend(qctx.response) + + qctx.prepare_new_response(with_zone_data=False) + qctx.response.set_rcode(dns.rcode.SERVFAIL) + yield DnsResponseSend(qctx.response) def main() -> None: - server = AsyncDnsServer(default_rcode=dns.rcode.NOERROR, default_aa=True) - server.install_response_handler(IxfrRaceHandler()) + server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR) + progress = TransferState() + server.install_response_handlers( + InitialSoaHandler(progress), + RefreshSoaHandler(progress), + InitialAxfrHandler(progress), + TruncatedIxfrHandler(), + RaceIxfrHandler(), + ) server.run() diff -Nru bind9-9.20.26/bin/tests/system/xfer/ans5/ans.py bind9-9.20.29/bin/tests/system/xfer/ans5/ans.py --- bind9-9.20.26/bin/tests/system/xfer/ans5/ans.py 2026-07-20 14:47:53.928847860 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ans5/ans.py 2026-09-11 19:41:01.398328531 +0000 @@ -114,29 +114,40 @@ return f"SignResponses({self._inner}, key={self._key})" -class SignFirstResponse(ResponseHandlerWrapper): +class SignFirstAndLastResponses(ResponseHandlerWrapper): + """Sign the first and last of the three responses yielded by AxfrHandler.""" + def __init__(self, inner: ResponseHandler, key: dns.tsig.Key = DEFAULT_KEY) -> None: super().__init__(inner) self._key = key - self._first_yielded = False + self._response_number = 0 + self._tsig_ctx: dns.tsig.GSSTSig | dns.tsig.HMACTSig | None = None def _on_query_received(self, qctx: QueryContext) -> None: - self._first_yielded = False + self._response_number = 0 + self._tsig_ctx = None def _modify_response( self, qctx: QueryContext, response_action: ResponseAction ) -> None: assert isinstance( response_action, DnsResponseSend - ), "SignFirstResponse can only wrap handlers that yield DnsResponseSend" - if not self._first_yielded: - response_action.response.use_tsig(self._key) - self._first_yielded = True + ), "sparse signing requires DnsResponseSend" + response = response_action.response + if self._response_number == 1: + response.tsig = None + wire = response.to_wire(max_size=65535) + assert self._tsig_ctx is not None + # Keep the unsigned message in the digest so the final TSIG is valid. + self._tsig_ctx.update(wire) else: - response_action.response.tsig = None + response.use_tsig(self._key) + _ = response.to_wire(multi=True, tsig_ctx=self._tsig_ctx) + self._tsig_ctx = response.tsig_ctx + self._response_number += 1 def __str__(self) -> str: - return f"SignFirstResponse({self._inner}, key={self._key})" + return f"SignFirstAndLastResponses({self._inner}, key={self._key})" class Add50ToMessageIdFromSecondResponse(ResponseHandlerWrapper): @@ -366,7 +377,7 @@ ), "partial": ( SignResponses(SoaHandler(serial := 4)), - SignFirstResponse( + SignFirstAndLastResponses( XferAxfrHandler( soa_serial=serial, txt_data="partially signed AXFR", diff -Nru bind9-9.20.26/bin/tests/system/xfer/ans9/ans.py bind9-9.20.29/bin/tests/system/xfer/ans9/ans.py --- bind9-9.20.26/bin/tests/system/xfer/ans9/ans.py 2026-07-20 14:47:53.929847876 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ans9/ans.py 2026-09-11 19:41:01.398328531 +0000 @@ -11,132 +11,153 @@ information regarding copyright ownership. """ -from collections.abc import AsyncGenerator +from collections.abc import AsyncGenerator, Collection import dns.name import dns.rcode +import dns.rdataclass import dns.rdatatype import dns.rrset from isctest.asyncserver import ( + AxfrHandler, ControllableAsyncDnsServer, DnsResponseSend, - DomainHandler, QueryContext, ResponseAction, + ResponseHandler, ToggleResponsesCommand, ) +TTL = 300 -class AXFRServer(DomainHandler): +RECONFIG_ZONE = "xfr-and-reconfig." +OVERRUN_ZONE = "private-dns-overrun." + +# The malformed DNSKEY's algorithm identifier finishes on a 00 byte in the +# record that follows it in the same message. That following record, the +# well-formed DNSKEY, starts with a compression pointer followed by the type, +# which starts with 00. +OVERRUN_DNSKEY = "\\# 12 00 00 00 fd 09 00 00 00 00 00 00 00" +WELL_FORMED_DNSKEY = "\\# 12 00 00 00 fd 06 00 00 00 00 00 00 00" + + +def rrset( + owner: str | dns.name.Name, rdtype: dns.rdatatype.RdataType, rdata: str +) -> dns.rrset.RRset: + return dns.rrset.from_text(owner, TTL, dns.rdataclass.IN, rdtype, rdata) + + +def soa(owner: str | dns.name.Name, serial: int) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.SOA, f". . {serial} 0 0 0 0") + + +def ns(owner: str | dns.name.Name) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.NS, ".") + + +def txt(owner: str | dns.name.Name) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.TXT, "foo bar") + + +def dnskey(owner: str | dns.name.Name, keydata: str) -> dns.rrset.RRset: + return rrset(owner, dns.rdatatype.DNSKEY, keydata) + + +class SerialCounter: """ - Yield SOA and AXFR responses. Every new AXFR response increments the SOA - version. + Shared SOA serial advanced by one after every completed AXFR, so each + secondary refresh sees a newer serial and re-transfers the zone. """ - domains = ["xfr-and-reconfig", "private-dns-overrun"] - def __init__(self) -> None: + self.serial = 0 + + +class SerialCounted(ResponseHandler): + def __init__(self, serials: SerialCounter) -> None: super().__init__() - self.soa_version = 0 + self._serials = serials + + +class SoaHandler(SerialCounted): + def match(self, qctx: QueryContext) -> bool: + return qctx.qtype == dns.rdatatype.SOA + + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[DnsResponseSend, None]: + qctx.response.answer.append(soa(qctx.qname, self._serials.serial)) + yield DnsResponseSend(qctx.response) + + +class ZoneAxfrHandler(AxfrHandler, SerialCounted): + """ + Serve an AXFR for a single zone whose SOA serial is drawn from a shared + SerialCounter, bumping it once the transfer completes. Subclasses set + `zone` and define `zone_contents`. + """ + + zone: str + + def match(self, qctx: QueryContext) -> bool: + return super().match(qctx) and qctx.qname == dns.name.from_text(self.zone) async def get_responses( self, qctx: QueryContext ) -> AsyncGenerator[ResponseAction, None]: - # This is oversimplified because I am lazy - we are appending the SOA - # RRset to the ANSWER section for _every_ QTYPE. named is only - # expected to send a SOA query over UDP and then an AXFR query over - # TCP. Responses to both of those start with a SOA RRset in the ANSWER - # section :-) - soa_message = qctx.response - soa_rrset = dns.rrset.from_text( - qctx.qname, - 300, - qctx.qclass, - dns.rdatatype.SOA, - f". . {self.soa_version} 0 0 0 0", - ) - soa_message.answer.append(soa_rrset) - - yield DnsResponseSend(soa_message) - - if qctx.qtype == dns.rdatatype.SOA: - # If QTYPE=SOA, the SOA record is the complete response. - return - - if qctx.qtype != dns.rdatatype.AXFR: - # If QTYPE=AXFR, we will continue cramming RRsets into the ANSWER - # section of a subsequent DNS message below. - # - # If QTYPE was not SOA or AXFR, abort. Yeah, we just sent a broken - # response by yielding DnsResponseSend() with a SOA RRset in the - # ANSWER section above. We will have to carry that burden for the - # rest of our lives. - return - - # Send just the obligatory NS RRset at zone apex in the next message. - # This is stupidly inefficient, but makes looping below simpler as we - # will already have been done with the mandatory stuff by then. - ns_message = qctx.prepare_new_response() - ns_rrset = dns.rrset.from_text( - qctx.qname, 300, qctx.qclass, dns.rdatatype.NS, "." - ) - ns_message.answer.append(ns_rrset) - - yield DnsResponseSend(ns_message) - - # Generate the AXFR with a txt rrset. - txt_message = qctx.prepare_new_response() - txt_rrset = dns.rrset.from_text( - qctx.qname, - 300, - qctx.qclass, - dns.rdatatype.TXT, - "foo bar", - ) - txt_message.answer.append(txt_rrset) - - yield DnsResponseSend(txt_message) - - if qctx.qname == dns.name.from_text("private-dns-overrun"): - # A message where the malformed DNSKEY algorithm identifier - # finishes on a 00 byte in the next record. Assumes the - # next record starts with a compression pointer which is - # followed by the type which starts with 00. - - # Generate malformed PRIVATE DNS DNSKEY - dnskey_message = qctx.prepare_new_response() - dnskey_rrset = dns.rrset.from_text( - qctx.qname, - 300, - qctx.qclass, - dns.rdatatype.DNSKEY, - "\\# 12 00 00 00 fd 09 00 00 00 00 00 00 00", - ) - dnskey_message.answer.append(dnskey_rrset) - # Generate well formed PRIVATE DNS DNSKEY - dnskey_rrset = dns.rrset.from_text( - qctx.qname, - 300, - qctx.qclass, - dns.rdatatype.DNSKEY, - "\\# 12 00 00 00 fd 06 00 00 00 00 00 00 00", - ) - dnskey_message.answer.append(dnskey_rrset) + async for action in super().get_responses(qctx): + yield action + self._serials.serial += 1 - yield DnsResponseSend(dnskey_message) + @property + def initial_soa(self) -> dns.rrset.RRset: + return soa(self.zone, self._serials.serial) - # Finish the AXFR transaction by sending the second SOA RRset. - yield DnsResponseSend(soa_message) + @property + def final_soa(self) -> dns.rrset.RRset: + return soa(self.zone, self._serials.serial) - # This makes sure that the next SOA request causes a new zone transfer - self.soa_version += 1 +class ReconfigAxfrHandler(ZoneAxfrHandler): + zone = RECONFIG_ZONE -if __name__ == "__main__": + @property + def zone_contents(self) -> Collection[dns.rrset.RRset]: + return [ + ns(self.zone), + txt(self.zone), + ] + + +class OverrunAxfrHandler(ZoneAxfrHandler): + """Serve the malformed PRIVATEDNS DNSKEY overrun; see OVERRUN_DNSKEY.""" + + zone = OVERRUN_ZONE + + @property + def zone_contents(self) -> Collection[dns.rrset.RRset]: + return [ + ns(self.zone), + txt(self.zone), + dnskey(self.zone, OVERRUN_DNSKEY), + dnskey(self.zone, WELL_FORMED_DNSKEY), + ] + + +def main() -> None: server = ControllableAsyncDnsServer( default_aa=True, default_rcode=dns.rcode.NOERROR ) server.install_control_command(ToggleResponsesCommand()) - server.install_response_handler(AXFRServer()) + serials = SerialCounter() + server.install_response_handlers( + SoaHandler(serials), + OverrunAxfrHandler(serials), + ReconfigAxfrHandler(serials), + ) server.run() + + +if __name__ == "__main__": + main() diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns1/named.conf.j2 2026-07-20 14:47:53.929847876 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns1/named.conf.j2 2026-09-11 19:41:01.399328555 +0000 @@ -11,24 +11,13 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; }; zone "." { @@ -60,7 +49,7 @@ {% if enable_some_zones | default(True) %} zone "secondary" { type primary; - allow-transfer { 10.53.0.1; 10.53.0.2; 10.53.0.6; 10.53.0.7; }; + allow-transfer { @ns.ip@; 10.53.0.2; 10.53.0.6; 10.53.0.7; }; file "sec.db"; }; diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns1/named2.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns1/named2.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns1/named2.conf.j2 2026-07-20 14:47:53.929847876 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns1/named2.conf.j2 2026-09-11 19:41:01.399328555 +0000 @@ -11,24 +11,13 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; }; zone "." { diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns1/named3.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns1/named3.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns1/named3.conf.j2 2026-07-20 14:47:53.930847891 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns1/named3.conf.j2 2026-09-11 19:41:01.399328555 +0000 @@ -11,24 +11,13 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; }; zone "." { diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns2/named.conf.j2 2026-07-20 14:47:53.930847891 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns2/named.conf.j2 2026-09-11 19:41:01.400328579 +0000 @@ -12,29 +12,15 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; ixfr-from-differences yes; check-integrity no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key tsigzone. { algorithm @DEFAULT_HMAC@; @@ -45,10 +31,7 @@ key tsigzone.; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type primary; @@ -61,7 +44,7 @@ allow-transfer { tzkey; }; }; -remote-servers "ns1" port @PORT@ source 10.53.0.2 { +remote-servers "ns1" port @PORT@ source @ns.ip@ { 10.53.0.1; }; diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns3/named.conf.j2 2026-07-20 14:47:53.930847891 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns3/named.conf.j2 2026-09-11 19:41:01.400328579 +0000 @@ -12,37 +12,19 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; - recursion yes; dnssec-validation no; - notify yes; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} key tsigzone. { algorithm @DEFAULT_HMAC@; secret "1234abcd8765"; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "example" { type secondary; @@ -52,7 +34,7 @@ zone "primary" { type secondary; - transfer-source 10.53.0.3 port @EXTRAPORT1@; + transfer-source @ns.ip@ port @EXTRAPORT1@; primaries { 10.53.0.6; }; file "primary.bk"; }; diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns4/named.conf.j2 2026-07-20 14:47:53.930847891 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns4/named.conf.j2 2026-09-11 19:41:01.400328579 +0000 @@ -13,25 +13,13 @@ {% set ns4_as_secondary_for_nil = ns4_as_secondary_for_nil | default(False) %} options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; blackhole { none; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - key unused_key. { secret "1234abcd8765"; algorithm @DEFAULT_HMAC@; @@ -42,9 +30,7 @@ algorithm @DEFAULT_HMAC@; }; -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; @@ -53,8 +39,8 @@ {% if ns4_as_secondary_for_nil %} zone "nil" { - type secondary; - file "nil.db"; - primaries { 10.53.0.5 key tsig_key; }; + type secondary; + file "nil.db"; + primaries { 10.53.0.5 key tsig_key; }; }; {% endif %} diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns6/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns6/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns6/named.conf.j2 2026-07-20 14:47:53.931847907 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns6/named.conf.j2 2026-09-11 19:41:01.400328579 +0000 @@ -11,34 +11,20 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.6; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; ixfr-from-differences primary; check-integrity no; tcp-idle-timeout 600; min-transfer-rate-in 10240 300; # this is tested as seconds, when used with '-T transferinsecs' (i.e. convert the default '10240 5' back so that it doesn't interfere with other tests) }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "primary" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns7/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns7/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns7/named.conf.j2 2026-07-20 14:47:53.931847907 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns7/named.conf.j2 2026-09-11 19:41:01.400328579 +0000 @@ -11,32 +11,18 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.7; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; ixfr-from-differences secondary; check-integrity no; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/root.hint.conf" %} zone "primary2" { type primary; diff -Nru bind9-9.20.26/bin/tests/system/xfer/ns8/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer/ns8/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer/ns8/named.conf.j2 2026-07-20 14:47:53.931847907 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/ns8/named.conf.j2 2026-09-11 19:41:01.400328579 +0000 @@ -11,20 +11,10 @@ * information regarding copyright ownership. */ -include "../../_common/rndc.key"; - -controls { - inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} options { - query-source address 10.53.0.8; - notify-source 10.53.0.8; - transfer-source 10.53.0.8; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.8; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; diff -Nru bind9-9.20.26/bin/tests/system/xfer/prereq.sh bind9-9.20.29/bin/tests/system/xfer/prereq.sh --- bind9-9.20.26/bin/tests/system/xfer/prereq.sh 2026-07-20 14:47:53.931847907 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -#!/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. - -. ../conf.sh - -# macOS ships with Net::DNS 0.74 which does not work with -# HMAC-SHA256, despite the workarounds in ans.pl - -if ${PERL} -MNet::DNS -e 'exit ($Net::DNS::VERSION >= 1.0)'; then - version=$(${PERL} -MNet::DNS -e 'print $Net::DNS::VERSION') - echo_i "perl Net::DNS $version is too old - skipping xfer test" - exit 1 -fi - -if ! ${PERL} -MDigest::HMAC -e ''; then - echo_i "perl Digest::HMAC module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/xfer/tests_xfer.py bind9-9.20.29/bin/tests/system/xfer/tests_xfer.py --- bind9-9.20.26/bin/tests/system/xfer/tests_xfer.py 2026-07-20 14:47:53.932847922 +0000 +++ bind9-9.20.29/bin/tests/system/xfer/tests_xfer.py 2026-09-11 19:41:01.401328603 +0000 @@ -616,8 +616,8 @@ ) -# See #5767 -def test_ixfr_race(ns6): +# See #5767 and #6114 +def test_ixfr_race(named_port, ns6): isctest.log.info( "Check that ixfr-race has been successfully transferred by the secondary" ) @@ -631,9 +631,13 @@ "zone ixfr-race/IN: zone transfer finished: success" ) - isctest.log.info("Try to reload the zone from the primary") + isctest.log.info("Trigger IXFR fallback while a second diff is queued") with ns6.watch_log_from_here() as watcher_transfer_completed: ns6.rndc("reload ixfr-race") watcher_transfer_completed.wait_for_line( + f"transfer of 'ixfr-race/IN' from 10.53.0.11#{named_port}: " + "got SERVFAIL, retrying with AXFR" + ) + watcher_transfer_completed.wait_for_line( "zone ixfr-race/IN: zone transfer finished: success" ) diff -Nru bind9-9.20.26/bin/tests/system/xfer_servers_list/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer_servers_list/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer_servers_list/ns1/named.conf.j2 2026-07-20 14:47:53.932847922 +0000 +++ bind9-9.20.29/bin/tests/system/xfer_servers_list/ns1/named.conf.j2 2026-09-11 19:41:01.401328603 +0000 @@ -12,9 +12,10 @@ */ options { - listen-on port @PORT@ { 10.53.0.1; }; - transfer-source 10.53.0.1; - pid-file "named.pid"; + {% include_indented "_common/options/server.conf.j2" %} + {% include_indented "_common/options/listen.conf.j2" %} + query-source address @ns.ip@; + transfer-source @ns.ip@; recursion no; /* * Notifications are sent from 10.53.1.1. This, the `notify @@ -67,11 +68,4 @@ file "test.db"; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/xfer_servers_list/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer_servers_list/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer_servers_list/ns2/named.conf.j2 2026-07-20 14:47:53.932847922 +0000 +++ bind9-9.20.29/bin/tests/system/xfer_servers_list/ns2/named.conf.j2 2026-09-11 19:41:01.402328626 +0000 @@ -12,9 +12,7 @@ */ options { - listen-on port @PORT@ { 10.53.0.2; }; - transfer-source 10.53.0.2; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} recursion no; }; @@ -38,11 +36,4 @@ primaries { 10.53.0.1 port @PORT@ key xfrkey; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/xfer_servers_list/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer_servers_list/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer_servers_list/ns3/named.conf.j2 2026-07-20 14:47:53.932847922 +0000 +++ bind9-9.20.29/bin/tests/system/xfer_servers_list/ns3/named.conf.j2 2026-09-11 19:41:01.402328626 +0000 @@ -12,9 +12,7 @@ */ options { - listen-on port @PORT@ { 10.53.0.3; }; - transfer-source 10.53.0.3; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} recursion no; }; @@ -38,11 +36,4 @@ primaries { 10.53.0.1 port @PORT@ key xfrkey; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/xfer_servers_list/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/xfer_servers_list/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xfer_servers_list/ns4/named.conf.j2 2026-07-20 14:47:53.932847922 +0000 +++ bind9-9.20.29/bin/tests/system/xfer_servers_list/ns4/named.conf.j2 2026-09-11 19:41:01.402328626 +0000 @@ -12,9 +12,7 @@ */ options { - listen-on port @PORT@ { 10.53.0.4; }; - transfer-source 10.53.0.4; - pid-file "named.pid"; + {% include_indented "_common/options.conf.j2" %} recursion no; }; @@ -38,11 +36,4 @@ primaries { 10.53.0.1 port @PORT@ key xfrkey; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} diff -Nru bind9-9.20.26/bin/tests/system/xferquota/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/xferquota/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xferquota/ns1/named.conf.j2 2026-07-20 14:47:53.933847938 +0000 +++ bind9-9.20.29/bin/tests/system/xferquota/ns1/named.conf.j2 2026-09-11 19:41:01.402328626 +0000 @@ -12,29 +12,15 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; - notify yes; transfers-out 3; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/xferquota/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/xferquota/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xferquota/ns2/named.conf.j2 2026-07-20 14:47:53.933847938 +0000 +++ bind9-9.20.29/bin/tests/system/xferquota/ns2/named.conf.j2 2026-09-11 19:41:01.403328651 +0000 @@ -12,13 +12,7 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} allow-transfer { any; }; recursion no; dnssec-validation no; @@ -28,10 +22,9 @@ transfers-per-ns 5; }; -zone "." { - type hint; - file "../../_common/root.hint"; -}; +{% include "_common/controls.conf.j2" %} + +{% include "_common/root.hint.conf" %} zone "changing." { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/xferquota/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/xferquota/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/xferquota/ns3/named.conf.j2 2026-07-20 14:47:53.933847938 +0000 +++ bind9-9.20.29/bin/tests/system/xferquota/ns3/named.conf.j2 2026-09-11 19:41:01.403328651 +0000 @@ -12,13 +12,7 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; @@ -26,14 +20,7 @@ allow-transfer { 10.53.0.2; }; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "." { type primary; diff -Nru bind9-9.20.26/bin/tests/system/zero/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/zero/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/zero/ns1/named.conf.j2 2026-07-20 14:47:53.934847953 +0000 +++ bind9-9.20.29/bin/tests/system/zero/ns1/named.conf.j2 2026-09-11 19:41:01.403328651 +0000 @@ -12,17 +12,13 @@ */ options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} + zone "." { type primary; file "root.db"; diff -Nru bind9-9.20.26/bin/tests/system/zero/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/zero/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/zero/ns2/named.conf.j2 2026-07-20 14:47:53.934847953 +0000 +++ bind9-9.20.29/bin/tests/system/zero/ns2/named.conf.j2 2026-09-11 19:41:01.404328674 +0000 @@ -12,18 +12,14 @@ */ options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; allow-transfer { any; }; }; +{% include "_common/controls.conf.j2" %} + zone "example" { type primary; file "example.db"; diff -Nru bind9-9.20.26/bin/tests/system/zero/ns3/named.conf.j2 bind9-9.20.29/bin/tests/system/zero/ns3/named.conf.j2 --- bind9-9.20.26/bin/tests/system/zero/ns3/named.conf.j2 2026-07-20 14:47:53.934847953 +0000 +++ bind9-9.20.29/bin/tests/system/zero/ns3/named.conf.j2 2026-09-11 19:41:01.404328674 +0000 @@ -12,18 +12,12 @@ */ options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.3; }; - listen-on-v6 { none; }; - recursion yes; + {% include_indented "_common/options.conf.j2" %} dnssec-validation no; servfail-ttl 0; }; +{% include "_common/controls.conf.j2" %} zone "." { type hint; diff -Nru bind9-9.20.26/bin/tests/system/zero/ns4/named.conf.j2 bind9-9.20.29/bin/tests/system/zero/ns4/named.conf.j2 --- bind9-9.20.26/bin/tests/system/zero/ns4/named.conf.j2 2026-07-20 14:47:53.935847969 +0000 +++ bind9-9.20.29/bin/tests/system/zero/ns4/named.conf.j2 2026-09-11 19:41:01.404328674 +0000 @@ -12,17 +12,12 @@ */ options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.4; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; dnssec-validation no; }; +{% include "_common/controls.conf.j2" %} zone "example" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/zero/prereq.sh bind9-9.20.29/bin/tests/system/zero/prereq.sh --- bind9-9.20.26/bin/tests/system/zero/prereq.sh 2026-07-20 14:47:53.935847969 +0000 +++ bind9-9.20.29/bin/tests/system/zero/prereq.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#!/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. - -. ../conf.sh - -if ! ${PERL} -MNet::DNS -e ''; then - echo_i "perl Net::DNS module is required" - exit 1 -fi - -exit 0 diff -Nru bind9-9.20.26/bin/tests/system/zonechecks/ns1/named.conf.j2 bind9-9.20.29/bin/tests/system/zonechecks/ns1/named.conf.j2 --- bind9-9.20.26/bin/tests/system/zonechecks/ns1/named.conf.j2 2026-07-20 14:47:53.935847969 +0000 +++ bind9-9.20.29/bin/tests/system/zonechecks/ns1/named.conf.j2 2026-09-11 19:41:01.405328698 +0000 @@ -14,27 +14,13 @@ // NS1 options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.1; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} dnssec-policy "zonechecks" { inline-signing no; diff -Nru bind9-9.20.26/bin/tests/system/zonechecks/ns2/named.conf.j2 bind9-9.20.29/bin/tests/system/zonechecks/ns2/named.conf.j2 --- bind9-9.20.26/bin/tests/system/zonechecks/ns2/named.conf.j2 2026-07-20 14:47:53.936847984 +0000 +++ bind9-9.20.29/bin/tests/system/zonechecks/ns2/named.conf.j2 2026-09-11 19:41:01.405328698 +0000 @@ -14,27 +14,13 @@ // NS2 options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; - port @PORT@; - pid-file "named.pid"; - listen-on { 10.53.0.2; }; - listen-on-v6 { none; }; + {% include_indented "_common/options.conf.j2" %} recursion no; - notify yes; dnssec-validation no; }; -key rndc_key { - secret "1234abcd8765"; - algorithm @DEFAULT_HMAC@; -}; - -controls { - inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; -}; +{% include "_common/controls.conf.j2" %} zone "primary.example" { type secondary; diff -Nru bind9-9.20.26/bin/tests/system/zonechecks/tests_sh_zonechecks.py bind9-9.20.29/bin/tests/system/zonechecks/tests_sh_zonechecks.py --- bind9-9.20.26/bin/tests/system/zonechecks/tests_sh_zonechecks.py 2026-07-20 14:47:53.936847984 +0000 +++ bind9-9.20.29/bin/tests/system/zonechecks/tests_sh_zonechecks.py 2026-09-11 19:41:01.406328722 +0000 @@ -20,6 +20,7 @@ "ns1/dsset-primary.example.", "ns1/duplicate.db", "ns1/primary.db", + "ns1/primary.db.jnl", "ns1/primary.db.signed", "ns1/reload.db", "ns1/signer.err", diff -Nru bind9-9.20.26/bin/tools/Makefile.in bind9-9.20.29/bin/tools/Makefile.in --- bind9-9.20.26/bin/tools/Makefile.in 2026-07-20 14:49:10.502579621 +0000 +++ bind9-9.20.29/bin/tools/Makefile.in 2026-09-11 19:42:18.474186705 +0000 @@ -315,6 +315,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/bin/tools/dnstap-read.c bind9-9.20.29/bin/tools/dnstap-read.c --- bind9-9.20.26/bin/tools/dnstap-read.c 2026-07-20 14:47:53.937848000 +0000 +++ bind9-9.20.29/bin/tools/dnstap-read.c 2026-09-11 19:41:01.407328746 +0000 @@ -189,6 +189,18 @@ } static void +print_ip(ProtobufCBinaryData *ip, const char *label) { + char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; + if (ip->len == 4 || ip->len == 16) { + if (inet_ntop(ip->len == 4 ? AF_INET : AF_INET6, ip->data, buf, + sizeof(buf)) != NULL) + { + printf(" %s: \"%s\"\n", label, buf); + } + } +} + +static void print_yaml(dns_dtdata_t *dt) { Dnstap__Dnstap *frame = dt->frame; Dnstap__Message *m = frame->message; @@ -274,20 +286,14 @@ if (m->has_query_address) { ProtobufCBinaryData *ip = &m->query_address; - char buf[100]; - (void)inet_ntop(ip->len == 4 ? AF_INET : AF_INET6, ip->data, - buf, sizeof(buf)); - printf(" query_address: \"%s\"\n", buf); + print_ip(ip, "query_address"); } if (m->has_response_address) { ProtobufCBinaryData *ip = &m->response_address; - char buf[100]; - (void)inet_ntop(ip->len == 4 ? AF_INET : AF_INET6, ip->data, - buf, sizeof(buf)); - printf(" response_address: \"%s\"\n", buf); + print_ip(ip, "response_address"); } if (m->has_query_port) { diff -Nru bind9-9.20.26/bin/tools/mdig.c bind9-9.20.29/bin/tools/mdig.c --- bind9-9.20.26/bin/tools/mdig.c 2026-07-20 14:47:53.937848000 +0000 +++ bind9-9.20.29/bin/tools/mdig.c 2026-09-11 19:41:01.407328746 +0000 @@ -1806,6 +1806,23 @@ memmove(query->ecs_addr, default_query.ecs_addr, len); } + if (default_query.ednsopts != NULL) { + newopts(query); + for (size_t i = 0; i < default_query.ednsoptscnt; i++) { + query->ednsopts[i].code = + default_query.ednsopts[i].code; + if (default_query.ednsopts[i].value != NULL) { + query->ednsopts[i].value = isc_mem_allocate( + mctx, default_query.ednsopts[i].length); + memmove(query->ednsopts[i].value, + default_query.ednsopts[i].value, + default_query.ednsopts[i].length); + query->ednsopts[i].length = + default_query.ednsopts[i].length; + } + } + } + if (query->timeout == 0) { query->timeout = tcp_mode ? TCPTIMEOUT : UDPTIMEOUT; } @@ -1877,6 +1894,26 @@ } static void +free_query(struct query *query) { + if (query->ecs_addr != NULL) { + isc_mem_free(mctx, query->ecs_addr); + } + + if (query->ednsopts != NULL) { + for (size_t i = 0; i < EDNSOPTS; i++) { + if (query->ednsopts[i].value != NULL) { + isc_mem_free(mctx, query->ednsopts[i].value); + } + } + isc_mem_free(mctx, query->ednsopts); + } + + if (query != &default_query) { + isc_mem_free(mctx, query); + } +} + +static void parse_args(bool is_batchfile, int argc, char **argv) { struct query *query = NULL; char batchline[MXNAME]; @@ -2024,12 +2061,7 @@ fclose(batchfp); } } - if (query != &default_query) { - if (query->ecs_addr != NULL) { - isc_mem_free(mctx, query->ecs_addr); - } - isc_mem_free(mctx, query); - } + free_query(query); } /* @@ -2100,11 +2132,10 @@ /*% Main processing routine for mdig */ int main(int argc, char *argv[]) { - struct query *query = NULL; + struct query *query = NULL, *next; isc_result_t result; isc_log_t *lctx = NULL; isc_logconfig_t *lcfg = NULL; - unsigned int i; int ns; if (isc_net_probeipv4() == ISC_R_SUCCESS) { @@ -2186,30 +2217,11 @@ isc_log_destroy(&lctx); - query = ISC_LIST_HEAD(queries); - while (query != NULL) { - struct query *next = ISC_LIST_NEXT(query, link); - - if (query->ednsopts != NULL) { - for (i = 0; i < EDNSOPTS; i++) { - if (query->ednsopts[i].value != NULL) { - isc_mem_free(mctx, - query->ednsopts[i].value); - } - } - isc_mem_free(mctx, query->ednsopts); - } - if (query->ecs_addr != NULL) { - isc_mem_free(mctx, query->ecs_addr); - query->ecs_addr = NULL; - } - isc_mem_free(mctx, query); - query = next; + ISC_LIST_FOREACH_SAFE(queries, query, link, next) { + free_query(query); } - if (default_query.ecs_addr != NULL) { - isc_mem_free(mctx, default_query.ecs_addr); - } + free_query(&default_query); isc_managers_destroy(&mctx, &loopmgr, &netmgr); return 0; diff -Nru bind9-9.20.26/bin/tools/named-rrchecker.c bind9-9.20.29/bin/tools/named-rrchecker.c --- bind9-9.20.26/bin/tools/named-rrchecker.c 2026-07-20 14:47:53.938848016 +0000 +++ bind9-9.20.29/bin/tools/named-rrchecker.c 2026-09-11 19:41:01.408328770 +0000 @@ -121,7 +121,7 @@ continue; } dns_rdataclass_format(t, text, sizeof(text)); - if (strncmp(text, "CLASS", 4) != 0) { + if (strncmp(text, "CLASS", 5) != 0) { fprintf(stdout, "%s\n", text); } } diff -Nru bind9-9.20.26/config.h.in bind9-9.20.29/config.h.in --- bind9-9.20.26/config.h.in 2026-07-20 14:49:09.719561577 +0000 +++ bind9-9.20.29/config.h.in 2026-09-11 19:42:17.693167686 +0000 @@ -27,6 +27,9 @@ /* define if you want TCP_FASTOPEN enabled if available */ #undef ENABLE_TCP_FASTOPEN +/* Define to 1 if you have the 'arc4random' function. */ +#undef HAVE_ARC4RANDOM + /* define if the ARM yield instruction is available */ #undef HAVE_ARM_YIELD @@ -252,6 +255,9 @@ /* Build with DNS-over-HTTPS support */ #undef HAVE_LIBNGHTTP2 +/* Define to 1 if libscf was found */ +#undef HAVE_LIBSCF + /* Use libxml2 library */ #undef HAVE_LIBXML2 diff -Nru bind9-9.20.26/configure bind9-9.20.29/configure --- bind9-9.20.26/configure 2026-07-20 14:49:09.273551388 +0000 +++ bind9-9.20.29/configure 2026-09-11 19:42:17.243156722 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for BIND 9.20.26. +# Generated by GNU Autoconf 2.72 for BIND 9.20.29. # # Report bugs to . # @@ -615,8 +615,8 @@ # Identity of this package. PACKAGE_NAME='BIND' PACKAGE_TARNAME='bind' -PACKAGE_VERSION='9.20.26' -PACKAGE_STRING='BIND 9.20.26' +PACKAGE_VERSION='9.20.29' +PACKAGE_STRING='BIND 9.20.29' PACKAGE_BUGREPORT='https://gitlab.isc.org/isc-projects/bind9/-/issues/new?issuable_template=Bug' PACKAGE_URL='https://www.isc.org/downloads/' @@ -653,11 +653,13 @@ #endif" ac_header_c_list= +ac_func_c_list= enable_year2038=no ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +LIBSCF_LIBS HAVE_DTRACE_FALSE HAVE_DTRACE_TRUE HAVE_SYSTEMTAP_FALSE @@ -1571,7 +1573,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures BIND 9.20.26 to adapt to many kinds of systems. +'configure' configures BIND 9.20.29 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1643,7 +1645,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of BIND 9.20.26:";; + short | recursive ) echo "Configuration of BIND 9.20.29:";; esac cat <<\_ACEOF @@ -1893,7 +1895,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -BIND configure 9.20.26 +BIND configure 9.20.29 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -2313,7 +2315,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by BIND $as_me 9.20.26, which was +It was created by BIND $as_me 9.20.29, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -2920,6 +2922,7 @@ as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" +as_fn_append ac_func_c_list " arc4random HAVE_ARC4RANDOM" # Auxiliary files required by this configure script. ac_aux_files="ltmain.sh ar-lib compile missing install-sh config.guess config.sub" @@ -3097,7 +3100,7 @@ printf "%s\n" "#define PACKAGE_VERSION_MINOR \"20\"" >>confdefs.h -printf "%s\n" "#define PACKAGE_VERSION_PATCH \"26\"" >>confdefs.h +printf "%s\n" "#define PACKAGE_VERSION_PATCH \"29\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION_EXTRA \"\"" >>confdefs.h @@ -3106,7 +3109,7 @@ printf "%s\n" "#define PACKAGE_DESCRIPTION \" (Stable Release)\"" >>confdefs.h -printf "%s\n" "#define PACKAGE_SRCID \"5a605f8\"" >>confdefs.h +printf "%s\n" "#define PACKAGE_SRCID \"c3d4465\"" >>confdefs.h bind_CONFIGARGS="${ac_configure_args:-default}" @@ -3941,7 +3944,7 @@ # Define the identity of the package. PACKAGE='bind' - VERSION='9.20.26' + VERSION='9.20.29' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -22682,7 +22685,20 @@ fi -CRYPTO=OpenSSL +ac_func= +for ac_item in $ac_func_c_list +do + if test $ac_func; then + ac_fn_c_check_func "$LINENO" $ac_func ac_cv_func_$ac_func + if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then + echo "#define $ac_item 1" >> confdefs.h + fi + ac_func= + else + ac_func=$ac_item + fi +done + # # OpenSSL/LibreSSL is mandatory @@ -29833,6 +29849,68 @@ # +# In solaris 10, SMF can manage named service +# +LIBSCF_LIBS= +ac_fn_c_check_header_compile "$LINENO" "libscf.h" "ac_cv_header_libscf_h" "$ac_includes_default" +if test "x$ac_cv_header_libscf_h" = xyes +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for smf_enable_instance in -lscf" >&5 +printf %s "checking for smf_enable_instance in -lscf... " >&6; } +if test ${ac_cv_lib_scf_smf_enable_instance+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-lscf $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char smf_enable_instance (void); +int +main (void) +{ +return smf_enable_instance (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_scf_smf_enable_instance=yes +else case e in #( + e) ac_cv_lib_scf_smf_enable_instance=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_scf_smf_enable_instance" >&5 +printf "%s\n" "$ac_cv_lib_scf_smf_enable_instance" >&6; } +if test "x$ac_cv_lib_scf_smf_enable_instance" = xyes +then : + +printf "%s\n" "#define HAVE_LIBSCF 1" >>confdefs.h + + LIBSCF_LIBS="-lscf" +fi + +fi + + + +# # Files to configure. These are listed here because we used to # specify them as arguments to AC_OUTPUT. # @@ -30536,7 +30614,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by BIND $as_me 9.20.26, which was +This file was extended by BIND $as_me 9.20.29, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -30605,7 +30683,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -BIND config.status 9.20.26 +BIND config.status 9.20.29 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -Nru bind9-9.20.26/configure.ac bind9-9.20.29/configure.ac --- bind9-9.20.26/configure.ac 2026-07-20 14:47:53.941848062 +0000 +++ bind9-9.20.29/configure.ac 2026-09-11 19:41:01.410328818 +0000 @@ -16,7 +16,7 @@ # m4_define([bind_VERSION_MAJOR], 9)dnl m4_define([bind_VERSION_MINOR], 20)dnl -m4_define([bind_VERSION_PATCH], 26)dnl +m4_define([bind_VERSION_PATCH], 29)dnl m4_define([bind_VERSION_EXTRA], )dnl m4_define([bind_DESCRIPTION], [(Stable Release)])dnl m4_define([bind_SRCID], [m4_esyscmd_s([git rev-parse --short HEAD | cut -b1-7])])dnl @@ -662,7 +662,7 @@ ]) AM_CONDITIONAL([USE_ISC_RWLOCK], [test "$enable_pthread_rwlock" != "yes"]) -CRYPTO=OpenSSL +AC_CHECK_FUNCS_ONCE([arc4random]) # # OpenSSL/LibreSSL is mandatory @@ -1594,6 +1594,17 @@ AC_DEFINE_UNQUOTED([CACHEDB_DEFAULT], ["$cachedb"], [Default cache database type]) # +# In solaris 10, SMF can manage named service +# +LIBSCF_LIBS= +AC_CHECK_HEADER([libscf.h], + [AC_CHECK_LIB([scf], [smf_enable_instance], + [AC_DEFINE([HAVE_LIBSCF], [1], + [Define to 1 if libscf was found]) + LIBSCF_LIBS="-lscf"])]) +AC_SUBST([LIBSCF_LIBS]) + +# # Files to configure. These are listed here because we used to # specify them as arguments to AC_OUTPUT. # diff -Nru bind9-9.20.26/contrib/gitchangelog/gitchangelog.py bind9-9.20.29/contrib/gitchangelog/gitchangelog.py --- bind9-9.20.26/contrib/gitchangelog/gitchangelog.py 2026-07-20 14:47:53.942848078 +0000 +++ bind9-9.20.29/contrib/gitchangelog/gitchangelog.py 2026-09-11 19:41:01.412328866 +0000 @@ -1079,7 +1079,9 @@ @property def date(self): - d = datetime.datetime.utcfromtimestamp(float(self.author_date_timestamp)) + d = datetime.datetime.fromtimestamp( + float(self.author_date_timestamp), datetime.timezone.utc + ) return d.strftime("%Y-%m-%d") @property diff -Nru bind9-9.20.26/debian/changelog bind9-9.20.29/debian/changelog --- bind9-9.20.26/debian/changelog 2026-07-21 13:09:54.000000000 +0000 +++ bind9-9.20.29/debian/changelog 2026-09-16 13:42:29.000000000 +0000 @@ -1,3 +1,29 @@ +bind9 (1:9.20.29-1~deb13u1) trixie-security; urgency=high + + * New upstream version 9.20.29 + - [CVE-2026-19668] Prevent excessive CPU use validating crafted DNSSEC responses. + - [CVE-2026-19033] Require a TSIG on every message of incoming zone + transfers. + - [CVE-2026-77119] Prevent a DNSSEC downgrade of secure delegations via + unrelated NSEC3 records. + - [CVE-2026-19666] DNS64 with `break-dnssec` could cause an assertion + failure. + - [CVE-2026-19667] Reject oversized negative cache records. + - [CVE-2026-19662] Prevent resolver crash with cached DNSSEC proofs. + - [CVE-2026-75029] Discard repeated SOA, CNAME, and DNAME records when + parsing DNS messages. + - [CVE-2026-77692] Fix an unauthenticated crash on HTTPS using SIG(0). + - [CVE-2026-81736] Cached HTTPS/SVCB aliases could exhaust resolver + CPU. + - [CVE-2026-76163] Prevent TKEY queries from terminating `named` + without global options. + - [CVE-2026-80274] Fix crash on wildcard answers carrying both NSEC and + NSEC3 proofs. + - [CVE-2026-81563] Following HTTPS/SVCB aliases could leak resolver + cache memory. + + -- Ondřej Surý Wed, 16 Sep 2026 15:42:29 +0200 + bind9 (1:9.20.26-1~deb13u1) trixie-security; urgency=high * New upstream version 9.20.26 diff -Nru bind9-9.20.26/doc/Makefile.in bind9-9.20.29/doc/Makefile.in --- bind9-9.20.26/doc/Makefile.in 2026-07-20 14:49:10.518579988 +0000 +++ bind9-9.20.29/doc/Makefile.in 2026-09-11 19:42:18.490187095 +0000 @@ -276,6 +276,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/doc/arm/Makefile.in bind9-9.20.29/doc/arm/Makefile.in --- bind9-9.20.26/doc/arm/Makefile.in 2026-07-20 14:49:10.535580379 +0000 +++ bind9-9.20.29/doc/arm/Makefile.in 2026-09-11 19:42:18.508187533 +0000 @@ -219,6 +219,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/doc/arm/changelog.rst bind9-9.20.29/doc/arm/changelog.rst --- bind9-9.20.26/doc/arm/changelog.rst 2026-07-20 14:47:53.944848109 +0000 +++ bind9-9.20.29/doc/arm/changelog.rst 2026-09-11 19:41:01.414328914 +0000 @@ -18,6 +18,9 @@ development. Regular users should refer to :ref:`Release Notes ` for changes relevant to them. +.. include:: ../changelog/changelog-9.20.29.rst +.. include:: ../changelog/changelog-9.20.28.rst +.. include:: ../changelog/changelog-9.20.27.rst .. include:: ../changelog/changelog-9.20.26.rst .. include:: ../changelog/changelog-9.20.25.rst .. include:: ../changelog/changelog-9.20.24.rst diff -Nru bind9-9.20.26/doc/arm/notes.rst bind9-9.20.29/doc/arm/notes.rst --- bind9-9.20.26/doc/arm/notes.rst 2026-07-20 14:47:53.949848187 +0000 +++ bind9-9.20.29/doc/arm/notes.rst 2026-09-11 19:41:01.419329033 +0000 @@ -45,6 +45,9 @@ found at https://gitlab.isc.org/isc-projects/bind9/-/wikis/Known-Issues-in-BIND-9.20 +.. include:: ../notes/notes-9.20.29.rst +.. include:: ../notes/notes-9.20.28.rst +.. include:: ../notes/notes-9.20.27.rst .. include:: ../notes/notes-9.20.26.rst .. include:: ../notes/notes-9.20.25.rst .. include:: ../notes/notes-9.20.24.rst diff -Nru bind9-9.20.26/doc/arm/platforms.inc.rst bind9-9.20.29/doc/arm/platforms.inc.rst --- bind9-9.20.26/doc/arm/platforms.inc.rst 2026-07-20 14:47:53.949848187 +0000 +++ bind9-9.20.29/doc/arm/platforms.inc.rst 2026-09-11 19:41:01.419329033 +0000 @@ -47,7 +47,7 @@ - Ubuntu LTS 22.04, 24.04, 26.04 - Fedora 44 - Red Hat Enterprise Linux / CentOS / AlmaLinux 8, 9, 10 -- FreeBSD 13, 14, 15 +- FreeBSD 14, 15 - Alpine Linux 3.24 The amd64 CPU architecture is fully supported and regularly tested. @@ -90,7 +90,7 @@ - Ubuntu 14.04, 16.04, 18.04, 20.04 (Ubuntu ESM releases are not supported) - Red Hat Enterprise Linux / CentOS / Oracle Linux 6, 7 - Debian 8 Jessie, 9 Stretch, 10 Buster, 11 Bullseye - - FreeBSD 10.x, 11.x, 12.x + - FreeBSD 10.x, 11.x, 12.x, 13.x - Less common CPU architectures (i386, i686, mips, mipsel, sparc, ppc, and others) diff -Nru bind9-9.20.26/doc/arm/reference.rst bind9-9.20.29/doc/arm/reference.rst --- bind9-9.20.26/doc/arm/reference.rst 2026-07-20 14:47:53.951848218 +0000 +++ bind9-9.20.29/doc/arm/reference.rst 2026-09-11 19:41:01.421329082 +0000 @@ -2635,6 +2635,14 @@ owner name indicates that it is a reverse lookup of a hostname (the owner name ends in IN-ADDR.ARPA, IP6.ARPA, or IP6.INT). + Owner names of A and AAAA records starting with the Active + Directory Forest prefix labels ``gc._msdcs`` are excluded if the + remainder of the name meets the check-names rules. + + Owner names of A records meeting the :rfc:`7208` rules for the + labels ``_spf``, ``_spf_verify`` and ``_spf_rate`` are also + excluded. + .. namedconf:statement:: check-dup-records :tags: dnssec, query :short: Checks primary zones for records that are treated as different by DNSSEC but are semantically equal in plain DNS. @@ -5255,8 +5263,8 @@ response-policy option. 2. Prefer CLIENT-IP to QNAME to IP to NSDNAME to NSIP triggers in a single zone. -3. Among NSDNAME triggers, prefer the trigger that matches the smallest - name under the DNSSEC ordering. +3. Among NSDNAME triggers, prefer the trigger whose matched name server + domain name appears last in the DNSSEC canonical ordering. 4. Among IP or NSIP triggers, prefer the trigger with the longest prefix. 5. Among triggers with the same prefix length, prefer the IP or NSIP diff -Nru bind9-9.20.26/doc/changelog/changelog-9.20.27.rst bind9-9.20.29/doc/changelog/changelog-9.20.27.rst --- bind9-9.20.26/doc/changelog/changelog-9.20.27.rst 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/doc/changelog/changelog-9.20.27.rst 2026-09-11 19:41:01.425329177 +0000 @@ -0,0 +1,193 @@ +.. 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. + +BIND 9.20.27 +------------ + +New Features +~~~~~~~~~~~~ + +- Disclose active Negative Trust Anchors with Extended DNS Error 33. + ``566e7018278`` + + A Negative Trust Anchor (RFC 7646) turns off DNSSEC validation for a + domain, so a name that would normally fail validation resolves + instead. named now marks such answers with Extended DNS Error code 33, + "Negative Trust Anchor", so operators can see at a glance when a + response came back only because an NTA was in effect. :gl:`#6268` + :gl:`!12426` + +- Add development guidance for AI coding agents under .agents/skills/ + ``ef651c93709`` + + This adds a set of skill documents that give AI coding agents the + project's established practices up front instead of having them + rediscovered (or gotten wrong) in every session: the canonical build + and test invocations, the memory-allocator contract, the disciplines + for RCU mutation, per-loop sharded structures, struct-layout work, and + flight-recorder debugging of concurrency bugs, plus the commit and + merge-request conventions. :gl:`!12401` + +- Add more unit tests for isc_time API. ``9d6855ef735`` + + While working on internal 64-bit time for BIND 9, the unit test suite + for isc_time API has been extended. + + Backport the unit tests from 64-bit time branch to the main branch. + This should make the unit tests for isc_time API (mostly) complete. + + Related to #2959 :gl:`!12432` + +Feature Changes +~~~~~~~~~~~~~~~ + +- Batch qp transaction for RPZ updates. ``cb40fb91fa2`` + + RPZ was built around fine-grained locking, but that forces the use of + many small qp transactions. With this MR, we switch qp transaction to + handle the full update to the rpz summary structure. While this + serializes the RPZ updates, the reduced overhead from batching qp + transactions more than compensates for it and results in improvements + for big RPZ zones. :gl:`#5787`, #6270 :gl:`!12493` + +- Pass the work callback result to the done callback. ``65cdb7c7613`` + + The `isc_work` callback now returns `isc_result_t` and the value is + handed to the done callback, so the callers no longer need their own + result-passing state. :gl:`!12391` + +Bug Fixes +~~~~~~~~~ + +- Dig +yaml producing invalid YAML when a lookup fails. ``65d1776959e`` + + When "dig +yaml" was run and no server could be reached, dig printed + its plain-text startup banner (the "; \<\<\>\> DiG ..." and ";; global + options" lines) ahead of the machine-readable output, so the result + was not valid YAML and could not be parsed. dig no longer emits that + banner in YAML mode. As part of the same change, the banner is now + built only after the whole command line has been read, so options + given after the query name (such as +nocmd, +short and +yaml) are + correctly reflected in it. :gl:`#1230` :gl:`!12430` + +- Ensure NSEC authority does not cross zonecut boundary. ``0baaddd096a`` + + When using a cached NSEC record to prove that a delegation is + insecure, we now check that the signer name in the corresponding RRSIG + is not above a known secure delegation point. This prevents a signed + namespace from being downgraded to insecure using an NSEC record from + the grandparent zone. :gl:`#5967` :gl:`!12394` + +- Treat non canonical RPZ prefixes as any other failure. ``17f0828b460`` + + RPZ prefixes that were not encoded in canonical form do not work. + Treat them as any other encoding error. :gl:`#6043` :gl:`!12482` + +- Properly prevent TSIG generation command line injection attacks. + ``f777451d261`` + + When key names are generated with `rndc-confgen`, `tsig-keygen` and + `ddns-confgen`, special characters must be escaped to ensure the + configuration is parsed correctly. :gl:`#6071` :gl:`!12396` + +- Dig with IDN output could leak memory on ISC_R_NOSPACE retry. + ``c4e53b59b2e`` + + The IDN to text display call back could leak the memory holding the + converted name if it did not fit into the buffer. This has been + fixed. :gl:`#6073` :gl:`!12483` + +- Dnssec-signzone had a potential heap bounds overflow write. + ``994c3bd4323`` + + It was possible for `dnssec-signzone` to overflow array bounds while + signing. This has been fixed. :gl:`#6076` :gl:`!12503` + +- Restore SMF support on Solaris and illumos. ``8bde9318f63`` + + SMF support on Solaris and illumos was silently dropped by a build + system rewrite in 2018; it is now detected and enabled again. + :gl:`#6096` :gl:`!12456` + +- Fix NULL pointer dereference in dnstap-read. ``9c459b1854d`` + + It was possible to dereference a NULL pointer in dnstap-read causing + it to exit on a malformed DNSTAP file. This has been fixed. + :gl:`#6124` :gl:`!12494` + +- Change catz coo locking. ``78265c8f6fc`` + + Catalog zones might need to inspect the change-of-ownership records of + other catalog zones, which required to release the lock in the middle + of certain operations, leading to possible race conditions. + + Since the operations on change-of-ownership records are limited, we + can instead use a design with a second lock protecting the + change-of-ownership records on read. We structure the API so that + holding two change-of-ownership locks at the same time is impossible. + :gl:`#6131` :gl:`!12410` + +- Treat an unusable NSEC3 chain as a verification failure. + ``879a383ef16`` + + When transferring in a mirror zone, DNSSEC verification could + incorrectly succeed when the zone had an invalid `NSEC3PARAM` record, + leading to subsequent validation failures. This has been fixed. + :gl:`#6136` :gl:`!12431` + +- Unterminated OpenSSL private-key `Label:` field can be read past its + parser buffer. ``932581b74bd`` + + Check that the string encoded in the Label: field of the .private file + of a key pair is NUL terminated and the correct length. Reject the + .private file if it is not. :gl:`#6193` :gl:`!12417` + +- Negative caching stopped working with stale-answer-client-timeout 0. + ``2687d16ed2f`` + + With "stale-answer-client-timeout 0" configured, every client query + for a name cached as NXDOMAIN or NODATA was sent on to the + authoritative servers, even while the cached negative answer was still + within its TTL, so the resolver effectively lost negative caching. + Negative answers are now refreshed only once they have actually gone + stale. :gl:`#6245` :gl:`!12384` + +- MacOS byte swapping macros already defined. ``5c1d3df49c0`` + + Don't redefine them if the development environment already defines + them. :gl:`#6250` :gl:`!12406` + +- Use memmove in isc_sockaddr_fromin/isc_sockaddr_fromin6. + ``3f3c82292c9`` + + Use memmove instead of direct assignment from the source pointer + because the source pointer is not guaranteed to be correctly aligned. + :gl:`#6260` :gl:`!12449` + +- Fix compilation on GNU/Hurd. ``20f5580e017`` + + Fix compilation issues on GNU/Hurd. :gl:`#6285` :gl:`!12496` + +- Restore arc4random() detection dropped in the v9.21.14 merge. + ``86ad6866eeb`` + + Commit 4db9e5d90e2 ("Use arc4random for CSPRNG when available", part + of the CVE-2025-40780 fix) guarded the arc4random() code paths in + lib/isc/random.h and lib/isc/random.c with HAVE_ARC4RANDOM and added + the corresponding function check to meson.build. The manual conflict + resolution in merge c2a672bbaef ("Merge tag 'v9.21.14'") kept the code + changes but dropped the meson.build hunk, so HAVE_ARC4RANDOM was never + defined and platforms with arc4random() (macOS and the BSDs) silently + fell back to the internal ChaCha-based CSPRNG. Restore the check. + + Assisted-by: Claude:claude-fable-5 :gl:`!12452` + + diff -Nru bind9-9.20.26/doc/changelog/changelog-9.20.28.rst bind9-9.20.29/doc/changelog/changelog-9.20.28.rst --- bind9-9.20.26/doc/changelog/changelog-9.20.28.rst 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/doc/changelog/changelog-9.20.28.rst 2026-09-11 19:41:01.425329177 +0000 @@ -0,0 +1,18 @@ +.. 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. + +BIND 9.20.28 +------------ + +.. note:: + + The BIND 9.20.28 release was withdrawn after the discovery of a + regression in it during pre-release testing. diff -Nru bind9-9.20.26/doc/changelog/changelog-9.20.29.rst bind9-9.20.29/doc/changelog/changelog-9.20.29.rst --- bind9-9.20.26/doc/changelog/changelog-9.20.29.rst 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/doc/changelog/changelog-9.20.29.rst 2026-09-11 19:41:01.426329201 +0000 @@ -0,0 +1,443 @@ +.. 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. + +BIND 9.20.29 +------------ + +Security Fixes +~~~~~~~~~~~~~~ + +- [CVE-2026-19668] Prevent excessive CPU use validating crafted DNSSEC + responses. ``a0a61dba9e`` + + A malicious authoritative server could serve a securely delegated zone + whose DS and DNSKEY records carry many distinct key tags but no valid + match, forcing a validating resolver into excessive key-tag matching + and high CPU use for every query. BIND now bounds this work with the + per-query validation limit (max-validations-per-fetch). :gl:`#5349` + +- [CVE-2026-19033] Require a TSIG on every message of incoming zone + transfers. ``9404cd2b8c`` + + BIND 9 used to accept TSIG-signed zone transfers in which some + messages were unsigned, and processed those messages before the next + signature could vouch for them. It now requires a TSIG on every + message of an incoming AXFR or IXFR; all modern nameserver already + sign every message, so no change is expected in practice. :gl:`#6062` + +- [CVE-2026-77119] Prevent a DNSSEC downgrade of secure delegations via + unrelated NSEC3. ``3bed9c8e9e`` + + A validating resolver could be tricked into treating a secure + delegation as unsigned and accepting forged answers for names beneath + it, if an attacker could inject responses to its queries. Such forged + proofs are now rejected. :gl:`#6234` + +- [CVE-2026-19941] Prevent forged DNSSEC-validated NXDOMAIN responses. + ``a36bf58daf`` + + A validating resolver could accept a signed NSEC record from an + unrelated zone as proof that a wildcard did not exist. An on-path + attacker or malicious forwarder controlling a signed zone could + therefore forge an authenticated NXDOMAIN response for a name that + should resolve through a wildcard. BIND now requires the + wildcard-denial and name-nonexistence proofs to be signed by the same + zone. :gl:`#6253` + +- [CVE-2026-19666] DNS64 with break-dnssec could cause an assertion + failure. ``4cec4965c4`` + + When a "dns64" statement is configured with "break-dnssec yes" and its + "exclude" list matches some but not all of the addresses in an AAAA + RRset, named removes the excluded addresses from the answer instead of + synthesizing new ones. If the answer being filtered had been cached + together with a proof that the queried name does not exist -- which is + what a wildcard match produces -- named terminated with an assertion + failure. + + Only recursive resolvers are affected, and only when "break-dnssec + yes" is in use; the answer has to come from the cache, so a server + that is only authoritative cannot reach this. :gl:`#6301` + +- [CVE-2026-19667] Reject negative cache records that do not fit in a + dns_rdata_t. ``dbf08c8581`` + + A single crafted response from a server could make a resolver cache a + malformed negative entry and then terminate with an assertion failure + when reading it back. Only recursive resolvers are affected, on a + default configuration. :gl:`#6302` + +- [CVE-2026-19662] Prevent resolver crash with cached DNSSEC proofs. + ``c884cc1ba0`` + + Under certain timing conditions, concurrent recursive queries could + cause named to crash when cached DNSSEC NOQNAME proof data was + replaced while still in use. Cached proof data is now retained until + all queries using it have completed. :gl:`#6333` + +- [CVE-2026-75029] Discard repeated SOA, CNAME, and DNAME records when + parsing DNS messages. ``0d630758c2`` + + A DNS message could carry the same SOA, CNAME, or DNAME record many + times, and named kept every copy while parsing it. With name + compression those copies took up far more memory internally than in + the message itself, and every later processing step had to handle all + of them. named now keeps the first copy of such a record and discards + identical repeats. :gl:`#6335` + +- [CVE-2026-77692] Fix an unauthenticated crash on HTTPS using SIG(0) + ``5a24401c5c`` + + A specifically crafted HTTPS query using SIG(0) as authentication + could crash named if the client closes the connection before named + actually verifies the signature. This is now fixed. :gl:`#6343` + +- [CVE-2026-81736] Cached HTTPS/SVCB aliases could exhaust resolver CPU. + ``20bbb1639a`` + + A recursive resolver that had cached a large set of interlinked HTTPS + or SVCB records in alias form could be driven to do an excessive + amount of work assembling a single response, because it followed every + cached alias target when building the additional section. A client + permitted to use recursion, together with an attacker-controlled zone + used to plant the records, could repeat small queries to consume + enough CPU to delay or deny service to other clients. The amount of + additional processing done for one query is now bounded. :gl:`#6347` + +- [CVE-2026-76163] Prevent TKEY queries from terminating named without + global options. ``7645138538`` + + named could terminate unexpectedly when a remote client sent a TKEY + query if the configuration did not include a global options statement. + This has been fixed. + + ISC thanks Owais Lone (thesecguy) for reporting the issue. :gl:`#6357` + +- [CVE-2026-78301] Out-of-zone records in a zone database could be + served as authoritative. ``72a10c3a0b`` + + When a zone database contained records for names outside the zone — + such as a delegation above the zone apex, left behind by a secondary + that had accepted out-of-zone data from its primary — the server could + treat them as authoritative and answer queries for names inside the + zone with that out-of-zone data instead of the zone's own. A server + that was also a resolver could follow such a delegation and cache the + answers of the server it named, affecting names outside the configured + zone. Zone database lookups are now confined to names at or below the + zone's origin. + + ISC would like to thank Henrique Pereira for reporting the issue. + :gl:`#6361` + +- [CVE-2026-80274] Crash on wildcard answers carrying both NSEC and + NSEC3 proofs. ``0e44451b1a`` + + When a wildcard answer arrived with both NSEC and NSEC3 records at the + name proving that the queried name does not exist, the resolver could + pick different records when caching the answer and when retrieving the + proof, depending on the order in which the authoritative server sent + them. This could terminate named with an assertion failure, fail the + query with SERVFAIL, or serve a denial record other than the one that + had been verified. The resolver now caches and serves the same denial + record it accepted when the answer was received. + + ISC would like to thank hythyt for reporting the issue. :gl:`#6369` + +- [CVE-2026-81563] Following HTTPS/SVCB aliases could leak resolver + cache memory. ``3162df369e`` + + When a recursive server answered a query for an HTTPS or SVCB record + in alias form and the alias target had more than 13 records, the + target records were pinned in the cache permanently instead of being + released once the answer was sent. A remote party who could make the + server follow such aliases to a steady stream of fresh names could + grow the cache beyond the configured max-cache-size until the server + was unable to resolve unrelated names. The records are now released + correctly. + + ISC would like to thank Samy Medjahed/Ap4sh for reporting the issue. + :gl:`#6374` + +New Features +~~~~~~~~~~~~ + +- Add an agent skill for the isc_job/isc_async/isc_work APIs. + ``fe32990b06`` + + Documents when to use isc_job_run(), isc_async_run() or + isc_work_enqueue(), and the contract each one imposes. No functional + change. :gl:`!12561` + +Removed Features +~~~~~~~~~~~~~~~~ + +- Remove unused closest encloser proof caching. ``abd8b5bfd8`` + + BIND used to cache an NSEC3 closest encloser proof alongside positive + wildcard answers so that a resolver could re-send it when answering + from its cache. That stopped being used in BIND 9.9 (2011), when + positive wildcard responses were changed to omit that NSEC3 record — + RFC 5155 requires only the next closer name proof — and the closest + encloser came to be derived during validation instead. The caching + code has been unreachable ever since, so this removes it with no + change in behaviour. :gl:`#5803` :gl:`!12660` + +Feature Changes +~~~~~~~~~~~~~~~ + +- Reject oversized and malformed DNSKEY records up front. ``6c22109924`` + + Oversized RSA key material in a DNSKEY record was only rejected after + it had been converted, allocating memory proportional to the record + size. Such records are now rejected before conversion, as are Ed25519 + and Ed448 keys with trailing bytes that were previously silently + ignored. :gl:`#4537` :gl:`!12560` + +Bug Fixes +~~~~~~~~~ + +- Prevent a crash when using both dns64 and filter-a. ``bce5d10d18`` + + An assertion failure was possible when using both `dns64` and the + `filter-a` plugin simultaneously; this has been fixed. :gl:`#5979` + :gl:`!12663` + +- Fix update-policy grant external address passing. ``b1e955c326`` + + Only TCP client addresses are supposed to be passed to an `external` + handler for the associated `update-policy` rule, but UDP client + addresses were also being passed. This could have caused the external + handler to return a result it otherwise wouldn't. This has been fixed. + :gl:`#6061` :gl:`!12555` + +- Missing required NSEC3 for delegation not detected. ``e84ed2e9d7`` + + A missing required NSEC3 record for an insecure delegation in a non + OPTOUT range was not being detected. This has been fixed. :gl:`#6063` + :gl:`!12611` + +- Tighten EUI48 and EUI48 text parsing. ``ff50f2cdf1`` + + Malformed EUI48 and EUI64 records could be accepted. This has been + fixed. :gl:`#6082` :gl:`!12521` + +- GeoIP ACL state can be stale or wrong after reload. ``63baf425b3`` + + `named` caches GeoIP information after looking it up, but the cached + information was not invalidated when the GeoIP database was reloaded, + so it could continue to be used. We now invalidate existing cached + GeoIP information as part of the reloading process. :gl:`#6083` + :gl:`!12662` + +- Honor DNSSEC policy key tag ranges. ``b82e5834b7`` + + When a DNSSEC policy configured a non-default tag-range, dnssec-keygen + and dnssec-ksr could accept generated keys outside that range. Both + tools now honor the configured minimum and maximum key tags. + :gl:`#6091` :gl:`!12549` + +- Fix double free in mdig when EDNS options are specified. + ``af5bd0b0ff`` + + When the default_query is cloned the EDNS options need to be cloned + rather than the pointer copied. The old behaviour results in a double + free of the options. This has been fixed. :gl:`#6095` :gl:`!12661` + +- Fix a crash when an IXFR falls back to AXFR with updates still + pending. ``e34062bc7e`` + + When a secondary zone received an incremental transfer (IXFR) and the + primary then caused named to fall back to a full transfer (AXFR) while + some of the already-received incremental changes were still waiting to + be applied, named could later crash when that transfer finished. The + pending changes are now discarded correctly before the AXFR retry. + :gl:`#6114` :gl:`!12624` + +- Fix DS requests to parental agents over TLS. ``55830d30f6`` + + TLS configuration for parental agents was being ignored when sending + DS requests. This has been fixed. :gl:`#6135` :gl:`!12613` + +- Fix a crash when resolving names below a cached DNAME. ``b94e940f52`` + + A recursive resolver could crash when it answered a query for a name + beneath a cached DNAME while that same DNAME record was concurrently + refreshed or evicted from the cache. :gl:`#6182` :gl:`!12593` + +- Rndc-confgen `-q` (quiet) option is documented but doesn't work. + ``7e4a7ca1a7`` + + The command line parsing in rndc-confgen was broken so `rndc-confgen + -q` did not work. This has been fixed. :gl:`#6187` :gl:`!12575` + +- Enforce query ACLs for redirect zones and searched DLZs. + ``bc69876b2e`` + + Queries answered from redirect zones or searched DLZ databases did not + consistently honor `allow-query` and `allow-query-on`, potentially + exposing restricted DNS data to excluded clients or through excluded + listening addresses. These ACLs are now enforced before redirect or + DLZ data is returned. :gl:`#6251`, #6252 :gl:`!12646` + +- Check "asnum" validity in GeoIP ACLs. ``28c2bfdc7b`` + + We now check the validity of autonomous system (AS) numbers when + parsing GeoIP ACLs that use `asnum` elements at configuration time. + + `asnum` values start with an optional case-insensitive "AS" prefix, + followed only by decimal digits, with no spaces or other extraneous + characters. The value represented cannot exceed 2^32. :gl:`#6255` + :gl:`!12511` + +- Prevent crashes while reporting DNSSEC signing statistics. + ``c190514f0a`` + + Servers with zone-statistics full could terminate while reporting + DNSSEC signing statistics for a zone tracking adding more than four + signing keys. :gl:`#6256` :gl:`!12674` + +- Fix various nits in the netmgr code. ``c28cdad51b`` + + The MR consists of couple of small fixes and uncaught errors in the + Network Manager. :gl:`#6257` :gl:`!12576` + +- Fix a crash on remote-servers lists that reference themselves. + ``aaae614f9d`` + + Since 9.21.16 and 9.20.17, a remote-servers, primaries, masters, or + parental-agents list that referenced itself, directly or through + another list, made named crash on startup or reconfiguration. Such + references are again skipped and the remaining entries in the list are + used, as in earlier versions. :gl:`#6287` :gl:`!12604` + +- A record from outside a response policy zone could stop named. + ``d135513b37`` + + A response policy zone transferred from a primary can contain a record + whose name lies outside the zone. Such a record could stop named, both + when it arrived and again at every startup afterwards, because a + secondary keeps it in its own copy of the zone. Records like this are + now rejected and logged; previously one could also silently create a + policy entry for an unrelated name. :gl:`#6304` :gl:`!12543` + +- "rndc flushtree ." failed to flush the cache. ``96e8b585ed`` + + `rndc flushtree` flushes cache data below a specified name. If the + name specified is the DNS root, it should fully empty the cache, the + same as `rndc flush`. However, there was a bug causing the command, + in that case, to have no effect on the cache at all; this has been + fixed. :gl:`#6308` :gl:`!12582` + +- Invalid key-store configuration could abort the DNSSEC tools. + ``1d796ab072`` + + Invalid configured key-stores named "key-directory" in configuration + files could abort the DNSSEC tools. This has been fixed. :gl:`#6313` + :gl:`!12653` + +- NSEC signature set could bypass the secure-delegation check. + ``c966177f6c`` + + When proving that a delegation is insecure, the validator bounded an + NSEC record's authority by the signer of whichever RRSIG happened to + come first in the record's signature set, rather than the signature + that actually verified. A grandparent NSEC padded with an extra, + unverifiable signature could therefore pass the check that keeps such + proofs from reaching below a signed child zone. The validator now + requires every signature on the NSEC to name the same signer and + refuses proofs whose signature set is malformed or larger than + max-validations-per-fetch allows. :gl:`#6321` + +- Fix a possible nsupdate issue when using GSS-TSIG. ``4ddcab2d3c`` + + The :iscman:`nsupdate` process could terminate unexpectedly when using + the GSS-TSIG mode executed with the :option:`nsupdate -g` option. This + has been fixed. :gl:`#6325` :gl:`!12588` + +- Fix isccc_alist_define error paths. ``af1349552a`` + + If there is an out of memory error in isccc_alist_define a memory leak + (the sexpr holding the key name) or a double free (value) could occur. + This has been fixed. :gl:`#6329` :gl:`!12636` + +- Check for empty 'endpoints' list. ``23f58af443`` + + Configuring an `http` block with `endpoints {};` previously caused a + crash in `named`. This is now rejected earlier by the configuration + check. :gl:`#6330` :gl:`!12552` + +- Named could crash with a single-element geoip sortlist. ``0e996a4d3b`` + + If `named` was configured with a single-element sortlist containing a + `geoip` ACL element, any matching query triggered an assertion + failure. This has been fixed. :gl:`#6342` :gl:`!12583` + +- Prevent out-of-bailiwick CNAMEs from evicting cached records. + ``cdedd4acd5`` + + A recursive resolver could remove valid cached records when a DNS + response contained an out-of-bailiwick CNAME with the same owner name. + Out-of-bailiwick data is now discarded before it can modify the cache. + :gl:`#6345` :gl:`!12651` + +- Restore periodic cleanup of stale resolver address data. + ``356f4013f8`` + + Stale resolver address data could remain cached until memory pressure + or an explicit flush. Correct the cleanup interval so it is removed + periodically. :gl:`#6346` :gl:`!12589` + +- Fix named-checkconf/named crash with malformed key name. + ``9f218f6aaf`` + + When a primary/remote-server key name was malformed, named-checkconf + and named were both crashing (after warning about the invalid key + name). This is now fixed. :gl:`#6362` :gl:`!12639` + +- Fix -Wformat-truncation warning in totext_in_wks() ``f97c2bea40`` + + BIND 9 failed to build with GCC 16 at -O3: rendering a WKS record as + text triggered a -Wformat-truncation error, which is fatal in + developer builds. The port number is now printed with a 16-bit format + specifier, so the compiler can see it always fits the output buffer. + :gl:`!12542` + +- Fix off-by-one errors caused by magic hardcoded values. ``726c6cb795`` + + Fix off-by-one comparinson errors: "named -p http=" dropped the first + digit of the given port (for example, "http=8080" selected port 80) + and now uses the port as given, and "named-rrchecker -C" compared only + part of the "CLASS" prefix when filtering generic class names, which + was harmless in practice but is now corrected. :gl:`!12616` + +- Hmac_verify() now accepts truncated HMACs only when requested. + ``c81b111496`` + + The hmac_verify() function incorrectly compares only up to + 'sig->length' bytes, but the signature and its length should not be + trusted, e.g. in case if it comes from a user query. + + Don't accept signatures which length isn't equal to the expected + calculated HMAC length unless it is explicitly requested by the + caller, e.g. for truncated TSIG [1] support. + + [1] https://datatracker.ietf.org/doc/html/rfc8945#name-tsig-truncation + -policy :gl:`!12629` + +- Prevent resolver crashes while processing DNS over TCP. ``81b3b6d89f`` + + Recursive resolvers could terminate with an assertion failure while + processing DNS responses over TCP under sustained traffic. The failure + was observed on resolvers configured globally with forward only; the + same transport path is also used by iterative resolution. This has + been fixed. :gl:`!12537` + + diff -Nru bind9-9.20.26/doc/man/Makefile.in bind9-9.20.29/doc/man/Makefile.in --- bind9-9.20.26/doc/man/Makefile.in 2026-07-20 14:49:10.557580884 +0000 +++ bind9-9.20.29/doc/man/Makefile.in 2026-09-11 19:42:18.530188069 +0000 @@ -258,6 +258,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/doc/man/rndc-confgen.8in bind9-9.20.29/doc/man/rndc-confgen.8in --- bind9-9.20.26/doc/man/rndc-confgen.8in 2026-07-20 14:50:05.741850293 +0000 +++ bind9-9.20.29/doc/man/rndc-confgen.8in 2026-09-11 19:43:12.413493062 +0000 @@ -85,8 +85,10 @@ .INDENT 0.0 .TP .B \-k keyname -This option specifies the key name of the \fBrndc\fP \%<#\:std-iscman-rndc> authentication key. This must be a -valid domain name. The default is \fBrndc\-key\fP\&. +This option specifies the key name of the \fBrndc\fP \%<#\:std-iscman-rndc> +authentication key. This must be a valid domain name and will +be sanitized using the domain name semantics. The default is +\fBrndc\-key\fP\&. .UNINDENT .INDENT 0.0 .TP diff -Nru bind9-9.20.26/doc/misc/Makefile.in bind9-9.20.29/doc/misc/Makefile.in --- bind9-9.20.26/doc/misc/Makefile.in 2026-07-20 14:49:10.585581527 +0000 +++ bind9-9.20.29/doc/misc/Makefile.in 2026-09-11 19:42:18.558188751 +0000 @@ -277,6 +277,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/doc/notes/notes-9.20.27.rst bind9-9.20.29/doc/notes/notes-9.20.27.rst --- bind9-9.20.26/doc/notes/notes-9.20.27.rst 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/doc/notes/notes-9.20.27.rst 2026-09-11 19:41:01.453329848 +0000 @@ -0,0 +1,102 @@ +.. 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. + +Notes for BIND 9.20.27 +---------------------- + +New Features +~~~~~~~~~~~~ + +- Disclose active Negative Trust Anchors with Extended DNS Error 33. + + A Negative Trust Anchor (:rfc:`7646`) turns off DNSSEC validation for + a domain, so a name that would normally fail validation resolves + instead. :iscman:`named` now marks such answers with Extended DNS + Error code 33, "Negative Trust Anchor", so operators can see at a + glance when a response came back only because an NTA was in effect. + :gl:`#6268` + +Feature Changes +~~~~~~~~~~~~~~~ + +- Speed up RPZ policy zone updates. + + RPZ updates used to be applied one small step at a time, adding + overhead on large policy zones. Updates are now applied as a single + batch, improving update performance for large RPZ zones, at the cost + of no longer overlapping with concurrent updates. :gl:`#5787` + :gl:`#6270` + +Bug Fixes +~~~~~~~~~ + +- Ensure NSEC authority does not cross zonecut boundary. + + When using a cached NSEC record to prove that a delegation is + insecure, :iscman:`named` now checks that the signer name in the + corresponding RRSIG is not above a known secure delegation point. + This prevents a signed namespace from being downgraded to insecure + using an NSEC record from the grandparent zone. :gl:`#5967` + +- Treat an unusable NSEC3 chain as a verification failure. + + When transferring in a mirror zone, DNSSEC verification could + incorrectly succeed when the zone had an invalid NSEC3PARAM record, + leading to subsequent validation failures. This has been fixed. + :gl:`#6136` + +- Treat non-canonical RPZ prefixes as any other failure. + + RPZ prefixes that were not encoded in canonical form did not work. + They are now handled in the same way as any other encoding error. :gl:`#6043` + +- Negative caching stopped working with stale-answer-client-timeout set + to ``0``. + + Negative answers were re-fetched on every query instead of once they + actually expired, effectively disabling negative caching. This has + been fixed. :gl:`#6245` + +- An unterminated OpenSSL private-key ``Label:`` field could be read past + its parser buffer. + + The ``Label:`` field in a ``.private`` key file is now checked for + length and NUL-termination. Malformed files are rejected. :gl:`#6193` + +- Restore SMF support on Solaris and illumos. :gl:`#6096` + +- Fix compilation on GNU/Hurd. :gl:`#6285` + +- :option:`dig +yaml` was producing invalid YAML when a lookup failed. + + When no server could be reached, :iscman:`dig` printed its + plain-text startup banner ahead of the YAML output, making the + result unparsable. :iscman:`dig` no longer does this and correctly + reflects options such as ``+nocmd``, ``+short`` and ``+yaml``, + regardless of where they appear on the command line. :gl:`#1230` + +- Properly prevent TSIG generation command line injection attacks. + + When key names are generated with :iscman:`rndc-confgen`, + :iscman:`tsig-keygen` and :iscman:`ddns-confgen`, special characters + must be escaped to ensure that the configuration is parsed correctly. + :gl:`#6071` + +- Fix a potential heap bounds overflow write in :iscman:`dnssec-signzone`. + + It was possible for :iscman:`dnssec-signzone` to overflow array + bounds while signing. This has been fixed. :gl:`#6076` + +- Fix crashes on invalid DNSTAP input in :iscman:`dnstap-read`. + + Malformed DNSTAP files could trigger a NULL pointer dereference or an + out-of-bounds memory read in :iscman:`dnstap-read`. This has been + fixed. :gl:`#6077` :gl:`#6124` diff -Nru bind9-9.20.26/doc/notes/notes-9.20.28.rst bind9-9.20.29/doc/notes/notes-9.20.28.rst --- bind9-9.20.26/doc/notes/notes-9.20.28.rst 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/doc/notes/notes-9.20.28.rst 2026-09-11 19:41:01.453329848 +0000 @@ -0,0 +1,18 @@ +.. 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. + +Notes for BIND 9.20.28 +---------------------- + +.. note:: + + The BIND 9.20.28 release was withdrawn after the discovery of a + regression in it during pre-release testing. diff -Nru bind9-9.20.26/doc/notes/notes-9.20.29.rst bind9-9.20.29/doc/notes/notes-9.20.29.rst --- bind9-9.20.26/doc/notes/notes-9.20.29.rst 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/doc/notes/notes-9.20.29.rst 2026-09-11 19:41:01.453329848 +0000 @@ -0,0 +1,367 @@ +.. 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. + +Notes for BIND 9.20.29 +---------------------- + +Security Fixes +~~~~~~~~~~~~~~ + +- Prevent excessive CPU use validating crafted DNSSEC responses. + :cve:`2026-19668` + + A malicious authoritative server could serve a securely delegated zone + whose DS and DNSKEY records carried many distinct key tags but no valid + match, forcing a validating resolver into excessive key-tag matching + and high CPU use for every query. This work is now bounded by the + per-query validation limit (:any:`max-validations-per-fetch`). + + ISC would like to thank Zuyao Xu and Xiang Li of the All-in-One + Security and Privacy Laboratory, Nankai University, for bringing this + vulnerability to our attention. :gl:`#5349` + +- Require a TSIG on every message of incoming zone transfers. + :cve:`2026-19033` + + Previously, :iscman:`named` accepted TSIG-signed zone transfers in + which some messages were unsigned, and processed those messages + before the next signature could vouch for them. It now requires a + TSIG on every message of an incoming AXFR or IXFR; all modern + nameservers already sign every message, so no change is expected in + practice. :gl:`#6062` + +- Prevent a DNSSEC downgrade of secure delegations via unrelated NSEC3 + records. :cve:`2026-77119` + + A validating resolver could be tricked into treating a secure + delegation as unsigned and accepting forged answers for names beneath + it, if an attacker could inject responses to its queries. Such forged + proofs are now rejected. :gl:`#6234` + +- Prevent forged DNSSEC-validated NXDOMAIN responses. :cve:`2026-19941` + + A validating resolver could accept a signed NSEC record from an + unrelated zone as proof that a wildcard did not exist. An on-path + attacker or malicious forwarder controlling a signed zone could + therefore forge an authenticated NXDOMAIN response for a name that + should resolve through a wildcard. The wildcard-denial and + name-nonexistence proofs are now required to be signed by the same + zone. :gl:`#6253` + +- DNS64 with :any:`break-dnssec` could cause an assertion failure. + :cve:`2026-19666` + + When a :any:`dns64` statement is configured with ``break-dnssec yes;`` + and its ``exclude`` list matches some but not all of the addresses in + an AAAA RRset, :iscman:`named` removes the excluded addresses from the + answer instead of synthesizing new ones. If the answer being filtered + had been cached together with a proof that the queried name did not + exist — which is what a wildcard match produces — :iscman:`named` + terminated with an assertion failure. + + Only recursive resolvers are affected, and only when + ``break-dnssec yes;`` is in use; the answer has to come from the + cache, so a server that is only authoritative cannot reach this. + + ISC would like to thank Rintaro Kawasugi for bringing this + vulnerability to our attention. :gl:`#6301` + +- Reject oversized negative cache records. :cve:`2026-19667` + + A single crafted response from a server could make a resolver cache a + malformed negative entry and then terminate with an assertion failure + when reading it back. Only recursive resolvers are affected, on a + default configuration. + + ISC would like to thank Rintaro Kawasugi for bringing this + vulnerability to our attention. :gl:`#6302` + +- Prevent resolver crash with cached DNSSEC proofs. :cve:`2026-19662` + + Under certain timing conditions, concurrent recursive queries could + cause :iscman:`named` to crash when cached DNSSEC NOQNAME proof data + was replaced while still in use. Cached proof data is now retained + until all queries using it have completed. + + ISC would like to thank Samy Medjahed/Ap4sh for bringing this + vulnerability to our attention. :gl:`#6333` + +- Discard repeated SOA, CNAME, and DNAME records when parsing DNS + messages. :cve:`2026-75029` + + A DNS message could carry the same SOA, CNAME, or DNAME record many + times, and :iscman:`named` kept every copy while parsing it. With name + compression those copies took up far more memory internally than in + the message itself, and every later processing step had to handle all + of them. Only the first copy of such a record is now kept; identical + repeats are discarded. :gl:`#6335` + +- Fix an unauthenticated crash on HTTPS using SIG(0). :cve:`2026-77692` + + A specifically crafted HTTPS query using SIG(0) as authentication + could crash :iscman:`named` if the client closed the connection before + :iscman:`named` actually verified the signature. This is now fixed. + + ISC would like to thank Vitaly Simonovich for bringing this + vulnerability to our attention. :gl:`#6343` + +- Cached HTTPS/SVCB aliases could exhaust resolver CPU. + :cve:`2026-81736` + + A recursive resolver that had cached a large set of interlinked HTTPS + or SVCB records in alias form could be driven to do an excessive + amount of work assembling a single response, because it followed every + cached alias target when building the additional section. A client + permitted to use recursion, together with an attacker-controlled zone + used to plant the records, could repeat small queries to consume + enough CPU to delay or deny service to other clients. The amount of + additional processing done for one query is now bounded. + + ISC would like to thank Henrique Pereira for bringing this + vulnerability to our attention. :gl:`#6347` + +- Prevent TKEY queries from terminating :iscman:`named` without global + options. :cve:`2026-76163` + + The :iscman:`named` process could terminate unexpectedly when a remote + client sent a TKEY query and the configuration did not include a + global :namedconf:ref:`options` statement. This has been fixed. + + ISC would like to thank Owais Lone (thesecguy) for bringing this + vulnerability to our attention. :gl:`#6357` + +- Out-of-zone records in a zone database could be served as + authoritative. :cve:`2026-78301` + + When a zone database contained records for names outside the zone — + such as a delegation above the zone apex, left behind by a secondary + that had accepted out-of-zone data from its primary — the server could + treat them as authoritative and answer queries for names inside the + zone with that out-of-zone data instead of the zone's own. A server + that was also a resolver could follow such a delegation and cache the + answers of the server it named, affecting names outside the configured + zone. Zone database lookups are now confined to names at or below the + zone's origin. + + ISC would like to thank Henrique Pereira for bringing this + vulnerability to our attention. :gl:`#6361` + +- Fix crash on wildcard answers carrying both NSEC and NSEC3 proofs. + :cve:`2026-80274` + + When a wildcard answer arrived with both NSEC and NSEC3 records at the + name proving that the queried name did not exist, the resolver could + pick different records when caching the answer and when retrieving the + proof, depending on the order in which the authoritative server sent + them. This could terminate :iscman:`named` with an assertion failure, + fail the query with SERVFAIL, or serve a denial record other than the + one that had been verified. The resolver now caches and serves the + same denial record it accepted when the answer was received. + + ISC would like to thank hythyt for bringing this vulnerability to our + attention. :gl:`#6369` + +- Following HTTPS/SVCB aliases could leak resolver cache memory. + :cve:`2026-81563` + + When a recursive server answered a query for an HTTPS or SVCB record + in alias form and the alias target had more than 13 records, the + target records were pinned in the cache permanently instead of being + released once the answer was sent. A remote party who could make the + server follow such aliases to a steady stream of fresh names could + grow the cache beyond the configured :any:`max-cache-size` until the + server was unable to resolve unrelated names. The records are now + released correctly. + + ISC would like to thank Samy Medjahed/Ap4sh for bringing this + vulnerability to our attention. :gl:`#6374` + +Feature Changes +~~~~~~~~~~~~~~~ + +- Reject oversized and malformed DNSKEY records up front. + + Oversized RSA key material in a DNSKEY record was only rejected after + it had been converted, allocating memory proportional to the record + size. Such records are now rejected before conversion, as are Ed25519 + and Ed448 keys with trailing bytes that were previously silently + ignored. :gl:`#4537` + +Bug Fixes +~~~~~~~~~ + +- Prevent a crash when using both :any:`dns64` and ``filter-a``. + + An assertion failure was possible when using both :any:`dns64` and the + ``filter-a`` plugin simultaneously; this has been fixed. + :gl:`#5979` + +- Stop passing UDP client addresses to :any:`update-policy` ``external`` + helpers. + + Dynamic update rules of type ``external`` delegate the authorization + decision to an external helper daemon. The client address field in + the helper request is only meant to carry TCP client addresses, which + cannot easily be spoofed, but UDP client addresses were passed as + well, so the helper could base its decision on an untrustworthy + address. For updates arriving over UDP, the helper request no longer + includes a client address. :gl:`#6061` + +- Missing required NSEC3 for delegation not detected. + + A missing required NSEC3 record for an insecure delegation in a + non-opt-out range was not being detected. This has been fixed. + :gl:`#6063` + +- Tighten EUI48 and EUI64 text parsing. + + Malformed EUI48 and EUI64 records could be accepted. This has been + fixed. :gl:`#6082` + +- GeoIP ACL state could be stale or wrong after reload. + + Previously, :iscman:`named` cached GeoIP information after looking it + up, but the cached information was not invalidated when the GeoIP + database was reloaded, so it could continue to be used. Existing + cached GeoIP information is now invalidated as part of the reloading + process. :gl:`#6083` + +- Honor DNSSEC policy key tag ranges. + + When a :any:`dnssec-policy` configured a non-default ``tag-range``, + :iscman:`dnssec-keygen` and :iscman:`dnssec-ksr` could accept + generated keys outside that range. Both tools now honor the configured + minimum and maximum key tags. :gl:`#6091` + +- Fix a double free in :iscman:`mdig` when EDNS options are specified. + + The :iscman:`mdig` utility could terminate with a double free when + EDNS options were specified on the command line. This has been fixed. + :gl:`#6095` + +- Fix a crash when an IXFR falls back to AXFR with updates still + pending. + + When a secondary zone received an incremental transfer (IXFR) and the + primary then caused :iscman:`named` to fall back to a full transfer + (AXFR) while some of the already-received incremental changes were + still waiting to be applied, :iscman:`named` could later crash when + that transfer finished. The pending changes are now discarded + correctly before the AXFR retry. :gl:`#6114` + +- Fix DS requests to parental agents over TLS. + + TLS configuration for parental agents was being ignored when sending + DS requests. This has been fixed. :gl:`#6135` + +- Fix the :option:`rndc-confgen -q` (quiet) option. + + The command-line parsing in :iscman:`rndc-confgen` was broken, so + :option:`rndc-confgen -q` did not work. This has been fixed. + :gl:`#6187` + +- Enforce query ACLs for redirect zones and searched DLZs. + + Queries answered from redirect zones or searched DLZ databases did not + consistently honor :any:`allow-query` and :any:`allow-query-on`, + potentially exposing restricted DNS data to excluded clients or + through excluded listening addresses. These ACLs are now enforced + before redirect or DLZ data is returned. :gl:`#6251` :gl:`#6252` + +- Check ``asnum`` validity in GeoIP ACLs. + + The validity of autonomous system (AS) numbers is now checked at + configuration time when parsing GeoIP ACLs that use ``asnum`` + elements. + + ``asnum`` values start with an optional case-insensitive ``AS`` + prefix, followed only by decimal digits, with no spaces or other + extraneous characters. The value represented cannot exceed 2^32. + :gl:`#6255` + +- Fix a crash on :any:`remote-servers` lists that reference themselves. + + Since 9.21.16 and 9.20.17, a :any:`remote-servers`, :any:`primaries`, + ``masters``, or :any:`parental-agents` list that referenced itself, + directly or through another list, made :iscman:`named` crash on + startup or reconfiguration. Such references are again skipped and the + remaining entries in the list are used, as in earlier versions. + :gl:`#6287` + +- A record from outside a response policy zone could crash + :iscman:`named`. + + A response policy zone transferred from a primary can contain a record + whose name lies outside the zone. Such a record could terminate + :iscman:`named` with an assertion failure, both when it arrived and + again at every startup afterwards, because a secondary keeps it in its + own copy of the zone. Records like this are now rejected and logged; + previously one could also silently create a policy entry for an + unrelated name. :gl:`#6304` + +- Invalid :any:`key-store` configuration could abort the DNSSEC tools. + + An invalid :any:`key-store` block named ``key-directory`` in a + configuration file could abort the DNSSEC tools. This has been fixed. + :gl:`#6313` + +- NSEC signature set could bypass the secure-delegation check. + + When proving that a delegation was insecure, the validator bounded an + NSEC record's authority by the signer of whichever RRSIG happened to + come first in the record's signature set, rather than the signature + that actually verified. A grandparent NSEC padded with an extra, + unverifiable signature could therefore pass the check that kept such + proofs from reaching below a signed child zone. The validator now + requires every signature on the NSEC to name the same signer and + refuses proofs whose signature set is malformed or larger than + :any:`max-validations-per-fetch` allows. :gl:`#6321` + +- Fix a possible :iscman:`nsupdate` issue when using GSS-TSIG. + + The :iscman:`nsupdate` process could terminate unexpectedly when using + the GSS-TSIG mode executed with the :option:`nsupdate -g` option. This + has been fixed. :gl:`#6325` + +- Fix a crash with a single-element ``geoip`` sortlist. + + If :iscman:`named` was configured with a single-element + :any:`sortlist` containing a ``geoip`` ACL element, any matching query + triggered an assertion failure. This has been fixed. :gl:`#6342` + +- Prevent out-of-bailiwick CNAMEs from evicting cached records. + + A recursive resolver could remove valid cached records when a DNS + response contained an out-of-bailiwick CNAME with the same owner name. + Out-of-bailiwick data is now discarded before it can modify the cache. + :gl:`#6345` + +- Restore periodic cleanup of stale resolver address data. + + Stale resolver address data could remain cached until memory pressure + or an explicit flush. The cleanup interval has been corrected, so + stale entries are removed periodically again. :gl:`#6346` + +- Fix :iscman:`named-checkconf`/:iscman:`named` crash with malformed + key name. + + When a primary/remote-server key name was malformed, + :iscman:`named-checkconf` and :iscman:`named` were both crashing + (after warning about the invalid key name). This is now fixed. + :gl:`#6362` + +- Prevent resolver crashes while processing DNS over TCP. + + Recursive resolvers could terminate with an assertion failure while + processing DNS responses over TCP under sustained traffic. The failure + was observed on resolvers configured globally with ``forward only;``, + but the same transport path is also used by iterative resolution. + This has been fixed. :gl:`!12537` diff -Nru bind9-9.20.26/fuzz/Makefile.in bind9-9.20.29/fuzz/Makefile.in --- bind9-9.20.26/fuzz/Makefile.in 2026-07-20 14:49:10.631582584 +0000 +++ bind9-9.20.29/fuzz/Makefile.in 2026-09-11 19:42:18.602189823 +0000 @@ -573,6 +573,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/fuzz/dns_message_checksig.c bind9-9.20.29/fuzz/dns_message_checksig.c --- bind9-9.20.26/fuzz/dns_message_checksig.c 2026-07-20 14:47:53.983848716 +0000 +++ bind9-9.20.29/fuzz/dns_message_checksig.c 2026-09-11 19:41:01.454329872 +0000 @@ -124,8 +124,6 @@ sig0key. 0 IN NS .\n\ sig0key. 0 IN KEY 512 3 8 AwEAAa22lgHi1vAbQvu5ETdTrm2H8rwga9tvyMa6LFiSDyevLvSv0Uo5 uvfrXnxaLdtBMts6e1Ly2piSH9JRbOGMNibOK4EXWhWAn8MII4SWgQAs bFwtiz4HyPn2wScrUQdo8DocKiQJBanesr7vDO8fdA6Rg1e0yAtSeNti e8avx46/HJa6CFs3CoE0sf6oOFSxM954AgCBTXOGNBt1Nt3Bhfqt2qyA TLFii5K1jLDTZDVkoiyDXL1M7wcTwKf9METgj1eQmH3GGlRM/OJ/j8xk ZiFGbL3cipWdiH48031jiV2hlc92mKn8Ya0d9AN6c44piza/JSFydZXw sY32nxzjDbs=\n"; -static bool destroy_dst = false; - int LLVMFuzzerInitialize(int *argc ISC_ATTR_UNUSED, char ***argv ISC_ATTR_UNUSED) { isc_result_t result; @@ -179,7 +177,6 @@ isc_result_totext(result)); return 1; } - destroy_dst = true; isc_loopmgr_create(mctx, 1, &loopmgr); diff -Nru bind9-9.20.26/fuzz/dns_rdata_fromwire_text.c bind9-9.20.29/fuzz/dns_rdata_fromwire_text.c --- bind9-9.20.26/fuzz/dns_rdata_fromwire_text.c 2026-07-20 14:47:54.016849229 +0000 +++ bind9-9.20.29/fuzz/dns_rdata_fromwire_text.c 2026-09-11 19:41:01.489330710 +0000 @@ -49,7 +49,6 @@ isc_lex_create(mctx, 64, &lex); memset(specials, 0, sizeof(specials)); - specials[0] = 1; specials['('] = 1; specials[')'] = 1; specials['"'] = 1; diff -Nru bind9-9.20.26/lib/Makefile.in bind9-9.20.29/lib/Makefile.in --- bind9-9.20.26/lib/Makefile.in 2026-07-20 14:49:10.649582998 +0000 +++ bind9-9.20.29/lib/Makefile.in 2026-09-11 19:42:18.620190261 +0000 @@ -276,6 +276,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/lib/dns/Makefile.in bind9-9.20.29/lib/dns/Makefile.in --- bind9-9.20.26/lib/dns/Makefile.in 2026-07-20 14:49:10.776585915 +0000 +++ bind9-9.20.29/lib/dns/Makefile.in 2026-09-11 19:42:18.747193355 +0000 @@ -553,6 +553,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/lib/dns/acl.c bind9-9.20.29/lib/dns/acl.c --- bind9-9.20.26/lib/dns/acl.c 2026-07-20 14:47:54.020849291 +0000 +++ bind9-9.20.29/lib/dns/acl.c 2026-09-11 19:41:01.493330806 +0000 @@ -422,7 +422,13 @@ if (env == NULL || env->geoip == NULL) { return false; } - return dns_geoip_match(reqaddr, env->geoip, &e->geoip_elem); + if (dns_geoip_match(reqaddr, env->geoip, &e->geoip_elem)) { + if (matchelt != NULL) { + *matchelt = e; + } + return true; + } + return false; #endif /* if defined(HAVE_GEOIP2) */ default: UNREACHABLE(); diff -Nru bind9-9.20.26/lib/dns/adb.c bind9-9.20.29/lib/dns/adb.c --- bind9-9.20.26/lib/dns/adb.c 2026-07-20 14:47:54.020849291 +0000 +++ bind9-9.20.29/lib/dns/adb.c 2026-09-11 19:41:01.494330830 +0000 @@ -1292,7 +1292,7 @@ RWLOCK(&adb->names_lock, locktype); last_update = adb->names_last_update; - if (last_update + ADB_STALE_MARGIN >= now || overmem) { + if (now - last_update > ADB_STALE_MARGIN || overmem) { last_update = now; UPGRADELOCK(&adb->names_lock, locktype); if (overmem) { @@ -1381,7 +1381,6 @@ if (now - last_update > ADB_STALE_MARGIN || overmem) { last_update = now; - UPGRADELOCK(&adb->entries_lock, locktype); if (overmem) { purge_entries_overmem(adb, 2 * sizeof(*adbentry)); diff -Nru bind9-9.20.26/lib/dns/cache.c bind9-9.20.29/lib/dns/cache.c --- bind9-9.20.26/lib/dns/cache.c 2026-07-20 14:47:54.021849307 +0000 +++ bind9-9.20.29/lib/dns/cache.c 2026-09-11 19:41:01.494330830 +0000 @@ -486,9 +486,7 @@ dns_dbnode_t *node = NULL; dns_db_t *db = NULL; - if (tree && dns_name_equal(name, dns_rootname)) { - return dns_cache_flush(cache); - } + REQUIRE(!(tree && dns_name_equal(name, dns_rootname))); LOCK(&cache->lock); if (cache->db != NULL) { diff -Nru bind9-9.20.26/lib/dns/catz.c bind9-9.20.29/lib/dns/catz.c --- bind9-9.20.26/lib/dns/catz.c 2026-07-20 14:47:54.021849307 +0000 +++ bind9-9.20.29/lib/dns/catz.c 2026-09-11 19:41:01.495330854 +0000 @@ -56,6 +56,12 @@ isc_refcount_t references; }; +typedef struct coos { + isc_mutex_t lock; + isc_mem_t *mctx; + isc_ht_t *inner; +} coos_t; + /*% * Single member zone in a catalog */ @@ -79,7 +85,7 @@ /* key in entries is 'mhash', not domain name! */ isc_ht_t *entries; /* key in coos is domain name */ - isc_ht_t *coos; + coos_t coos; /* * defoptions are taken from named.conf @@ -91,7 +97,6 @@ bool updatepending; /* there is an update pending */ bool updaterunning; /* there is an update running */ - isc_result_t updateresult; /* result from the offloaded work */ dns_db_t *db; /* zones database */ dns_dbversion_t *dbversion; /* version we will be updating to */ dns_db_t *updb; /* zones database we're working on */ @@ -113,7 +118,7 @@ static void dns__catz_timer_stop(void *arg); -static void +static isc_result_t dns__catz_update_cb(void *data); static void dns__catz_done_cb(void *data, isc_result_t result); @@ -261,16 +266,15 @@ } static void -catz_coo_detach(dns_catz_zone_t *catz, dns_catz_coo_t **coop) { +catz_coo_detach(isc_mem_t *mctx, dns_catz_coo_t **coop) { dns_catz_coo_t *coo; - REQUIRE(DNS_CATZ_ZONE_VALID(catz)); + REQUIRE(mctx != NULL); REQUIRE(coop != NULL && DNS_CATZ_COO_VALID(*coop)); coo = *coop; *coop = NULL; if (isc_refcount_decrement(&coo->references) == 1) { - isc_mem_t *mctx = catz->catzs->mctx; coo->magic = 0; isc_refcount_destroy(&coo->references); if (dns_name_dynamic(&coo->name)) { @@ -281,24 +285,126 @@ } static void -catz_coo_add(dns_catz_zone_t *catz, dns_catz_entry_t *entry, - const dns_name_t *domain) { - REQUIRE(DNS_CATZ_ZONE_VALID(catz)); +coos_init(coos_t *coos, isc_mem_t *mctx) { + REQUIRE(coos != NULL); + REQUIRE(mctx != NULL); + + isc_mutex_init(&coos->lock); + isc_mem_attach(mctx, &coos->mctx); + isc_ht_init(&coos->inner, coos->mctx, 4, ISC_HT_CASE_INSENSITIVE); +} + +static isc_ht_t * +coos_replace(coos_t *coos, isc_ht_t *newinner) { + isc_ht_t *oldinner = NULL; + + REQUIRE(coos != NULL); + REQUIRE(coos->mctx != NULL); + + LOCK(&coos->lock); + oldinner = coos->inner; + coos->inner = newinner; + UNLOCK(&coos->lock); + + return oldinner; +} + +static isc_ht_t * +coos_take(coos_t *coos) { + return coos_replace(coos, NULL); +} + +static void +coos_destroy_table(coos_t *coos, isc_ht_t **innerp) { + isc_ht_iter_t *iter = NULL; + isc_ht_t *inner = NULL; + isc_result_t result; + + REQUIRE(coos != NULL); + REQUIRE(coos->mctx != NULL); + REQUIRE(innerp != NULL); + + inner = *innerp; + if (inner == NULL) { + return; + } + + isc_ht_iter_create(inner, &iter); + for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS; + result = isc_ht_iter_delcurrent_next(iter)) + { + dns_catz_coo_t *coo = NULL; + + isc_ht_iter_current(iter, (void **)&coo); + catz_coo_detach(coos->mctx, &coo); + } + INSIST(result == ISC_R_NOMORE); + isc_ht_iter_destroy(&iter); + + /* The hashtable has to be empty now. */ + INSIST(isc_ht_count(inner) == 0); + isc_ht_destroy(innerp); +} + +static void +coos_destroy(coos_t *coos) { + isc_ht_t *inner = NULL; + + REQUIRE(coos != NULL); + REQUIRE(coos->mctx != NULL); + + inner = coos_take(coos); + coos_destroy_table(coos, &inner); + isc_mutex_destroy(&coos->lock); + isc_mem_detach(&coos->mctx); +} + +static void +coos_add(coos_t *coos, dns_catz_entry_t *entry, const dns_name_t *domain) { + dns_catz_coo_t *coo = NULL; + isc_result_t result; + + REQUIRE(coos != NULL); + REQUIRE(coos->mctx != NULL); REQUIRE(DNS_CATZ_ENTRY_VALID(entry)); REQUIRE(domain != NULL); - /* We are write locked, so the add must succeed if not found */ - dns_catz_coo_t *coo = NULL; - isc_result_t result = isc_ht_find(catz->coos, entry->name.ndata, - entry->name.length, (void **)&coo); + LOCK(&coos->lock); + INSIST(coos->inner != NULL); + result = isc_ht_find(coos->inner, entry->name.ndata, entry->name.length, + (void **)&coo); if (result != ISC_R_SUCCESS) { - coo = catz_coo_new(catz->catzs->mctx, domain); - result = isc_ht_add(catz->coos, entry->name.ndata, + coo = catz_coo_new(coos->mctx, domain); + result = isc_ht_add(coos->inner, entry->name.ndata, entry->name.length, coo); } + UNLOCK(&coos->lock); + INSIST(result == ISC_R_SUCCESS); } +static bool +coos_match(coos_t *coos, const dns_name_t *zone, const dns_name_t *catz) { + dns_catz_coo_t *coo = NULL; + bool match = false; + + REQUIRE(coos != NULL); + REQUIRE(coos->mctx != NULL); + REQUIRE(zone != NULL); + REQUIRE(catz != NULL); + + LOCK(&coos->lock); + if (coos->inner != NULL && + isc_ht_find(coos->inner, zone->ndata, zone->length, + (void **)&coo) == ISC_R_SUCCESS) + { + match = dns_name_equal(&coo->name, catz); + } + UNLOCK(&coos->lock); + + return match; +} + dns_catz_entry_t * dns_catz_entry_new(isc_mem_t *mctx, const dns_name_t *domain) { REQUIRE(mctx != NULL); @@ -581,25 +687,19 @@ dns_catz_entry_getname(nentry), DNS_ZTFIND_EXACT, &zone); if (find_result == ISC_R_SUCCESS) { - dns_catz_coo_t *coo = NULL; char pczname[DNS_NAME_FORMATSIZE]; - bool parentcatz_locked = false; + bool coo_match = false; /* * Change of ownership (coo) processing, if required */ parentcatz = dns_zone_get_parentcatz(zone); if (parentcatz != NULL && parentcatz != catz) { - UNLOCK(&catz->lock); - LOCK(&parentcatz->lock); - parentcatz_locked = true; + coo_match = coos_match(&parentcatz->coos, + &nentry->name, + &catz->name); } - if (parentcatz_locked && - isc_ht_find(parentcatz->coos, nentry->name.ndata, - nentry->name.length, - (void **)&coo) == ISC_R_SUCCESS && - dns_name_equal(&coo->name, &catz->name)) - { + if (coo_match) { dns_name_format(&parentcatz->name, pczname, DNS_NAME_FORMATSIZE); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, @@ -620,10 +720,6 @@ zname, pczname, isc_result_totext(result)); } - if (parentcatz_locked) { - UNLOCK(&parentcatz->lock); - LOCK(&catz->lock); - } dns_zone_detach(&zone); } @@ -750,28 +846,9 @@ * We do not need to merge old coo (change of ownership) permission * records with the new ones, just replace them. */ - if (catz->coos != NULL && newcatz->coos != NULL) { - isc_ht_iter_t *iter = NULL; - - isc_ht_iter_create(catz->coos, &iter); - for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS; - result = isc_ht_iter_delcurrent_next(iter)) - { - dns_catz_coo_t *coo = NULL; - - isc_ht_iter_current(iter, (void **)&coo); - catz_coo_detach(catz, &coo); - } - INSIST(result == ISC_R_NOMORE); - isc_ht_iter_destroy(&iter); - - /* The hashtable has to be empty now. */ - INSIST(isc_ht_count(catz->coos) == 0); - isc_ht_destroy(&catz->coos); - - catz->coos = newcatz->coos; - newcatz->coos = NULL; - } + isc_ht_t *newcoos = coos_take(&newcatz->coos); + isc_ht_t *oldcoos = coos_replace(&catz->coos, newcoos); + coos_destroy_table(&catz->coos, &oldcoos); result = ISC_R_SUCCESS; @@ -841,7 +918,7 @@ isc_mutex_init(&catz->lock); isc_refcount_init(&catz->references, 1); isc_ht_init(&catz->entries, catzs->mctx, 4, ISC_HT_CASE_INSENSITIVE); - isc_ht_init(&catz->coos, catzs->mctx, 4, ISC_HT_CASE_INSENSITIVE); + coos_init(&catz->coos, catzs->mctx); isc_time_settoepoch(&catz->lastupdated); dns_catz_options_init(&catz->defoptions); dns_catz_options_init(&catz->zoneoptions); @@ -1005,25 +1082,7 @@ INSIST(isc_ht_count(catz->entries) == 0); isc_ht_destroy(&catz->entries); } - if (catz->coos != NULL) { - isc_ht_iter_t *iter = NULL; - isc_result_t result; - isc_ht_iter_create(catz->coos, &iter); - for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS; - result = isc_ht_iter_delcurrent_next(iter)) - { - dns_catz_coo_t *coo = NULL; - - isc_ht_iter_current(iter, (void **)&coo); - catz_coo_detach(catz, &coo); - } - INSIST(result == ISC_R_NOMORE); - isc_ht_iter_destroy(&iter); - - /* The hashtable has to be empty now. */ - INSIST(isc_ht_count(catz->coos) == 0); - isc_ht_destroy(&catz->coos); - } + coos_destroy(&catz->coos); catz->magic = 0; isc_mutex_destroy(&catz->lock); @@ -1235,7 +1294,7 @@ goto cleanup; } - catz_coo_add(catz, entry, &ptr.ptr); + coos_add(&catz->coos, entry, &ptr.ptr); cleanup: dns_rdata_freestruct(&ptr); @@ -2101,7 +2160,6 @@ catz->updatepending = false; catz->updaterunning = true; - catz->updateresult = ISC_R_UNSET; dns_name_format(&catz->name, domain, DNS_NAME_FORMATSIZE); @@ -2111,7 +2169,6 @@ "catz: %s: no longer active, reload is canceled", domain); catz->updaterunning = false; - catz->updateresult = ISC_R_CANCELED; goto exit; } @@ -2231,7 +2288,7 @@ * It creates a new catz, iterates over database to fill it with content, and * then merges new catz into old catz. */ -static void +static isc_result_t dns__catz_update_cb(void *data) { dns_catz_zone_t *catz = (dns_catz_zone_t *)data; dns_db_t *updb = NULL; @@ -2261,8 +2318,7 @@ catzs = catz->catzs; if (atomic_load(&catzs->shuttingdown)) { - result = ISC_R_SHUTTINGDOWN; - goto exit; + return ISC_R_SHUTTINGDOWN; } dns_name_format(&updb->origin, bname, DNS_NAME_FORMATSIZE); @@ -2274,8 +2330,7 @@ LOCK(&catzs->lock); if (catzs->zones == NULL) { UNLOCK(&catzs->lock); - result = ISC_R_SHUTTINGDOWN; - goto exit; + return ISC_R_SHUTTINGDOWN; } result = isc_ht_find(catzs->zones, r.base, r.length, (void **)&oldcatz); is_active = (result == ISC_R_SUCCESS && oldcatz->active); @@ -2285,7 +2340,6 @@ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, "catz: zone '%s' not in config", bname); - goto exit; } if (!is_active) { @@ -2293,8 +2347,7 @@ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_INFO, "catz: zone '%s' is no longer active", bname); - result = ISC_R_CANCELED; - goto exit; + return ISC_R_CANCELED; } result = dns_db_getsoaserial(updb, oldcatz->updbversion, &vers); @@ -2304,7 +2357,7 @@ DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, "catz: zone '%s' has no SOA record (%s)", bname, isc_result_totext(result)); - goto exit; + return result; } isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, @@ -2318,7 +2371,7 @@ DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, "catz: failed to create DB iterator - %s", isc_result_totext(result)); - goto exit; + return result; } name = dns_fixedname_initname(&fixname); @@ -2335,7 +2388,7 @@ DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, "catz: failed to create name from string - %s", isc_result_totext(result)); - goto exit; + return result; } result = dns_dbiterator_seek(updbit, name); @@ -2346,7 +2399,8 @@ "catz: zone '%s' has no 'version' record (%s) " "and will not be processed", bname, isc_result_totext(result)); - goto exit; + + return result; } newcatz = dns_catz_zone_new(catzs, &updb->origin); @@ -2409,14 +2463,6 @@ goto next; } - /* - * Although newcatz->coos is accessed in - * catz_process_coo() in the call-chain below, we don't - * need to hold the newcatz->lock, because the newcatz - * is still local to this thread and function and - * newcatz->coos can't be accessed from the outside - * until dns__catz_zones_merge() has been called. - */ result = dns__catz_update_process(newcatz, name, &rdataset); if (result != ISC_R_SUCCESS) { @@ -2491,8 +2537,7 @@ "will not be processed", bname); dns_catz_zone_detach(&newcatz); - result = ISC_R_FAILURE; - goto exit; + return ISC_R_FAILURE; } /* @@ -2506,19 +2551,18 @@ "catz: failed merging zones: %s", isc_result_totext(result)); - goto exit; + return result; } isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3), "catz: update_from_db: new zone merged"); -exit: - catz->updateresult = result; + return result; } static void -dns__catz_done_cb(void *data, isc_result_t result ISC_ATTR_UNUSED) { +dns__catz_done_cb(void *data, isc_result_t result) { dns_catz_zone_t *catz = (dns_catz_zone_t *)data; char dname[DNS_NAME_FORMATSIZE]; @@ -2541,7 +2585,7 @@ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_INFO, "catz: %s: reload done: %s", dname, - isc_result_totext(catz->updateresult)); + isc_result_totext(result)); dns_catz_zone_unref(catz); } diff -Nru bind9-9.20.26/lib/dns/dnstap.c bind9-9.20.29/lib/dns/dnstap.c --- bind9-9.20.26/lib/dns/dnstap.c 2026-07-20 14:47:54.023849338 +0000 +++ bind9-9.20.29/lib/dns/dnstap.c 2026-09-11 19:41:01.497330902 +0000 @@ -1039,6 +1039,10 @@ m = frame->message; + if (m == NULL) { + CLEANUP(DNS_R_BADDNSTAP); + } + /* Message type */ switch (m->type) { case DNSTAP__MESSAGE__TYPE__AUTH_QUERY: diff -Nru bind9-9.20.26/lib/dns/dst_parse.c bind9-9.20.29/lib/dns/dst_parse.c --- bind9-9.20.26/lib/dns/dst_parse.c 2026-07-20 14:47:54.024849354 +0000 +++ bind9-9.20.29/lib/dns/dst_parse.c 2026-09-11 19:41:01.498330926 +0000 @@ -765,4 +765,14 @@ return result; } +isc_result_t +dst__privelement_is_nul_terminated(const dst_private_element_t *element) { + if (element->length < 1 || element->data[element->length - 1] != 0 || + strlen((char *)element->data) != (size_t)element->length - 1) + { + return DST_R_INVALIDPRIVATEKEY; + } + return ISC_R_SUCCESS; +} + /*! \file */ diff -Nru bind9-9.20.26/lib/dns/dst_parse.h bind9-9.20.29/lib/dns/dst_parse.h --- bind9-9.20.26/lib/dns/dst_parse.h 2026-07-20 14:47:54.024849354 +0000 +++ bind9-9.20.29/lib/dns/dst_parse.h 2026-09-11 19:41:01.498330926 +0000 @@ -122,4 +122,8 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, const char *directory); +isc_result_t +dst__privelement_is_nul_terminated( + const dst_private_element_t *dst_private_element_t); + ISC_LANG_ENDDECLS diff -Nru bind9-9.20.26/lib/dns/ede.c bind9-9.20.29/lib/dns/ede.c --- bind9-9.20.26/lib/dns/ede.c 2026-07-20 14:47:54.025849369 +0000 +++ bind9-9.20.29/lib/dns/ede.c 2026-09-11 19:41:01.498330926 +0000 @@ -13,6 +13,8 @@ /*! \file */ +#include + #include #include @@ -23,11 +25,11 @@ static bool dns__ede_checkandupdateedeused(dns_edectx_t *edectx, uint16_t code) { - if (edectx->edeused & (1 << code)) { + if (edectx->edeused & (UINT64_C(1) << code)) { return true; } - edectx->edeused |= 1 << code; + edectx->edeused |= UINT64_C(1) << code; return false; } diff -Nru bind9-9.20.26/lib/dns/geoip2.c bind9-9.20.29/lib/dns/geoip2.c --- bind9-9.20.26/lib/dns/geoip2.c 2026-07-20 14:47:54.025849369 +0000 +++ bind9-9.20.29/lib/dns/geoip2.c 2026-09-11 19:41:01.498330926 +0000 @@ -63,26 +63,31 @@ isc_netaddr_t addr; MMDB_lookup_result_s mmresult; MMDB_entry_s entry; + uint_fast64_t serial; } geoip_state_t; static thread_local geoip_state_t geoip_state = { 0 }; +static atomic_int_fast64_t geoip_state_serial = 0; static void -set_state(const MMDB_s *db, const isc_netaddr_t *addr, +set_state(uint_fast64_t serial, const MMDB_s *db, const isc_netaddr_t *addr, MMDB_lookup_result_s mmresult, MMDB_entry_s entry) { geoip_state.db = db; geoip_state.addr = *addr; geoip_state.mmresult = mmresult; geoip_state.entry = entry; + geoip_state.serial = serial; } static geoip_state_t * get_entry_for(MMDB_s *const db, const isc_netaddr_t *addr) { isc_sockaddr_t sa; + uint_fast64_t serial = atomic_load(&geoip_state_serial); MMDB_lookup_result_s match; int err; - if (db == geoip_state.db && isc_netaddr_equal(addr, &geoip_state.addr)) + if (serial == geoip_state.serial && db == geoip_state.db && + isc_netaddr_equal(addr, &geoip_state.addr)) { return &geoip_state; } @@ -93,7 +98,7 @@ return NULL; } - set_state(db, addr, match, match.entry); + set_state(serial, db, addr, match, match.entry); return &geoip_state; } @@ -214,6 +219,11 @@ return value->uint32 == ui32; } +void +dns_geoip_invalidate(void) { + atomic_fetch_add(&geoip_state_serial, 1); +} + bool dns_geoip_match(const isc_netaddr_t *reqaddr, const dns_geoip_databases_t *geoip, diff -Nru bind9-9.20.26/lib/dns/hmac_link.c bind9-9.20.29/lib/dns/hmac_link.c --- bind9-9.20.26/lib/dns/hmac_link.c 2026-07-20 14:47:54.025849369 +0000 +++ bind9-9.20.29/lib/dns/hmac_link.c 2026-09-11 19:41:01.499330949 +0000 @@ -240,6 +240,8 @@ isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; unsigned char digest[ISC_MAX_MD_SIZE]; unsigned int digestlen = sizeof(digest); + unsigned int sig_expected_length = ISC_MAX_MD_SIZE; + uint16_t digestbits = dst_key_getbits(dctx->key); REQUIRE(ctx != NULL); @@ -251,7 +253,21 @@ return DST_R_OPENSSLFAILURE; } - if (sig->length > digestlen) { + if (digestbits == 0) { + /* + * If digestbits is zero then HMAC truncation is not used, just + * use the key's actual length. + */ + isc_result_t result = dst_key_sigsize(dctx->key, + &sig_expected_length); + if (result != ISC_R_SUCCESS) { + return DST_R_VERIFYFAILURE; + } + } else { + sig_expected_length = (digestbits + 7) / 8; + } + + if (sig->length != sig_expected_length || sig->length > digestlen) { return DST_R_VERIFYFAILURE; } diff -Nru bind9-9.20.26/lib/dns/include/dns/cache.h bind9-9.20.29/lib/dns/include/dns/cache.h --- bind9-9.20.26/lib/dns/include/dns/cache.h 2026-07-20 14:47:54.026849385 +0000 +++ bind9-9.20.29/lib/dns/include/dns/cache.h 2026-09-11 19:41:01.500330973 +0000 @@ -199,12 +199,16 @@ isc_result_t dns_cache_flushnode(dns_cache_t *cache, const dns_name_t *name, bool tree); /* - * Flush a given name from the cache. If 'tree' is true, then - * also flush all names under 'name'. + * Flush the data for node 'name' from the cache. + * + * If 'tree' is true, then also flush all nodes under 'name'. (Note that + * flushing of a tree only works for names below the root. To flush the + * entire tree, use dns_cache_flush().) * * Requires: *\li 'cache' to be valid. *\li 'name' to be valid. + *\li if 'tree' is true, then 'name' is not root. * * Returns: *\li #ISC_R_SUCCESS diff -Nru bind9-9.20.26/lib/dns/include/dns/ede.h bind9-9.20.29/lib/dns/include/dns/ede.h --- bind9-9.20.26/lib/dns/include/dns/ede.h 2026-07-20 14:47:54.029849431 +0000 +++ bind9-9.20.29/lib/dns/include/dns/ede.h 2026-09-11 19:41:01.502331021 +0000 @@ -43,8 +43,9 @@ #define DNS_EDE_NOREACHABLEAUTH 22 /*%< No Reachable Authority */ #define DNS_EDE_NETWORKERROR 23 /*%< Network Error */ #define DNS_EDE_INVALIDDATA 24 /*%< Invalid Data */ +#define DNS_EDE_NTA 33 /*%< Negative Trust Anchor */ -#define DNS_EDE_MAX_CODE DNS_EDE_INVALIDDATA +#define DNS_EDE_MAX_CODE DNS_EDE_NTA /* * From RFC 8914: @@ -63,7 +64,7 @@ int magic; isc_mem_t *mctx; dns_ednsopt_t *ede[DNS_EDE_MAX_ERRORS]; - uint32_t edeused; + uint64_t edeused; size_t nextede; }; /*%< @@ -75,6 +76,13 @@ * the response client message. */ +STATIC_ASSERT(DNS_EDE_MAX_CODE <= + CHAR_BIT * sizeof(((dns_edectx_t *){ NULL })->edeused), + "DNS_EDE_MAX_CODE does not fit in the edeused bitmap"); +/* + * Make sure we can fit the currently supported EDE codes in the edeused bitmap. + */ + void dns_ede_init(isc_mem_t *mctx, dns_edectx_t *edectx); /*%< diff -Nru bind9-9.20.26/lib/dns/include/dns/geoip.h bind9-9.20.29/lib/dns/include/dns/geoip.h --- bind9-9.20.26/lib/dns/include/dns/geoip.h 2026-07-20 14:47:54.029849431 +0000 +++ bind9-9.20.29/lib/dns/include/dns/geoip.h 2026-09-11 19:41:01.502331021 +0000 @@ -106,6 +106,9 @@ const dns_geoip_databases_t *geoip, const dns_geoip_elem_t *elt); +void +dns_geoip_invalidate(void); + ISC_LANG_ENDDECLS #endif /* HAVE_GEOIP2 */ diff -Nru bind9-9.20.26/lib/dns/include/dns/name.h bind9-9.20.29/lib/dns/include/dns/name.h --- bind9-9.20.26/lib/dns/include/dns/name.h 2026-07-20 14:47:54.031849462 +0000 +++ bind9-9.20.29/lib/dns/include/dns/name.h 2026-09-11 19:41:01.504331069 +0000 @@ -857,6 +857,7 @@ #define DNS_NAME_OMITFINALDOT 0x01U #define DNS_NAME_PRINCIPAL 0x02U /* do not escape $ and @ */ +#define DNS_NAME_QUOTED 0x04U /* minimal escaping within double quotes */ isc_result_t dns_name_totext(const dns_name_t *name, unsigned int options, @@ -1287,7 +1288,7 @@ bool dns_name_ishostname(const dns_name_t *name, bool wildcard); /*%< - * Return if 'name' is a valid hostname. RFC 952 / RFC 1123. + * Return true if 'name' is a valid hostname. RFC 952 / RFC 1123. * If 'wildcard' is true then allow the first label of name to * be a wildcard. * The root is also accepted. @@ -1299,7 +1300,7 @@ bool dns_name_ismailbox(const dns_name_t *name); /*%< - * Return if 'name' is a valid mailbox. RFC 821. + * Return true if 'name' is a valid mailbox. RFC 821. * * Requires: * \li 'name' to be valid. @@ -1308,7 +1309,7 @@ bool dns_name_internalwildcard(const dns_name_t *name); /*%< - * Return if 'name' contains a internal wildcard name. + * Return true if 'name' contains a internal wildcard name. * * Requires: * \li 'name' to be valid. diff -Nru bind9-9.20.26/lib/dns/include/dns/rdatalist.h bind9-9.20.29/lib/dns/include/dns/rdatalist.h --- bind9-9.20.26/lib/dns/include/dns/rdatalist.h 2026-07-20 14:47:54.032849478 +0000 +++ bind9-9.20.29/lib/dns/include/dns/rdatalist.h 2026-09-11 19:41:01.506331117 +0000 @@ -131,21 +131,14 @@ dns_rdatalist_count(dns_rdataset_t *rdataset); isc_result_t -dns_rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name); +dns_rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name, + dns_rdatatype_t type); isc_result_t dns_rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG); -isc_result_t -dns_rdatalist_addclosest(dns_rdataset_t *rdataset, const dns_name_t *name); - -isc_result_t -dns_rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *neg, - dns_rdataset_t *negsig DNS__DB_FLARG); - void dns_rdatalist_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name); diff -Nru bind9-9.20.26/lib/dns/include/dns/rdataset.h bind9-9.20.29/lib/dns/include/dns/rdataset.h --- bind9-9.20.26/lib/dns/include/dns/rdataset.h 2026-07-20 14:47:54.033849494 +0000 +++ bind9-9.20.29/lib/dns/include/dns/rdataset.h 2026-09-11 19:41:01.506331117 +0000 @@ -85,15 +85,11 @@ dns_rdataset_t *target DNS__DB_FLARG); unsigned int (*count)(dns_rdataset_t *rdataset); isc_result_t (*addnoqname)(dns_rdataset_t *rdataset, - const dns_name_t *name); + const dns_name_t *name, + dns_rdatatype_t type); isc_result_t (*getnoqname)(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG); - isc_result_t (*addclosest)(dns_rdataset_t *rdataset, - const dns_name_t *name); - isc_result_t (*getclosest)(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *neg, - dns_rdataset_t *negsig DNS__DB_FLARG); void (*settrust)(dns_rdataset_t *rdataset, dns_trust_t trust); void (*expire)(dns_rdataset_t *rdataset DNS__DB_FLARG); void (*clearprefetch)(dns_rdataset_t *rdataset); @@ -185,8 +181,8 @@ * an rbtdb database, 'raw' will generally point to the * memory immediately following a slabheader. (There * is an exception in the case of rdatasets returned by - * the `getnoqname` and `getclosest` methods; see - * comments in rbtdb.c for details.) + * the `getnoqname` method; see comments in rbtdb.c + * for details.) */ struct { struct dns_db *db; @@ -194,10 +190,25 @@ unsigned char *raw; unsigned char *iter_pos; unsigned int iter_count; - dns_slabheader_proof_t *noqname, *closest; + dns_slabheader_proof_t *noqname; } slab; /* + * A proof rdataset is a view into a slabheader's noqname or + * closest-encloser proof. The header reference keeps the + * proof memory alive for as long as the view is associated. + * Keep the fields shared with 'slab' at the same offsets. + */ + struct { + struct dns_db *db; + dns_dbnode_t *node; + unsigned char *raw; + unsigned char *iter_pos; + unsigned int iter_count; + dns_slabheader_t *header; + } proof; + + /* * A simple rdatalist, plus an optional dbnode used by * builtin and sdlz. */ @@ -206,10 +217,12 @@ struct dns_rdata *iter; /* - * These refer to names passed in by the caller of - * dns_rdataset_addnoqname() and _addclosest() + * Refers to the name passed in by the caller of + * dns_rdataset_addnoqname(), and the denial type + * (NSEC or NSEC3) of the proof selected there. */ - const struct dns_name *noqname, *closest; + const struct dns_name *noqname; + dns_rdatatype_t noqnametype; dns_dbnode_t *node; } rdlist; @@ -266,7 +279,7 @@ #define DNS_RDATASETATTR_REQUIREDGLUE DNS_RDATASETATTR_REQUIRED #define DNS_RDATASETATTR_LOADORDER 0x00020000 #define DNS_RDATASETATTR_RESIGN 0x00040000 -#define DNS_RDATASETATTR_CLOSEST 0x00080000 +/* #define DNS_RDATASETATTR_CLOSEST 0x00080000 - Obsolete */ #define DNS_RDATASETATTR_OPTOUT 0x00100000 /*%< OPTOUT proof */ #define DNS_RDATASETATTR_NEGATIVE 0x00200000 #define DNS_RDATASETATTR_PREFETCH 0x00400000 @@ -583,45 +596,26 @@ */ isc_result_t -dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name); +dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdatatype_t type); /*%< - * Associate a noqname proof with this record. + * Associate a noqname proof with this record: the rdataset of 'type' + * (NSEC or NSEC3) at 'name' together with the RRSIG rdataset covering it. * Sets #DNS_RDATASETATTR_NOQNAME if successful. * Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and * the 'nsec'/'nsec3' and 'rrsig(nsec)'/'rrsig(nsec3)' ttl. * * Requires: - *\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set. - *\li 'name' to be valid and have NSEC or NSEC3 and associated RRSIG - * rdatasets. - */ - -#define dns_rdataset_getclosest(rdataset, name, nsec, nsecsig) \ - dns__rdataset_getclosest(rdataset, name, nsec, nsecsig DNS__DB_FILELINE) -isc_result_t -dns__rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *nsec, - dns_rdataset_t *nsecsig DNS__DB_FLARG); -/*%< - * Return the closest encloser for this record. - * - * Requires: - *\li 'rdataset' to be valid and #DNS_RDATASETATTR_CLOSEST to be set. + *\li 'rdataset' to be valid. *\li 'name' to be valid. - *\li 'nsec' and 'nsecsig' to be valid and not associated. - */ - -isc_result_t -dns_rdataset_addclosest(dns_rdataset_t *rdataset, const dns_name_t *name); -/*%< - * Associate a closest encloset proof with this record. - * Sets #DNS_RDATASETATTR_CLOSEST if successful. - * Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and - * the 'nsec' and 'rrsig(nsec)' ttl. + *\li 'type' to be dns_rdatatype_nsec or dns_rdatatype_nsec3. * - * Requires: - *\li 'rdataset' to be valid and #DNS_RDATASETATTR_CLOSEST to be set. - *\li 'name' to be valid and have NSEC3 and RRSIG(NSEC3) rdatasets. + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTFOUND if 'name' has no rdataset of 'type' or no RRSIG + * rdataset covering it. + *\li #ISC_R_NOTIMPLEMENTED if the rdataset implementation does not + * support noqname proofs. */ void diff -Nru bind9-9.20.26/lib/dns/include/dns/rdataslab.h bind9-9.20.29/lib/dns/include/dns/rdataslab.h --- bind9-9.20.26/lib/dns/include/dns/rdataslab.h 2026-07-20 14:47:54.033849494 +0000 +++ bind9-9.20.29/lib/dns/include/dns/rdataslab.h 2026-09-11 19:41:01.506331117 +0000 @@ -99,7 +99,6 @@ isc_refcount_t references; dns_slabheader_proof_t *noqname; - dns_slabheader_proof_t *closest; /*%< * We don't use the LIST macros, because the LIST structure has * both head and tail pointers, and is doubly linked. diff -Nru bind9-9.20.26/lib/dns/include/dns/rpz.h bind9-9.20.29/lib/dns/include/dns/rpz.h --- bind9-9.20.26/lib/dns/include/dns/rpz.h 2026-07-20 14:47:54.034849509 +0000 +++ bind9-9.20.29/lib/dns/include/dns/rpz.h 2026-09-11 19:41:01.507331141 +0000 @@ -135,6 +135,9 @@ unsigned int magic; isc_loop_t *loop; + /* Protect this zone's database, timer, and update state. */ + isc_mutex_t update_lock; + dns_rpz_num_t num; /* ordinal in list of policy zones */ dns_name_t origin; /* Policy zone name */ dns_name_t client_ip; /* DNS_RPZ_CLIENT_IP_ZONE.origin. */ @@ -159,14 +162,10 @@ bool dbregistered; /* db callback notify is registered. */ bool updatepending; /* there is an update pending */ bool updaterunning; /* there is an update running */ - isc_result_t updateresult; /* result from the offloaded work */ dns_db_t *db; /* zones database */ dns_dbversion_t *dbversion; /* version we will be updating to */ - dns_db_t *updb; /* zones database we're working on */ - dns_dbversion_t *updbversion; /* version we're currently working - * on */ - bool addsoa; /* add soa to the additional section */ - isc_timer_t *updatetimer; + bool addsoa; /* add soa to the additional section */ + isc_timer_t *updatetimer; }; /* @@ -263,17 +262,15 @@ */ dns_rpz_triggers_t total_triggers; - /* - * One lock for short term read-only search that guarantees the - * consistency of the pointers. - * A second lock for maintenance that guarantees no other thread - * is adding or deleting nodes. - */ + /* Protect query readers against changes to the CIDR tree. */ isc_rwlock_t search_lock; - isc_mutex_t maint_lock; + + /* Serialize summary QP and CIDR updates and their derived state. */ + isc_mutex_t data_lock; bool first_time; - bool shuttingdown; + /* Publish shutdown without waiting for an update or data lock. */ + atomic_bool shuttingdown; dns_rpz_cidr_node_t *cidr; dns_qpmulti_t *table; diff -Nru bind9-9.20.26/lib/dns/include/dns/stats.h bind9-9.20.29/lib/dns/include/dns/stats.h --- bind9-9.20.26/lib/dns/include/dns/stats.h 2026-07-20 14:47:54.034849509 +0000 +++ bind9-9.20.29/lib/dns/include/dns/stats.h 2026-09-11 19:41:01.508331165 +0000 @@ -320,7 +320,7 @@ void dns_dnssecsignstats_create(isc_mem_t *mctx, dns_stats_t **statsp); /*%< - * Create a statistics counter structure per assigned DNSKEY id. + * Create a statistics counter structure per DNSKEY algorithm and key tag. * * Requires: *\li 'mctx' must be a valid memory context. @@ -418,6 +418,7 @@ * * Requires: *\li 'stats' is a valid dns_stats_t created by dns_dnssecsignstats_create(). + *\li Calls that increment or clear 'stats' are serialized by the caller. */ void @@ -427,6 +428,7 @@ * * Requires: *\li 'stats' is a valid dns_stats_t created by dns_dnssecsignstats_create(). + *\li Calls that increment or clear 'stats' are serialized by the caller. */ void @@ -478,14 +480,15 @@ dns_dnssecsignstats_dumper_t dump_fn, void *arg, unsigned int options); /*%< - * Dump the current statistics counters in a specified way. For each counter - * in stats, dump_fn is called with the corresponding type in the form of - * dns_rdatastatstype_t, the current counter value and the given argument - * arg. By default counters that have a value of 0 is skipped; if options has - * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * Dump the current statistics counters for 'operation'. For each DNSKEY, + * dump_fn is called with the algorithm in the upper 16 bits of the key and the + * key tag in the lower 16 bits, the current counter value, and 'arg'. By + * default counters with a value of 0 are skipped; if options has the + * ISC_STATSDUMP_VERBOSE flag, zero-valued counters are dumped too. * * Requires: - *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + *\li 'stats' is a valid dns_stats_t created by + * dns_dnssecsignstats_create(). */ void diff -Nru bind9-9.20.26/lib/dns/include/dns/validator.h bind9-9.20.29/lib/dns/include/dns/validator.h --- bind9-9.20.26/lib/dns/include/dns/validator.h 2026-07-20 14:47:54.035849525 +0000 +++ bind9-9.20.29/lib/dns/include/dns/validator.h 2026-09-11 19:41:01.509331189 +0000 @@ -115,6 +115,10 @@ */ dns_name_t *proofs[4]; /* + * The denial type (NSEC or NSEC3) of the NOQNAME proof. + */ + dns_rdatatype_t noqnametype; + /* * Optout proof seen. */ bool optout; @@ -127,7 +131,7 @@ atomic_bool canceling; unsigned int attributes; isc_work_t *offloaded_work; - isc_job_cb offloaded_cb; + isc_work_cb offloaded_cb; dns_fetch_t *fetch; dns_validator_t *subvalidator; dns_validator_t *parent; @@ -144,20 +148,21 @@ dns_fixedname_t fname; dns_fixedname_t wild; dns_fixedname_t wildsigner; + dns_fixedname_t nseczone; dns_fixedname_t closest; ISC_LINK(dns_validator_t) link; - bool mustbesecure; - unsigned int depth; - unsigned int authcount; - unsigned int authfail; - isc_stdtime_t start; - + bool mustbesecure; + unsigned int depth; + unsigned int authcount; + unsigned int authfail; + isc_stdtime_t start; + bool resume; bool digest_sha1; uint8_t unsupported_algorithm; uint8_t unsupported_digest; - uint8_t validation_attempts; + uint16_t matchds_attempts; + uint16_t validation_attempts; dns_rdata_t rdata; - bool resume; isc_counter_t *nvalidations; isc_counter_t *nfails; isc_counter_t *qc; diff -Nru bind9-9.20.26/lib/dns/include/dns/view.h bind9-9.20.29/lib/dns/include/dns/view.h --- bind9-9.20.26/lib/dns/include/dns/view.h 2026-07-20 14:47:54.036849540 +0000 +++ bind9-9.20.29/lib/dns/include/dns/view.h 2026-09-11 19:41:01.509331189 +0000 @@ -869,10 +869,9 @@ dns_view_flushcache(dns_view_t *view, bool fixuponly); /*%< * Flush the view's cache (and ADB). If 'fixuponly' is true, it only updates - * the internal reference to the cache DB with omitting actual flush operation. + * the internal reference to the cache DB, omitting actual flush operation. * 'fixuponly' is intended to be used for a view that shares a cache with - * a different view. dns_view_flushcache() is a backward compatible version - * that always sets fixuponly to false. + * a different view. * * Requires: * 'view' is valid. diff -Nru bind9-9.20.26/lib/dns/kasp.c bind9-9.20.29/lib/dns/kasp.c --- bind9-9.20.26/lib/dns/kasp.c 2026-07-20 14:47:54.037849556 +0000 +++ bind9-9.20.29/lib/dns/kasp.c 2026-09-11 19:41:01.511331237 +0000 @@ -533,7 +533,7 @@ uint16_t dns_kasp_key_tagmax(dns_kasp_key_t *key) { REQUIRE(key != NULL); - return key->tag_min; + return key->tag_max; } bool diff -Nru bind9-9.20.26/lib/dns/master.c bind9-9.20.29/lib/dns/master.c --- bind9-9.20.26/lib/dns/master.c 2026-07-20 14:47:54.039849587 +0000 +++ bind9-9.20.29/lib/dns/master.c 2026-09-11 19:41:01.512331261 +0000 @@ -244,7 +244,9 @@ } else \ goto log_and_cleanup; \ } \ - if ((token)->type == isc_tokentype_special) { \ + if ((token)->type == isc_tokentype_special || \ + (token)->type == isc_tokentype_unknown) \ + { \ result = DNS_R_SYNTAX; \ if (MANYERRS(lctx, result)) { \ SETRESULT(lctx, result); \ @@ -548,7 +550,6 @@ * in lib/dns/tests/dnstest.c. */ memset(specials, 0, sizeof(specials)); - specials[0] = 1; specials['('] = 1; specials[')'] = 1; specials['"'] = 1; @@ -2666,37 +2667,40 @@ } /* - * The combination of isc_work_enqueue() on the current loop and callback on - * lctx->loop ensures the correct ordering: + * The load runs on the SLOW work lane of lctx->loop: * - * 1. dns_master_loadfileasync() calls isc_work_enqueue() on the current loop. - * 2. master_load() runs asynchronously and can finish before the entry point - * returns; master_load_done() is queued on the current loop and cannot run - * until the entry point returns. - * 3. The entry point publishes *lctxp. - * 4. master_load_done() runs on the current loop and hands off to lctx->loop. - * 5. lctx->done() runs on lctx->loop asynchronously. + * 1. dns_master_loadfileasync() publishes *lctxp, then starts + * master_load_start() on lctx->loop with isc_async_run(). Publishing + * first ensures lctx->done() cannot observe *lctxp unset even when the + * caller runs on a different loop. + * 2. master_load_start() enqueues the work; isc_work_enqueue() must be + * called on the loop the work is bound to, hence the extra hop. + * 3. master_load() runs on the worker thread and its result is handed to + * master_load_done() on lctx->loop. + * 4. master_load_done() calls lctx->done() and drops the loop and lctx + * references. */ -static void +static isc_result_t master_load(void *arg) { dns_loadctx_t *lctx = arg; - lctx->result = (lctx->load)(lctx); + return (lctx->load)(lctx); } static void -master_load_callback(void *arg) { +master_load_done(void *arg, isc_result_t result) { dns_loadctx_t *lctx = arg; - (lctx->done)(lctx->done_arg, lctx->result); + (lctx->done)(lctx->done_arg, result); isc_loop_detach(&lctx->loop); dns_loadctx_detach(&lctx); } static void -master_load_done(void *arg, isc_result_t result ISC_ATTR_UNUSED) { +master_load_start(void *arg) { dns_loadctx_t *lctx = arg; - isc_async_run(lctx->loop, master_load_callback, lctx); + isc_work_enqueue(lctx->loop, ISC_WORKLANE_SLOW, master_load, + master_load_done, lctx); } isc_result_t @@ -2729,11 +2733,12 @@ dns_loadctx_ref(lctx); isc_loop_attach(loop, &lctx->loop); - isc_work_enqueue(isc_loop(), ISC_WORKLANE_SLOW, master_load, - master_load_done, lctx); + /* Publish *lctxp before the load can start (see master_load). */ *lctxp = lctx; + isc_async_run(loop, master_load_start, lctx); + return ISC_R_SUCCESS; } diff -Nru bind9-9.20.26/lib/dns/masterdump.c bind9-9.20.29/lib/dns/masterdump.c --- bind9-9.20.26/lib/dns/masterdump.c 2026-07-20 14:47:54.039849587 +0000 +++ bind9-9.20.29/lib/dns/masterdump.c 2026-09-11 19:41:01.512331261 +0000 @@ -249,7 +249,6 @@ dns_dumpdonefunc_t done; void *done_arg; /* dns_master_dumpasync() */ - isc_result_t result; char *file; char *tmpfile; dns_masterformat_t format; @@ -1488,19 +1487,20 @@ } /* - * The combination of isc_work_enqueue() on the current loop and callback on - * dctx->loop ensures the correct ordering: + * The dump runs on the SLOW work lane of dctx->loop: * - * 1. dns_master_dumptostreamasync() (or dns_master_dumpasync()) calls - * isc_work_enqueue() on the current loop. - * 2. master_dump() runs asynchronously and can finish before the entry point - * returns; master_dump_done() is queued on the current loop and cannot run - * until the entry point returns. - * 3. The entry point publishes *dctxp. - * 4. master_dump_done() runs on the current loop and hands off to dctx->loop. - * 5. dctx->done() runs on dctx->loop asynchronously. + * 1. dns_master_dumptostreamasync() (or dns_master_dumpasync()) publishes + * *dctxp, then starts master_dump_start() on dctx->loop with + * isc_async_run(). Publishing first ensures dctx->done() cannot observe + * *dctxp unset even when the caller runs on a different loop. + * 2. master_dump_start() enqueues the work; isc_work_enqueue() must be + * called on the loop the work is bound to, hence the extra hop. + * 3. master_dump() runs on the worker thread and its result is handed to + * master_dump_done() on dctx->loop. + * 4. master_dump_done() calls dctx->done() and drops the loop and dctx + * references. */ -static void +static isc_result_t master_dump(void *data) { isc_result_t result = ISC_R_UNSET; dns_dumpctx_t *dctx = data; @@ -1523,23 +1523,24 @@ result = flushandsync(dctx->f, result, NULL); } - dctx->result = result; + return result; } static void -master_dump_callback(void *data) { +master_dump_done(void *data, isc_result_t result) { dns_dumpctx_t *dctx = data; - (dctx->done)(dctx->done_arg, dctx->result); + (dctx->done)(dctx->done_arg, result); isc_loop_detach(&dctx->loop); dns_dumpctx_detach(&dctx); } static void -master_dump_done(void *data, isc_result_t result ISC_ATTR_UNUSED) { +master_dump_start(void *data) { dns_dumpctx_t *dctx = data; - isc_async_run(dctx->loop, master_dump_callback, dctx); + isc_work_enqueue(dctx->loop, ISC_WORKLANE_SLOW, master_dump, + master_dump_done, dctx); } static isc_result_t @@ -1795,11 +1796,12 @@ dns_dumpctx_ref(dctx); isc_loop_attach(loop, &dctx->loop); - isc_work_enqueue(isc_loop(), ISC_WORKLANE_SLOW, master_dump, - master_dump_done, dctx); + /* Publish *dctxp before the dump can start (see master_dump). */ *dctxp = dctx; + isc_async_run(loop, master_dump_start, dctx); + return ISC_R_SUCCESS; } @@ -1894,11 +1896,12 @@ dns_dumpctx_ref(dctx); isc_loop_attach(loop, &dctx->loop); - isc_work_enqueue(isc_loop(), ISC_WORKLANE_SLOW, master_dump, - master_dump_done, dctx); + /* Publish *dctxp before the dump can start (see master_dump). */ *dctxp = dctx; + isc_async_run(loop, master_dump_start, dctx); + return ISC_R_SUCCESS; cleanup_tempname: diff -Nru bind9-9.20.26/lib/dns/message.c bind9-9.20.29/lib/dns/message.c --- bind9-9.20.26/lib/dns/message.c 2026-07-20 14:47:54.039849587 +0000 +++ bind9-9.20.29/lib/dns/message.c 2026-09-11 19:41:01.513331285 +0000 @@ -200,7 +200,6 @@ dns_view_t *view; dns_message_cb_t cb; void *cbarg; - isc_result_t result; } checksig_ctx_t; /* @@ -1598,6 +1597,10 @@ if (dns_rdata_compare(rdata, first) != 0) { DO_ERROR(DNS_R_FORMERR); } + if (!best_effort) { + dns_rdata_reset(rdata); + dns_message_puttemprdata(msg, &rdata); + } break; case ISC_R_SUCCESS: ISC_LIST_APPEND(name->list, rdataset, link); @@ -1623,8 +1626,10 @@ } /* Append this rdata to the rdataset. */ - dns_rdatalist_fromrdataset(rdataset, &rdatalist); - ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + if (rdata != NULL) { + dns_rdatalist_fromrdataset(rdataset, &rdatalist); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + } /* * If this is an OPT, SIG(0) or TSIG record, remember it. @@ -3182,20 +3187,19 @@ static void checksig_done(void *arg, isc_result_t result); -static void +static isc_result_t checksig_run(void *arg) { checksig_ctx_t *chsigctx = arg; - chsigctx->result = dns_message_checksig(chsigctx->msg, chsigctx->view); + return dns_message_checksig(chsigctx->msg, chsigctx->view); } static void -checksig_done(void *arg, isc_result_t result ISC_ATTR_UNUSED) { +checksig_done(void *arg, isc_result_t result) { checksig_ctx_t *chsigctx = arg; dns_message_t *msg = chsigctx->msg; - chsigctx->cb(chsigctx->cbarg, - (result != ISC_R_SUCCESS) ? result : chsigctx->result); + chsigctx->cb(chsigctx->cbarg, result); dns_view_detach(&chsigctx->view); isc_loop_detach(&chsigctx->loop); @@ -3215,7 +3219,6 @@ *chsigctx = (checksig_ctx_t){ .cb = cb, .cbarg = cbarg, - .result = ISC_R_UNSET, .loop = isc_loop_ref(loop), }; dns_message_attach(msg, &chsigctx->msg); diff -Nru bind9-9.20.26/lib/dns/name.c bind9-9.20.29/lib/dns/name.c --- bind9-9.20.26/lib/dns/name.c 2026-07-20 14:47:54.040849603 +0000 +++ bind9-9.20.29/lib/dns/name.c 2026-09-11 19:41:01.513331285 +0000 @@ -1033,6 +1033,8 @@ bool saw_root = false; unsigned int oused; bool omit_final_dot = ((options & DNS_NAME_OMITFINALDOT) != 0); + bool minimal = ((options & DNS_NAME_QUOTED) != 0); + bool principal = ((options & DNS_NAME_PRINCIPAL) != 0); /* * This function assumes the name is in proper uncompressed @@ -1110,16 +1112,19 @@ /* Special modifiers in zone files. */ case 0x40: /* '@' */ case 0x24: /* '$' */ - if ((options & DNS_NAME_PRINCIPAL) != 0) - { + if (principal) { goto no_escape; } FALLTHROUGH; - case 0x22: /* '"' */ case 0x28: /* '(' */ case 0x29: /* ')' */ - case 0x2E: /* '.' */ case 0x3B: /* ';' */ + if (minimal) { + goto no_escape; + } + FALLTHROUGH; + case 0x22: /* '"' */ + case 0x2E: /* '.' */ case 0x5C: /* '\\' */ if (trem < 2) { return ISC_R_NOSPACE; @@ -1132,7 +1137,9 @@ break; no_escape: default: - if (c > 0x20 && c < 0x7f) { + if ((c > 0x20 && c < 0x7f) || + (c == 0x20 && minimal)) + { if (trem == 0) { return ISC_R_NOSPACE; } diff -Nru bind9-9.20.26/lib/dns/ncache.c bind9-9.20.29/lib/dns/ncache.c --- bind9-9.20.26/lib/dns/ncache.c 2026-07-20 14:47:54.040849603 +0000 +++ bind9-9.20.29/lib/dns/ncache.c 2026-09-11 19:41:01.513331285 +0000 @@ -71,14 +71,30 @@ return ISC_R_NOSPACE; } count = dns_rdataset_count(rdataset); + + /* + * Reject duplicate singleton records. + */ + if (dns_rdatatype_issingleton(rdataset->type) && count != 1) { + return DNS_R_TOOMANYRECORDS; + } + INSIST(count <= 65535); isc_buffer_putuint16(buffer, (uint16_t)count); + if (ar.length < 2 + count * 2) { + /* + * The count took 2 bytes and each rdata needs at least 2 + * more for its length. Bail early if that cannot fit. + */ + return ISC_R_NOSPACE; + } + result = dns_rdataset_first(rdataset); while (result == ISC_R_SUCCESS) { dns_rdataset_current(rdataset, &rdata); dns_rdata_toregion(&rdata, &r); - INSIST(r.length <= 65535); + INSIST(r.length <= DNS_RDATA_MAXLENGTH); isc_buffer_availableregion(buffer, &ar); if (ar.length < 2) { return ISC_R_NOSPACE; @@ -87,6 +103,7 @@ * Copy the rdata length to the buffer. */ isc_buffer_putuint16(buffer, (uint16_t)r.length); + /* * Copy the rdata to the buffer. */ @@ -137,8 +154,9 @@ dns_rdata_t rdata[DNS_NCACHE_RDATA]; dns_rdataset_t ncrdataset; dns_rdatalist_t ncrdatalist; - unsigned char data[65536]; + unsigned char data[UINT16_MAX]; unsigned int next = 0; + bool seen_soa = false; /* * Convert the authority data from 'message' into a negative cache @@ -185,6 +203,20 @@ continue; } type = rdataset->type; + + /* + * A negative response carries one SOA + * RRset. The resolver rejects a second + * one before it gets here; don't rely on + * that. + */ + if (type == dns_rdatatype_soa) { + if (seen_soa) { + return DNS_R_TOOMANYRECORDS; + } + seen_soa = true; + } + if (type == dns_rdatatype_rrsig) { type = rdataset->covers; } @@ -232,10 +264,20 @@ } if (next >= DNS_NCACHE_RDATA) { - return ISC_R_NOSPACE; + return DNS_R_TOOMANYRECORDS; } dns_rdata_init(&rdata[next]); isc_buffer_remainingregion(&buffer, &r); + /* + * dns_rdata_t.length is 16 bits wide, + * so a longer record would be silently + * truncated here and would then pass + * the size checks in + * dns_rdataslab_fromrdataset(). + */ + if (r.length > DNS_RDATA_MAXLENGTH) { + return ISC_R_NOSPACE; + } rdata[next].data = r.base; rdata[next].length = r.length; rdata[next].rdclass = diff -Nru bind9-9.20.26/lib/dns/opensslecdsa_link.c bind9-9.20.29/lib/dns/opensslecdsa_link.c --- bind9-9.20.26/lib/dns/opensslecdsa_link.c 2026-07-20 14:47:54.041849618 +0000 +++ bind9-9.20.29/lib/dns/opensslecdsa_link.c 2026-09-11 19:41:01.515331333 +0000 @@ -1042,6 +1042,9 @@ engine = (char *)priv.elements[i].data; break; case TAG_ECDSA_LABEL: + /* NUL terminated data? */ + CHECK(dst__privelement_is_nul_terminated( + &priv.elements[i])); label = (char *)priv.elements[i].data; break; case TAG_ECDSA_PRIVATEKEY: diff -Nru bind9-9.20.26/lib/dns/openssleddsa_link.c bind9-9.20.29/lib/dns/openssleddsa_link.c --- bind9-9.20.26/lib/dns/openssleddsa_link.c 2026-07-20 14:47:54.041849618 +0000 +++ bind9-9.20.29/lib/dns/openssleddsa_link.c 2026-09-11 19:41:01.515331333 +0000 @@ -87,13 +87,13 @@ static isc_result_t raw_key_to_ossl(const eddsa_alginfo_t *alginfo, int private, - const unsigned char *key, size_t *key_len, EVP_PKEY **pkey) { + const unsigned char *key, size_t key_len, EVP_PKEY **pkey) { isc_result_t result; int pkey_type = alginfo->pkey_type; size_t len = alginfo->key_size; result = (private ? DST_R_INVALIDPRIVATEKEY : DST_R_INVALIDPUBLICKEY); - if (*key_len < len) { + if (key_len != len) { return result; } @@ -106,7 +106,6 @@ return dst__openssl_toresult(result); } - *key_len = len; return ISC_R_SUCCESS; } @@ -339,7 +338,6 @@ const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); isc_result_t ret; isc_region_t r; - size_t len; EVP_PKEY *pkey = NULL; REQUIRE(alginfo != NULL); @@ -349,15 +347,14 @@ return ISC_R_SUCCESS; } - len = r.length; - ret = raw_key_to_ossl(alginfo, 0, r.base, &len, &pkey); + ret = raw_key_to_ossl(alginfo, 0, r.base, r.length, &pkey); if (ret != ISC_R_SUCCESS) { return ret; } - isc_buffer_forward(data, len); + isc_buffer_forward(data, alginfo->key_size); key->keydata.pkeypair.pub = pkey; - key->key_size = len * 8; + key->key_size = alginfo->key_size * 8; return ISC_R_SUCCESS; } @@ -429,7 +426,6 @@ int i, privkey_index = -1; const char *engine = NULL, *label = NULL; EVP_PKEY *pkey = NULL; - size_t len; isc_mem_t *mctx = key->mctx; REQUIRE(alginfo != NULL); @@ -457,6 +453,9 @@ engine = (char *)priv.elements[i].data; break; case TAG_EDDSA_LABEL: + /* NUL terminated data? */ + CHECK(dst__privelement_is_nul_terminated( + &priv.elements[i])); label = (char *)priv.elements[i].data; break; case TAG_EDDSA_PRIVATEKEY: @@ -482,9 +481,8 @@ DST_RET(DST_R_INVALIDPRIVATEKEY); } - len = priv.elements[privkey_index].length; CHECK(raw_key_to_ossl(alginfo, 1, priv.elements[privkey_index].data, - &len, &pkey)); + priv.elements[privkey_index].length, &pkey)); /* Check that the public component matches if given */ if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) { DST_RET(DST_R_INVALIDPRIVATEKEY); @@ -492,7 +490,7 @@ key->keydata.pkeypair.priv = pkey; key->keydata.pkeypair.pub = pkey; - key->key_size = len * 8; + key->key_size = alginfo->key_size * 8; pkey = NULL; result = ISC_R_SUCCESS; @@ -625,7 +623,7 @@ } INSIST(alginfo != NULL); - CHECK(raw_key_to_ossl(alginfo, 0, key, &key_len, &pkey)); + CHECK(raw_key_to_ossl(alginfo, 0, key, key_len, &pkey)); /* * Check that we can verify the signature. diff -Nru bind9-9.20.26/lib/dns/opensslrsa_link.c bind9-9.20.29/lib/dns/opensslrsa_link.c --- bind9-9.20.26/lib/dns/opensslrsa_link.c 2026-07-20 14:47:54.041849618 +0000 +++ bind9-9.20.29/lib/dns/opensslrsa_link.c 2026-09-11 19:41:01.515331333 +0000 @@ -48,8 +48,11 @@ const BIGNUM *e, *n, *d, *p, *q, *dmp1, *dmq1, *iqmp; } rsa_components_t; -#define OPENSSLRSA_MAX_MODULUS_BITS 4096 -#define OPENSSLRSA_MIN_MODULUS_BITS 512 +static const int rsa_max_modulus_bits = 4096; +static const int rsa_min_modulus_bits = 512; +static const unsigned int rsa_max_modulus_bytes = (rsa_max_modulus_bits + 7) / + 8; +static const unsigned int rsa_max_exponent_bytes = 5; /* 2^32 + 1 */ static BIGNUM *rsa_exponent_min = NULL; static BIGNUM *rsa_exponent_max = NULL; @@ -393,8 +396,8 @@ evp_md_ctx = dctx->ctxdata.evp_md_ctx; pkey = key->keydata.pkeypair.pub; - if (!opensslrsa_check_modulus_bits(pkey, OPENSSLRSA_MIN_MODULUS_BITS, - OPENSSLRSA_MAX_MODULUS_BITS) || + if (!opensslrsa_check_modulus_bits(pkey, rsa_min_modulus_bits, + rsa_max_modulus_bits) || !opensslrsa_rsa_exponent_is_allowed(pkey)) { return DST_R_VERIFYFAILURE; @@ -888,14 +891,19 @@ if (r.length < e_bytes) { DST_RET(DST_R_INVALIDPUBLICKEY); } + if (e_bytes > rsa_max_exponent_bytes || + r.length - e_bytes > rsa_max_modulus_bytes) + { + CLEANUP(ISC_R_RANGE); + } c.e = BN_bin2bn(r.base, e_bytes, NULL); isc_region_consume(&r, e_bytes); c.n = BN_bin2bn(r.base, r.length, NULL); if (c.e == NULL || c.n == NULL) { DST_RET(ISC_R_NOMEMORY); } - if (BN_num_bits(c.n) < OPENSSLRSA_MIN_MODULUS_BITS || - BN_num_bits(c.n) > OPENSSLRSA_MAX_MODULUS_BITS) + if (BN_num_bits(c.n) < rsa_min_modulus_bits || + BN_num_bits(c.n) > rsa_max_modulus_bits) { DST_RET(ISC_R_RANGE); } @@ -1071,6 +1079,9 @@ engine = (char *)priv.elements[i].data; break; case TAG_RSA_LABEL: + /* NUL terminated data? */ + CHECK(dst__privelement_is_nul_terminated( + &priv.elements[i])); label = (char *)priv.elements[i].data; break; default: @@ -1144,8 +1155,8 @@ if (c.n == NULL || c.e == NULL) { DST_RET(DST_R_INVALIDPRIVATEKEY); } - if (BN_num_bits(c.n) < OPENSSLRSA_MIN_MODULUS_BITS || - BN_num_bits(c.n) > OPENSSLRSA_MAX_MODULUS_BITS) + if (BN_num_bits(c.n) < rsa_min_modulus_bits || + BN_num_bits(c.n) > rsa_max_modulus_bits) { DST_RET(ISC_R_RANGE); } @@ -1187,8 +1198,8 @@ CHECK(dst__openssl_fromlabel(EVP_PKEY_RSA, engine, label, pin, &pubpkey, &privpkey)); - if (!opensslrsa_check_modulus_bits(pubpkey, OPENSSLRSA_MIN_MODULUS_BITS, - OPENSSLRSA_MAX_MODULUS_BITS)) + if (!opensslrsa_check_modulus_bits(pubpkey, rsa_min_modulus_bits, + rsa_max_modulus_bits)) { DST_RET(ISC_R_RANGE); } diff -Nru bind9-9.20.26/lib/dns/qp.c bind9-9.20.29/lib/dns/qp.c --- bind9-9.20.26/lib/dns/qp.c 2026-07-20 14:47:54.042849634 +0000 +++ bind9-9.20.29/lib/dns/qp.c 2026-09-11 19:41:01.516331356 +0000 @@ -88,8 +88,8 @@ DNS_LOGMODULE_QP, ISC_LOG_DEBUG(7), \ "%s:%d:%s(qp %p uctx \"%s\"):t%u: " fmt, \ __FILE__, __LINE__, __func__, qp, \ - qp ? TRIENAME(qp) : "(null)", isc_tid(), \ - ##__VA_ARGS__); \ + qp ? TRIENAME(qp) : "(null)", \ + isc_tid(), ##__VA_ARGS__); \ } \ } while (0) #else diff -Nru bind9-9.20.26/lib/dns/qpcache.c bind9-9.20.29/lib/dns/qpcache.c --- bind9-9.20.26/lib/dns/qpcache.c 2026-07-20 14:47:54.043849649 +0000 +++ bind9-9.20.29/lib/dns/qpcache.c 2026-09-11 19:41:01.516331356 +0000 @@ -325,7 +325,6 @@ unsigned int options; dns_qpchain_t chain; dns_qpiter_t iter; - bool need_cleanup; qpcnode_t *zonecut; dns_slabheader_t *zonecut_header; dns_slabheader_t *zonecut_sigheader; @@ -1167,15 +1166,12 @@ if (header->noqname != NULL) { rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; } - rdataset->slab.closest = header->closest; - if (header->closest != NULL) { - rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; - } } static isc_result_t setup_delegation(qpc_search_t *search, dns_dbnode_t **nodep, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + isc_rwlocktype_t nlocktype, isc_rwlocktype_t tlocktype DNS__DB_FLARG) { dns_typepair_t type; qpcnode_t *node = NULL; @@ -1183,6 +1179,7 @@ REQUIRE(search != NULL); REQUIRE(search->zonecut != NULL); REQUIRE(search->zonecut_header != NULL); + REQUIRE(nlocktype == isc_rwlocktype_none); /* * The caller MUST NOT be holding any node locks. @@ -1192,16 +1189,11 @@ type = search->zonecut_header->type; if (nodep != NULL) { - /* - * Note that we don't have to increment the node's reference - * count here because we're going to use the reference we - * already have in the search block. - */ - *nodep = node; - search->need_cleanup = false; + qpcnode_acquire(search->qpdb, node, nlocktype, + tlocktype DNS__DB_FLARG_PASS); + *nodep = (dns_dbnode_t *)node; } if (rdataset != NULL) { - isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = &search->qpdb->buckets[node->locknum].lock; NODE_RDLOCK(nlock, &nlocktype); @@ -1372,15 +1364,19 @@ (search->options & DNS_DBFIND_PENDINGOK) != 0)) { /* - * We increment the reference count on node to ensure that - * search->zonecut_header will still be valid later. + * We increment the reference count on the node to keep it + * alive, and we attach to the DNAME header (and its signature) + * so that they stay valid after the node lock is released. */ qpcnode_acquire(search->qpdb, node, nlocktype, isc_rwlocktype_none DNS__DB_FLARG_PASS); search->zonecut = node; + isc_refcount_increment(&dname_header->references); search->zonecut_header = dname_header; - search->zonecut_sigheader = sigdname_header; - search->need_cleanup = true; + if (sigdname_header != NULL) { + isc_refcount_increment(&sigdname_header->references); + search->zonecut_sigheader = sigdname_header; + } result = DNS_R_PARTIALMATCH; } else { result = DNS_R_CONTINUE; @@ -1621,6 +1617,50 @@ return result; } +static void +qpc_search_init(qpc_search_t *search, qpcache_t *db, unsigned int options, + isc_stdtime_t now) { + /* + * qpc_search_t contains two structures with large buffers (dns_qpiter_t + * and dns_qpchain_t). Those two structures will be initialized later by + * dns_qp_lookup anyway. + * To avoid the overhead of zero initialization, we avoid designated + * initializers and initialize all "small" fields manually. + */ + search->qpdb = (qpcache_t *)db; + search->options = options; + /* + * qpch->in - Init by dns_qp_lookup + * qpiter - Init by dns_qp_lookup + */ + search->now = now ? now : isc_stdtime_now(); + search->zonecut = NULL; + search->zonecut_header = NULL; + search->zonecut_sigheader = NULL; +} + +static void +qpc_search_deinit(qpc_search_t *search DNS__DB_FLARG) { + if (search->zonecut_sigheader != NULL) { + isc_refcount_decrement(&search->zonecut_sigheader->references); + } + if (search->zonecut_header != NULL) { + isc_refcount_decrement(&search->zonecut_header->references); + } + if (search->zonecut != NULL) { + qpcnode_t *node = search->zonecut; + isc_rwlock_t *nlock = + &search->qpdb->buckets[node->locknum].lock; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + + NODE_RDLOCK(nlock, &nlocktype); + qpcnode_release(search->qpdb, node, &nlocktype, &tlocktype, + false DNS__DB_FLARG_PASS); + NODE_UNLOCK(nlock, &nlocktype); + } +} + static isc_result_t find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, @@ -1653,11 +1693,7 @@ now = isc_stdtime_now(); } - search = (qpc_search_t){ - .qpdb = (qpcache_t *)db, - .options = options, - .now = now, - }; + qpc_search_init(&search, (qpcache_t *)db, options, now); TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype); @@ -1720,7 +1756,7 @@ } if (search.zonecut != NULL) { result = setup_delegation(&search, nodep, rdataset, - sigrdataset, + sigrdataset, nlocktype, tlocktype DNS__DB_FLARG_PASS); goto tree_exit; } else { @@ -2046,21 +2082,7 @@ tree_exit: TREE_UNLOCK(&search.qpdb->tree_lock, &tlocktype); - /* - * If we found a zonecut but aren't going to use it, we have to - * let go of it. - */ - if (search.need_cleanup) { - node = search.zonecut; - INSIST(node != NULL); - nlock = &search.qpdb->buckets[node->locknum].lock; - - NODE_RDLOCK(nlock, &nlocktype); - qpcnode_release(search.qpdb, node, &nlocktype, &tlocktype, - true DNS__DB_FLARG_PASS); - NODE_UNLOCK(nlock, &nlocktype); - INSIST(tlocktype == isc_rwlocktype_none); - } + qpc_search_deinit(&search DNS__DB_FLARG_PASS); update_cachestats(search.qpdb, result); return result; @@ -2088,11 +2110,7 @@ now = isc_stdtime_now(); } - search = (qpc_search_t){ - .qpdb = (qpcache_t *)db, - .options = options, - .now = now, - }; + qpc_search_init(&search, (qpcache_t *)db, options, now); if (dcnull) { dcname = foundname; @@ -2224,7 +2242,7 @@ tree_exit: TREE_UNLOCK(&search.qpdb->tree_lock, &tlocktype); - INSIST(!search.need_cleanup); + qpc_search_deinit(&search DNS__DB_FLARG_PASS); if (result == DNS_R_DELEGATION) { result = ISC_R_SUCCESS; @@ -3102,12 +3120,6 @@ header->noqname = newheader->noqname; newheader->noqname = NULL; } - if (header->closest == NULL && - newheader->closest != NULL) - { - header->closest = newheader->closest; - newheader->closest = NULL; - } dns_slabheader_destroy(&newheader); if (addedrdataset != NULL) { bindrdataset(qpdb, qpnode, header, now, @@ -3165,12 +3177,6 @@ header->noqname = newheader->noqname; newheader->noqname = NULL; } - if (header->closest == NULL && - newheader->closest != NULL) - { - header->closest = newheader->closest; - newheader->closest = NULL; - } dns_slabheader_destroy(&newheader); if (addedrdataset != NULL) { bindrdataset(qpdb, qpnode, header, now, @@ -3378,52 +3384,6 @@ return result; } -static isc_result_t -addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset, - dns_rdataset_t *rdataset) { - isc_result_t result; - dns_slabheader_proof_t *closest = NULL; - dns_name_t name = DNS_NAME_INITEMPTY; - dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT; - isc_region_t r1 = { .base = NULL }, r2 = { .base = NULL }; - - result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - - result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - closest = isc_mem_get(mctx, sizeof(*closest)); - *closest = (dns_slabheader_proof_t){ - .neg = r1.base, - .negsig = r2.base, - .name = DNS_NAME_INITEMPTY, - .type = neg.type, - }; - dns_name_dup(&name, mctx, &closest->name); - newheader->closest = closest; - -cleanup: - if (result != ISC_R_SUCCESS) { - if (r1.base != NULL) { - isc_mem_put(mctx, r1.base, r1.length); - } - if (r2.base != NULL) { - isc_mem_put(mctx, r2.base, r2.length); - } - } - dns_rdataset_disassociate(&neg); - dns_rdataset_disassociate(&negsig); - return result; -} - static void expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum, isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep, @@ -3505,14 +3465,6 @@ return result; } } - if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) { - result = addclosest(qpdb->common.mctx, newheader, - qpdb->maxrrperset, rdataset); - if (result != ISC_R_SUCCESS) { - dns_slabheader_destroy(&newheader); - return result; - } - } /* * If we're adding a delegation type (which would be an NS or DNAME @@ -4355,9 +4307,6 @@ if (header->noqname != NULL) { dns_slabheader_freeproof(db->mctx, &header->noqname); } - if (header->closest != NULL) { - dns_slabheader_freeproof(db->mctx, &header->closest); - } } /* diff -Nru bind9-9.20.26/lib/dns/qpzone.c bind9-9.20.29/lib/dns/qpzone.c --- bind9-9.20.26/lib/dns/qpzone.c 2026-07-20 14:47:54.044849665 +0000 +++ bind9-9.20.29/lib/dns/qpzone.c 2026-09-11 19:41:01.517331381 +0000 @@ -273,6 +273,11 @@ uint32_t serial; unsigned int options; dns_qpchain_t chain; + /* + * Index of the origin node in 'chain'. The nodes before it are + * above the zone and must not be looked at. + */ + unsigned int chain_base; dns_qpiter_t iter; bool copy_name; bool need_cleanup; @@ -950,10 +955,6 @@ if (header->noqname != NULL) { rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; } - rdataset->slab.closest = header->closest; - if (header->closest != NULL) { - rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; - } /* * Copy out re-signing information. @@ -2857,7 +2858,9 @@ * can be no possible wildcard match and again we're done. If not, * continue the search. */ - for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) { + for (int i = dns_qpchain_length(&search->chain) - 1; + i >= (int)search->chain_base; i--) + { qpznode_t *node = NULL; isc_rwlock_t *nlock = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; @@ -2965,6 +2968,32 @@ } /* + * The database may contain nodes outside the zone (out-of-zone data + * loaded from a secondary zone file or a journal), so the walks through + * the predecessors of a name must know where the zone ends. + * + * Within a tree the nodes of the zone form a contiguous block that starts + * at the zone origin, so a walk backwards leaves the zone exactly when it + * steps onto a name that is not below the origin. (The NSEC tree has no + * origin node that could be compared by pointer, so all three trees are + * checked by name; the iterator has to copy the name out anyway.) + */ +static isc_result_t +prev_in_zone(qpz_search_t *search, dns_qpiter_t *it, dns_name_t *name, + qpznode_t **nodep) { + isc_result_t result; + + result = dns_qpiter_prev(it, name, (void **)nodep, NULL); + if (result == ISC_R_SUCCESS && + !dns_name_issubdomain(name, &search->qpdb->common.origin)) + { + return ISC_R_NOMORE; + } + + return result; +} + +/* * Find node of the NSEC/NSEC3 record that is 'name'. */ static isc_result_t @@ -2977,8 +3006,7 @@ REQUIRE(type == dns_rdatatype_nsec3 || firstp != NULL); if (type == dns_rdatatype_nsec3) { - result = dns_qpiter_prev(&search->iter, name, (void **)nodep, - NULL); + result = prev_in_zone(search, &search->iter, name, nodep); return result; } @@ -3000,7 +3028,7 @@ * unacceptable NSEC record. * Try the previous node in the NSEC tree. */ - result = dns_qpiter_prev(nit, name, NULL, NULL); + result = prev_in_zone(search, nit, name, NULL); } else if (result == DNS_R_PARTIALMATCH) { /* * The iterator is already where we want it. @@ -3016,7 +3044,7 @@ * must have found nodes in the main tree with NSEC * records. Perhaps they lacked signature records. */ - result = dns_qpiter_prev(nit, name, NULL, NULL); + result = prev_in_zone(search, nit, name, NULL); } if (result != ISC_R_SUCCESS) { break; @@ -3047,6 +3075,23 @@ return result; } +static isc_result_t +wrap_nsec3(qpz_search_t *search, dns_name_t *name, qpznode_t **nodep) { + dns_qpiter_init(&search->qpr, &search->iter); + while (true) { + isc_result_t result = dns_qpiter_prev(&search->iter, name, + (void **)nodep, NULL); + if (result != ISC_R_SUCCESS) { + return result; + } + + if (dns_name_issubdomain(name, &search->qpdb->common.origin)) { + return ISC_R_SUCCESS; + } + } + UNREACHABLE(); +} + /* * Find the NSEC/NSEC3 which is or before the current point on the * search chain. For NSEC3 records only NSEC3 records that match the @@ -3198,13 +3243,15 @@ &first); } NODE_UNLOCK(nlock, &nlocktype); - node = prevnode; - prevnode = NULL; + node = MOVE_OWNERSHIP(prevnode); } while (empty_node && result == ISC_R_SUCCESS); if (result == ISC_R_NOMORE && wraps) { - result = dns_qpiter_prev(&search->iter, name, (void **)&node, - NULL); + /* + * Start over from the last node of the zone in the NSEC3 + * tree, skipping any nodes that sort after it. + */ + result = wrap_nsec3(search, name, &node); if (result == ISC_R_SUCCESS) { wraps = false; goto again; @@ -3349,6 +3396,36 @@ return result; } +/* + * Find the origin node of the tree being searched in the search chain + * and remember its index. + * + * The database may contain nodes above its origin (out-of-zone data + * loaded from a secondary zone file or a journal). They come before the + * origin in the chain and are not part of the zone, so they must not act + * as zone cuts, wildcard parents or closest enclosers for the names + * inside it: the chain is only used from 'chain_base' on. + * + * Returns false if the origin is not in the chain, which means that the + * name being looked up is not in the zone at all. + */ +static bool +qpz_search_setbase(qpz_search_t *search, qpznode_t *origin) { + unsigned int len = dns_qpchain_length(&search->chain); + + for (unsigned int i = 0; i < len; i++) { + qpznode_t *node = NULL; + + dns_qpchain_node(&search->chain, i, NULL, (void **)&node, NULL); + if (node == origin) { + search->chain_base = i; + return true; + } + } + + return false; +} + static isc_result_t find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, dns_rdatatype_t type, unsigned int options, @@ -3405,9 +3482,14 @@ */ result = dns_qp_lookup(&search.qpr, name, NULL, &search.iter, &search.chain, (void **)&node, NULL); - if (result != ISC_R_NOTFOUND) { - dns_name_copy(&node->name, foundname); + if (!qpz_search_setbase(&search, + nsec3 ? qpdb->nsec3_origin : qpdb->origin)) + { + /* The name is not in the zone. */ + result = ISC_R_NOTFOUND; + goto tree_exit; } + dns_name_copy(&node->name, foundname); /* * Check the QP chain to see if there's a node above us with a @@ -3420,7 +3502,9 @@ if (result == ISC_R_SUCCESS) { clen--; } - for (unsigned int i = 0; i < clen && search.zonecut == NULL; i++) { + for (unsigned int i = search.chain_base; + i < clen && search.zonecut == NULL; i++) + { qpznode_t *n = NULL; isc_result_t tresult; @@ -3428,7 +3512,6 @@ tresult = check_zonecut(n, &search DNS__DB_FLARG_PASS); if (tresult != DNS_R_CONTINUE) { result = tresult; - search.chain.len = i - 1; node = n; if (foundname != NULL) { dns_name_copy(&node->name, foundname); @@ -4951,7 +5034,6 @@ newheader->serial = version->serial; newheader->trust = 0; newheader->noqname = NULL; - newheader->closest = NULL; atomic_init(&newheader->count, atomic_fetch_add_relaxed(&init_count, 1)); newheader->last_used = 0; diff -Nru bind9-9.20.26/lib/dns/rbt-zonedb.c bind9-9.20.29/lib/dns/rbt-zonedb.c --- bind9-9.20.26/lib/dns/rbt-zonedb.c 2026-07-20 14:47:54.044849665 +0000 +++ bind9-9.20.29/lib/dns/rbt-zonedb.c 2026-09-11 19:41:01.518331404 +0000 @@ -119,6 +119,19 @@ onode = search->rbtdb->origin_node; + /* + * The database may contain nodes above its origin (out-of-zone + * data loaded from a secondary zone file or a journal). They are + * not part of the zone and must not act as zone cuts or wildcard + * parents for the names inside it. The origin itself is the + * usual callback node, so spare it the name comparison. + */ + if (node != onode && + !dns_name_issubdomain(name, &search->rbtdb->common.origin)) + { + return result; + } + NODE_RDLOCK(&(search->rbtdb->node_locks[node->locknum].lock), &nlocktype); @@ -603,11 +616,12 @@ } } - if (active) { + if (active || node == rbtdb->origin_node) { /* - * The level node is active. Any wildcarding - * present at higher levels has no - * effect and we're done. + * The level node is active, or it is the origin + * of the zone. Any wildcarding present at higher + * levels has no effect (the nodes above the origin + * are not part of the zone) and we're done. */ result = ISC_R_NOTFOUND; break; @@ -679,6 +693,22 @@ REQUIRE(type == dns_rdatatype_nsec3 || firstp != NULL); if (type == dns_rdatatype_nsec3) { + dns_rbtnode_t *current = NULL; + + /* + * The NSEC3 nodes of the zone form the subtree of its + * origin node in the NSEC3 tree, and in DNSSEC order the + * origin node comes first: once it has been examined, + * anything before it in the tree is outside the zone. + */ + result = dns_rbtnodechain_current(&search->chain, NULL, NULL, + ¤t); + if (result == ISC_R_SUCCESS && + current == search->rbtdb->nsec3_origin_node) + { + return ISC_R_NOMORE; + } + result = dns_rbtnodechain_prev(&search->chain, NULL, NULL); if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { return result; @@ -754,6 +784,17 @@ return result; } + /* + * The NSEC tree may contain nodes outside the zone; a + * predecessor that is not below the origin means that the + * walk has left the zone. + */ + if (!dns_name_issubdomain(target, + &search->rbtdb->common.origin)) + { + return ISC_R_NOMORE; + } + *nodep = NULL; result = dns_rbt_findnode(search->rbtdb->tree, target, NULL, nodep, &search->chain, @@ -778,6 +819,39 @@ } /* + * Point the search chain at the last node of the zone in 'tree', skipping + * any nodes that sort after it (out-of-zone data loaded from a secondary + * zone file or a journal). + */ +static isc_result_t +last_in_zone(rbtdb_search_t *search, dns_rbt_t *tree) { + dns_fixedname_t fname, forigin, ffull; + dns_name_t *name = dns_fixedname_initname(&fname); + dns_name_t *origin = dns_fixedname_initname(&forigin); + dns_name_t *full = dns_fixedname_initname(&ffull); + isc_result_t result; + + result = dns_rbtnodechain_last(&search->chain, tree, NULL, NULL); + while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { + result = dns_rbtnodechain_current(&search->chain, name, origin, + NULL); + if (result != ISC_R_SUCCESS) { + break; + } + result = dns_name_concatenate(name, origin, full, NULL); + if (result != ISC_R_SUCCESS) { + break; + } + if (dns_name_issubdomain(full, &search->rbtdb->common.origin)) { + return ISC_R_SUCCESS; + } + result = dns_rbtnodechain_prev(&search->chain, NULL, NULL); + } + + return result; +} + +/* * Find the NSEC/NSEC3 which is or before the current point on the * search chain. For NSEC3 records only NSEC3 records that match the * current NSEC3PARAM record are considered. @@ -957,9 +1031,12 @@ } if (result == ISC_R_NOMORE && wraps) { - result = dns_rbtnodechain_last(&search->chain, tree, NULL, - NULL); - if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { + /* + * Start over from the last node of the zone in the NSEC3 + * tree, skipping any nodes that sort after it. + */ + result = last_in_zone(search, tree); + if (result == ISC_R_SUCCESS) { wraps = false; goto again; } @@ -1027,6 +1104,17 @@ TREE_RDLOCK(&search.rbtdb->tree_lock, &tlocktype); /* + * The database may contain nodes that are not below its origin + * (out-of-zone data loaded from a secondary zone file or a + * journal). A name that is not below the origin is not in the + * zone, whatever stray nodes exist for it. + */ + if (!dns_name_issubdomain(name, &search.rbtdb->common.origin)) { + result = ISC_R_NOTFOUND; + goto tree_exit; + } + + /* * Search down from the root of the tree. If, while going down, we * encounter a callback node, zone_zonecut_callback() will search the * rdatasets at the zone cut for active DNAME or NS rdatasets. diff -Nru bind9-9.20.26/lib/dns/rbtdb.c bind9-9.20.29/lib/dns/rbtdb.c --- bind9-9.20.26/lib/dns/rbtdb.c 2026-07-20 14:47:54.045849680 +0000 +++ bind9-9.20.29/lib/dns/rbtdb.c 2026-09-11 19:41:01.519331428 +0000 @@ -2222,10 +2222,6 @@ if (header->noqname != NULL) { rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; } - rdataset->slab.closest = header->closest; - if (header->closest != NULL) { - rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; - } /* * Copy out re-signing information. @@ -2903,12 +2899,6 @@ header->noqname = newheader->noqname; newheader->noqname = NULL; } - if (header->closest == NULL && - newheader->closest != NULL) - { - header->closest = newheader->closest; - newheader->closest = NULL; - } dns_slabheader_destroy(&newheader); if (addedrdataset != NULL) { dns__rbtdb_bindrdataset( @@ -2967,12 +2957,6 @@ header->noqname = newheader->noqname; newheader->noqname = NULL; } - if (header->closest == NULL && - newheader->closest != NULL) - { - header->closest = newheader->closest; - newheader->closest = NULL; - } dns_slabheader_destroy(&newheader); if (addedrdataset != NULL) { dns__rbtdb_bindrdataset( @@ -3270,52 +3254,6 @@ return result; } -static isc_result_t -addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset, - dns_rdataset_t *rdataset) { - isc_result_t result; - dns_slabheader_proof_t *closest = NULL; - dns_name_t name = DNS_NAME_INITEMPTY; - dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT; - isc_region_t r1 = { .base = NULL }, r2 = { .base = NULL }; - - result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - - result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - closest = isc_mem_get(mctx, sizeof(*closest)); - *closest = (dns_slabheader_proof_t){ - .neg = r1.base, - .negsig = r2.base, - .name = DNS_NAME_INITEMPTY, - .type = neg.type, - }; - dns_name_dup(&name, mctx, &closest->name); - newheader->closest = closest; - -cleanup: - if (result != ISC_R_SUCCESS) { - if (r1.base != NULL) { - isc_mem_put(mctx, r1.base, r1.length); - } - if (r2.base != NULL) { - isc_mem_put(mctx, r2.base, r2.length); - } - } - dns_rdataset_disassociate(&neg); - dns_rdataset_disassociate(&negsig); - return result; -} - static void expire_ttl_headers(dns_rbtdb_t *rbtdb, unsigned int locknum, isc_rwlocktype_t *tlocktypep, isc_stdtime_t now, @@ -3442,14 +3380,6 @@ return result; } } - if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) { - result = addclosest(rbtdb->common.mctx, newheader, - rbtdb->maxrrperset, rdataset); - if (result != ISC_R_SUCCESS) { - dns_slabheader_destroy(&newheader); - return result; - } - } } /* @@ -3609,7 +3539,6 @@ newheader->serial = rbtversion->serial; newheader->trust = 0; newheader->noqname = NULL; - newheader->closest = NULL; atomic_init(&newheader->count, atomic_fetch_add_relaxed(&init_count, 1)); newheader->last_used = 0; @@ -5070,9 +4999,6 @@ if (header->noqname != NULL) { dns_slabheader_freeproof(db->mctx, &header->noqname); } - if (header->closest != NULL) { - dns_slabheader_freeproof(db->mctx, &header->closest); - } } } diff -Nru bind9-9.20.26/lib/dns/rdata/generic/eui48_108.c bind9-9.20.29/lib/dns/rdata/generic/eui48_108.c --- bind9-9.20.26/lib/dns/rdata/generic/eui48_108.c 2026-07-20 14:47:54.050849758 +0000 +++ bind9-9.20.29/lib/dns/rdata/generic/eui48_108.c 2026-09-11 19:41:01.524331548 +0000 @@ -23,6 +23,7 @@ isc_token_t token; unsigned char eui48[6]; unsigned int l0, l1, l2, l3, l4, l5; + char buf[sizeof("xx-xx-xx-xx-xx-xx")]; int n; REQUIRE(type == dns_rdatatype_eui48); @@ -43,6 +44,16 @@ return DNS_R_BADEUI; } + /* + * Check that leading zeros were present and that there wasn't + * trailing garbage. + */ + n = snprintf(buf, sizeof(buf), "%02x-%02x-%02x-%02x-%02x-%02x", l0, l1, + l2, l3, l4, l5); + if (n != sizeof(buf) - 1 || strcasecmp(DNS_AS_STR(token), buf) != 0) { + return DNS_R_BADEUI; + } + eui48[0] = l0; eui48[1] = l1; eui48[2] = l2; diff -Nru bind9-9.20.26/lib/dns/rdata/generic/eui64_109.c bind9-9.20.29/lib/dns/rdata/generic/eui64_109.c --- bind9-9.20.26/lib/dns/rdata/generic/eui64_109.c 2026-07-20 14:47:54.050849758 +0000 +++ bind9-9.20.29/lib/dns/rdata/generic/eui64_109.c 2026-09-11 19:41:01.524331548 +0000 @@ -23,6 +23,7 @@ isc_token_t token; unsigned char eui64[8]; unsigned int l0, l1, l2, l3, l4, l5, l6, l7; + char buf[sizeof("xx-xx-xx-xx-xx-xx-xx-xx")]; int n; REQUIRE(type == dns_rdatatype_eui64); @@ -43,6 +44,17 @@ return DNS_R_BADEUI; } + /* + * Check that leading zeros were present and that there wasn't + * trailing garbage. + */ + n = snprintf(buf, sizeof(buf), + "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", l0, l1, l2, l3, + l4, l5, l6, l7); + if (n != sizeof(buf) - 1 || strcasecmp(DNS_AS_STR(token), buf) != 0) { + return DNS_R_BADEUI; + } + eui64[0] = l0; eui64[1] = l1; eui64[2] = l2; diff -Nru bind9-9.20.26/lib/dns/rdata/in_1/svcb_64.c bind9-9.20.29/lib/dns/rdata/in_1/svcb_64.c --- bind9-9.20.26/lib/dns/rdata/in_1/svcb_64.c 2026-07-20 14:47:54.064849976 +0000 +++ bind9-9.20.29/lib/dns/rdata/in_1/svcb_64.c 2026-09-11 19:41:01.538331883 +0000 @@ -1082,6 +1082,7 @@ dns_rdataset_t rdataset; isc_region_t region; unsigned int cnames = 0; + isc_result_t result; dns_name_init(&name, offsets); dns_rdata_toregion(rdata, ®ion); @@ -1110,10 +1111,16 @@ dns_rdataset_init(&rdataset); fname = dns_fixedname_initname(&fixed); do { - RETERR((add)(arg, &name, dns_rdatatype_cname, - &rdataset DNS__DB_FILELINE)); + result = (add)(arg, &name, dns_rdatatype_cname, + &rdataset DNS__DB_FILELINE); + if (result != ISC_R_SUCCESS) { + if (dns_rdataset_isassociated(&rdataset)) { + dns__rdataset_disassociate(&rdataset); + } + return result; + } + if (dns_rdataset_isassociated(&rdataset)) { - isc_result_t result; result = dns_rdataset_first(&rdataset); if (result == ISC_R_SUCCESS) { dns_rdata_t current = DNS_RDATA_INIT; @@ -1145,11 +1152,23 @@ * Look up HTTPS/SVCB records when processing the alias form. */ if (alias) { - RETERR((add)(arg, &name, rdata->type, - &rdataset DNS__DB_FILELINE)); + result = (add)(arg, &name, rdata->type, + &rdataset DNS__DB_FILELINE); + if (result != ISC_R_SUCCESS) { + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + return result; + } + /* - * Don't return A or AAAA if this is not the last element - * in the HTTP / SVCB chain. + * If the target has an HTTPS/SVCB RRset, the callback has + * already added and followed it, and the client will use it + * next; the target's own A/AAAA would only be dead weight. + * + * If it has none, the alias chain ends here and the client + * resolves the target's A/AAAA directly (RFC 9460 section + * 3), so look those up. */ if (dns_rdataset_isassociated(&rdataset)) { dns_rdataset_disassociate(&rdataset); diff -Nru bind9-9.20.26/lib/dns/rdata/in_1/wks_11.c bind9-9.20.29/lib/dns/rdata/in_1/wks_11.c --- bind9-9.20.26/lib/dns/rdata/in_1/wks_11.c 2026-07-20 14:47:54.064849976 +0000 +++ bind9-9.20.29/lib/dns/rdata/in_1/wks_11.c 2026-09-11 19:41:01.538331883 +0000 @@ -193,8 +193,8 @@ for (j = 0; j < 8; j++) { if ((sr.base[i] & (0x80 >> j)) != 0) { { - snprintf(buf, sizeof(buf), "%u", - i * 8 + j); + snprintf(buf, sizeof(buf), + "%hu", i * 8 + j); RETERR(str_totext(" ", target)); RETERR(str_totext(buf, target)); } diff -Nru bind9-9.20.26/lib/dns/rdatalist.c bind9-9.20.29/lib/dns/rdatalist.c --- bind9-9.20.26/lib/dns/rdatalist.c 2026-07-20 14:47:54.064849976 +0000 +++ bind9-9.20.29/lib/dns/rdatalist.c 2026-09-11 19:41:01.539331907 +0000 @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -33,8 +32,6 @@ .count = dns_rdatalist_count, .addnoqname = dns_rdatalist_addnoqname, .getnoqname = dns_rdatalist_getnoqname, - .addclosest = dns_rdatalist_addclosest, - .getclosest = dns_rdatalist_getclosest, .setownercase = dns_rdatalist_setownercase, .getownercase = dns_rdatalist_getownercase, }; @@ -173,213 +170,91 @@ return count; } -isc_result_t -dns_rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name) { +/* + * Find the denial of existence proof of the given type at 'name': the + * NSEC or NSEC3 rdataset together with the RRSIG rdataset covering it. + */ +static bool +findproof(const dns_name_t *name, dns_rdataclass_t rdclass, + dns_rdatatype_t type, dns_rdataset_t **negp, + dns_rdataset_t **negsigp) { dns_rdataset_t *neg = NULL; dns_rdataset_t *negsig = NULL; - dns_rdataset_t *rdset; - dns_rdataset_t *sigset; - dns_ttl_t ttl; + dns_rdataset_t *rdset = NULL; - REQUIRE(rdataset != NULL); + REQUIRE(type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3); - for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL; - rdset = ISC_LIST_NEXT(rdset, link)) - { - if (rdset->rdclass != rdataset->rdclass || - (rdset->type != dns_rdatatype_nsec && - rdset->type != dns_rdatatype_nsec3)) - { + ISC_LIST_FOREACH(name->list, rdset, link) { + if (rdset->rdclass != rdclass) { continue; } - for (sigset = ISC_LIST_HEAD(name->list); sigset != NULL; - sigset = ISC_LIST_NEXT(sigset, link)) + if (rdset->type == type) { + neg = rdset; + } else if (rdset->type == dns_rdatatype_rrsig && + rdset->covers == type) { - if (sigset->type == dns_rdatatype_rrsig && - sigset->covers == rdset->type) - { - neg = rdset; - negsig = sigset; - break; - } + negsig = rdset; } - } - - if (neg == NULL || negsig == NULL) { - return ISC_R_NOTFOUND; - } - - /* - * Minimise ttl. - */ - ttl = rdataset->ttl; - if (neg->ttl < ttl) { - ttl = neg->ttl; - } - if (negsig->ttl < ttl) { - ttl = negsig->ttl; - } - rdataset->ttl = neg->ttl = negsig->ttl = ttl; - rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; - rdataset->rdlist.noqname = name; - - return ISC_R_SUCCESS; -} -isc_result_t -dns_rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *neg, - dns_rdataset_t *negsig DNS__DB_FLARG) { - dns_rdataclass_t rdclass; - dns_rdataset_t *tneg = NULL; - dns_rdataset_t *tnegsig = NULL; - const dns_name_t *noqname; - - REQUIRE(rdataset != NULL); - REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0); - - rdclass = rdataset->rdclass; - noqname = rdataset->rdlist.noqname; - - (void)dns_name_dynamic(noqname); /* Sanity Check. */ - - for (rdataset = ISC_LIST_HEAD(noqname->list); rdataset != NULL; - rdataset = ISC_LIST_NEXT(rdataset, link)) - { - if (rdataset->rdclass != rdclass) { - continue; - } - if (rdataset->type == dns_rdatatype_nsec || - rdataset->type == dns_rdatatype_nsec3) - { - tneg = rdataset; + if (neg != NULL && negsig != NULL) { + *negp = neg; + *negsigp = negsig; + return true; } } - if (tneg == NULL) { - return ISC_R_NOTFOUND; - } - for (rdataset = ISC_LIST_HEAD(noqname->list); rdataset != NULL; - rdataset = ISC_LIST_NEXT(rdataset, link)) - { - if (rdataset->type == dns_rdatatype_rrsig && - rdataset->covers == tneg->type) - { - tnegsig = rdataset; - } - } - if (tnegsig == NULL) { - return ISC_R_NOTFOUND; - } - - dns_name_clone(noqname, name); - dns_rdataset_clone(tneg, neg); - dns_rdataset_clone(tnegsig, negsig); - return ISC_R_SUCCESS; + return false; } isc_result_t -dns_rdatalist_addclosest(dns_rdataset_t *rdataset, const dns_name_t *name) { +dns_rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name, + dns_rdatatype_t type) { dns_rdataset_t *neg = NULL; dns_rdataset_t *negsig = NULL; - dns_rdataset_t *rdset; dns_ttl_t ttl; REQUIRE(rdataset != NULL); + REQUIRE(DNS_NAME_VALID(name)); - for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL; - rdset = ISC_LIST_NEXT(rdset, link)) - { - if (rdset->rdclass != rdataset->rdclass) { - continue; - } - if (rdset->type == dns_rdatatype_nsec || - rdset->type == dns_rdatatype_nsec3) - { - neg = rdset; - } - } - if (neg == NULL) { + if (!findproof(name, rdataset->rdclass, type, &neg, &negsig)) { return ISC_R_NOTFOUND; } - for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL; - rdset = ISC_LIST_NEXT(rdset, link)) - { - if (rdset->type == dns_rdatatype_rrsig && - rdset->covers == neg->type) - { - negsig = rdset; - } - } - - if (negsig == NULL) { - return ISC_R_NOTFOUND; - } /* * Minimise ttl. */ - ttl = rdataset->ttl; - if (neg->ttl < ttl) { - ttl = neg->ttl; - } - if (negsig->ttl < ttl) { - ttl = negsig->ttl; - } + ttl = ISC_MIN(rdataset->ttl, ISC_MIN(neg->ttl, negsig->ttl)); rdataset->ttl = neg->ttl = negsig->ttl = ttl; - rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; - rdataset->rdlist.closest = name; + rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; + rdataset->rdlist.noqname = name; + rdataset->rdlist.noqnametype = type; + return ISC_R_SUCCESS; } isc_result_t -dns_rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, +dns_rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG) { - dns_rdataclass_t rdclass; dns_rdataset_t *tneg = NULL; dns_rdataset_t *tnegsig = NULL; - const dns_name_t *closest; + const dns_name_t *noqname; REQUIRE(rdataset != NULL); - REQUIRE((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0); - - rdclass = rdataset->rdclass; - closest = rdataset->rdlist.closest; + REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0); - (void)dns_name_dynamic(closest); /* Sanity Check. */ + noqname = rdataset->rdlist.noqname; - for (rdataset = ISC_LIST_HEAD(closest->list); rdataset != NULL; - rdataset = ISC_LIST_NEXT(rdataset, link)) - { - if (rdataset->rdclass != rdclass) { - continue; - } - if (rdataset->type == dns_rdatatype_nsec || - rdataset->type == dns_rdatatype_nsec3) - { - tneg = rdataset; - } - } - if (tneg == NULL) { - return ISC_R_NOTFOUND; - } + REQUIRE(DNS_NAME_VALID(noqname)); - for (rdataset = ISC_LIST_HEAD(closest->list); rdataset != NULL; - rdataset = ISC_LIST_NEXT(rdataset, link)) + if (!findproof(noqname, rdataset->rdclass, rdataset->rdlist.noqnametype, + &tneg, &tnegsig)) { - if (rdataset->type == dns_rdatatype_rrsig && - rdataset->covers == tneg->type) - { - tnegsig = rdataset; - } - } - if (tnegsig == NULL) { return ISC_R_NOTFOUND; } - dns_name_clone(closest, name); + dns_name_clone(noqname, name); dns_rdataset_clone(tneg, neg); dns_rdataset_clone(tnegsig, negsig); return ISC_R_SUCCESS; diff -Nru bind9-9.20.26/lib/dns/rdataset.c bind9-9.20.29/lib/dns/rdataset.c --- bind9-9.20.26/lib/dns/rdataset.c 2026-07-20 14:47:54.064849976 +0000 +++ bind9-9.20.29/lib/dns/rdataset.c 2026-09-11 19:41:01.539331907 +0000 @@ -548,13 +548,14 @@ } isc_result_t -dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) { +dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdatatype_t type) { REQUIRE(DNS_RDATASET_VALID(rdataset)); REQUIRE(rdataset->methods != NULL); if (rdataset->methods->addnoqname == NULL) { return ISC_R_NOTIMPLEMENTED; } - return (rdataset->methods->addnoqname)(rdataset, name); + return (rdataset->methods->addnoqname)(rdataset, name, type); } isc_result_t @@ -571,30 +572,6 @@ negsig DNS__DB_FLARG_PASS); } -isc_result_t -dns_rdataset_addclosest(dns_rdataset_t *rdataset, const dns_name_t *name) { - REQUIRE(DNS_RDATASET_VALID(rdataset)); - REQUIRE(rdataset->methods != NULL); - if (rdataset->methods->addclosest == NULL) { - return ISC_R_NOTIMPLEMENTED; - } - return (rdataset->methods->addclosest)(rdataset, name); -} - -isc_result_t -dns__rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *neg, - dns_rdataset_t *negsig DNS__DB_FLARG) { - REQUIRE(DNS_RDATASET_VALID(rdataset)); - REQUIRE(rdataset->methods != NULL); - - if (rdataset->methods->getclosest == NULL) { - return ISC_R_NOTIMPLEMENTED; - } - return (rdataset->methods->getclosest)(rdataset, name, neg, - negsig DNS__DB_FLARG_PASS); -} - void dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { REQUIRE(DNS_RDATASET_VALID(rdataset)); diff -Nru bind9-9.20.26/lib/dns/rdataslab.c bind9-9.20.29/lib/dns/rdataslab.c --- bind9-9.20.26/lib/dns/rdataslab.c 2026-07-20 14:47:54.065849991 +0000 +++ bind9-9.20.29/lib/dns/rdataslab.c 2026-09-11 19:41:01.539331907 +0000 @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -40,6 +41,16 @@ ((atomic_load_acquire(&(header)->attributes) & \ DNS_SLABHEADERATTR_NONEXISTENT) != 0) +STATIC_ASSERT(offsetof(dns_rdataset_t, slab.raw) == + offsetof(dns_rdataset_t, proof.raw), + "slab and proof raw pointers must have the same offset"); +STATIC_ASSERT(offsetof(dns_rdataset_t, slab.iter_pos) == + offsetof(dns_rdataset_t, proof.iter_pos), + "slab and proof iterators must have the same offset"); +STATIC_ASSERT(offsetof(dns_rdataset_t, slab.iter_count) == + offsetof(dns_rdataset_t, proof.iter_count), + "slab and proof iterator counts must have the same offset"); + /* * The rdataslab structure allows iteration to occur in both load order * and DNSSEC order. The structure is as follows: @@ -99,6 +110,8 @@ static void rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG); +static void +rdataproof_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG); static isc_result_t rdataset_first(dns_rdataset_t *rdataset); static isc_result_t @@ -107,14 +120,13 @@ rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata); static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG); +static void +rdataproof_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG); static unsigned int rdataset_count(dns_rdataset_t *rdataset); static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG); -static isc_result_t -rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG); static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust); static void @@ -1166,7 +1178,6 @@ .clone = rdataset_clone, .count = rdataset_count, .getnoqname = rdataset_getnoqname, - .getclosest = rdataset_getclosest, .settrust = rdataset_settrust, .expire = rdataset_expire, .clearprefetch = rdataset_clearprefetch, @@ -1175,14 +1186,13 @@ }; dns_rdatasetmethods_t dns_rdataproof_rdatasetmethods = { - .disassociate = rdataset_disassociate, + .disassociate = rdataproof_disassociate, .first = rdataset_first, .next = rdataset_next, .current = rdataset_current, - .clone = rdataset_clone, + .clone = rdataproof_clone, .count = rdataset_count, .getnoqname = rdataset_getnoqname, - .getclosest = rdataset_getclosest, .settrust = rdataset_settrust, .expire = rdataset_expire, .clearprefetch = rdataset_clearprefetch, @@ -1215,6 +1225,15 @@ dns__db_detachnode(db, &node DNS__DB_FLARG_PASS); } +static void +rdataproof_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { + dns_db_t *db = rdataset->proof.db; + dns_dbnode_t *node = rdataset->proof.node; + + isc_refcount_decrement(&rdataset->proof.header->references); + dns__db_detachnode(db, &node DNS__DB_FLARG_PASS); +} + static isc_result_t rdataset_first(dns_rdataset_t *rdataset) { unsigned char *raw = rdataset->slab.raw; @@ -1331,6 +1350,23 @@ target->slab.iter_count = 0; } +static void +rdataproof_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) { + dns_db_t *db = source->proof.db; + dns_dbnode_t *node = source->proof.node; + dns_dbnode_t *cloned_node = NULL; + + isc_refcount_increment(&source->proof.header->references); + + dns__db_attachnode(db, node, &cloned_node DNS__DB_FLARG_PASS); + INSIST(!ISC_LINK_LINKED(target, link)); + *target = *source; + ISC_LINK_INIT(target, link); + + target->proof.iter_pos = NULL; + target->proof.iter_count = 0; +} + static unsigned int rdataset_count(dns_rdataset_t *rdataset) { unsigned char *raw = NULL; @@ -1348,6 +1384,7 @@ dns_rdataset_t *nsecsig DNS__DB_FLARG) { dns_db_t *db = rdataset->slab.db; dns_dbnode_t *node = rdataset->slab.node; + dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); const dns_slabheader_proof_t *noqname = rdataset->slab.noqname; /* @@ -1360,15 +1397,17 @@ */ dns__db_attachnode(db, node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); + isc_refcount_increment(&header->references); *nsec = (dns_rdataset_t){ .methods = &dns_rdataproof_rdatasetmethods, .rdclass = db->rdclass, .type = noqname->type, .ttl = rdataset->ttl, .trust = rdataset->trust, - .slab.db = db, - .slab.node = node, - .slab.raw = noqname->neg, + .proof.db = db, + .proof.node = node, + .proof.raw = noqname->neg, + .proof.header = header, .link = nsec->link, .count = nsec->count, .attributes = nsec->attributes | DNS_RDATASETATTR_KEEPCASE, @@ -1377,6 +1416,7 @@ dns__db_attachnode(db, node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); + isc_refcount_increment(&header->references); *nsecsig = (dns_rdataset_t){ .methods = &dns_rdataproof_rdatasetmethods, .rdclass = db->rdclass, @@ -1384,9 +1424,10 @@ .covers = noqname->type, .ttl = rdataset->ttl, .trust = rdataset->trust, - .slab.db = db, - .slab.node = node, - .slab.raw = noqname->negsig, + .proof.db = db, + .proof.node = node, + .proof.raw = noqname->negsig, + .proof.header = header, .link = nsecsig->link, .count = nsecsig->count, .attributes = nsecsig->attributes | DNS_RDATASETATTR_KEEPCASE, @@ -1397,59 +1438,6 @@ return ISC_R_SUCCESS; } - -static isc_result_t -rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *nsec, - dns_rdataset_t *nsecsig DNS__DB_FLARG) { - dns_db_t *db = rdataset->slab.db; - dns_dbnode_t *node = rdataset->slab.node; - const dns_slabheader_proof_t *closest = rdataset->slab.closest; - - /* - * As mentioned above, rdataset->slab.raw usually refers the data - * following an dns_slabheader, but in this case it points to a bare - * rdataslab belonging to the dns_slabheader's `closest` field. - */ - dns__db_attachnode(db, node, - &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); - *nsec = (dns_rdataset_t){ - .methods = &dns_rdataproof_rdatasetmethods, - .rdclass = db->rdclass, - .type = closest->type, - .ttl = rdataset->ttl, - .trust = rdataset->trust, - .slab.db = db, - .slab.node = node, - .slab.raw = closest->neg, - .link = nsec->link, - .count = nsec->count, - .attributes = nsec->attributes | DNS_RDATASETATTR_KEEPCASE, - .magic = nsec->magic, - }; - - dns__db_attachnode(db, node, - &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); - *nsecsig = (dns_rdataset_t){ - .methods = &dns_rdataproof_rdatasetmethods, - .rdclass = db->rdclass, - .type = dns_rdatatype_rrsig, - .covers = closest->type, - .ttl = rdataset->ttl, - .trust = rdataset->trust, - .slab.db = db, - .slab.node = node, - .slab.raw = closest->negsig, - .link = nsecsig->link, - .count = nsecsig->count, - .attributes = nsecsig->attributes | DNS_RDATASETATTR_KEEPCASE, - .magic = nsecsig->magic, - }; - - dns_name_clone(&closest->name, name); - - return ISC_R_SUCCESS; -} static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { diff -Nru bind9-9.20.26/lib/dns/resolver.c bind9-9.20.29/lib/dns/resolver.c --- bind9-9.20.26/lib/dns/resolver.c 2026-07-20 14:47:54.066850007 +0000 +++ bind9-9.20.29/lib/dns/resolver.c 2026-09-11 19:41:01.541331955 +0000 @@ -698,7 +698,8 @@ isc_result_t reason, badnstype_t badtype); static isc_result_t findnoqname(fetchctx_t *fctx, dns_message_t *message, dns_name_t *name, - dns_rdatatype_t type, dns_name_t **noqname); + dns_rdatatype_t type, dns_name_t **noqnamep, + dns_rdatatype_t *noqnametypep); #define fctx_done_detach(fctxp, result) \ if (fctx__done(*fctxp, result, __func__, __FILE__, __LINE__)) { \ @@ -2328,9 +2329,12 @@ static isc_result_t issecuredomain(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type, - isc_stdtime_t now, bool checknta, bool *ntap, bool *issecure) { + dns_edectx_t *edectx, isc_stdtime_t now, bool checknta, + bool *ntap, bool *issecure) { dns_name_t suffix; unsigned int labels; + bool nta = false; + isc_result_t result; /* * For DS variants we need to check fom the parent domain, @@ -2345,8 +2349,24 @@ name = &suffix; } - return dns_view_issecuredomain(view, name, now, checknta, ntap, - issecure); + result = dns_view_issecuredomain(view, name, now, checknta, &nta, + issecure); + + /* + * A covering negative trust anchor suppressed DNSSEC validation for + * an otherwise secure name (RFC 7646). Disclose that to the client + * via an Extended DNS Error (draft-farrokhi-dnsop-ede-nta). Duplicate + * codes are coalesced by dns_ede_add(), so this is emitted at most + * once per fetch. + */ + if (nta && edectx != NULL) { + dns_ede_add(edectx, DNS_EDE_NTA, + "Negative Trust Anchor applied (RFC 7646)"); + } + + SET_IF_NOT_NULL(ntap, nta); + + return result; } static isc_result_t @@ -2422,6 +2442,7 @@ bool checknta = ((query->options & DNS_FETCHOPT_NONTA) == 0); bool ntacovered = false; result = issecuredomain(res->view, fctx->name, fctx->type, + &fctx->edectx, isc_time_seconds(&query->start), checknta, &ntacovered, &secure_domain); if (result != ISC_R_SUCCESS) { @@ -5535,27 +5556,14 @@ inc_stats(res, dns_resstatscounter_valfail); fctx->valfail++; fctx->vresult = val->result; - if (fctx->vresult != DNS_R_BROKENCHAIN) { - result = ISC_R_NOTFOUND; - if (val->rdataset != NULL) { - result = dns_db_findnode(fctx->cache, val->name, - false, &node); - } - if (result == ISC_R_SUCCESS) { - (void)dns_db_deleterdataset(fctx->cache, node, - NULL, val->type, 0); - } - if (result == ISC_R_SUCCESS && val->sigrdataset != NULL) - { - (void)dns_db_deleterdataset( - fctx->cache, node, NULL, - dns_rdatatype_rrsig, val->type); - } - if (result == ISC_R_SUCCESS) { - dns_db_detachnode(fctx->cache, &node); + switch (fctx->vresult) { + case DNS_R_BROKENCHAIN: + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + case ISC_R_QUOTA: + if (negative) { + break; } - } - if (fctx->vresult == DNS_R_BROKENCHAIN && !negative) { /* * Cache the data as pending for later * validation. @@ -5579,6 +5587,27 @@ if (result == ISC_R_SUCCESS) { dns_db_detachnode(fctx->cache, &node); } + break; + default: + result = ISC_R_NOTFOUND; + if (val->rdataset != NULL) { + result = dns_db_findnode(fctx->cache, val->name, + false, &node); + } + if (result == ISC_R_SUCCESS) { + (void)dns_db_deleterdataset(fctx->cache, node, + NULL, val->type, 0); + } + if (result == ISC_R_SUCCESS && val->sigrdataset != NULL) + { + (void)dns_db_deleterdataset( + fctx->cache, node, NULL, + dns_rdatatype_rrsig, val->type); + } + if (result == ISC_R_SUCCESS) { + dns_db_detachnode(fctx->cache, &node); + } + break; } result = fctx->vresult; add_bad(fctx, message, addrinfo, result, badns_validation); @@ -5594,10 +5623,21 @@ } else if (sentresponse) { done = true; goto cleanup_fetchctx; - } else if (result == DNS_R_BROKENCHAIN) { + } + + /* + * A broken trust chain isn't recoverable, and neither is an + * exhausted DNSSEC validation budget: retrying would only do + * more validation work against the same quota. + */ + switch (result) { + case DNS_R_BROKENCHAIN: + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + case ISC_R_QUOTA: done = true; goto cleanup_fetchctx; - } else { + default: fctx_try(fctx, true); goto cleanup_fetchctx; } @@ -5667,28 +5707,25 @@ if (val->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) { result = dns_rdataset_addnoqname( - val->rdataset, val->proofs[DNS_VALIDATOR_NOQNAMEPROOF]); + val->rdataset, val->proofs[DNS_VALIDATOR_NOQNAMEPROOF], + val->noqnametype); if (result != ISC_R_SUCCESS) { goto noanswer_response; } INSIST(val->sigrdataset != NULL); val->sigrdataset->ttl = val->rdataset->ttl; - if (val->proofs[DNS_VALIDATOR_CLOSESTENCLOSER] != NULL) { - result = dns_rdataset_addclosest( - val->rdataset, - val->proofs[DNS_VALIDATOR_CLOSESTENCLOSER]); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - } } else if (val->rdataset->trust == dns_trust_answer && val->rdataset->type != dns_rdatatype_rrsig) { isc_result_t tresult; dns_name_t *noqname = NULL; + dns_rdatatype_t noqnametype = dns_rdatatype_none; tresult = findnoqname(fctx, message, val->name, - val->rdataset->type, &noqname); + val->rdataset->type, &noqname, + &noqnametype); if (tresult == ISC_R_SUCCESS && noqname != NULL) { tresult = dns_rdataset_addnoqname(val->rdataset, - noqname); + noqname, noqnametype); RUNTIME_CHECK(tresult == ISC_R_SUCCESS); } } @@ -5961,7 +5998,8 @@ static isc_result_t findnoqname(fetchctx_t *fctx, dns_message_t *message, dns_name_t *name, - dns_rdatatype_t type, dns_name_t **noqnamep) { + dns_rdatatype_t type, dns_name_t **noqnamep, + dns_rdatatype_t *noqnametypep) { dns_rdataset_t *nrdataset, *next, *sigrdataset; dns_rdata_rrsig_t rrsig; isc_result_t result; @@ -5979,6 +6017,7 @@ FCTXTRACE("findnoqname"); REQUIRE(noqnamep != NULL && *noqnamep == NULL); + REQUIRE(noqnametypep != NULL); /* * Find the SIG for this rdataset, if we have it. @@ -6089,6 +6128,7 @@ } if (sigrdataset != NULL) { *noqnamep = noqname; + *noqnametypep = found; } } return result; @@ -6129,8 +6169,9 @@ } if (res->view->enablevalidation) { - result = issecuredomain(res->view, name, fctx->type, now, - checknta, NULL, &secure_domain); + result = issecuredomain(res->view, name, fctx->type, + &fctx->edectx, now, checknta, NULL, + &secure_domain); if (result != ISC_R_SUCCESS) { return result; } @@ -6217,6 +6258,13 @@ } /* + * Do not cache or otherwise process out-of-bailiwick data. + */ + if (EXTERNAL(rdataset)) { + continue; + } + + /* * If CNAME, delete other RRsets at the same name * from the cache. */ @@ -6269,9 +6317,7 @@ * only cached if validated within the context of a * query to the domain that owns them.) */ - if (secure_domain && rdataset->trust != dns_trust_glue && - !EXTERNAL(rdataset)) - { + if (secure_domain && rdataset->trust != dns_trust_glue) { dns_trust_t trust; /* @@ -6335,14 +6381,18 @@ { isc_result_t tresult; dns_name_t *noqname = NULL; + dns_rdatatype_t noqnametype = + dns_rdatatype_none; tresult = findnoqname( fctx, message, name, - rdataset->type, &noqname); + rdataset->type, &noqname, + &noqnametype); if (tresult == ISC_R_SUCCESS && noqname != NULL) { (void)dns_rdataset_addnoqname( - rdataset, noqname); + rdataset, noqname, + noqnametype); } } if ((fctx->options & DNS_FETCHOPT_PREFETCH) != @@ -6462,7 +6512,7 @@ eresult = DNS_R_DNAME; } } - } else if (!EXTERNAL(rdataset)) { + } else { /* * It's OK to cache this rdataset now. */ @@ -6508,12 +6558,15 @@ { isc_result_t tresult; dns_name_t *noqname = NULL; + dns_rdatatype_t noqnametype = + dns_rdatatype_none; tresult = findnoqname(fctx, message, name, - rdataset->type, &noqname); + rdataset->type, &noqname, + &noqnametype); if (tresult == ISC_R_SUCCESS && noqname != NULL) { - (void)dns_rdataset_addnoqname(rdataset, - noqname); + (void)dns_rdataset_addnoqname( + rdataset, noqname, noqnametype); } } @@ -6753,8 +6806,9 @@ } if (fctx->res->view->enablevalidation) { - result = issecuredomain(res->view, name, fctx->type, now, - checknta, NULL, &secure_domain); + result = issecuredomain(res->view, name, fctx->type, + &fctx->edectx, now, checknta, NULL, + &secure_domain); if (result != ISC_R_SUCCESS) { return result; } @@ -9613,8 +9667,9 @@ if (fctx->res->view->enablevalidation) { result = issecuredomain( fctx->res->view, name, - dns_rdatatype_ds, fctx->now, - checknta, NULL, &secure_domain); + dns_rdatatype_ds, &fctx->edectx, + fctx->now, checknta, NULL, + &secure_domain); if (result != ISC_R_SUCCESS) { return result; } diff -Nru bind9-9.20.26/lib/dns/rpz.c bind9-9.20.29/lib/dns/rpz.c --- bind9-9.20.26/lib/dns/rpz.c 2026-07-20 14:47:54.067850023 +0000 +++ bind9-9.20.29/lib/dns/rpz.c 2026-09-11 19:41:01.541331955 +0000 @@ -182,6 +182,12 @@ dns_rpz_nm_zbits_t wild; }; +typedef struct rpz_update { + dns_rpz_zone_t *rpz; + dns_db_t *db; + dns_dbversion_t *dbversion; +} rpz_update_t; + #ifdef DNS_RPZ_TRACE #define nmdata_ref(ptr) nmdata__ref(ptr, __func__, __FILE__, __LINE__) #define nmdata_unref(ptr) nmdata__unref(ptr, __func__, __FILE__, __LINE__) @@ -194,9 +200,9 @@ #endif static isc_result_t -rpz_add(dns_rpz_zone_t *rpz, const dns_name_t *src_name); +rpz_add(dns_rpz_zone_t *rpz, dns_qp_t *qp, const dns_name_t *src_name); static void -rpz_del(dns_rpz_zone_t *rpz, const dns_name_t *src_name); +rpz_del(dns_rpz_zone_t *rpz, dns_qp_t *qp, const dns_name_t *src_name); static nmdata_t * new_nmdata(isc_mem_t *mctx, const dns_name_t *name, const nmdata_t *data); @@ -449,7 +455,7 @@ } while (cnode != NULL); } -/* Caller must hold rpzs->maint_lock */ +/* Caller must hold rpzs->data_lock. */ static void fix_qname_skip_recurse(dns_rpz_zones_t *rpzs) { dns_rpz_zbits_t mask; @@ -716,7 +722,8 @@ } static void -badname(int level, const dns_name_t *name, const char *str1, const char *str2) { +log_badname(int level, const dns_name_t *name, const char *str1, + const char *str2) { /* * bin/tests/system/rpz/tests.sh looks for "invalid rpz". */ @@ -730,6 +737,22 @@ } } +static void +log_badowner(int level, const dns_name_t *name) { + /* + * bin/tests/system/rpz/tests.sh looks for "invalid rpz". + */ + if (level < DNS_RPZ_DEBUG_QUIET && isc_log_wouldlog(dns_lctx, level)) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namebuf, sizeof(namebuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, + DNS_LOGMODULE_RBTDB, level, + "invalid rpz owner name \"%s\"; " + "not within the policy zone", + namebuf); + } +} + /* * Convert an IP address from radix tree binary (host byte order) to * to its canonical response policy domain name without the origin of the @@ -878,6 +901,14 @@ REQUIRE(rpz != NULL); REQUIRE(rpz->rpzs != NULL && rpz->num < rpz->rpzs->p.num_zones); + /* + * The IPv6 parsing loop below only writes as many words as the + * name has labels, so a name with too few of them would otherwise + * leave part of the key holding whatever was on the caller's + * stack. + */ + *tgt_ip = (dns_rpz_cidr_key_t){ 0 }; + make_addr_set(new_set, DNS_RPZ_ZBIT(rpz->num), rpz_type); ip_labels = dns_name_countlabels(src_name); @@ -887,7 +918,7 @@ ip_labels -= dns_name_countlabels(&rpz->nsdname); } if (ip_labels < 2) { - badname(log_level, src_name, "; too short", ""); + log_badname(log_level, src_name, "; too short", ""); return ISC_R_FAILURE; } dns_name_init(&ip_name, ip_name_offsets); @@ -902,15 +933,15 @@ prefix_num = strtoul(prefix_str, &cp2, 10); if (*cp2 != '.') { - badname(log_level, src_name, "; invalid leading prefix length", - ""); + log_badname(log_level, src_name, + "; invalid leading prefix length", ""); return ISC_R_FAILURE; } prefix_end = cp2; if (prefix_num < 1U || prefix_num > 128U) { *prefix_end = '\0'; - badname(log_level, src_name, "; invalid prefix length of ", - prefix_str); + log_badname(log_level, src_name, "; invalid prefix length of ", + prefix_str); return ISC_R_FAILURE; } cp = cp2 + 1; @@ -922,8 +953,9 @@ */ if (prefix_num > 32U) { *prefix_end = '\0'; - badname(log_level, src_name, - "; invalid IPv4 prefix length of ", prefix_str); + log_badname(log_level, src_name, + "; invalid IPv4 prefix length of ", + prefix_str); return ISC_R_FAILURE; } prefix_num += 96; @@ -938,8 +970,8 @@ if (*cp2 == '.') { *cp2 = '\0'; } - badname(log_level, src_name, - "; invalid IPv4 octet ", cp); + log_badname(log_level, src_name, + "; invalid IPv4 octet ", cp); return ISC_R_FAILURE; } tgt_ip->w[3] |= l << i; @@ -971,8 +1003,8 @@ if (*cp2 == '.') { *cp2 = '\0'; } - badname(log_level, src_name, - "; invalid IPv6 word ", cp); + log_badname(log_level, src_name, + "; invalid IPv6 word ", cp); return ISC_R_FAILURE; } if ((i & 1) == 0) { @@ -986,7 +1018,7 @@ } } if (cp != end) { - badname(log_level, src_name, "", ""); + log_badname(log_level, src_name, "", ""); return ISC_R_FAILURE; } @@ -1001,8 +1033,9 @@ aword = tgt_ip->w[prefix / DNS_RPZ_CIDR_WORD_BITS]; if ((aword & ~DNS_RPZ_WORD_MASK(i)) != 0) { *prefix_end = '\0'; - badname(log_level, src_name, - "; too small prefix length of ", prefix_str); + log_badname(log_level, src_name, + "; too small prefix length of ", + prefix_str); return ISC_R_FAILURE; } prefix -= i; @@ -1010,29 +1043,24 @@ } /* - * Complain about bad names but be generous and accept them. + * Convert the address back to a canonical domain name + * to ensure that the original name is in canonical form. */ - if (log_level < DNS_RPZ_DEBUG_QUIET && - isc_log_wouldlog(dns_lctx, log_level)) - { - /* - * Convert the address back to a canonical domain name - * to ensure that the original name is in canonical form. - */ - dns_name_t *ip_name2 = dns_fixedname_initname(&ip_name2f); - result = ip2name(tgt_ip, (dns_rpz_prefix_t)prefix_num, NULL, - ip_name2); - if (result != ISC_R_SUCCESS || - !dns_name_equal(&ip_name, ip_name2)) - { - char ip2_str[DNS_NAME_FORMATSIZE]; - dns_name_format(ip_name2, ip2_str, sizeof(ip2_str)); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, - DNS_LOGMODULE_RBTDB, log_level, - "rpz IP address \"%s\"" - " is not the canonical \"%s\"", - ip_str, ip2_str); + dns_name_t *ip_name2 = dns_fixedname_initname(&ip_name2f); + result = ip2name(tgt_ip, (dns_rpz_prefix_t)prefix_num, NULL, ip_name2); + if (result != ISC_R_SUCCESS || !dns_name_equal(&ip_name, ip_name2)) { + char ip2_str[DNS_NAME_FORMATSIZE]; + if (rpz_type == DNS_RPZ_TYPE_QNAME) { + dns_name_concatenate(ip_name2, &rpz->origin, ip_name2, + NULL); + } else { + dns_name_concatenate(ip_name2, &rpz->nsdname, ip_name2, + NULL); } + dns_name_format(ip_name2, ip2_str, sizeof(ip2_str)); + log_badname(log_level, src_name, " is not in canonical form ", + ip2_str); + return ISC_R_FAILURE; } return ISC_R_SUCCESS; @@ -1042,23 +1070,48 @@ * Get trigger name and data bits for adding or deleting summary NSDNAME * or QNAME data. */ -static void -name2data(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, +static isc_result_t +name2data(int log_level, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, const dns_name_t *src_name, dns_name_t *trig_name, nmdata_t *new_data) { dns_offsets_t tmp_name_offsets; + const dns_name_t *suffix = NULL; dns_name_t tmp_name; - unsigned int prefix_len, n; + unsigned int prefix_len, nlabels; REQUIRE(rpz != NULL); REQUIRE(rpz->rpzs != NULL && rpz->num < rpz->rpzs->p.num_zones); + if (rpz_type == DNS_RPZ_TYPE_QNAME) { + suffix = &rpz->origin; + } else { + suffix = &rpz->nsdname; + } + + /* + * A zone transfer can carry records whose owner name lies outside the + * zone, and a secondary keeps them when it reloads its own copy of the + * zone. We are about to strip 'suffix' off the owner name, so require + * that it is really there, the way dns_catz_update_process() does + * before splitting a catalog zone entry. + */ + if (!dns_name_issubdomain(src_name, suffix)) { + log_badowner(log_level, src_name); + return ISC_R_FAILURE; + } + + nlabels = dns_name_countlabels(src_name) - dns_name_countlabels(suffix); + /* * Handle wildcards by putting only the parent into the * summary database. The database only causes a check of the * real policy zone where wildcards will be handled. + * + * The "*" label is one of the labels we are keeping, so there has to + * be one to spare; a policy zone whose own origin is a wildcard has + * none at its apex. */ - if (dns_name_iswildcard(src_name)) { + if (nlabels > 0 && dns_name_iswildcard(src_name)) { prefix_len = 1; memset(&new_data->set, 0, sizeof(new_data->set)); make_nm_set(&new_data->wild, rpz->num, rpz_type); @@ -1069,15 +1122,11 @@ } dns_name_init(&tmp_name, tmp_name_offsets); - n = dns_name_countlabels(src_name); - n -= prefix_len; - if (rpz_type == DNS_RPZ_TYPE_QNAME) { - n -= dns_name_countlabels(&rpz->origin); - } else { - n -= dns_name_countlabels(&rpz->nsdname); - } - dns_name_getlabelsequence(src_name, prefix_len, n, &tmp_name); + dns_name_getlabelsequence(src_name, prefix_len, nlabels - prefix_len, + &tmp_name); (void)dns_name_concatenate(&tmp_name, dns_rootname, trig_name, NULL); + + return ISC_R_SUCCESS; } #ifndef HAVE_BUILTIN_CLZ @@ -1422,19 +1471,18 @@ } static isc_result_t -add_nm(dns_rpz_zones_t *rpzs, dns_name_t *trig_name, const nmdata_t *new_data) { +add_nm(dns_rpz_zones_t *rpzs, dns_qp_t *qp, dns_name_t *trig_name, + const nmdata_t *new_data) { isc_result_t result; nmdata_t *data = NULL; - dns_qp_t *qp = NULL; - dns_qpmulti_write(rpzs->table, &qp); result = dns_qp_getname(qp, trig_name, (void **)&data, NULL); if (result != ISC_R_SUCCESS) { INSIST(data == NULL); data = new_nmdata(rpzs->mctx, trig_name, new_data); result = dns_qp_insert(qp, data, 0); nmdata_detach(&data); - goto done; + return result; } /* @@ -1454,15 +1502,11 @@ data->wild.qname |= new_data->wild.qname; data->wild.ns |= new_data->wild.ns; -done: - dns_qp_compact(qp, DNS_QPGC_MAYBE); - dns_qpmulti_commit(rpzs->table, &qp); - return result; } static isc_result_t -add_name(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, +add_name(dns_rpz_zone_t *rpz, dns_qp_t *qp, dns_rpz_type_t rpz_type, const dns_name_t *src_name) { nmdata_t new_data; dns_fixedname_t trig_namef; @@ -1475,9 +1519,16 @@ */ trig_name = dns_fixedname_initname(&trig_namef); - name2data(rpz, rpz_type, src_name, trig_name, &new_data); + result = name2data(DNS_RPZ_ERROR_LEVEL, rpz, rpz_type, src_name, + trig_name, &new_data); + /* + * Log complaints about bad owner names but let the zone load. + */ + if (result != ISC_R_SUCCESS) { + return ISC_R_SUCCESS; + } - result = add_nm(rpz->rpzs, trig_name, &new_data); + result = add_nm(rpz->rpzs, qp, trig_name, &new_data); /* * Do not worry if the node already exists, @@ -1522,7 +1573,8 @@ }; isc_rwlock_init(&rpzs->search_lock); - isc_mutex_init(&rpzs->maint_lock); + isc_mutex_init(&rpzs->data_lock); + atomic_init(&rpzs->shuttingdown, false); isc_refcount_init(&rpzs->references, 1); #ifdef USE_DNSRPS @@ -1549,7 +1601,7 @@ cleanup: isc_refcount_decrementz(&rpzs->references); isc_refcount_destroy(&rpzs->references); - isc_mutex_destroy(&rpzs->maint_lock); + isc_mutex_destroy(&rpzs->data_lock); isc_rwlock_destroy(&rpzs->search_lock); isc_mem_put(mctx, rpzs, sizeof(*rpzs)); @@ -1580,6 +1632,7 @@ .magic = DNS_RPZ_ZONE_MAGIC, .rpzs = rpzs, }; + isc_mutex_init(&rpz->update_lock); /* * This will never be used, but costs us nothing and @@ -1616,9 +1669,9 @@ REQUIRE(DNS_DB_VALID(db)); REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); - LOCK(&rpz->rpzs->maint_lock); + LOCK(&rpz->update_lock); - if (rpz->rpzs->shuttingdown) { + if (atomic_load(&rpz->rpzs->shuttingdown)) { result = ISC_R_SHUTTINGDOWN; goto unlock; } @@ -1660,7 +1713,7 @@ } unlock: - UNLOCK(&rpz->rpzs->maint_lock); + UNLOCK(&rpz->update_lock); return result; } @@ -1670,7 +1723,7 @@ REQUIRE(DNS_DB_VALID(db)); REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); - LOCK(&rpz->rpzs->maint_lock); + LOCK(&rpz->update_lock); dns_db_updatenotify_unregister(db, dns_rpz_dbupdate_callback, rpz); if (rpz->processed) { rpz->processed = false; @@ -1682,7 +1735,7 @@ INSIST(atomic_fetch_sub_acq_rel(&rpz->rpzs->zones_registered, 1) > 0); } - UNLOCK(&rpz->rpzs->maint_lock); + UNLOCK(&rpz->update_lock); } void @@ -1690,13 +1743,13 @@ REQUIRE(DNS_DB_VALID(db)); REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); - LOCK(&rpz->rpzs->maint_lock); + LOCK(&rpz->update_lock); if (!rpz->dbregistered) { rpz->dbregistered = true; atomic_fetch_add_acq_rel(&rpz->rpzs->zones_registered, 1); } dns_db_updatenotify_register(db, dns_rpz_dbupdate_callback, rpz); - UNLOCK(&rpz->rpzs->maint_lock); + UNLOCK(&rpz->update_lock); } static void @@ -1744,41 +1797,44 @@ } static void -update_rpz_done_cb(void *data, isc_result_t result ISC_ATTR_UNUSED) { - dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)data; +update_rpz_done_cb(void *data, isc_result_t result) { + rpz_update_t *update = data; + dns_rpz_zone_t *rpz = update->rpz; char dname[DNS_NAME_FORMATSIZE]; REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); - LOCK(&rpz->rpzs->maint_lock); + LOCK(&rpz->update_lock); rpz->updaterunning = false; dns_name_format(&rpz->origin, dname, DNS_NAME_FORMATSIZE); - if (rpz->updatepending && !rpz->rpzs->shuttingdown) { + if (rpz->updatepending && !atomic_load(&rpz->rpzs->shuttingdown)) { /* Restart the timer */ dns__rpz_timer_start(rpz); } - dns_db_closeversion(rpz->updb, &rpz->updbversion, false); - dns_db_detach(&rpz->updb); + dns_db_closeversion(update->db, &update->dbversion, false); + dns_db_detach(&update->db); if (rpz->dbregistered && !rpz->processed) { rpz->processed = true; atomic_fetch_add_acq_rel(&rpz->rpzs->zones_processed, 1); } - UNLOCK(&rpz->rpzs->maint_lock); + UNLOCK(&rpz->update_lock); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_INFO, "rpz: %s: reload done: %s", dname, - isc_result_totext(rpz->updateresult)); + isc_result_totext(result)); + isc_mem_put(rpz->rpzs->mctx, update, sizeof(*update)); dns_rpz_zones_unref(rpz->rpzs); } static isc_result_t -update_nodes(dns_rpz_zone_t *rpz, isc_ht_t *newnodes) { +update_nodes(dns_rpz_zone_t *rpz, dns_db_t *db, dns_dbversion_t *dbversion, + isc_ht_t *newnodes) { isc_result_t result; dns_dbiterator_t *updbit = NULL; dns_name_t *name = NULL; @@ -1790,7 +1846,7 @@ name = dns_fixedname_initname(&fixname); - result = dns_db_createiterator(rpz->updb, DNS_DB_NONSEC3, &updbit); + result = dns_db_createiterator(db, DNS_DB_NONSEC3, &updbit); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, @@ -1808,18 +1864,20 @@ goto cleanup; } - LOCK(&rpz->rpzs->maint_lock); + LOCK(&rpz->rpzs->data_lock); slow_mode = rpz->rpzs->p.slow_mode; - UNLOCK(&rpz->rpzs->maint_lock); + + dns_qp_t *qp = NULL; + dns_qpmulti_write(rpz->rpzs->table, &qp); while (result == ISC_R_SUCCESS) { char namebuf[DNS_NAME_FORMATSIZE]; dns_rdatasetiter_t *rdsiter = NULL; dns_dbnode_t *node = NULL; - result = dns__rpz_shuttingdown(rpz->rpzs); - if (result != ISC_R_SUCCESS) { - goto cleanup; + if (atomic_load(&rpz->rpzs->shuttingdown)) { + result = ISC_R_SHUTTINGDOWN; + goto done; } result = dns_dbiterator_current(updbit, &node, name); @@ -1828,28 +1886,28 @@ DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, "rpz: %s: failed to get dbiterator - %s", domain, isc_result_totext(result)); - goto cleanup; + goto done; } result = dns_dbiterator_pause(updbit); RUNTIME_CHECK(result == ISC_R_SUCCESS); - result = dns_db_allrdatasets(rpz->updb, node, rpz->updbversion, - 0, 0, &rdsiter); + result = dns_db_allrdatasets(db, node, dbversion, 0, 0, + &rdsiter); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, "rpz: %s: failed to fetch " "rrdatasets - %s", domain, isc_result_totext(result)); - dns_db_detachnode(rpz->updb, &node); - goto cleanup; + dns_db_detachnode(db, &node); + goto done; } result = dns_rdatasetiter_first(rdsiter); dns_rdatasetiter_destroy(&rdsiter); - dns_db_detachnode(rpz->updb, &node); + dns_db_detachnode(db, &node); if (result != ISC_R_SUCCESS) { /* skip empty non-terminal */ if (result != ISC_R_NOMORE) { @@ -1878,21 +1936,12 @@ } /* Does the entry exist in the old nodes table? */ - result = isc_ht_find(rpz->nodes, name->ndata, name->length, - NULL); + result = isc_ht_delete(rpz->nodes, name->ndata, name->length); if (result == ISC_R_SUCCESS) { /* found */ - isc_ht_delete(rpz->nodes, name->ndata, name->length); goto next; } - /* - * Only the single rpz updates are serialized, so we need to - * lock here because we can be processing more updates to - * different rpz zones at the same time - */ - LOCK(&rpz->rpzs->maint_lock); - result = rpz_add(rpz, name); - UNLOCK(&rpz->rpzs->maint_lock); + result = rpz_add(rpz, qp, name); if (result != ISC_R_SUCCESS) { dns_name_format(name, namebuf, sizeof(namebuf)); @@ -1922,6 +1971,11 @@ result = ISC_R_SUCCESS; } +done: + dns_qp_compact(qp, DNS_QPGC_MAYBE); + dns_qpmulti_commit(rpz->rpzs->table, &qp); + UNLOCK(&rpz->rpzs->data_lock); + cleanup: dns_dbiterator_destroy(&updbit); @@ -1934,9 +1988,13 @@ isc_ht_iter_t *iter = NULL; dns_name_t *name = NULL; dns_fixedname_t fixname; + dns_qp_t *qp = NULL; name = dns_fixedname_initname(&fixname); + LOCK(&rpz->rpzs->data_lock); + dns_qpmulti_write(rpz->rpzs->table, &qp); + isc_ht_iter_create(rpz->nodes, &iter); for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS; @@ -1956,51 +2014,46 @@ region.length = (unsigned int)keysize; dns_name_fromregion(name, ®ion); - LOCK(&rpz->rpzs->maint_lock); - rpz_del(rpz, name); - UNLOCK(&rpz->rpzs->maint_lock); + rpz_del(rpz, qp, name); } INSIST(result != ISC_R_SUCCESS); if (result == ISC_R_NOMORE) { result = ISC_R_SUCCESS; } + dns_qp_compact(qp, DNS_QPGC_MAYBE); + dns_qpmulti_commit(rpz->rpzs->table, &qp); + isc_ht_iter_destroy(&iter); + UNLOCK(&rpz->rpzs->data_lock); + return result; } static isc_result_t dns__rpz_shuttingdown(dns_rpz_zones_t *rpzs) { - bool shuttingdown = false; - - LOCK(&rpzs->maint_lock); - shuttingdown = rpzs->shuttingdown; - UNLOCK(&rpzs->maint_lock); - - if (shuttingdown) { + if (atomic_load(&rpzs->shuttingdown)) { return ISC_R_SHUTTINGDOWN; } return ISC_R_SUCCESS; } -static void +static isc_result_t update_rpz_cb(void *data) { - dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)data; + rpz_update_t *update = data; + dns_rpz_zone_t *rpz = update->rpz; isc_result_t result = ISC_R_SUCCESS; isc_ht_t *newnodes = NULL; REQUIRE(rpz->nodes != NULL); - result = dns__rpz_shuttingdown(rpz->rpzs); - if (result != ISC_R_SUCCESS) { - goto shuttingdown; - } + RETERR(dns__rpz_shuttingdown(rpz->rpzs)); isc_ht_init(&newnodes, rpz->rpzs->mctx, 1, ISC_HT_CASE_SENSITIVE); - result = update_nodes(rpz, newnodes); + result = update_nodes(rpz, update->db, update->dbversion, newnodes); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -2016,33 +2069,34 @@ cleanup: isc_ht_destroy(&newnodes); -shuttingdown: - rpz->updateresult = result; + return result; } static void dns__rpz_timer_cb(void *arg) { char domain[DNS_NAME_FORMATSIZE]; dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)arg; + rpz_update_t *update = NULL; REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); - REQUIRE(DNS_DB_VALID(rpz->db)); - REQUIRE(rpz->updb == NULL); - REQUIRE(rpz->updbversion == NULL); - LOCK(&rpz->rpzs->maint_lock); + LOCK(&rpz->update_lock); - if (rpz->rpzs->shuttingdown) { + if (atomic_load(&rpz->rpzs->shuttingdown)) { goto unlock; } + REQUIRE(DNS_DB_VALID(rpz->db)); rpz->updatepending = false; rpz->updaterunning = true; - rpz->updateresult = ISC_R_UNSET; - dns_db_attach(rpz->db, &rpz->updb); + update = isc_mem_get(rpz->rpzs->mctx, sizeof(*update)); + *update = (rpz_update_t){ + .rpz = rpz, + }; + dns_db_attach(rpz->db, &update->db); INSIST(rpz->dbversion != NULL); - rpz->updbversion = rpz->dbversion; + update->dbversion = rpz->dbversion; rpz->dbversion = NULL; dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE); @@ -2051,14 +2105,14 @@ dns_rpz_zones_ref(rpz->rpzs); isc_work_enqueue(rpz->loop, ISC_WORKLANE_SLOW, update_rpz_cb, - update_rpz_done_cb, rpz); + update_rpz_done_cb, update); isc_timer_destroy(&rpz->updatetimer); rpz->loop = NULL; rpz->lastupdated = isc_time_now(); unlock: - UNLOCK(&rpz->rpzs->maint_lock); + UNLOCK(&rpz->update_lock); } /* @@ -2096,7 +2150,7 @@ static void dns__rpz_shutdown(dns_rpz_zone_t *rpz) { - /* maint_lock must be locked */ + /* update_lock must be locked. */ if (rpz->updatetimer != NULL) { /* Don't wait for timer to trigger for shutdown */ INSIST(rpz->loop != NULL); @@ -2155,13 +2209,14 @@ INSIST(!rpz->updaterunning); isc_ht_destroy(&rpz->nodes); + isc_mutex_destroy(&rpz->update_lock); isc_mem_put(rpzs->mctx, rpz, sizeof(*rpz)); } static void dns__rpz_zones_destroy(dns_rpz_zones_t *rpzs) { - REQUIRE(rpzs->shuttingdown); + REQUIRE(atomic_load(&rpzs->shuttingdown)); for (dns_rpz_num_t rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; ++rpz_num) { @@ -2184,7 +2239,7 @@ dns_qpmulti_destroy(&rpzs->table); } - isc_mutex_destroy(&rpzs->maint_lock); + isc_mutex_destroy(&rpzs->data_lock); isc_rwlock_destroy(&rpzs->search_lock); isc_mem_putanddetach(&rpzs->mctx, rpzs, sizeof(*rpzs)); } @@ -2194,25 +2249,27 @@ REQUIRE(DNS_RPZ_ZONES_VALID(rpzs)); /* * Forget the last of the view's rpz machinery when shutting down. + * + * shuttingdown is monotonic: it changes from false to true and is never + * cleared. Publish it without taking update_lock or data_lock so + * workers can observe shutdown immediately. atomic_exchange() also + * preserves idempotency: only the caller that changes the flag performs + * the per-zone shutdown work. */ - - LOCK(&rpzs->maint_lock); - if (rpzs->shuttingdown) { - UNLOCK(&rpzs->maint_lock); + if (atomic_exchange(&rpzs->shuttingdown, true)) { return; } - rpzs->shuttingdown = true; - for (dns_rpz_num_t rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; ++rpz_num) { if (rpzs->zones[rpz_num] == NULL) { continue; } + LOCK(&rpzs->zones[rpz_num]->update_lock); dns__rpz_shutdown(rpzs->zones[rpz_num]); + UNLOCK(&rpzs->zones[rpz_num]->update_lock); } - UNLOCK(&rpzs->maint_lock); } #ifdef DNS_RPZ_TRACE @@ -2225,7 +2282,7 @@ * Add an IP address to the radix tree or a name to the summary database. */ static isc_result_t -rpz_add(dns_rpz_zone_t *rpz, const dns_name_t *src_name) { +rpz_add(dns_rpz_zone_t *rpz, dns_qp_t *qp, const dns_name_t *src_name) { dns_rpz_type_t rpz_type; isc_result_t result = ISC_R_FAILURE; dns_rpz_zones_t *rpzs = NULL; @@ -2242,7 +2299,7 @@ switch (rpz_type) { case DNS_RPZ_TYPE_QNAME: case DNS_RPZ_TYPE_NSDNAME: - result = add_name(rpz, rpz_type, src_name); + result = add_name(rpz, qp, rpz_type, src_name); break; case DNS_RPZ_TYPE_CLIENT_IP: case DNS_RPZ_TYPE_IP: @@ -2347,32 +2404,36 @@ } static void -del_name(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, +del_name(dns_rpz_zone_t *rpz, dns_qp_t *qp, dns_rpz_type_t rpz_type, const dns_name_t *src_name) { isc_result_t result; char namebuf[DNS_NAME_FORMATSIZE]; dns_fixedname_t trig_namef; dns_name_t *trig_name = NULL; - dns_rpz_zones_t *rpzs = rpz->rpzs; nmdata_t *data = NULL; nmdata_t del_data; - dns_qp_t *qp = NULL; bool exists; - dns_qpmulti_write(rpzs->table, &qp); - /* * We need a summary database of names even with 1 policy zone, * because wildcard triggers are handled differently. */ trig_name = dns_fixedname_initname(&trig_namef); - name2data(rpz, rpz_type, src_name, trig_name, &del_data); + /* + * Do not worry about invalid rpz owner names. If we are here, then + * something relevant was added and so was valid. + */ + result = name2data(DNS_RPZ_DEBUG_QUIET, rpz, rpz_type, src_name, + trig_name, &del_data); + if (result != ISC_R_SUCCESS) { + return; + } result = dns_qp_getname(qp, trig_name, (void **)&data, NULL); if (result != ISC_R_SUCCESS) { INSIST(data == NULL); - goto done; + return; } INSIST(data != NULL); @@ -2413,17 +2474,13 @@ adj_trigger_cnt(rpz, rpz_type, NULL, 0, false); RWUNLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write); } - -done: - dns_qp_compact(qp, DNS_QPGC_MAYBE); - dns_qpmulti_commit(rpzs->table, &qp); } /* * Remove an IP address from the radix tree or a name from the summary database. */ static void -rpz_del(dns_rpz_zone_t *rpz, const dns_name_t *src_name) { +rpz_del(dns_rpz_zone_t *rpz, dns_qp_t *qp, const dns_name_t *src_name) { dns_rpz_type_t rpz_type; dns_rpz_zones_t *rpzs = NULL; dns_rpz_num_t rpz_num; @@ -2439,7 +2496,7 @@ switch (rpz_type) { case DNS_RPZ_TYPE_QNAME: case DNS_RPZ_TYPE_NSDNAME: - del_name(rpz, rpz_type, src_name); + del_name(rpz, qp, rpz_type, src_name); break; case DNS_RPZ_TYPE_CLIENT_IP: case DNS_RPZ_TYPE_IP: diff -Nru bind9-9.20.26/lib/dns/ssu.c bind9-9.20.29/lib/dns/ssu.c --- bind9-9.20.26/lib/dns/ssu.c 2026-07-20 14:47:54.068850038 +0000 +++ bind9-9.20.29/lib/dns/ssu.c 2026-09-11 19:41:01.542331979 +0000 @@ -525,8 +525,8 @@ break; case dns_ssumatchtype_external: if (!dns_ssu_external_match(rule->identity, signer, - name, addr, type, key, - table->mctx)) + name, tcp ? addr : NULL, + type, key, table->mctx)) { continue; } diff -Nru bind9-9.20.26/lib/dns/stats.c bind9-9.20.29/lib/dns/stats.c --- bind9-9.20.26/lib/dns/stats.c 2026-07-20 14:47:54.068850038 +0000 +++ bind9-9.20.29/lib/dns/stats.c 2026-09-11 19:41:01.543332003 +0000 @@ -16,10 +16,12 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -97,22 +99,32 @@ #define RDTYPECOUNTER_MAXVAL 0x0602 /* - * DNSSEC sign statistics. - * - * Per key we maintain 3 counters. The first is actually no counter but - * a key id reference. The second is the number of signatures the key created. - * The third is the number of signatures refreshed by the key. + * DNSSEC signing counters are a small RCU-protected list keyed by the DNSKEY + * algorithm and key tag. The key is immutable after publication; the counters + * remain atomic for concurrent dumps. List mutations are serialized by the + * caller. */ - -/* Maximum number of keys to keep track of for DNSSEC signing statistics. */ -static int dnssecsign_num_keys = 4; -static int dnssecsign_block_size = 3; +typedef struct dns_dnssecsignstat { + isc_mem_t *mctx; + uint32_t key; + isc_atomic_statscounter_t signatures; + isc_atomic_statscounter_t refreshes; + struct cds_list_head link; + struct rcu_head rcu_head; +} dns_dnssecsignstat_t; + +typedef struct dns_dnssecsignstats { + struct cds_list_head keys; +} dns_dnssecsignstats_t; struct dns_stats { unsigned int magic; dns_statstype_t type; isc_mem_t *mctx; - isc_stats_t *counters; + union { + isc_stats_t *counters; + dns_dnssecsignstats_t *dnssec; + }; isc_refcount_t references; }; @@ -130,10 +142,27 @@ dns_rcodestats_dumper_t fn; void *arg; } rcodedumparg_t; -typedef struct dnssecsigndumparg { - dns_dnssecsignstats_dumper_t fn; - void *arg; -} dnssecsigndumparg_t; + +static void +dns_dnssecsignstat_destroy(struct rcu_head *rcu_head) { + dns_dnssecsignstat_t *entry = + caa_container_of(rcu_head, dns_dnssecsignstat_t, rcu_head); + + isc_mem_putanddetach(&entry->mctx, entry, sizeof(*entry)); +} + +static void +dns_dnssecsignstats_destroy(dns_stats_t *stats) { + dns_dnssecsignstats_t *dnssec = stats->dnssec; + + dns_dnssecsignstat_t *entry, *next; + cds_list_for_each_entry_safe(entry, next, &dnssec->keys, link) { + cds_list_del_rcu(&entry->link); + call_rcu(&entry->rcu_head, dns_dnssecsignstat_destroy); + } + + isc_mem_put(stats->mctx, dnssec, sizeof(*dnssec)); +} void dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) { @@ -156,7 +185,11 @@ if (isc_refcount_decrement(&stats->references) == 1) { isc_refcount_destroy(&stats->references); - isc_stats_detach(&stats->counters); + if (stats->type == dns_statstype_dnssec) { + dns_dnssecsignstats_destroy(stats); + } else { + isc_stats_detach(&stats->counters); + } isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); } } @@ -164,20 +197,26 @@ /*% * Create methods */ +static dns_stats_t * +allocate_stats(isc_mem_t *mctx, dns_statstype_t type) { + dns_stats_t *stats = isc_mem_get(mctx, sizeof(*stats)); + + *stats = (dns_stats_t){ + .magic = DNS_STATS_MAGIC, + .type = type, + .references = ISC_REFCOUNT_INITIALIZER(1), + }; + isc_mem_attach(mctx, &stats->mctx); + + return stats; +} + static void create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters, dns_stats_t **statsp) { - dns_stats_t *stats = isc_mem_get(mctx, sizeof(*stats)); - - stats->counters = NULL; - isc_refcount_init(&stats->references, 1); + dns_stats_t *stats = allocate_stats(mctx, type); isc_stats_create(mctx, &stats->counters, ncounters); - - stats->magic = DNS_STATS_MAGIC; - stats->type = type; - stats->mctx = NULL; - isc_mem_attach(mctx, &stats->mctx); *statsp = stats; } @@ -227,12 +266,16 @@ dns_dnssecsignstats_create(isc_mem_t *mctx, dns_stats_t **statsp) { REQUIRE(statsp != NULL && *statsp == NULL); - /* - * Create two counters per key, one is the key id, the other two are - * the actual counters for creating and refreshing signatures. - */ - create_stats(mctx, dns_statstype_dnssec, - dnssecsign_num_keys * dnssecsign_block_size, statsp); + dns_stats_t *stats = allocate_stats(mctx, dns_statstype_dnssec); + + dns_dnssecsignstats_t *dnssec = isc_mem_get(mctx, sizeof(*dnssec)); + *dnssec = (dns_dnssecsignstats_t){ + .keys = CDS_LIST_HEAD_INIT(dnssec->keys), + }; + + stats->dnssec = dnssec; + + *statsp = stats; } /*% @@ -347,80 +390,92 @@ } } +static void +dnssecsignstat_new(dns_stats_t *stats, uint32_t key, + dnssecsignstats_type_t operation) { + dns_dnssecsignstats_t *dnssec = stats->dnssec; + + dns_dnssecsignstat_t *entry = isc_mem_get(stats->mctx, sizeof(*entry)); + *entry = (dns_dnssecsignstat_t){ + .key = key, + .link = CDS_LIST_HEAD_INIT(entry->link), + }; + isc_mem_attach(stats->mctx, &entry->mctx); + + switch (operation) { + case dns_dnssecsignstats_sign: + atomic_init(&entry->signatures, 1); + break; + case dns_dnssecsignstats_refresh: + atomic_init(&entry->refreshes, 1); + break; + default: + UNREACHABLE(); + } + + cds_list_add_rcu(&entry->link, &dnssec->keys); +} + +static isc_result_t +dnssecsignstat_increment(dns_stats_t *stats, uint32_t key, + dnssecsignstats_type_t operation) { + dns_dnssecsignstats_t *dnssec = stats->dnssec; + dns_dnssecsignstat_t *entry; + cds_list_for_each_entry_rcu(entry, &dnssec->keys, link) { + if (entry->key != key) { + continue; + } + + switch (operation) { + case dns_dnssecsignstats_sign: + atomic_fetch_add_relaxed(&entry->signatures, 1); + break; + case dns_dnssecsignstats_refresh: + atomic_fetch_add_relaxed(&entry->refreshes, 1); + break; + default: + UNREACHABLE(); + } + return ISC_R_SUCCESS; + } + + return ISC_R_NOTFOUND; +} + void dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id, uint8_t alg, dnssecsignstats_type_t operation) { - uint32_t kval; - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_dnssec); - int num_keys = isc_stats_ncounters(stats->counters) / - dnssecsign_block_size; - - /* Shift algorithm in front of key tag, which is 16 bits */ - kval = (uint32_t)(alg << 16 | id); - - /* Look up correct counter. */ - for (int i = 0; i < num_keys; i++) { - int idx = i * dnssecsign_block_size; - uint32_t counter = isc_stats_get_counter(stats->counters, idx); - if (counter == kval) { - /* Match */ - isc_stats_increment(stats->counters, idx + operation); - return; - } - } + isc_result_t result; + uint32_t key = (uint32_t)alg << 16 | id; - /* No match found. Store key in unused slot. */ - for (int i = 0; i < num_keys; i++) { - int idx = i * dnssecsign_block_size; - uint32_t counter = isc_stats_get_counter(stats->counters, idx); - if (counter == 0) { - isc_stats_set(stats->counters, kval, idx); - isc_stats_increment(stats->counters, idx + operation); - return; - } + rcu_read_lock(); + result = dnssecsignstat_increment(stats, key, operation); + rcu_read_unlock(); + if (result == ISC_R_SUCCESS) { + return; } - /* No room, grow stats storage. */ - isc_stats_resize(&stats->counters, - num_keys * dnssecsign_block_size * 2); - - /* Reset counters for new key (new index, nidx). */ - int nidx = num_keys * dnssecsign_block_size; - isc_stats_set(stats->counters, kval, nidx); - isc_stats_set(stats->counters, 0, nidx + dns_dnssecsignstats_sign); - isc_stats_set(stats->counters, 0, nidx + dns_dnssecsignstats_refresh); - - /* And increment the counter for the given operation. */ - isc_stats_increment(stats->counters, nidx + operation); + dnssecsignstat_new(stats, key, operation); } void dns_dnssecsignstats_clear(dns_stats_t *stats, dns_keytag_t id, uint8_t alg) { - uint32_t kval; - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_dnssec); - int num_keys = isc_stats_ncounters(stats->counters) / - dnssecsign_block_size; + dns_dnssecsignstats_t *dnssec = stats->dnssec; + uint32_t key = (uint32_t)alg << 16 | id; - /* Shift algorithm in front of key tag, which is 16 bits */ - kval = (uint32_t)(alg << 16 | id); - - /* Look up correct counter. */ - for (int i = 0; i < num_keys; i++) { - int idx = i * dnssecsign_block_size; - uint32_t counter = isc_stats_get_counter(stats->counters, idx); - if (counter == kval) { - /* Match */ - isc_stats_set(stats->counters, 0, idx); - isc_stats_set(stats->counters, 0, - idx + dns_dnssecsignstats_sign); - isc_stats_set(stats->counters, 0, - idx + dns_dnssecsignstats_refresh); - return; + dns_dnssecsignstat_t *entry; + cds_list_for_each_entry(entry, &dnssec->keys, link) { + if (entry->key != key) { + continue; } + + cds_list_del_rcu(&entry->link); + call_rcu(&entry->rcu_head, dns_dnssecsignstat_destroy); + return; } } @@ -523,50 +578,36 @@ isc_stats_dump(stats->counters, rdataset_dumpcb, &arg, options); } -static void -dnssec_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) { - dnssecsigndumparg_t *dnssecarg = arg; - - dnssecarg->fn((uint32_t)counter, value, dnssecarg->arg); -} +void +dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation, + dns_dnssecsignstats_dumper_t dump_fn, void *arg, + unsigned int options) { + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_dnssec); -static void -dnssec_statsdump(isc_stats_t *stats, dnssecsignstats_type_t operation, - isc_stats_dumper_t dump_fn, void *arg, unsigned int options) { - int i, num_keys; - - num_keys = isc_stats_ncounters(stats) / dnssecsign_block_size; - for (i = 0; i < num_keys; i++) { - int idx = dnssecsign_block_size * i; - uint32_t kval, val; + dns_dnssecsignstats_t *dnssec = stats->dnssec; - kval = isc_stats_get_counter(stats, idx); - if (kval == 0) { - continue; + rcu_read_lock(); + dns_dnssecsignstat_t *entry; + cds_list_for_each_entry_rcu(entry, &dnssec->keys, link) { + isc_statscounter_t value; + + switch (operation) { + case dns_dnssecsignstats_sign: + value = atomic_load_acquire(&entry->signatures); + break; + case dns_dnssecsignstats_refresh: + value = atomic_load_acquire(&entry->refreshes); + break; + default: + UNREACHABLE(); } - val = isc_stats_get_counter(stats, idx + operation); - if ((options & ISC_STATSDUMP_VERBOSE) == 0 && val == 0) { + if ((options & ISC_STATSDUMP_VERBOSE) == 0 && value == 0) { continue; } - - dump_fn(kval, val, arg); + dump_fn(entry->key, value, arg); } -} - -void -dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation, - dns_dnssecsignstats_dumper_t dump_fn, void *arg0, - unsigned int options) { - dnssecsigndumparg_t arg; - - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_dnssec); - - arg.fn = dump_fn; - arg.arg = arg0; - - dnssec_statsdump(stats->counters, operation, dnssec_dumpcb, &arg, - options); + rcu_read_unlock(); } static void diff -Nru bind9-9.20.26/lib/dns/tkey.c bind9-9.20.29/lib/dns/tkey.c --- bind9-9.20.26/lib/dns/tkey.c 2026-07-20 14:47:54.068850038 +0000 +++ bind9-9.20.29/lib/dns/tkey.c 2026-09-11 19:41:01.543332003 +0000 @@ -675,6 +675,15 @@ dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); + /* + * 'tkeyname' gets destroyed by dns_message_reset(), create a + * local copy of it for buildquery(). + */ + dns_fixedname_t fixed; + dns_fixedname_init(&fixed); + dns_name_copy(tkeyname, dns_fixedname_name(&fixed)); + tkeyname = dns_fixedname_name(&fixed); + dns_message_reset(qmsg, DNS_MESSAGE_INTENTRENDER); CHECK(buildquery(qmsg, tkeyname, &tkey)); return DNS_R_CONTINUE; diff -Nru bind9-9.20.26/lib/dns/tsig.c bind9-9.20.29/lib/dns/tsig.c --- bind9-9.20.26/lib/dns/tsig.c 2026-07-20 14:47:54.069850054 +0000 +++ bind9-9.20.29/lib/dns/tsig.c 2026-09-11 19:41:01.543332003 +0000 @@ -609,8 +609,9 @@ isc_buffer_putuint48(&otherbuf, tsig.timesigned); } - if ((key->key != NULL) && (tsig.error != dns_tsigerror_badsig) && - (tsig.error != dns_tsigerror_badkey)) + if (key->key != NULL && tsig.error != dns_tsigerror_badsig && + tsig.error != dns_tsigerror_badkey && + tsig.error != dns_tsigerror_badtrunc) { unsigned char header[DNS_MESSAGE_HEADERLEN]; isc_buffer_t headerbuf; @@ -981,6 +982,8 @@ return result; } if (dns__tsig_algvalid(alg)) { + uint16_t digestbits = dst_key_getbits(key); + if (tsig.siglen > siglen) { tsig_log(msg->tsigkey, 2, "signature length too big"); return DNS_R_FORMERR; @@ -992,6 +995,21 @@ "signature length below minimum"); return DNS_R_FORMERR; } + + if (tsig.siglen > 0 && digestbits != 0 && + tsig.siglen < ((digestbits + 7) / 8)) + { + msg->tsigstatus = dns_tsigerror_badtrunc; + tsig_log(msg->tsigkey, 2, + "truncated signature length too small"); + return DNS_R_TSIGVERIFYFAILURE; + } + if (tsig.siglen > 0 && digestbits == 0 && tsig.siglen < siglen) + { + msg->tsigstatus = dns_tsigerror_badtrunc; + tsig_log(msg->tsigkey, 2, "signature length too small"); + return DNS_R_TSIGVERIFYFAILURE; + } } if (tsig.siglen > 0) { @@ -1152,27 +1170,6 @@ goto cleanup_context; } - if (dns__tsig_algvalid(alg)) { - uint16_t digestbits = dst_key_getbits(key); - - if (tsig.siglen > 0 && digestbits != 0 && - tsig.siglen < ((digestbits + 7) / 8)) - { - msg->tsigstatus = dns_tsigerror_badtrunc; - tsig_log(msg->tsigkey, 2, - "truncated signature length too small"); - result = DNS_R_TSIGVERIFYFAILURE; - goto cleanup_context; - } - if (tsig.siglen > 0 && digestbits == 0 && tsig.siglen < siglen) - { - msg->tsigstatus = dns_tsigerror_badtrunc; - tsig_log(msg->tsigkey, 2, "signature length too small"); - result = DNS_R_TSIGVERIFYFAILURE; - goto cleanup_context; - } - } - if (response && tsig.error != dns_rcode_noerror) { msg->tsigstatus = tsig.error; if (tsig.error == dns_tsigerror_badtime) { @@ -1284,6 +1281,8 @@ goto cleanup_querystruct; } if (dns__tsig_algvalid(alg)) { + uint16_t digestbits = dst_key_getbits(key); + if (tsig.siglen > siglen) { tsig_log(tsigkey, 2, "signature length too big"); @@ -1299,6 +1298,26 @@ result = DNS_R_FORMERR; goto cleanup_querystruct; } + + if (tsig.siglen > 0 && digestbits != 0 && + tsig.siglen < ((digestbits + 7) / 8)) + { + msg->tsigstatus = dns_tsigerror_badtrunc; + tsig_log(msg->tsigkey, 2, + "truncated signature length " + "too small"); + result = DNS_R_TSIGVERIFYFAILURE; + goto cleanup_querystruct; + } + if (tsig.siglen > 0 && digestbits == 0 && + tsig.siglen < siglen) + { + msg->tsigstatus = dns_tsigerror_badtrunc; + tsig_log(msg->tsigkey, 2, + "signature length too small"); + result = DNS_R_TSIGVERIFYFAILURE; + goto cleanup_querystruct; + } } } @@ -1456,35 +1475,6 @@ goto cleanup_context; } - alg = dst_key_alg(key); - result = dst_key_sigsize(key, &siglen); - if (result != ISC_R_SUCCESS) { - goto cleanup_context; - } - if (dns__tsig_algvalid(alg)) { - uint16_t digestbits = dst_key_getbits(key); - - if (tsig.siglen > 0 && digestbits != 0 && - tsig.siglen < ((digestbits + 7) / 8)) - { - msg->tsigstatus = dns_tsigerror_badtrunc; - tsig_log(msg->tsigkey, 2, - "truncated signature length " - "too small"); - result = DNS_R_TSIGVERIFYFAILURE; - goto cleanup_context; - } - if (tsig.siglen > 0 && digestbits == 0 && - tsig.siglen < siglen) - { - msg->tsigstatus = dns_tsigerror_badtrunc; - tsig_log(msg->tsigkey, 2, - "signature length too small"); - result = DNS_R_TSIGVERIFYFAILURE; - goto cleanup_context; - } - } - if (tsig.error != dns_rcode_noerror) { msg->tsigstatus = tsig.error; if (tsig.error == dns_tsigerror_badtime) { diff -Nru bind9-9.20.26/lib/dns/validator.c bind9-9.20.29/lib/dns/validator.c --- bind9-9.20.26/lib/dns/validator.c 2026-07-20 14:47:54.070850069 +0000 +++ bind9-9.20.29/lib/dns/validator.c 2026-09-11 19:41:01.544332027 +0000 @@ -120,6 +120,13 @@ #define MAXVALIDATIONFAILS(r) \ (((r)->attributes & VALATTR_MAXVALIDATIONFAILS) != 0) +/* + * How many DS x DNSKEY matching combinations to allow per validation + * permitted by max-validations-per-fetch; matching a DS against a DNSKEY + * (a keytag computation) is far cheaper than a signature validation. + */ +#define DS_DNSKEY_COMBINATIONS_PER_VALIDATION 2 + static void destroy_validator(dns_validator_t *val); @@ -133,7 +140,7 @@ static isc_result_t validate_async_run(dns_validator_t *val, isc_job_cb cb); static isc_result_t -validate_work_enqueue(dns_validator_t *val, isc_job_cb cb); +validate_work_enqueue(dns_validator_t *val, isc_work_cb cb); static void validate_dnskey(void *arg); @@ -164,6 +171,9 @@ create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, isc_job_cb callback, const char *caller); +static isc_result_t +view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type); + /*% * Ensure the validator's rdatasets are marked as expired. */ @@ -256,6 +266,76 @@ isc_async_run(val->loop, val->cb, val); } +static bool +closer_secure_ds_exists(dns_validator_t *val, const dns_name_t *signer, + const dns_name_t *name) { + dns_fixedname_t fl; + dns_name_t *l = dns_fixedname_initname(&fl); + unsigned int n = dns_name_countlabels(name); + unsigned int s = dns_name_countlabels(signer); + + for (unsigned int i = s + 1; i < n; i++) { + isc_result_t result; + bool secure; + + dns_name_getlabelsequence(name, n - i, i, l); + result = view_find(val, l, dns_rdatatype_ds); + secure = (result == ISC_R_SUCCESS && + val->frdataset.trust >= dns_trust_secure); + disassociate_rdatasets(val); + + if (secure) { + return true; + } + } + + return false; +} + +static bool +find_nsec_signer(dns_validator_t *val, dns_rdataset_t *sigp, + dns_name_t *signer) { + dns_rdata_rrsig_t sig; + + if (val->nvalidations != NULL && + dns_rdataset_count(sigp) >= isc_counter_getlimit(val->nvalidations)) + { + validator_log(val, ISC_LOG_DEBUG(3), + "is_insecure_referral: NSEC " + "RRSIG too many signatures; refusing " + "insecure-delegation proof"); + return false; + } + + for (isc_result_t result = dns_rdataset_first(sigp); + result == ISC_R_SUCCESS; result = dns_rdataset_next(sigp)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(sigp, &rdata); + + result = dns_rdata_tostruct(&rdata, &sig, NULL); + if (result != ISC_R_SUCCESS) { + validator_log(val, ISC_LOG_DEBUG(3), + "is_insecure_referral: NSEC " + "RRSIG invalid; refusing " + "insecure-delegation proof"); + return false; + } + + if (dns_name_countlabels(signer) == 0) { + dns_name_copy(&sig.signer, signer); + } else if (!dns_name_equal(signer, &sig.signer)) { + validator_log(val, ISC_LOG_DEBUG(3), + "is_insecure_referral: NSEC " + "RRSIG signers differ; refusing " + "insecure-delegation proof"); + return false; + } + } + + return dns_name_countlabels(signer) != 0; +} + /*% * The is_insecure_referral() function is called as part of seeking the DS * record. Look in the NSEC or NSEC3 record returned from a DS query to see if @@ -266,6 +346,11 @@ * are going to treat the message as insecure and just assume the DS was at * the delegation. * + * If 'crossed' is not NULL, it is set to true when a referral is rejected + * because the NSEC/NSEC3 signer sits above a known secure delegation point. + * Such a proof is forged: the caller can stop the insecurity walk rather than + * descend into more attacker-supplied labels. + * * Returns: *\li #true the NS bitmap was set in the NSEC or NSEC3 record, or * the NSEC3 covers the name (in case of opt-out), or @@ -276,28 +361,31 @@ static bool is_insecure_referral(dns_validator_t *val, dns_name_t *name, dns_rdataset_t *rdataset, isc_result_t dbresult, - const char *caller) { + const char *caller, bool *crossed) { dns_fixedname_t fixed; dns_label_t hashlabel; - dns_name_t nsec3name; + dns_name_t nsec3name = DNS_NAME_INITEMPTY; dns_rdata_nsec3_t nsec3; dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_t set; + dns_rdataset_t set = DNS_RDATASET_INIT; int order; int scope; - bool found; + bool found = false; isc_buffer_t buffer; isc_result_t result; unsigned char hash[NSEC3_MAX_HASH_LENGTH]; unsigned char owner[NSEC3_MAX_HASH_LENGTH]; unsigned int length; + dns_fixedname_t fsigner; + dns_name_t *signer = NULL; + dns_rdataset_t sigset = DNS_RDATASET_INIT; + const char *ntype = "NSEC"; - REQUIRE(dbresult == DNS_R_NXRRSET || dbresult == DNS_R_NCACHENXRRSET); - - dns_rdataset_init(&set); - if (dbresult == DNS_R_NXRRSET) { + switch (dbresult) { + case DNS_R_NXRRSET: dns_rdataset_clone(rdataset, &set); - } else { + break; + case DNS_R_NCACHENXRRSET: result = dns_ncache_getrdataset(rdataset, name, dns_rdatatype_nsec, &set); if (result == ISC_R_NOTFOUND) { @@ -312,11 +400,16 @@ } goto trynsec3; } + break; + default: + UNREACHABLE(); } INSIST(set.type == dns_rdatatype_nsec); - found = false; + /* + * Is there an NS in the NSEC? + */ result = dns_rdataset_first(&set); if (result == ISC_R_SUCCESS) { dns_rdataset_current(&set, &rdata); @@ -324,37 +417,105 @@ dns_rdata_reset(&rdata); } dns_rdataset_disassociate(&set); - return found; + + /* + * Recover the NSEC's RRSIG signer so its authority can be bounded. A + * cached proof keeps the signature in the ncache blob; a live NSEC has + * it in the parallel signature rdataset. + */ + if (found) { + dns_rdataset_t *sigp = NULL; + + if (dbresult == DNS_R_NCACHENXRRSET) { + if (dns_ncache_getsigrdataset(rdataset, name, + dns_rdatatype_nsec, + &sigset) == ISC_R_SUCCESS) + { + sigp = &sigset; + } + } else if (dns_rdataset_isassociated(&val->fsigrdataset) && + val->fsigrdataset.covers == dns_rdatatype_nsec) + { + sigp = &val->fsigrdataset; + } + + if (sigp != NULL) { + signer = dns_fixedname_initname(&fsigner); + if (!find_nsec_signer(val, sigp, signer)) { + found = false; + signer = NULL; + SET_IF_NOT_NULL(crossed, true); + } + } + if (sigp == &sigset) { + dns_rdataset_disassociate(&sigset); + } + } + + goto checksigner; trynsec3: + ntype = "NSEC3"; /* * Iterate over the ncache entry. */ - found = false; - dns_name_init(&nsec3name, NULL); dns_fixedname_init(&fixed); dns_name_downcase(name, dns_fixedname_name(&fixed), NULL); name = dns_fixedname_name(&fixed); + unsigned int nlabels = dns_name_countlabels(name); + for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { + if (dns_rdataset_isassociated(&set)) { + dns_rdataset_disassociate(&set); + } dns_ncache_current(rdataset, &nsec3name, &set); if (set.type != dns_rdatatype_nsec3) { - dns_rdataset_disassociate(&set); continue; } if (set.trust < dns_trust_secure) { - if (dns_rdataset_isassociated(&set)) { - dns_rdataset_disassociate(&set); - } continue; } + + unsigned int labels = dns_name_countlabels(&nsec3name); + if (labels < 2 || (labels - 1) > nlabels) { + /* An NSEC3 owner is a hash label below its zone. */ + continue; + } + + /* + * Only an NSEC3 whose zone encloses the DS name can say + * anything about it; dns_nsec3_noexistnodata() applies the + * same relevance gate. + */ + dns_name_t zone = DNS_NAME_INITEMPTY; + dns_name_getlabelsequence(&nsec3name, 1, labels - 1, &zone); + if (!dns_name_issubdomain(name, &zone)) { + validator_log(val, ISC_LOG_DEBUG(3), + "is_insecure_referral: NSEC3 owner zone " + "does not enclose the DS name; ignoring"); + signer = NULL; + continue; + } + + /* + * Remember this NSEC3's zone as the signer to bound. It is + * refreshed for every record so that, when one below triggers + * the terminal condition, 'signer' reflects that record -- not + * some earlier NSEC3. The bound check walks the cache and + * would disassociate 'rdataset' (== val->frdataset), which + * 'nsec3name' points into, so the zone is copied and the check + * runs only after the loop, at checksigner. + */ + signer = dns_fixedname_initname(&fsigner); + dns_name_copy(&zone, signer); + dns_name_getlabel(&nsec3name, 0, &hashlabel); isc_region_consume(&hashlabel, 1); isc_buffer_init(&buffer, owner, sizeof(owner)); result = isc_base32hexnp_decoderegion(&hashlabel, &buffer); if (result != ISC_R_SUCCESS) { - dns_rdataset_disassociate(&set); continue; } for (result = dns_rdataset_first(&set); result == ISC_R_SUCCESS; @@ -378,8 +539,8 @@ validator_log(val, ISC_LOG_DEBUG(3), "%s: too many iterations", caller); - dns_rdataset_disassociate(&set); - return true; + found = true; + goto checksigner; } length = isc_iterated_hash( hash, nsec3.hash, nsec3.iterations, nsec3.salt, @@ -391,8 +552,7 @@ if (order == 0) { found = dns_nsec3_typepresent(&rdata, dns_rdatatype_ns); - dns_rdataset_disassociate(&set); - return found; + goto checksigner; } if ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) == 0) { continue; @@ -407,12 +567,33 @@ (order > 0 || memcmp(hash, nsec3.next, length) < 0))) { - dns_rdataset_disassociate(&set); - return true; + found = true; + goto checksigner; } } + } + +checksigner: + if (dns_rdataset_isassociated(&set)) { dns_rdataset_disassociate(&set); } + + /* + * The proof claims an insecure delegation. Reject it if the NSEC/NSEC3 + * signer sits above a known secure delegation point: such a proof is + * forged by a zone above the real zone cut. + */ + if (found && signer != NULL && + closer_secure_ds_exists(val, signer, name)) + { + validator_log(val, ISC_LOG_DEBUG(3), + "is_insecure_referral: %s signer above known " + "secure DS; refusing insecure-delegation proof", + ntype); + SET_IF_NOT_NULL(crossed, true); + return false; + } + return found; } @@ -426,14 +607,19 @@ consume_validation_fail(dns_validator_t *val); static void +validate_answer_finish(void *arg); + +static void +validator_cancel_finish(dns_validator_t *validator); + +static isc_result_t resume_answer_with_key(void *arg) { dns_validator_t *val = arg; dns_rdataset_t *rdataset = &val->frdataset; if (CANCELED(val) || CANCELING(val)) { val->result = ISC_R_CANCELED; - (void)validate_async_run(val, resume_answer_with_key_done); - return; + return validate_async_run(val, resume_answer_with_key_done); } isc_result_t result = select_signing_key(val, rdataset); @@ -448,24 +634,29 @@ consume_validation_fail(val); } - (void)validate_async_run(val, resume_answer_with_key_done); + return validate_async_run(val, resume_answer_with_key_done); } static void resume_answer_with_key_done(void *arg) { dns_validator_t *val = arg; + val->attributes &= ~VALATTR_OFFLOADED; + if (CANCELING(val)) { + validator_cancel_finish(val); + val->result = ISC_R_CANCELED; + } + switch (val->result) { case ISC_R_CANCELED: /* Validation was canceled */ case ISC_R_SHUTTINGDOWN: /* Server shutting down */ case ISC_R_QUOTA: /* Validation fails quota reached */ - dns_validator_cancel(val); - break; + validate_answer_finish(val); + return; default: + resume_answer(val); break; } - - resume_answer(val); } /*% @@ -524,6 +715,12 @@ result = validate_async_run(val, resume_answer); } break; + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + case ISC_R_QUOTA: + /* Abort, abort, abort */ + result = eresult; + break; default: validator_log(val, ISC_LOG_DEBUG(3), "fetch_callback_dnskey: got %s", @@ -603,6 +800,12 @@ isc_result_totext(eresult)); result = proveunsecure(val, false, false); break; + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + case ISC_R_QUOTA: + /* Abort, abort, abort */ + result = eresult; + break; default: validator_log(val, ISC_LOG_DEBUG(3), "fetch_callback_ds: got %s", @@ -632,10 +835,11 @@ result = proveunsecure(val, true, true); break; case DNS_R_NXRRSET: - case DNS_R_NCACHENXRRSET: + case DNS_R_NCACHENXRRSET: { + bool crossed = false; if (is_insecure_referral(val, resp->foundname, &val->frdataset, eresult, - "fetch_callback_ds")) + "fetch_callback_ds", &crossed)) { /* * Failed to find a DS while trying to prove @@ -647,7 +851,18 @@ "no DS and this is a delegation"); break; } - FALLTHROUGH; + if (crossed) { + /* + * The NSEC/NSEC3 signer sits above a known + * secure delegation, so this proof is forged. + * Stop instead of descending further. + */ + result = DNS_R_NOTINSECURE; + break; + } + result = proveunsecure(val, false, true); + break; + } case DNS_R_CNAME: /* * Not a zone cut, so we have to keep looking for @@ -655,6 +870,12 @@ */ result = proveunsecure(val, false, true); break; + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + case ISC_R_QUOTA: + /* Abort, abort, abort */ + result = eresult; + break; default: validator_log(val, ISC_LOG_DEBUG(3), "fetch_callback_ds: got %s", @@ -770,17 +991,33 @@ bool have_dsset = (val->frdataset.type == dns_rdatatype_ds); dns_name_t *name = dns_fixedname_name(&val->fname); - if ((val->attributes & VALATTR_INSECURITY) != 0 && - val->frdataset.covers == dns_rdatatype_ds && - NEGATIVE(&val->frdataset) && - is_insecure_referral(val, name, &val->frdataset, - DNS_R_NCACHENXRRSET, - "validator_callback_ds")) - { - result = markanswer(val, "validator_callback_ds", - "no DS and this is a delegation"); - } else if ((val->attributes & VALATTR_INSECURITY) != 0) { - result = proveunsecure(val, have_dsset, true); + if ((val->attributes & VALATTR_INSECURITY) != 0) { + bool crossed = false; + bool insecure = false; + + if (val->frdataset.covers == dns_rdatatype_ds && + NEGATIVE(&val->frdataset)) + { + insecure = is_insecure_referral( + val, name, &val->frdataset, + DNS_R_NCACHENXRRSET, + "validator_callback_ds", &crossed); + } + + if (insecure) { + result = markanswer( + val, "validator_callback_ds", + "no DS and this is a delegation"); + } else if (crossed) { + /* + * The NSEC/NSEC3 signer sits above a known + * secure delegation, so this proof is forged. + * Stop instead of descending further. + */ + result = DNS_R_NOTINSECURE; + } else { + result = proveunsecure(val, have_dsset, true); + } } else { result = validate_async_run(val, validate_dnskey); } @@ -922,6 +1159,12 @@ unsigned int clabels; val->attributes |= VALATTR_FOUNDNOQNAME; + if (subvalidator->siginfo != NULL) { + dns_name_copy( + &subvalidator->siginfo->signer, + dns_fixedname_name( + &val->nseczone)); + } closest = dns_fixedname_name(&val->closest); clabels = dns_name_countlabels(closest); @@ -944,6 +1187,7 @@ if (NEEDNOQNAME(val)) { proofs[DNS_VALIDATOR_NOQNAMEPROOF] = subvalidator->name; + val->noqnametype = dns_rdatatype_nsec; } } } @@ -1715,9 +1959,6 @@ validate_answer_iter_done(dns_validator_t *val, isc_result_t result); static void -validator_cancel_finish(dns_validator_t *validator); - -static void validate_answer_iter_start(dns_validator_t *val) { isc_result_t result = ISC_R_SUCCESS; @@ -1777,12 +2018,9 @@ } static void -validate_answer_finish(void *arg); - -static void validate_answer_signing_key_done(void *arg); -static void +static isc_result_t validate_answer_signing_key(void *arg) { dns_validator_t *val = arg; isc_result_t result; @@ -1823,7 +2061,7 @@ break; } - (void)validate_async_run(val, validate_answer_signing_key_done); + return validate_async_run(val, validate_answer_signing_key_done); } static void @@ -1945,18 +2183,7 @@ validate_async_done(val, val->result); return; case ISC_R_QUOTA: - if (MAXVALIDATIONS(val)) { - validator_log(val, ISC_LOG_DEBUG(3), - "maximum number of validations exceeded"); - } else if (MAXVALIDATIONFAILS(val)) { - validator_log(val, ISC_LOG_DEBUG(3), - "maximum number of validation failures " - "exceeded"); - } else { - validator_log( - val, ISC_LOG_DEBUG(3), - "unknown error: validation quota exceeded"); - } + /* validate_async_done() logs the specific quota reason. */ validate_async_done(val, val->result); return; default: @@ -2067,7 +2294,7 @@ } static isc_result_t -validate_work_enqueue(dns_validator_t *val, isc_job_cb cb) { +validate_work_enqueue(dns_validator_t *val, isc_work_cb cb) { val->attributes |= VALATTR_OFFLOADED; val->offloaded_cb = cb; val->offloaded_work = isc_work_enqueue(val->loop, ISC_WORKLANE_FAST, cb, @@ -2077,6 +2304,22 @@ static void validate_async_done(dns_validator_t *val, isc_result_t result) { + if (result == ISC_R_QUOTA) { + /* + * Log the reason on the validator that actually hit the quota + * (it set the attribute); a parent that merely inherits the + * quota result from a sub-validation stays quiet. + */ + if (MAXVALIDATIONS(val)) { + validator_log(val, ISC_LOG_DEBUG(3), + "maximum number of validations exceeded"); + } else if (MAXVALIDATIONFAILS(val)) { + validator_log(val, ISC_LOG_DEBUG(3), + "maximum number of validation failures " + "exceeded"); + } + } + if (result == DNS_R_NOVALIDSIG && (val->attributes & VALATTR_TRIEDVERIFY) == 0) { @@ -2224,6 +2467,7 @@ switch (result) { case ISC_R_CANCELED: case ISC_R_SHUTTINGDOWN: + case ISC_R_QUOTA: /* Abort, abort, abort! */ break; case ISC_R_SUCCESS: @@ -2263,7 +2507,6 @@ isc_result_t result; dns_rdata_ds_t ds; - dns_rdata_reset(&dsrdata); dns_rdataset_current(val->dsset, &dsrdata); result = dns_rdata_tostruct(&dsrdata, &ds, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -2290,7 +2533,31 @@ return DNS_R_BADALG; } - val->validation_attempts++; + val->matchds_attempts++; + + /* + * Matching one DS against the DNSKEY RRset derives a key tag for + * every DNSKEY, so each DS that reaches this point costs one key-tag + * computation per key. Bound the accumulated DS-by-DNSKEY work at + * DS_DNSKEY_COMBINATIONS_PER_VALIDATION key tags per allowed + * validation and stop once it is exceeded, so a flood of mismatched + * (or matching but unsigned) DS records cannot force unbounded + * matching. Ignored DS (unsupported digest or algorithm) return + * above without being counted. A trust-anchor dsset is locally + * configured, not attacker supplied, and its rdataset has no count + * method. + */ + if (val->nvalidations != NULL && val->dsset != &val->fdsset) { + size_t keycount = dns_rdataset_count(val->rdataset); + + if ((size_t)val->matchds_attempts * keycount > + (size_t)isc_counter_getlimit(val->nvalidations) * + DS_DNSKEY_COMBINATIONS_PER_VALIDATION) + { + val->attributes |= VALATTR_MAXVALIDATIONS; + return ISC_R_QUOTA; + } + } /* * Find the DNSKEY matching the DS... @@ -2298,15 +2565,35 @@ result = dns_dnssec_matchdskey(val->name, &dsrdata, val->rdataset, &keyrdata); if (result != ISC_R_SUCCESS) { + val->validation_attempts++; validator_log(val, ISC_LOG_DEBUG(3), "no DNSKEY matching DS"); + /* + * A DS that matches no DNSKEY is wasted key-tag matching + * work; count it against the validation quota so a flood of + * mismatched DS records cannot force unbounded matching. + */ + consume_validation(val); + if (over_max_validations(val)) { + return ISC_R_QUOTA; + } return DNS_R_NOKEYMATCH; } + val->validation_attempts++; + /* * ... and check that it signed the DNSKEY RRset. */ result = check_signer(val, &keyrdata, ds.key_tag, ds.algorithm); - if (result != ISC_R_SUCCESS) { + switch (result) { + case ISC_R_SUCCESS: + break; + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + case ISC_R_QUOTA: + /* Abort, abort, abort */ + return result; + default: validator_log(val, ISC_LOG_DEBUG(3), "no RRSIG matching DS key"); @@ -2319,7 +2606,7 @@ static void validate_dnskey_dsset_next_done(void *arg); -static void +static isc_result_t validate_dnskey_dsset_next(void *arg) { dns_validator_t *val = arg; @@ -2334,7 +2621,7 @@ val->result = validate_dnskey_dsset(val); } - validate_async_run(val, validate_dnskey_dsset_next_done); + return validate_async_run(val, validate_dnskey_dsset_next_done); } static void @@ -2351,14 +2638,21 @@ switch (result) { case ISC_R_CANCELED: case ISC_R_SHUTTINGDOWN: + case ISC_R_QUOTA: /* Abort, abort, abort! */ break; case ISC_R_SUCCESS: case ISC_R_NOMORE: - /* We are done */ break; default: - /* Continue validation until we have success or no more data */ + /* + * A DS that matched no DNSKEY, or matched one that did not + * sign the RRset (for example a standby KSK), is not a + * validation failure: mismatched DS records are already + * charged against the quota in validate_dnskey_dsset() and + * signature failures inside verify(). Continue until we + * have success or no more data. + */ (void)validate_work_enqueue(val, validate_dnskey_dsset_next); return; } @@ -2374,25 +2668,18 @@ static void validate_dnskey_dsset_first(dns_validator_t *val) { - isc_result_t result; - if (CANCELED(val) || CANCELING(val)) { - result = ISC_R_CANCELED; + val->result = ISC_R_CANCELED; } else { - result = dns_rdataset_first(val->dsset); + val->result = dns_rdataset_first(val->dsset); } - if (result == ISC_R_SUCCESS) { + if (val->result == ISC_R_SUCCESS) { /* continue async run */ - result = validate_dnskey_dsset(val); - if (result != ISC_R_SUCCESS) { - (void)validate_work_enqueue(val, - validate_dnskey_dsset_next); - return; - } + val->result = validate_dnskey_dsset(val); } - validate_dnskey_dsset_done(val, result); + (void)validate_async_run(val, validate_dnskey_dsset_next_done); } static void @@ -2592,6 +2879,79 @@ return result; } +static dns_rdataset_t * +find_sigrdataset(const dns_name_t *name, dns_rdatatype_t covers) { + for (dns_rdataset_t *sigrdataset = ISC_LIST_HEAD(name->list); + sigrdataset != NULL; + sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) + { + if (sigrdataset->type == dns_rdatatype_rrsig && + sigrdataset->covers == covers) + { + return sigrdataset; + } + } + return NULL; +} + +/*% + * Return ISC_R_SUCCESS if every RRSIG covering an NSEC is signed by 'zonename'. + */ +static isc_result_t +valid_nsec_signer(dns_validator_t *val, dns_name_t *name, + dns_name_t *zonename) { + isc_result_t result = DNS_R_NOVALIDNSEC; + dns_rdataset_t sigset = DNS_RDATASET_INIT; + dns_rdataset_t *sigrdataset = NULL; + + if (zonename == NULL || dns_name_countlabels(zonename) == 0) { + return DNS_R_EMPTYNAME; + } + + if (val->message != NULL) { + sigrdataset = find_sigrdataset(name, dns_rdatatype_nsec); + if (sigrdataset == NULL) { + return DNS_R_NOVALIDNSEC; + } + } else { + RETERR(dns_ncache_getsigrdataset(val->rdataset, name, + dns_rdatatype_nsec, &sigset)); + + sigrdataset = &sigset; + } + + if (sigrdataset->trust != dns_trust_secure) { + result = DNS_R_NOVALIDNSEC; + goto cleanup; + } + + for (isc_result_t r = dns_rdataset_first(sigrdataset); + r == ISC_R_SUCCESS; r = dns_rdataset_next(sigrdataset)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_rrsig_t sig = { 0 }; + + dns_rdataset_current(sigrdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &sig, NULL)); + + bool equal = dns_name_equal(zonename, &sig.signer); + dns_rdata_freestruct(&sig); + if (!equal) { + validator_log(val, ISC_LOG_DEBUG(3), + "ignoring NSEC wildcard proof from a " + "different zone"); + result = DNS_R_NOVALIDNSEC; + goto cleanup; + } + } + +cleanup: + if (sigrdataset == &sigset && dns_rdataset_isassociated(&sigset)) { + dns_rdataset_disassociate(&sigset); + } + return result; +} + /*% * Look for NODATA at the wildcard and NOWILDCARD proofs in the * previously validated NSEC records. As these proofs are mutually @@ -2640,58 +3000,53 @@ continue; } - if (rdataset->type == dns_rdatatype_nsec && - (NEEDNODATA(val) || NEEDNOWILDCARD(val)) && - !FOUNDNODATA(val) && !FOUNDNOWILDCARD(val) && - dns_nsec_noexistnodata(val->type, wild, name, rdataset, - &exists, &data, NULL, validator_log, - val) == ISC_R_SUCCESS) + if ((!NEEDNODATA(val) && !NEEDNOWILDCARD(val)) || + FOUNDNODATA(val) || FOUNDNOWILDCARD(val)) { - dns_name_t **proofs = val->proofs; - if (exists && !data) { - val->attributes |= VALATTR_FOUNDNODATA; - } - if (exists && !data && NEEDNODATA(val)) { - proofs[DNS_VALIDATOR_NODATAPROOF] = name; - } - if (!exists) { - val->attributes |= VALATTR_FOUNDNOWILDCARD; - } - if (!exists && NEEDNOQNAME(val)) { - proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; - } - if (dns_rdataset_isassociated(&trdataset)) { - dns_rdataset_disassociate(&trdataset); - } - return ISC_R_SUCCESS; + continue; } - if (rdataset->type == dns_rdatatype_nsec3 && - (NEEDNODATA(val) || NEEDNOWILDCARD(val)) && - !FOUNDNODATA(val) && !FOUNDNOWILDCARD(val) && - dns_nsec3_noexistnodata( - val->type, wild, name, rdataset, zonename, &exists, - &data, NULL, NULL, NULL, NULL, NULL, NULL, - validator_log, val) == ISC_R_SUCCESS) - { - dns_name_t **proofs = val->proofs; - if (exists && !data) { - val->attributes |= VALATTR_FOUNDNODATA; - } - if (exists && !data && NEEDNODATA(val)) { - proofs[DNS_VALIDATOR_NODATAPROOF] = name; - } - if (!exists) { - val->attributes |= VALATTR_FOUNDNOWILDCARD; + dns_name_t **proofs = val->proofs; + switch (rdataset->type) { + case dns_rdatatype_nsec: + result = valid_nsec_signer(val, name, zonename); + if (result != ISC_R_SUCCESS) { + continue; } - if (!exists && NEEDNOQNAME(val)) { - proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; + result = dns_nsec_noexistnodata( + val->type, wild, name, rdataset, &exists, &data, + NULL, validator_log, val); + + if (result != ISC_R_SUCCESS) { + continue; } - if (dns_rdataset_isassociated(&trdataset)) { - dns_rdataset_disassociate(&trdataset); + break; + case dns_rdatatype_nsec3: + result = dns_nsec3_noexistnodata( + val->type, wild, name, rdataset, zonename, + &exists, &data, NULL, NULL, NULL, NULL, NULL, + NULL, validator_log, val); + if (result != ISC_R_SUCCESS) { + continue; } - return ISC_R_SUCCESS; + break; + default: + continue; } + + if (exists && !data) { + val->attributes |= VALATTR_FOUNDNODATA; + } + if (exists && !data && NEEDNODATA(val)) { + proofs[DNS_VALIDATOR_NODATAPROOF] = name; + } + if (!exists) { + val->attributes |= VALATTR_FOUNDNOWILDCARD; + } + if (!exists && NEEDNOQNAME(val)) { + proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; + } + break; } if (result == ISC_R_NOMORE) { result = ISC_R_SUCCESS; @@ -2818,6 +3173,7 @@ proofs[DNS_VALIDATOR_NOQNAMEPROOF] == NULL) { proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name; + val->noqnametype = dns_rdatatype_nsec3; } else if (setclosest) { proofs[DNS_VALIDATOR_CLOSESTENCLOSER] = name; } else if (NEEDNODATA(val) && @@ -2848,6 +3204,7 @@ if (!exists && setnearest) { val->attributes |= VALATTR_FOUNDNOQNAME; proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name; + val->noqnametype = dns_rdatatype_nsec3; if (optout) { val->attributes |= VALATTR_FOUNDOPTOUT; } @@ -3002,16 +3359,7 @@ continue; } - for (sigrdataset = ISC_LIST_HEAD(name->list); - sigrdataset != NULL; - sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) - { - if (sigrdataset->type == dns_rdatatype_rrsig && - sigrdataset->covers == rdataset->type) - { - break; - } - } + sigrdataset = find_sigrdataset(name, rdataset->type); result = validate_neg_rrset(val, name, rdataset, sigrdataset); @@ -3158,10 +3506,12 @@ /* * Do we need to check for the wildcard? */ - if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val) && + dns_name_t *nseczone = dns_fixedname_name(&val->nseczone); + if (dns_name_countlabels(nseczone) != 0 && FOUNDNOQNAME(val) && + FOUNDCLOSEST(val) && ((NEEDNODATA(val) && !FOUNDNODATA(val)) || NEEDNOWILDCARD(val))) { - result = checkwildcard(val, dns_rdatatype_nsec, NULL); + result = checkwildcard(val, dns_rdatatype_nsec, nseczone); if (result != ISC_R_SUCCESS) { return result; } @@ -3363,12 +3713,25 @@ return ISC_R_COMPLETE; } - if (is_insecure_referral(val, tname, &val->frdataset, result, - "seek_ds")) { - *resp = markanswer(val, "seek_ds (3)", - "this is a delegation"); - return ISC_R_COMPLETE; + bool crossed = false; + if (is_insecure_referral(val, tname, &val->frdataset, + result, "seek_ds", &crossed)) + { + *resp = markanswer(val, "seek_ds (3)", + "this is a delegation"); + return ISC_R_COMPLETE; + } + if (crossed) { + /* + * The NSEC/NSEC3 signer sits above a known + * secure delegation, so this insecurity proof + * is forged. Stop walking instead of descending + * into more attacker-supplied labels. + */ + *resp = DNS_R_NOTINSECURE; + return ISC_R_COMPLETE; + } } break; @@ -3732,6 +4095,7 @@ dns_rdataset_init(&val->fsigrdataset); dns_fixedname_init(&val->wild); dns_fixedname_init(&val->wildsigner); + dns_fixedname_init(&val->nseczone); dns_fixedname_init(&val->closest); val->start = isc_stdtime_now(); val->magic = VALIDATOR_MAGIC; diff -Nru bind9-9.20.26/lib/dns/xfrin.c bind9-9.20.29/lib/dns/xfrin.c --- bind9-9.20.26/lib/dns/xfrin.c 2026-07-20 14:47:54.070850069 +0000 +++ bind9-9.20.29/lib/dns/xfrin.c 2026-09-11 19:41:01.545332051 +0000 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -127,8 +128,7 @@ /* Diff queue */ bool diff_running; - struct __cds_wfcq_head diff_head; - struct cds_wfcq_tail diff_tail; + isc_queue_t diff_queue; _Atomic xfrin_state_t state; uint32_t expireopt; @@ -157,8 +157,6 @@ dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */ isc_buffer_t *lasttsig; /*%< The last TSIG */ - dst_context_t *tsigctx; /*%< TSIG verification context */ - unsigned int sincetsig; /*%< recvd since the last TSIG */ dns_transport_t *transport; @@ -195,15 +193,6 @@ #define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I') #define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC) -#define XFRIN_WORK_MAGIC ISC_MAGIC('X', 'f', 'r', 'W') -#define VALID_XFRIN_WORK(x) ISC_MAGIC_VALID(x, XFRIN_WORK_MAGIC) - -typedef struct xfrin_work { - unsigned int magic; - isc_result_t result; - dns_xfrin_t *xfr; -} xfrin_work_t; - /**************************************************************************/ /* * Forward declarations. @@ -303,7 +292,7 @@ return result; } -static void +static isc_result_t axfr_apply(void *arg); static isc_result_t @@ -319,13 +308,7 @@ CHECK(dns_zone_checknames(xfr->zone, name, rdata)); if (dns_diff_size(&xfr->diff) > 128) { - xfrin_work_t work = (xfrin_work_t){ - .magic = XFRIN_WORK_MAGIC, - .result = ISC_R_UNSET, - .xfr = xfr, - }; - axfr_apply((void *)&work); - CHECK(work.result); + CHECK(axfr_apply(xfr)); } CHECK(dns_difftuple_create(xfr->diff.mctx, op, name, ttl, rdata, @@ -340,12 +323,9 @@ /* * Store a set of AXFR RRs in the database. */ -static void +static isc_result_t axfr_apply(void *arg) { - xfrin_work_t *work = arg; - REQUIRE(VALID_XFRIN_WORK(work)); - - dns_xfrin_t *xfr = work->xfr; + dns_xfrin_t *xfr = arg; REQUIRE(VALID_XFRIN(xfr)); isc_result_t result = ISC_R_SUCCESS; @@ -365,17 +345,13 @@ cleanup: dns_diff_clear(&xfr->diff); - work->result = result; + + return result; } static void -axfr_apply_done(void *arg, isc_result_t eresult) { - xfrin_work_t *work = arg; - REQUIRE(VALID_XFRIN_WORK(work)); - - dns_xfrin_t *xfr = work->xfr; - isc_result_t result = (eresult == ISC_R_SUCCESS) ? work->result - : eresult; +axfr_apply_done(void *arg, isc_result_t result) { + dns_xfrin_t *xfr = arg; REQUIRE(VALID_XFRIN(xfr)); @@ -394,8 +370,6 @@ cleanup: xfr->diff_running = false; - isc_mem_put(xfr->mctx, work, sizeof(*work)); - if (result == ISC_R_SUCCESS) { if (atomic_load(&xfr->state) == XFRST_AXFR_END) { xfrin_end(xfr, result); @@ -411,15 +385,10 @@ axfr_commit(dns_xfrin_t *xfr) { REQUIRE(!xfr->diff_running); - xfrin_work_t *work = isc_mem_get(xfr->mctx, sizeof(*work)); - *work = (xfrin_work_t){ - .magic = XFRIN_WORK_MAGIC, - .result = ISC_R_UNSET, - .xfr = dns_xfrin_ref(xfr), - }; + dns_xfrin_ref(xfr); xfr->diff_running = true; isc_work_enqueue(xfr->loop, ISC_WORKLANE_SLOW, axfr_apply, - axfr_apply_done, work); + axfr_apply_done, xfr); } static isc_result_t @@ -440,7 +409,7 @@ typedef struct ixfr_apply_data { dns_diff_t diff; /*%< Pending database changes */ - struct cds_wfcq_node wfcq_node; + isc_queue_node_t queue_node; } ixfr_apply_data_t; static isc_result_t @@ -561,30 +530,24 @@ return result; } -static void +static isc_result_t ixfr_apply(void *arg) { - xfrin_work_t *work = arg; - dns_xfrin_t *xfr = work->xfr; + dns_xfrin_t *xfr = arg; isc_result_t result = ISC_R_SUCCESS; REQUIRE(VALID_XFRIN(xfr)); - REQUIRE(VALID_XFRIN_WORK(work)); - struct __cds_wfcq_head diff_head; - struct cds_wfcq_tail diff_tail; + isc_queue_t diff_queue; - /* Initialize local wfcqueue */ - __cds_wfcq_init(&diff_head, &diff_tail); + /* Initialize local queue */ + isc_queue_init(&diff_queue); - enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking( - &diff_head, &diff_tail, &xfr->diff_head, &xfr->diff_tail); - INSIST(ret == CDS_WFCQ_RET_DEST_EMPTY); - - struct cds_wfcq_node *node, *next; - __cds_wfcq_for_each_blocking_safe(&diff_head, &diff_tail, node, next) { - ixfr_apply_data_t *data = - caa_container_of(node, ixfr_apply_data_t, wfcq_node); + if (!isc_queue_splice(&diff_queue, &xfr->diff_queue)) { + return ISC_R_SUCCESS; + } + ixfr_apply_data_t *data = NULL, *next = NULL; + isc_queue_for_each_entry_safe(&diff_queue, data, next, queue_node) { if (atomic_load(&xfr->shuttingdown)) { result = ISC_R_SHUTTINGDOWN; } @@ -600,20 +563,14 @@ isc_mem_put(xfr->mctx, data, sizeof(*data)); } - work->result = result; + return result; } static void -ixfr_apply_done(void *arg, isc_result_t eresult) { - xfrin_work_t *work = arg; - REQUIRE(VALID_XFRIN_WORK(work)); - - dns_xfrin_t *xfr = work->xfr; +ixfr_apply_done(void *arg, isc_result_t result) { + dns_xfrin_t *xfr = arg; REQUIRE(VALID_XFRIN(xfr)); - isc_result_t result = (eresult == ISC_R_SUCCESS) ? work->result - : eresult; - if (atomic_load(&xfr->shuttingdown)) { result = ISC_R_SHUTTINGDOWN; } @@ -621,19 +578,15 @@ CHECK(result); /* Reschedule */ - if (!xfr->retry_axfr && - !cds_wfcq_empty(&xfr->diff_head, &xfr->diff_tail)) - { + if (!xfr->retry_axfr && !isc_queue_empty(&xfr->diff_queue)) { isc_work_enqueue(xfr->loop, ISC_WORKLANE_SLOW, ixfr_apply, - ixfr_apply_done, work); + ixfr_apply_done, xfr); return; } cleanup: xfr->diff_running = false; - isc_mem_put(xfr->mctx, work, sizeof(*work)); - /* * Don't retry with AXFR (even if it was requested) because there was * an error or the transfer is shutting down. In case if it _was_ an @@ -684,7 +637,7 @@ ixfr_apply_data_t *data = isc_mem_get(xfr->mctx, sizeof(*data)); *data = (ixfr_apply_data_t){ 0 }; - cds_wfcq_node_init(&data->wfcq_node); + isc_queue_node_init(&data->queue_node); if (xfr->ver == NULL) { CHECK(dns_db_newversion(xfr->db, &xfr->ver)); @@ -694,19 +647,13 @@ /* FIXME: Should we add dns_diff_move() */ ISC_LIST_MOVE(data->diff.tuples, xfr->diff.tuples); - (void)cds_wfcq_enqueue(&xfr->diff_head, &xfr->diff_tail, - &data->wfcq_node); + isc_queue_enqueue(&xfr->diff_queue, &data->queue_node); if (!xfr->diff_running) { - xfrin_work_t *work = isc_mem_get(xfr->mctx, sizeof(*work)); - *work = (xfrin_work_t){ - .magic = XFRIN_WORK_MAGIC, - .result = ISC_R_UNSET, - .xfr = dns_xfrin_ref(xfr), - }; + dns_xfrin_ref(xfr); xfr->diff_running = true; isc_work_enqueue(xfr->loop, ISC_WORKLANE_SLOW, ixfr_apply, - ixfr_apply_done, work); + ixfr_apply_done, xfr); } cleanup: @@ -1288,7 +1235,7 @@ dns_view_weakattach(dns_zone_getview(zone), &xfr->view); dns_name_init(&xfr->name, NULL); - __cds_wfcq_init(&xfr->diff_head, &xfr->diff_tail); + isc_queue_init(&xfr->diff_queue); atomic_init(&xfr->is_ixfr, false); @@ -1691,10 +1638,6 @@ xfr->nbytes_saved = 0; msg->id = xfr->id; - if (xfr->tsigctx != NULL) { - dst_context_destroy(&xfr->tsigctx); - } - CHECK(render(msg, xfr->mctx, &xfr->qbuffer)); /* @@ -1823,7 +1766,6 @@ dns_xfrin_t *xfr = (dns_xfrin_t *)arg; dns_message_t *msg = NULL; dns_name_t *name = NULL; - const dns_name_t *tsigowner = NULL; isc_buffer_t buffer; REQUIRE(VALID_XFRIN(xfr)); @@ -1847,9 +1789,6 @@ CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); dns_message_setquerytsig(msg, xfr->lasttsig); - msg->tsigctx = xfr->tsigctx; - xfr->tsigctx = NULL; - dns_message_setclass(msg, xfr->rdclass); msg->tcp_continuation = (atomic_load_relaxed(&xfr->nmsg) > 0) ? 1 : 0; @@ -1871,6 +1810,22 @@ LIBDNS_XFRIN_RECV_PARSED(xfr, xfr->info, result); + /* Authenticate before stateful response handling. */ + if (result == ISC_R_SUCCESS) { + result = dns_message_checksig(msg, xfr->view); + if (result != ISC_R_SUCCESS) { + xfrin_log(xfr, ISC_LOG_DEBUG(3), + "TSIG check failed: %s", + isc_result_totext(result)); + goto cleanup; + } + if (dns_message_gettsigkey(msg) != NULL && + dns_message_gettsig(msg, NULL) == NULL) + { + CLEANUP(DNS_R_EXPECTEDTSIG); + } + } + if (result != ISC_R_SUCCESS || msg->rcode != dns_rcode_noerror || msg->opcode != dns_opcode_query || msg->rdclass != xfr->rdclass) { @@ -2007,19 +1962,11 @@ CHECK(DNS_R_NOTAUTHORITATIVE); } - result = dns_message_checksig(msg, xfr->view); - if (result != ISC_R_SUCCESS) { - xfrin_log(xfr, ISC_LOG_DEBUG(3), "TSIG check failed: %s", - isc_result_totext(result)); - goto cleanup; - } - for (result = dns_message_firstname(msg, DNS_SECTION_ANSWER); result == ISC_R_SUCCESS; result = dns_message_nextname(msg, DNS_SECTION_ANSWER)) { dns_rdataset_t *rds = NULL; - LIBDNS_XFRIN_RECV_ANSWER(xfr, xfr->info, msg); name = NULL; @@ -2042,12 +1989,7 @@ } CHECK(result); - if (dns_message_gettsig(msg, &tsigowner) != NULL) { - /* - * Reset the counter. - */ - xfr->sincetsig = 0; - + if (dns_message_gettsig(msg, NULL) != NULL) { /* * Free the last tsig, if there is one. */ @@ -2059,15 +2001,6 @@ * Update the last tsig pointer. */ CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); - } else if (dns_message_gettsigkey(msg) != NULL) { - xfr->sincetsig++; - if (xfr->sincetsig > 100 || - atomic_load_relaxed(&xfr->nmsg) == 0 || - atomic_load(&xfr->state) == XFRST_AXFR_END || - atomic_load(&xfr->state) == XFRST_IXFR_END) - { - CHECK(DNS_R_EXPECTEDTSIG); - } } /* @@ -2076,13 +2009,6 @@ atomic_fetch_add_relaxed(&xfr->nmsg, 1); atomic_fetch_add_relaxed(&xfr->nbytes, buffer.used); - /* - * Take the context back. - */ - INSIST(xfr->tsigctx == NULL); - xfr->tsigctx = msg->tsigctx; - msg->tsigctx = NULL; - if (!xfr->expireoptset && msg->opt != NULL) { get_edns_expire(xfr, msg); } @@ -2131,11 +2057,16 @@ static void xfrin_ixfrcleanup(dns_xfrin_t *xfr) { - struct cds_wfcq_node *node, *next; - __cds_wfcq_for_each_blocking_safe(&xfr->diff_head, &xfr->diff_tail, - node, next) { - ixfr_apply_data_t *data = - caa_container_of(node, ixfr_apply_data_t, wfcq_node); + isc_queue_t diff_queue; + + /* Leave the shared queue empty before freeing its entries. */ + isc_queue_init(&diff_queue); + if (!isc_queue_splice(&diff_queue, &xfr->diff_queue)) { + return; + } + + ixfr_apply_data_t *data = NULL, *next = NULL; + isc_queue_for_each_entry_safe(&diff_queue, data, next, queue_node) { /* We need to clear and free all data chunks */ dns_diff_clear(&data->diff); isc_mem_put(xfr->mctx, data, sizeof(*data)); @@ -2219,10 +2150,6 @@ (void)dns_db_endload(xfr->db, &xfr->axfr); } - if (xfr->tsigctx != NULL) { - dst_context_destroy(&xfr->tsigctx); - } - if (xfr->name.attributes.dynamic) { dns_name_free(&xfr->name, xfr->mctx); } diff -Nru bind9-9.20.26/lib/dns/zone.c bind9-9.20.29/lib/dns/zone.c --- bind9-9.20.26/lib/dns/zone.c 2026-07-20 14:47:54.073850116 +0000 +++ bind9-9.20.29/lib/dns/zone.c 2026-09-11 19:41:01.547332099 +0000 @@ -13021,6 +13021,11 @@ dns_notify_t *notify = NULL; dns_view_t *view = dns_zone_getview(zone); + dst = dns_remote_curraddr(&zone->notify); + if (isc_sockaddr_disabled(&dst)) { + goto next; + } + if (dns_remote_keyname(&zone->notify) != NULL) { dns_name_t *keyname = dns_remote_keyname(&zone->notify); (void)dns_view_gettsig(view, keyname, &key); @@ -13050,22 +13055,9 @@ flags |= DNS_NOTIFY_TCP; } - /* TODO: glue the transport to the notify */ - - dst = dns_remote_curraddr(&zone->notify); src = dns_remote_sourceaddr(&zone->notify); INSIST(isc_sockaddr_pf(&src) == isc_sockaddr_pf(&dst)); - if (isc_sockaddr_disabled(&dst)) { - if (key != NULL) { - dns_tsigkey_detach(&key); - } - if (transport != NULL) { - dns_transport_detach(&transport); - } - goto next; - } - if (notify_isqueued(zone, flags, NULL, &dst, key, transport)) { if (key != NULL) { dns_tsigkey_detach(&key); @@ -21575,6 +21567,7 @@ unsigned int options, timeout; bool have_checkdssource = false; bool canceled = checkds->rlevent->canceled; + isc_tlsctx_cache_t *zmgr_tlsctx_cache = NULL; REQUIRE(DNS_CHECKDS_VALID(checkds)); @@ -21687,16 +21680,22 @@ timeout = 5; options |= DNS_REQUESTOPT_TCP; + + zmgr_tlsctx_attach(checkds->zone->zmgr, &zmgr_tlsctx_cache); + result = dns_request_create( checkds->zone->view->requestmgr, message, &src, &checkds->dst, - NULL, NULL, options, key, timeout * 3 + 1, timeout, 2, - checkds->zone->loop, checkds_done, checkds, &checkds->request); + checkds->transport, zmgr_tlsctx_cache, options, key, + timeout * 3 + 1, timeout, 2, checkds->zone->loop, checkds_done, + checkds, &checkds->request); if (result != ISC_R_SUCCESS) { dns_zone_log(checkds->zone, ISC_LOG_DEBUG(3), "checkds: dns_request_create() to %s failed: %s", addrbuf, isc_result_totext(result)); } + isc_tlsctx_cache_detach(&zmgr_tlsctx_cache); + cleanup_key: if (key != NULL) { dns_tsigkey_detach(&key); @@ -21755,11 +21754,6 @@ default: UNREACHABLE(); } - /* - * XXXWMM: Should we attach key and transport here? - * Probably not, because we expect the name servers to be - * publicly available on the default transport protocol. - */ result = isc_ratelimiter_enqueue( newcheckds->zone->zmgr->checkdsrl, @@ -21808,6 +21802,11 @@ i++; + dst = dns_remote_curraddr(&zone->parentals); + if (isc_sockaddr_disabled(&dst)) { + goto next; + } + if (dns_remote_keyname(&zone->parentals) != NULL) { dns_name_t *keyname = dns_remote_keyname(&zone->parentals); @@ -21817,29 +21816,29 @@ if (dns_remote_tlsname(&zone->parentals) != NULL) { dns_name_t *tlsname = dns_remote_tlsname(&zone->parentals); - (void)dns_view_gettransport(view, DNS_TRANSPORT_TLS, - tlsname, &transport); - dns_zone_logc( - zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, - "got TLS configuration for zone transfer"); + result = dns_view_gettransport(view, DNS_TRANSPORT_TLS, + tlsname, &transport); + if (result == ISC_R_SUCCESS) { + dns_zone_logc( + zone, DNS_LOGCATEGORY_XFER_IN, + ISC_LOG_INFO, + "got TLS configuration for checkds"); + } else { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, + ISC_LOG_ERROR, + "could not get TLS configuration " + "for checkds: %s", + isc_result_totext(result)); + if (key != NULL) { + dns_tsigkey_detach(&key); + } + goto next; + } } - dst = dns_remote_curraddr(&zone->parentals); src = dns_remote_sourceaddr(&zone->parentals); INSIST(isc_sockaddr_pf(&src) == isc_sockaddr_pf(&dst)); - if (isc_sockaddr_disabled(&dst)) { - if (key != NULL) { - dns_tsigkey_detach(&key); - } - if (transport != NULL) { - dns_transport_detach(&transport); - } - goto next; - } - - /* TODO: glue the transport to the checkds request */ - if (checkds_isqueued(zone, NULL, &dst, key, transport)) { dns_zone_log(zone, ISC_LOG_DEBUG(3), "checkds: DS query to parent " diff -Nru bind9-9.20.26/lib/dns/zoneverify.c bind9-9.20.29/lib/dns/zoneverify.c --- bind9-9.20.26/lib/dns/zoneverify.c 2026-07-20 14:47:54.073850116 +0000 +++ bind9-9.20.29/lib/dns/zoneverify.c 2026-09-11 19:41:01.548332123 +0000 @@ -61,6 +61,7 @@ dns_keytable_t *secroots; bool goodksk; bool goodzsk; + bool nseconly; dns_rdataset_t keyset; dns_rdataset_t keysigs; dns_rdataset_t soaset; @@ -620,17 +621,16 @@ static isc_result_t isoptout(const vctx_t *vctx, const dns_rdata_nsec3param_t *nsec3param, bool *optout) { - dns_rdataset_t rdataset; + dns_rdataset_t rdataset = DNS_RDATASET_INIT; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_nsec3_t nsec3; dns_fixedname_t fixed; - dns_name_t *hashname; + dns_name_t *hashname = dns_fixedname_initname(&fixed); isc_result_t result; dns_dbnode_t *node = NULL; unsigned char rawhash[NSEC3_MAX_HASH_LENGTH]; size_t rhsize = sizeof(rawhash); - dns_fixedname_init(&fixed); result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, vctx->origin, vctx->origin, nsec3param->hash, nsec3param->iterations, nsec3param->salt, @@ -641,27 +641,21 @@ return result; } - dns_rdataset_init(&rdataset); - hashname = dns_fixedname_name(&fixed); result = dns_db_findnsec3node(vctx->db, hashname, false, &node); if (result == ISC_R_SUCCESS) { result = dns_db_findrdataset(vctx->db, node, vctx->ver, dns_rdatatype_nsec3, 0, 0, &rdataset, NULL); } + if (result == ISC_R_SUCCESS) { + result = dns_rdataset_first(&rdataset); + } if (result != ISC_R_SUCCESS) { *optout = false; result = ISC_R_SUCCESS; goto done; } - result = dns_rdataset_first(&rdataset); - if (result != ISC_R_SUCCESS) { - zoneverify_log_error(vctx, "dns_rdataset_first(): %s", - isc_result_totext(result)); - goto done; - } - dns_rdataset_current(&rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &nsec3, NULL); @@ -681,51 +675,36 @@ static isc_result_t verifynsec3(const vctx_t *vctx, const dns_name_t *name, - const dns_rdata_t *rdata, bool delegation, bool empty, - const unsigned char types[8192], unsigned int maxtype, + const dns_rdata_nsec3param_t *nsec3param, bool delegation, + bool empty, const unsigned char types[8192], unsigned int maxtype, isc_result_t *vresult) { char namebuf[DNS_NAME_FORMATSIZE]; char hashbuf[DNS_NAME_FORMATSIZE]; - dns_rdataset_t rdataset; - dns_rdata_nsec3param_t nsec3param; + dns_rdataset_t rdataset = DNS_RDATASET_INIT; dns_fixedname_t fixed; - dns_name_t *hashname; - isc_result_t result, tvresult = ISC_R_UNSET; + dns_name_t *hashname = dns_fixedname_initname(&fixed); + isc_result_t result; dns_dbnode_t *node = NULL; unsigned char rawhash[NSEC3_MAX_HASH_LENGTH]; size_t rhsize = sizeof(rawhash); bool optout = false; - result = dns_rdata_tostruct(rdata, &nsec3param, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - - if (nsec3param.flags != 0) { - return ISC_R_SUCCESS; - } + INSIST(nsec3param->flags == 0); - if (!dns_nsec3_supportedhash(nsec3param.hash)) { - return ISC_R_SUCCESS; - } - - if (nsec3param.iterations > DNS_NSEC3_MAXITERATIONS) { - result = DNS_R_NSEC3ITERRANGE; - zoneverify_log_error(vctx, "verifynsec3: %s", - isc_result_totext(result)); - return result; - } - - result = isoptout(vctx, &nsec3param, &optout); + result = isoptout(vctx, nsec3param, &optout); if (result != ISC_R_SUCCESS) { + *vresult = result; return result; } - dns_fixedname_init(&fixed); - result = dns_nsec3_hashname( - &fixed, rawhash, &rhsize, name, vctx->origin, nsec3param.hash, - nsec3param.iterations, nsec3param.salt, nsec3param.salt_length); + result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, name, + vctx->origin, nsec3param->hash, + nsec3param->iterations, nsec3param->salt, + nsec3param->salt_length); if (result != ISC_R_SUCCESS) { zoneverify_log_error(vctx, "dns_nsec3_hashname(): %s", isc_result_totext(result)); + *vresult = result; return result; } @@ -735,8 +714,6 @@ * from dnssec-signzone so the secure status of the zone may not * be up to date. */ - dns_rdataset_init(&rdataset); - hashname = dns_fixedname_name(&fixed); result = dns_db_findnsec3node(vctx->db, hashname, false, &node); if (result == ISC_R_SUCCESS) { result = dns_db_findrdataset(vctx->db, node, vctx->ver, @@ -744,7 +721,7 @@ &rdataset, NULL); } if (result != ISC_R_SUCCESS && - (!delegation || (empty && !optout) || + (!delegation || !optout || (!empty && dns_nsec_isset(types, dns_rdatatype_ds)))) { dns_name_format(name, namebuf, sizeof(namebuf)); @@ -755,9 +732,11 @@ { result = ISC_R_SUCCESS; } else if (result == ISC_R_SUCCESS) { - result = match_nsec3(vctx, name, &nsec3param, &rdataset, types, + isc_result_t tvresult = ISC_R_UNSET; + result = match_nsec3(vctx, name, nsec3param, &rdataset, types, maxtype, rawhash, rhsize, &tvresult); if (result != ISC_R_SUCCESS) { + *vresult = tvresult; goto done; } result = tvresult; @@ -788,13 +767,35 @@ result == ISC_R_SUCCESS; result = dns_rdataset_next(nsec3paramset)) { dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nsec3param_t nsec3param; dns_rdataset_current(nsec3paramset, &rdata); - result = verifynsec3(vctx, name, &rdata, delegation, empty, - types, maxtype, vresult); - if (result != ISC_R_SUCCESS) { - return result; + result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + /* Skip unusable NSEC3PARAM records. */ + if (nsec3param.flags != 0) { + continue; + } + + /* + * If an NSEC-only algorithm is in the DNSKEY set, + * any NSEC3PARAM with flags == 0 is an error. + */ + if (vctx->nseconly) { + *vresult = DNS_R_NSEC3BADALG; + break; } + + if (nsec3param.iterations > DNS_NSEC3_MAXITERATIONS || + !dns_nsec3_supportedhash(nsec3param.hash)) + { + continue; + } + + RETERR(verifynsec3(vctx, name, &nsec3param, delegation, empty, + types, maxtype, vresult)); + if (*vresult != ISC_R_SUCCESS) { break; } @@ -1341,21 +1342,17 @@ check_apex_rrsets(vctx_t *vctx) { dns_dbnode_t *node = NULL; isc_result_t result; + bool nsec3param_ok = false; - result = dns_db_findnode(vctx->db, vctx->origin, false, &node); - if (result != ISC_R_SUCCESS) { - zoneverify_log_error(vctx, - "failed to find the zone's origin: %s", - isc_result_totext(result)); - return result; + result = dns_db_getoriginnode(vctx->db, &node); + if (result == ISC_R_SUCCESS) { + result = dns_db_findrdataset(vctx->db, node, vctx->ver, + dns_rdatatype_dnskey, 0, 0, + &vctx->keyset, &vctx->keysigs); } - - result = dns_db_findrdataset(vctx->db, node, vctx->ver, - dns_rdatatype_dnskey, 0, 0, &vctx->keyset, - &vctx->keysigs); if (result != ISC_R_SUCCESS) { zoneverify_log_error(vctx, "Zone contains no DNSSEC keys"); - goto done; + goto cleanup; } result = dns_db_findrdataset(vctx->db, node, vctx->ver, @@ -1363,7 +1360,7 @@ &vctx->soasigs); if (result != ISC_R_SUCCESS) { zoneverify_log_error(vctx, "Zone contains no SOA record"); - goto done; + goto cleanup; } result = dns_db_findrdataset(vctx->db, node, vctx->ver, @@ -1371,7 +1368,7 @@ &vctx->nsecsigs); if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { zoneverify_log_error(vctx, "NSEC lookup failed"); - goto done; + goto cleanup; } result = dns_db_findrdataset( @@ -1379,21 +1376,21 @@ &vctx->nsec3paramset, &vctx->nsec3paramsigs); if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { zoneverify_log_error(vctx, "NSEC3PARAM lookup failed"); - goto done; + goto cleanup; } if (!dns_rdataset_isassociated(&vctx->keysigs)) { zoneverify_log_error(vctx, "DNSKEY is not signed " "(keys offline or inactive?)"); result = ISC_R_FAILURE; - goto done; + goto cleanup; } if (!dns_rdataset_isassociated(&vctx->soasigs)) { zoneverify_log_error(vctx, "SOA is not signed " "(keys offline or inactive?)"); result = ISC_R_FAILURE; - goto done; + goto cleanup; } if (dns_rdataset_isassociated(&vctx->nsecset) && @@ -1402,7 +1399,7 @@ zoneverify_log_error(vctx, "NSEC is not signed " "(keys offline or inactive?)"); result = ISC_R_FAILURE; - goto done; + goto cleanup; } if (dns_rdataset_isassociated(&vctx->nsec3paramset) && @@ -1411,21 +1408,45 @@ zoneverify_log_error(vctx, "NSEC3PARAM is not signed " "(keys offline or inactive?)"); result = ISC_R_FAILURE; - goto done; + goto cleanup; } - if (!dns_rdataset_isassociated(&vctx->nsecset) && - !dns_rdataset_isassociated(&vctx->nsec3paramset)) - { - zoneverify_log_error(vctx, "No valid NSEC/NSEC3 chain for " + /* + * Do we have a NSEC3PARAM record that indicates a complete + * chain? A forged NSEC3PARAM set will be detected later. + */ + if (dns_rdataset_isassociated(&vctx->nsec3paramset)) { + for (result = dns_rdataset_first(&vctx->nsec3paramset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&vctx->nsec3paramset)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nsec3param_t nsec3param; + + dns_rdataset_current(&vctx->nsec3paramset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (nsec3param.flags != 0 || + nsec3param.iterations > DNS_NSEC3_MAXITERATIONS || + !dns_nsec3_supportedhash(nsec3param.hash)) + { + continue; + } + nsec3param_ok = true; + break; + } + } + + if (!dns_rdataset_isassociated(&vctx->nsecset) && !nsec3param_ok) { + zoneverify_log_error(vctx, "No usable NSEC/NSEC3 chain for " "testing"); result = ISC_R_FAILURE; - goto done; + goto cleanup; } result = ISC_R_SUCCESS; -done: +cleanup: dns_db_detachnode(vctx->db, &node); return result; @@ -1839,10 +1860,7 @@ dns_db_detachnode(vctx->db, &node); goto done; } - if (*vresult == ISC_R_UNSET) { - *vresult = ISC_R_SUCCESS; - } - if (*vresult == ISC_R_SUCCESS) { + if (*vresult == ISC_R_UNSET || *vresult == ISC_R_SUCCESS) { *vresult = tvresult; } if (prevname != NULL) { @@ -1999,6 +2017,10 @@ goto done; } + /* Record whether NSEC3 is supported by the DNSKEY RRset */ + result = dns_nsec_nseconly(vctx.db, vctx.ver, NULL, &vctx.nseconly); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + determine_active_algorithms(&vctx, ignore_kskflag, keyset_kskonly, report); @@ -2008,10 +2030,9 @@ } result = verify_nsec3_chains(&vctx, mctx); - if (vresult == ISC_R_UNSET) { - vresult = ISC_R_SUCCESS; - } - if (result != ISC_R_SUCCESS && vresult == ISC_R_SUCCESS) { + if (result != ISC_R_SUCCESS && + (vresult == ISC_R_SUCCESS || vresult == ISC_R_UNSET)) + { vresult = result; } diff -Nru bind9-9.20.26/lib/isc/Makefile.in bind9-9.20.29/lib/isc/Makefile.in --- bind9-9.20.26/lib/isc/Makefile.in 2026-07-20 14:49:10.889588511 +0000 +++ bind9-9.20.29/lib/isc/Makefile.in 2026-09-11 19:42:18.858196058 +0000 @@ -505,6 +505,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/lib/isc/httpd.c bind9-9.20.29/lib/isc/httpd.c --- bind9-9.20.26/lib/isc/httpd.c 2026-07-20 14:47:54.076850163 +0000 +++ bind9-9.20.29/lib/isc/httpd.c 2026-09-11 19:41:01.551332195 +0000 @@ -748,7 +748,7 @@ } #endif /* ifdef HAVE_ZLIB */ -static void +static isc_result_t prepare_response(void *arg) { isc_httpd_sendreq_t *req = arg; isc_httpd_t *httpd = req->httpd; @@ -872,6 +872,8 @@ } httpd->recvlen -= httpd->consume; httpd->consume = 0; + + return ISC_R_SUCCESS; } static void diff -Nru bind9-9.20.26/lib/isc/include/isc/endian.h bind9-9.20.29/lib/isc/include/isc/endian.h --- bind9-9.20.26/lib/isc/include/isc/endian.h 2026-07-20 14:47:54.078850194 +0000 +++ bind9-9.20.29/lib/isc/include/isc/endian.h 2026-09-11 19:41:01.553332243 +0000 @@ -40,6 +40,7 @@ #include +#ifndef htobe16 #define htobe16(x) OSSwapHostToBigInt16(x) #define htole16(x) OSSwapHostToLittleInt16(x) #define be16toh(x) OSSwapBigToHostInt16(x) @@ -54,6 +55,7 @@ #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) +#endif /* !htobe16 */ #elif defined(sun) || defined(__sun) || defined(__SVR4) diff -Nru bind9-9.20.26/lib/isc/include/isc/lex.h bind9-9.20.29/lib/isc/include/isc/lex.h --- bind9-9.20.26/lib/isc/include/isc/lex.h 2026-07-20 14:47:54.080850225 +0000 +++ bind9-9.20.29/lib/isc/include/isc/lex.h 2026-09-11 19:41:01.554332267 +0000 @@ -208,7 +208,7 @@ isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials); /*!< * The characters in 'specials' are returned as tokens. Along with - * whitespace, they delimit strings and numbers. + * whitespace and NUL, they delimit strings and numbers. * * Note: *\li Comment processing takes precedence over special character diff -Nru bind9-9.20.26/lib/isc/include/isc/queue.h bind9-9.20.29/lib/isc/include/isc/queue.h --- bind9-9.20.26/lib/isc/include/isc/queue.h 2026-07-20 14:47:54.082850256 +0000 +++ bind9-9.20.29/lib/isc/include/isc/queue.h 2026-09-11 19:41:01.557332338 +0000 @@ -10,6 +10,7 @@ * See the COPYRIGHT file distributed with this work for additional * information regarding copyright ownership. */ +#pragma once #include #include diff -Nru bind9-9.20.26/lib/isc/include/isc/ratelimiter.h bind9-9.20.29/lib/isc/include/isc/ratelimiter.h --- bind9-9.20.26/lib/isc/include/isc/ratelimiter.h 2026-07-20 14:47:54.082850256 +0000 +++ bind9-9.20.29/lib/isc/include/isc/ratelimiter.h 2026-09-11 19:41:01.557332338 +0000 @@ -110,6 +110,10 @@ * Dequeue a event off the ratelimiter queue. If the event has not already * been posted, it will be freed and '*rleventp' will be set to NULL. * + * Requires: + *\li 'rl' is a valid ratelimiter. + *\li 'rleventp' is non NULL and '*rleventp' is non NULL. + * * Returns: * \li ISC_R_NOTFOUND if the event is no longer linked to the rate limiter. * \li ISC_R_SUCCESS diff -Nru bind9-9.20.26/lib/isc/include/isc/stats.h bind9-9.20.29/lib/isc/include/isc/stats.h --- bind9-9.20.26/lib/isc/include/isc/stats.h 2026-07-20 14:47:54.083850271 +0000 +++ bind9-9.20.29/lib/isc/include/isc/stats.h 2026-09-11 19:41:01.558332362 +0000 @@ -213,16 +213,3 @@ *\li counter is less than the maximum available ID for the stats specified * on creation. */ - -void -isc_stats_resize(isc_stats_t **stats, int ncounters); -/*%< - * Resize a statistics counter structure of general type. The new set of - * counters are indexed by an ID between 0 and ncounters -1. - * - * Requires: - *\li 'stats' is a valid isc_stats_t. - *\li 'ncounters' is a non-zero positive number. - */ - -ISC_LANG_ENDDECLS diff -Nru bind9-9.20.26/lib/isc/include/isc/time.h bind9-9.20.29/lib/isc/include/isc/time.h --- bind9-9.20.26/lib/isc/include/isc/time.h 2026-07-20 14:47:54.084850287 +0000 +++ bind9-9.20.29/lib/isc/include/isc/time.h 2026-09-11 19:41:01.559332386 +0000 @@ -32,6 +32,14 @@ ISC_CONSTEXPR unsigned int NS_PER_MS = 1000 * 1000; ISC_CONSTEXPR unsigned int NS_PER_SEC = 1000 * 1000 * 1000; +#define ISC_FORMATTIMESTAMP_SIZE sizeof("99-Bad-9999 99:99:99.999") +#define ISC_FORMATISO8601LMS_SIZE sizeof("9999-99-99T99:99:99.999") +#define ISC_FORMATISO8601_SIZE sizeof("9999-99-99T99:99:99Z") +#define ISC_FORMATISO8601MS_SIZE sizeof("9999-99-99T99:99:99.999Z") +#define ISC_FORMATISO8601US_SIZE sizeof("9999-99-99T99:99:99.999999Z") +#define ISC_FORMATISO8601TZMS_SIZE sizeof("9999-99-99T99:99:99.999+99:99") +#define ISC_FORMATSHORTTIMESTAMP_SIZE sizeof("99999999999999999") + /* * ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially * more for other locales to handle longer national abbreviations when diff -Nru bind9-9.20.26/lib/isc/include/isc/util.h bind9-9.20.29/lib/isc/include/isc/util.h --- bind9-9.20.26/lib/isc/include/isc/util.h 2026-07-20 14:47:54.085850303 +0000 +++ bind9-9.20.29/lib/isc/include/isc/util.h 2026-09-11 19:41:01.560332410 +0000 @@ -364,12 +364,12 @@ #define FATAL_ERROR(...) \ isc_error_fatal(__FILE__, __LINE__, __func__, __VA_ARGS__) -#define REPORT_SYSERROR(report, err, fmt, ...) \ - { \ - char strerr[ISC_STRERRORSIZE]; \ - strerror_r(err, strerr, sizeof(strerr)); \ - report(__FILE__, __LINE__, __func__, fmt ": %s (%d)", \ - ##__VA_ARGS__, strerr, err); \ +#define REPORT_SYSERROR(report, err, fmt, ...) \ + { \ + char strerr[ISC_STRERRORSIZE]; \ + strerror_r(err, strerr, sizeof(strerr)); \ + report(__FILE__, __LINE__, __func__, \ + fmt ": %s (%d)", ##__VA_ARGS__, strerr, err); \ } #define UNEXPECTED_SYSERROR(err, ...) \ @@ -404,6 +404,15 @@ } while (0) /* + * Unconditionally jump to the cleanup tag with 'result' set to 'r'. + */ +#define CLEANUP(r) \ + { \ + result = (r); \ + goto cleanup; \ + } + +/* * Check for ISC_R_SUCCESS and continue if found. For any other * result, return the result. */ diff -Nru bind9-9.20.26/lib/isc/include/isc/work.h bind9-9.20.29/lib/isc/include/isc/work.h --- bind9-9.20.26/lib/isc/include/isc/work.h 2026-07-20 14:47:54.085850303 +0000 +++ bind9-9.20.29/lib/isc/include/isc/work.h 2026-09-11 19:41:01.560332410 +0000 @@ -16,9 +16,9 @@ * * Each isc event loop has one worker thread per lane (see isc_worklane_t). * isc_work_enqueue() runs a callback on the worker thread bound to the calling - * loop's lane and, when it finishes, runs a second callback back on that loop. - * The handle it returns can be used to cancel a task that has not started - * running yet. + * loop's lane and, when it finishes, runs a second callback back on that loop + * with the first callback's result. The handle it returns can be used to + * cancel a task that has not started running yet. */ #pragma once @@ -37,7 +37,7 @@ * holding up short FAST tasks behind it. */ -typedef void (*isc_work_cb)(void *arg); +typedef isc_result_t (*isc_work_cb)(void *arg); typedef void (*isc_work_done_cb)(void *arg, isc_result_t result); typedef struct isc_work isc_work_t; @@ -49,18 +49,18 @@ /*%< * Schedule 'cb' to run on the worker thread bound to 'loop' and 'lane'. When * 'cb' returns, 'done_cb' is scheduled back on 'loop' with the result of the - * work: ISC_R_SUCCESS normally, or ISC_R_CANCELED if the task was canceled + * work: the value 'cb' returned, or ISC_R_CANCELED if the task was canceled * before it started (see isc_work_cancel()). * * Returns a handle that may be passed to isc_work_cancel(). The handle is - * owned by 'loop' and stays valid until 'after_cb' has run; it must not be used + * owned by 'loop' and stays valid until 'done_cb' has run; it must not be used * afterwards. * * Requires: * *\li 'loop' is a valid isc event loop. *\li 'cb' is non-NULL. - *\li 'after_cb' is non-NULL. + *\li 'done_cb' is non-NULL. *\li 'cbarg' is passed to both callbacks, may be NULL. */ @@ -69,7 +69,7 @@ /*%< * Try to cancel 'work' before its 'cb' starts running. If the task is still * queued it is marked canceled and 'cb' will not run; if it is already running - * or has finished this has no effect. Either way the 'after_cb' passed to + * or has finished this has no effect. Either way the 'done_cb' passed to * isc_work_enqueue() still runs on the origin loop, with ISC_R_CANCELED when * the cancel succeeded. Nothing is freed here. * @@ -80,7 +80,7 @@ * * Requires: * - *\li 'work' is a handle from isc_work_enqueue() whose 'after_cb' has not run. + *\li 'work' is a handle from isc_work_enqueue() whose 'done_cb' has not run. */ /* private */ diff -Nru bind9-9.20.26/lib/isc/lex.c bind9-9.20.29/lib/isc/lex.c --- bind9-9.20.26/lib/isc/lex.c 2026-07-20 14:47:54.086850318 +0000 +++ bind9-9.20.29/lib/isc/lex.c 2026-09-11 19:41:01.561332434 +0000 @@ -550,6 +550,12 @@ lex->last_was_eol = false; no_comments = true; state = lexstate_qstring; + } else if (c == '\0') { + lex->last_was_eol = false; + tokenp->type = isc_tokentype_unknown; + tokenp->value.as_textregion.base = NULL; + tokenp->value.as_textregion.length = 0; + done = true; } else if (lex->specials[c]) { lex->last_was_eol = false; if ((c == '(' || c == ')') && @@ -617,7 +623,8 @@ case lexstate_number: if (c == EOF || !isdigit((unsigned char)c)) { if (c == ' ' || c == '\t' || c == '\r' || - c == '\n' || c == EOF || lex->specials[c]) + c == '\n' || c == '\0' || c == EOF || + lex->specials[c]) { int base; if ((options & ISC_LEXOPT_OCTAL) != 0) { @@ -717,8 +724,8 @@ * as lex->specials[EOF] is not a good idea. */ if (c == '\r' || c == '\n' || c == EOF || - (!escaped && - (c == ' ' || c == '\t' || lex->specials[c]))) + (!escaped && (c == ' ' || c == '\t' || c == '\0' || + lex->specials[c]))) { pushback(source, c); if (source->result != ISC_R_SUCCESS) { @@ -867,6 +874,13 @@ result = ISC_R_UNEXPECTEDEND; goto done; } + if (c == '\0') { + tokenp->type = isc_tokentype_unknown; + tokenp->value.as_textregion.base = NULL; + tokenp->value.as_textregion.length = 0; + done = true; + break; + } if (c == '{') { if (escaped) { escaped = false; diff -Nru bind9-9.20.26/lib/isc/netmgr/http.c bind9-9.20.29/lib/isc/netmgr/http.c --- bind9-9.20.26/lib/isc/netmgr/http.c 2026-07-20 14:47:54.088850349 +0000 +++ bind9-9.20.29/lib/isc/netmgr/http.c 2026-09-11 19:41:01.563332482 +0000 @@ -309,12 +309,6 @@ static void http_initsocket(isc_nmsocket_t *sock); -static bool -http_session_active(isc_nm_http_session_t *session) { - REQUIRE(VALID_HTTP2_SESSION(session)); - return !session->closed && !session->closing; -} - static void * http_malloc(size_t sz, isc_mem_t *mctx) { return isc_mem_allocate(mctx, sz); @@ -422,6 +416,13 @@ return session->handle; } +bool +isc__nm_httpsession_active(isc_nm_http_session_t *session) { + REQUIRE(VALID_HTTP2_SESSION(session)); + + return !session->closed && !session->closing && session->handle != NULL; +} + static http_cstream_t * find_http_cstream(int32_t stream_id, isc_nm_http_session_t *session) { http_cstream_t *cstream = NULL; @@ -1081,7 +1082,7 @@ REQUIRE(VALID_HTTP2_SESSION(session)); REQUIRE(input_data != NULL); - if (!http_session_active(session)) { + if (!isc__nm_httpsession_active(session)) { return 0; } @@ -1328,7 +1329,7 @@ REQUIRE(VALID_HTTP2_SESSION(session)); REQUIRE(VALID_NMHANDLE(handle)); - if (http_session_active(session)) { + if (isc__nm_httpsession_active(session)) { INSIST(session->handle == handle); } @@ -1397,7 +1398,7 @@ size_t max_total_write_size = 0; #endif /* ENABLE_HTTP_WRITE_BUFFERING */ - if (!http_session_active(session)) { + if (!isc__nm_httpsession_active(session)) { if (cb != NULL) { isc__nm_uvreq_t *req = isc__nm_uvreq_get(httphandle->sock); @@ -2093,7 +2094,7 @@ sock = handle->sock; isc__nm_http_read(handle, cb, cbarg); - if (!http_session_active(handle->sock->h2->session)) { + if (!isc__nm_httpsession_active(handle->sock->h2->session)) { /* the callback was called by isc__nm_http_read() */ return ISC_R_CANCELED; } @@ -2557,7 +2558,7 @@ REQUIRE(VALID_HTTP2_SESSION(sock->h2->session)); if (sock->h2->response_submitted || - !http_session_active(sock->h2->session)) + !isc__nm_httpsession_active(sock->h2->session)) { return; } @@ -2717,7 +2718,7 @@ isc_nm_cb_t cb = req->cb.send; void *cbarg = req->cbarg; if (isc__nmsocket_closing(sock) || - !http_session_active(handle->httpsession)) + !isc__nm_httpsession_active(handle->httpsession)) { failed_send_cb(sock, req, ISC_R_CANCELED); return; @@ -2798,7 +2799,7 @@ REQUIRE(VALID_NMHANDLE(handle)); session = handle->sock->h2->session; - if (!http_session_active(session)) { + if (!isc__nm_httpsession_active(session)) { cb(handle, ISC_R_CANCELED, NULL, cbarg); return; } diff -Nru bind9-9.20.26/lib/isc/netmgr/netmgr-int.h bind9-9.20.29/lib/isc/netmgr/netmgr-int.h --- bind9-9.20.26/lib/isc/netmgr/netmgr-int.h 2026-07-20 14:47:54.088850349 +0000 +++ bind9-9.20.29/lib/isc/netmgr/netmgr-int.h 2026-09-11 19:41:01.563332482 +0000 @@ -103,7 +103,7 @@ * most in TCPDNS or TLSDNS connections, so there's no risk of overrun * when using a buffer this size. */ -#define NM_BIG_BUF ISC_NETMGR_TCP_RECVBUF_SIZE * 2 +#define NM_BIG_BUF (ISC_NETMGR_TCP_RECVBUF_SIZE * 2) /*% * Maximum segment size (MSS) of TCP socket on which the server responds to @@ -1118,6 +1118,9 @@ isc_nmhandle_t * isc__nm_httpsession_handle(isc_nm_http_session_t *session); +bool +isc__nm_httpsession_active(isc_nm_http_session_t *session); + void isc__nm_http_set_tlsctx(isc_nmsocket_t *sock, isc_tlsctx_t *tlsctx); diff -Nru bind9-9.20.26/lib/isc/netmgr/netmgr.c bind9-9.20.29/lib/isc/netmgr/netmgr.c --- bind9-9.20.26/lib/isc/netmgr/netmgr.c 2026-07-20 14:47:54.088850349 +0000 +++ bind9-9.20.29/lib/isc/netmgr/netmgr.c 2026-09-11 19:41:01.563332482 +0000 @@ -2220,7 +2220,9 @@ return handle; #ifdef HAVE_LIBNGHTTP2 case isc_nm_httpsocket: - if (sock->h2 != NULL) { + if (sock->h2 != NULL && + isc__nm_httpsession_active(sock->h2->session)) + { return get_proxy_handle( isc__nm_httpsession_handle(sock->h2->session)); } diff -Nru bind9-9.20.26/lib/isc/netmgr/streamdns.c bind9-9.20.29/lib/isc/netmgr/streamdns.c --- bind9-9.20.26/lib/isc/netmgr/streamdns.c 2026-07-20 14:47:54.089850365 +0000 +++ bind9-9.20.29/lib/isc/netmgr/streamdns.c 2026-09-11 19:41:01.564332506 +0000 @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -904,6 +905,8 @@ REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_tid()); + sock->processing = false; + if (streamdns_closing(sock)) { streamdns_failed_read_cb(sock, ISC_R_CANCELED, false); goto detach; @@ -942,6 +945,14 @@ } /* + * Prevent scheduling the job or processing data if streamdns_read_cb + * has been already scheduled. + */ + if (sock->processing) { + return; + } + + /* * In some cases there is little sense in making the operation * asynchronous as we just want to start reading from the * underlying transport. @@ -966,6 +977,7 @@ */ isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL }); + sock->processing = true; isc_job_run(sock->worker->loop, &sock->job, streamdns_read_cb, sock); } diff -Nru bind9-9.20.26/lib/isc/netmgr/tlsstream.c bind9-9.20.29/lib/isc/netmgr/tlsstream.c --- bind9-9.20.26/lib/isc/netmgr/tlsstream.c 2026-07-20 14:47:54.090850380 +0000 +++ bind9-9.20.29/lib/isc/netmgr/tlsstream.c 2026-09-11 19:41:01.565332530 +0000 @@ -955,8 +955,19 @@ handle->sock->tlsstream.tlssocket = tlssock; result = initialize_tls(tlssock, true); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - /* TODO: catch failure code, detach tlssock, and log the error */ + if (result != ISC_R_SUCCESS) { + isc__nmsocket_log(tlssock, ISC_LOG_ERROR, + "TLS initialization failed: %s", + isc_result_totext(result)); + handle->sock->tlsstream.tlssocket = NULL; + isc_nmhandle_detach(&tlssock->outerhandle); + tlssock->closed = true; + isc_tlsctx_free(&tlssock->tlsstream.ctx); + isc__nmsocket_detach(&tlssock->listener); + isc__nmsocket_detach(&tlssock->server); + isc__nmsocket_detach(&tlssock); + return result; + } tls_try_to_enable_tcp_nodelay(tlssock); diff -Nru bind9-9.20.26/lib/isc/netmgr/udp.c bind9-9.20.29/lib/isc/netmgr/udp.c --- bind9-9.20.26/lib/isc/netmgr/udp.c 2026-07-20 14:47:54.090850380 +0000 +++ bind9-9.20.29/lib/isc/netmgr/udp.c 2026-09-11 19:41:01.565332530 +0000 @@ -195,6 +195,7 @@ csock->fd = isc__nm_udp_lb_socket(mgr, iface->type.sa.sa_family); } else { + INSIST(fd >= 0); csock->fd = dup(fd); } INSIST(csock->fd >= 0); @@ -291,7 +292,7 @@ isc_result_t result; uv_os_sock_t fd = -1; #ifdef USE_NETLINK - struct sockaddr_nl sa; + struct sockaddr_nl sa = { 0 }; int r; #endif @@ -306,8 +307,9 @@ sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; r = bind(fd, (struct sockaddr *)&sa, sizeof(sa)); if (r < 0) { + result = isc_errno_toresult(errno); isc__nm_closesocket(fd); - return isc_errno_toresult(r); + return result; } #endif @@ -408,7 +410,6 @@ UNUSED(mgr); UNUSED(cb); UNUSED(cbarg); - UNUSED(extrahandlesize); return ISC_R_NOTIMPLEMENTED; #endif /* USE_ROUTE_SOCKET */ } diff -Nru bind9-9.20.26/lib/isc/ratelimiter.c bind9-9.20.29/lib/isc/ratelimiter.c --- bind9-9.20.26/lib/isc/ratelimiter.c 2026-07-20 14:47:54.091850396 +0000 +++ bind9-9.20.29/lib/isc/ratelimiter.c 2026-09-11 19:41:01.566332554 +0000 @@ -202,7 +202,7 @@ isc_result_t result = ISC_R_SUCCESS; REQUIRE(rl != NULL); - REQUIRE(rlep != NULL); + REQUIRE(rlep != NULL && *rlep != NULL); LOCK(&rl->lock); if (ISC_LINK_LINKED(*rlep, link)) { diff -Nru bind9-9.20.26/lib/isc/sockaddr.c bind9-9.20.29/lib/isc/sockaddr.c --- bind9-9.20.26/lib/isc/sockaddr.c 2026-07-20 14:47:54.092850411 +0000 +++ bind9-9.20.29/lib/isc/sockaddr.c 2026-09-11 19:41:01.567332578 +0000 @@ -264,7 +264,8 @@ in_port_t port) { memset(sockaddr, 0, sizeof(*sockaddr)); sockaddr->type.sin.sin_family = AF_INET; - sockaddr->type.sin.sin_addr = *ina; + /* Use memmove to avoid possible misaligned access. */ + memmove(&sockaddr->type.sin.sin_addr, ina, sizeof(*ina)); sockaddr->type.sin.sin_port = htons(port); sockaddr->length = sizeof(sockaddr->type.sin); ISC_LINK_INIT(sockaddr, link); @@ -289,7 +290,8 @@ in_port_t port) { memset(sockaddr, 0, sizeof(*sockaddr)); sockaddr->type.sin6.sin6_family = AF_INET6; - sockaddr->type.sin6.sin6_addr = *ina6; + /* Use memmove to avoid possible misaligned access. */ + memmove(&sockaddr->type.sin6.sin6_addr, ina6, sizeof(*ina6)); sockaddr->type.sin6.sin6_port = htons(port); sockaddr->length = sizeof(sockaddr->type.sin6); ISC_LINK_INIT(sockaddr, link); diff -Nru bind9-9.20.26/lib/isc/stats.c bind9-9.20.29/lib/isc/stats.c --- bind9-9.20.26/lib/isc/stats.c 2026-07-20 14:47:54.092850411 +0000 +++ bind9-9.20.29/lib/isc/stats.c 2026-09-11 19:41:01.567332578 +0000 @@ -164,35 +164,3 @@ return atomic_load_acquire(&stats->counters[counter]); } - -void -isc_stats_resize(isc_stats_t **statsp, int ncounters) { - isc_stats_t *stats; - size_t counters_alloc_size; - isc_atomic_statscounter_t *newcounters; - - REQUIRE(statsp != NULL && *statsp != NULL); - REQUIRE(ISC_STATS_VALID(*statsp)); - REQUIRE(ncounters > 0); - - stats = *statsp; - if (stats->ncounters >= ncounters) { - /* We already have enough counters. */ - return; - } - - /* Grow number of counters. */ - counters_alloc_size = sizeof(isc_atomic_statscounter_t) * ncounters; - newcounters = isc_mem_get(stats->mctx, counters_alloc_size); - for (int i = 0; i < ncounters; i++) { - atomic_init(&newcounters[i], 0); - } - for (int i = 0; i < stats->ncounters; i++) { - uint32_t counter = atomic_load_acquire(&stats->counters[i]); - atomic_store_release(&newcounters[i], counter); - } - isc_mem_cput(stats->mctx, stats->counters, stats->ncounters, - sizeof(isc_atomic_statscounter_t)); - stats->counters = newcounters; - stats->ncounters = ncounters; -} diff -Nru bind9-9.20.26/lib/isc/time.c bind9-9.20.29/lib/isc/time.c --- bind9-9.20.26/lib/isc/time.c 2026-07-20 14:47:54.093850427 +0000 +++ bind9-9.20.29/lib/isc/time.c 2026-09-11 19:41:01.568332602 +0000 @@ -30,6 +30,10 @@ #include #include +#define ISC_VALID_TIME(t) (t != NULL && t->nanoseconds < NS_PER_SEC) + +#define ISC_VALID_INTERVAL ISC_VALID_TIME + #if defined(CLOCK_REALTIME) #define CLOCKSOURCE_HIRES CLOCK_REALTIME #endif /* #if defined(CLOCK_REALTIME) */ @@ -70,8 +74,7 @@ bool isc_time_isepoch(const isc_time_t *t) { - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); if (t->seconds == 0 && t->nanoseconds == 0) { return true; @@ -130,35 +133,35 @@ struct timespec ts; REQUIRE(t != NULL); - REQUIRE(i != NULL); - INSIST(i->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_INTERVAL(i)); if (clock_gettime(CLOCKSOURCE, &ts) == -1) { - UNEXPECTED_SYSERROR(errno, "clock_gettime()"); + char strbuf[ISC_STRERRORSIZE]; + strerror_r(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR("%s", strbuf); return ISC_R_UNEXPECTED; } - if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= (long)NS_PER_SEC) { + if ((ts.tv_sec < 0 || (uint64_t)ts.tv_sec > UINT_MAX) || + (ts.tv_nsec < 0 || ts.tv_nsec >= (long)NS_PER_SEC)) + { return ISC_R_UNEXPECTED; } - /* - * Ensure the resulting seconds value fits in the size of an - * unsigned int. (It is written this way as a slight optimization; - * note that even if both values == INT_MAX, then when added - * and getting another 1 added below the result is UINT_MAX.) - */ - if ((ts.tv_sec > INT_MAX || i->seconds > INT_MAX) && - ((long long)ts.tv_sec + i->seconds > UINT_MAX)) + /* Seconds */ + if (ISC_OVERFLOW_ADD((unsigned int)ts.tv_sec, i->seconds, &t->seconds)) { return ISC_R_RANGE; } - t->seconds = ts.tv_sec + i->seconds; + /* Nanoseconds */ t->nanoseconds = ts.tv_nsec + i->nanoseconds; if (t->nanoseconds >= NS_PER_SEC) { - t->seconds++; + if (t->seconds == UINT_MAX) { + return ISC_R_RANGE; + } t->nanoseconds -= NS_PER_SEC; + t->seconds++; } return ISC_R_SUCCESS; @@ -166,8 +169,8 @@ int isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { - REQUIRE(t1 != NULL && t2 != NULL); - INSIST(t1->nanoseconds < NS_PER_SEC && t2->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t1)); + REQUIRE(ISC_VALID_TIME(t2)); if (t1->seconds < t2->seconds) { return -1; @@ -186,8 +189,9 @@ isc_result_t isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) { - REQUIRE(t != NULL && i != NULL && result != NULL); - REQUIRE(t->nanoseconds < NS_PER_SEC && i->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); + REQUIRE(ISC_VALID_INTERVAL(i)); + REQUIRE(result != NULL); /* Seconds */ if (ISC_OVERFLOW_ADD(t->seconds, i->seconds, &result->seconds)) { @@ -210,8 +214,9 @@ isc_result_t isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) { - REQUIRE(t != NULL && i != NULL && result != NULL); - REQUIRE(t->nanoseconds < NS_PER_SEC && i->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); + REQUIRE(ISC_VALID_INTERVAL(i)); + REQUIRE(result != NULL); /* Seconds */ if (ISC_OVERFLOW_SUB(t->seconds, i->seconds, &result->seconds)) { @@ -237,8 +242,8 @@ isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { uint64_t i1, i2, i3; - REQUIRE(t1 != NULL && t2 != NULL); - INSIST(t1->nanoseconds < NS_PER_SEC && t2->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t1)); + REQUIRE(ISC_VALID_TIME(t2)); i1 = (uint64_t)t1->seconds * NS_PER_SEC + t1->nanoseconds; i2 = (uint64_t)t2->seconds * NS_PER_SEC + t2->nanoseconds; @@ -259,8 +264,7 @@ uint32_t isc_time_seconds(const isc_time_t *t) { - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); return (uint32_t)t->seconds; } @@ -269,8 +273,7 @@ isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) { time_t seconds; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); /* * Ensure that the number of seconds represented by t->seconds @@ -305,17 +308,14 @@ uint32_t isc_time_nanoseconds(const isc_time_t *t) { - REQUIRE(t != NULL); - - ENSURE(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); return (uint32_t)t->nanoseconds; } uint32_t isc_time_miliseconds(const isc_time_t *t) { - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); return (t->seconds * MS_PER_SEC) + (t->nanoseconds / NS_PER_MS); } @@ -326,19 +326,17 @@ unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATTIMESTAMP_SIZE); now = (time_t)t->seconds; flen = strftime(buf, len, "%d-%b-%Y %X", localtime_r(&now, &tm)); - INSIST(flen < len); - if (flen != 0) { + if (flen == 0) { + strlcpy(buf, "99-Bad-9999 99:99:99.999", len); + } else { snprintf(buf + flen, len - flen, ".%03u", t->nanoseconds / NS_PER_MS); - } else { - strlcpy(buf, "99-Bad-9999 99:99:99.999", len); } } @@ -348,10 +346,9 @@ unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATHTTPTIMESTAMP_SIZE); /* * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+ @@ -360,7 +357,9 @@ now = (time_t)t->seconds; flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime_r(&now, &tm)); - INSIST(flen < len); + if (flen == 0) { + strlcpy(buf, "Bad, 99 Bad 9999 99:99:99 GMT", len); + } } isc_result_t @@ -406,15 +405,15 @@ unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601LMS_SIZE); now = (time_t)t->seconds; flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime_r(&now, &tm)); - INSIST(flen < len); - if (flen > 0U && len - flen >= 6) { + if (flen == 0) { + strlcpy(buf, "9999-99-99T99:99:99.999", len); + } else { snprintf(buf + flen, len - flen, ".%03u", t->nanoseconds / NS_PER_MS); } @@ -426,8 +425,7 @@ unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); REQUIRE(len > 0); @@ -446,14 +444,15 @@ unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601_SIZE); now = (time_t)t->seconds; flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm)); - INSIST(flen < len); + if (flen == 0) { + strlcpy(buf, "9999-99-99T99:99:99Z", len); + } } void @@ -462,16 +461,15 @@ unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601MS_SIZE); now = (time_t)t->seconds; - flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm)); - INSIST(flen < len); - if (flen > 0U && len - flen >= 5) { - flen -= 1; /* rewind one character (Z) */ + flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", gmtime_r(&now, &tm)); + if (flen == 0) { + strlcpy(buf, "9999-99-99T99:99:99.999Z", len); + } else { snprintf(buf + flen, len - flen, ".%03uZ", t->nanoseconds / NS_PER_MS); } @@ -483,16 +481,15 @@ unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601US_SIZE); now = (time_t)t->seconds; - flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm)); - INSIST(flen < len); - if (flen > 0U && len - flen >= 5) { - flen -= 1; /* rewind one character (Z) */ + flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", gmtime_r(&now, &tm)); + if (flen == 0) { + strlcpy(buf, "9999-99-99T99:99:99.999999Z", len); + } else { snprintf(buf + flen, len - flen, ".%06uZ", t->nanoseconds / NS_PER_US); } @@ -505,15 +502,15 @@ unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATSHORTTIMESTAMP_SIZE); now = (time_t)t->seconds; flen = strftime(buf, len, "%Y%m%d%H%M%S", gmtime_r(&now, &tm)); - INSIST(flen < len); - if (flen > 0U && len - flen >= 5) { + if (flen == 0) { + strlcpy(buf, "99999999999999999", len); + } else { snprintf(buf + flen, len - flen, "%03u", t->nanoseconds / NS_PER_MS); } diff -Nru bind9-9.20.26/lib/isc/work.c bind9-9.20.29/lib/isc/work.c --- bind9-9.20.26/lib/isc/work.c 2026-07-20 14:47:54.094850442 +0000 +++ bind9-9.20.29/lib/isc/work.c 2026-09-11 19:41:01.569332626 +0000 @@ -55,7 +55,8 @@ struct isc_work { unsigned int magic; - uint32_t state; /* enum workstate */ + uint32_t state; /* enum workstate */ + isc_result_t result; isc_work_cb cb; /* runs on a worker thread */ isc_work_done_cb done_cb; /* runs on the origin loop */ void *cbarg; @@ -191,12 +192,11 @@ work_done(void *arg) { isc_work_t *work = arg; isc_loop_t *loop = work->loop; - isc_result_t result = (uatomic_load(&work->state, CMM_ACQUIRE) != - WORK_CANCELED) - ? ISC_R_SUCCESS - : ISC_R_CANCELED; - work->done_cb(work->cbarg, result); + /* work_run() has settled work->result before scheduling us. */ + INSIST(work->result != ISC_R_UNSET); + + work->done_cb(work->cbarg, work->result); work->magic = 0; isc_mem_put(work->loop->mctx, work, sizeof(*work)); @@ -216,9 +216,10 @@ WORK_RUNNING); switch (prev) { case WORK_QUEUED: - work->cb(work->cbarg); + work->result = work->cb(work->cbarg); break; case WORK_CANCELED: + work->result = ISC_R_CANCELED; break; default: UNREACHABLE(); @@ -290,6 +291,7 @@ isc_work_t *work = isc_mem_get(loop->mctx, sizeof(*work)); *work = (isc_work_t){ .magic = WORK_MAGIC, + .result = ISC_R_UNSET, .cb = cb, .done_cb = done_cb, .cbarg = cbarg, @@ -331,7 +333,7 @@ /* * Tombstone: QUEUED -> CANCELED. The node stays in the queue * (no interior unlink in a singly-linked lock-free queue) and - * is discarded by whichever worker dequeues it; after_cb still + * is discarded by whichever worker dequeues it; done_cb still * fires with ISC_R_CANCELED. Nothing is freed here. False * means the callback is running or done — uv_cancel semantics. */ diff -Nru bind9-9.20.26/lib/isccc/Makefile.in bind9-9.20.29/lib/isccc/Makefile.in --- bind9-9.20.26/lib/isccc/Makefile.in 2026-07-20 14:49:10.923589292 +0000 +++ bind9-9.20.29/lib/isccc/Makefile.in 2026-09-11 19:42:18.891196862 +0000 @@ -313,6 +313,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/lib/isccc/alist.c bind9-9.20.29/lib/isccc/alist.c --- bind9-9.20.26/lib/isccc/alist.c 2026-07-20 14:47:54.094850442 +0000 +++ bind9-9.20.29/lib/isccc/alist.c 2026-09-11 19:41:01.569332626 +0000 @@ -169,11 +169,13 @@ } kv = isccc_sexpr_cons(k, value); if (kv == NULL) { - isccc_sexpr_free(&kv); + isccc_sexpr_free(&k); return NULL; } elt = isccc_sexpr_addtolist(&alist, kv); if (elt == NULL) { + /* 'value' is freed by caller */ + CDR(kv) = NULL; isccc_sexpr_free(&kv); return NULL; } diff -Nru bind9-9.20.26/lib/isccc/cc.c bind9-9.20.29/lib/isccc/cc.c --- bind9-9.20.26/lib/isccc/cc.c 2026-07-20 14:47:54.094850442 +0000 +++ bind9-9.20.29/lib/isccc/cc.c 2026-09-11 19:41:01.570332650 +0000 @@ -573,6 +573,7 @@ goto bad; } if (isccc_alist_define(alist, key, value) == NULL) { + isccc_sexpr_free(&value); result = ISC_R_NOMEMORY; goto bad; } diff -Nru bind9-9.20.26/lib/isccc/sexpr.c bind9-9.20.29/lib/isccc/sexpr.c --- bind9-9.20.26/lib/isccc/sexpr.c 2026-07-20 14:47:54.096850474 +0000 +++ bind9-9.20.29/lib/isccc/sexpr.c 2026-09-11 19:41:01.571332674 +0000 @@ -68,6 +68,8 @@ isccc_sexpr_fromstring(const char *str) { isccc_sexpr_t *sexpr; + REQUIRE(str != NULL); + sexpr = malloc(sizeof(*sexpr)); if (sexpr == NULL) { return NULL; @@ -87,6 +89,8 @@ isccc_sexpr_t *sexpr; unsigned int region_size; + REQUIRE(region != NULL); + sexpr = malloc(sizeof(*sexpr)); if (sexpr == NULL) { return NULL; @@ -121,6 +125,8 @@ isccc_sexpr_t *sexpr; isccc_sexpr_t *item; + REQUIRE(sexprp != NULL); + sexpr = *sexprp; *sexprp = NULL; if (sexpr == NULL) { @@ -168,6 +174,8 @@ unsigned int size, i; unsigned char *curr; + REQUIRE(stream != NULL); + if (sexpr == NULL) { fprintf(stream, "nil"); return; @@ -216,28 +224,28 @@ isccc_sexpr_t * isccc_sexpr_car(isccc_sexpr_t *list) { - REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); + REQUIRE(list != NULL && list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); return CAR(list); } isccc_sexpr_t * isccc_sexpr_cdr(isccc_sexpr_t *list) { - REQUIRE(list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); + REQUIRE(list != NULL && list->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); return CDR(list); } void isccc_sexpr_setcar(isccc_sexpr_t *pair, isccc_sexpr_t *car) { - REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); + REQUIRE(pair != NULL && pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); CAR(pair) = car; } void isccc_sexpr_setcdr(isccc_sexpr_t *pair, isccc_sexpr_t *cdr) { - REQUIRE(pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); + REQUIRE(pair != NULL && pair->type == ISCCC_SEXPRTYPE_DOTTEDPAIR); CDR(pair) = cdr; } diff -Nru bind9-9.20.26/lib/isccfg/Makefile.in bind9-9.20.29/lib/isccfg/Makefile.in --- bind9-9.20.26/lib/isccfg/Makefile.in 2026-07-20 14:49:10.958590096 +0000 +++ bind9-9.20.29/lib/isccfg/Makefile.in 2026-09-11 19:42:18.926197715 +0000 @@ -319,6 +319,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/lib/isccfg/aclconf.c bind9-9.20.29/lib/isccfg/aclconf.c --- bind9-9.20.26/lib/isccfg/aclconf.c 2026-07-20 14:47:54.096850474 +0000 +++ bind9-9.20.29/lib/isccfg/aclconf.c 2026-09-11 19:41:01.571332674 +0000 @@ -11,11 +11,13 @@ * information regarding copyright ownership. */ +#include #include #include #include #include +#include #include #include @@ -582,7 +584,20 @@ strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "asnum") == 0) { + const char *s = search; + uint32_t val; + + /* check asnum validity */ subtype = dns_geoip_as_asnum; + if (strncasecmp(s, "AS", 2) == 0) { + s += 2; + } + if (isc_parse_uint32(&val, s, 10) != ISC_R_SUCCESS) { + cfg_obj_log(obj, lctx, ISC_LOG_ERROR, + "invalid asnum '%s'", search); + return ISC_R_UNEXPECTEDTOKEN; + } + strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "org") == 0) { diff -Nru bind9-9.20.26/lib/isccfg/check.c bind9-9.20.29/lib/isccfg/check.c --- bind9-9.20.26/lib/isccfg/check.c 2026-07-20 14:47:54.097850489 +0000 +++ bind9-9.20.29/lib/isccfg/check.c 2026-09-11 19:41:01.572332698 +0000 @@ -1298,6 +1298,14 @@ "dns64-server", "dns64-contact", NULL }; +#ifndef IOV_MAX +/* + * FSTRM_IOTHR_INPUT_QUEUE_SIZE_MAX is defined as IOV_MAX, but IOV_MAX can be + * undefined. + */ +#define IOV_MAX 1024 +#endif /* ifndef IOV_MAX */ + #ifdef HAVE_DNSTAP static fstrmtable fstrm[] = { { "fstrm-set-buffer-hint", FSTRM_IOTHR_BUFFER_HINT_MIN, @@ -1456,8 +1464,8 @@ DNS_KEYSTORE_KEYDIRECTORY); if (result == ISC_R_SUCCESS) { result = ISC_R_FAILURE; - continue; } + continue; } kopt = cfg_tuple_get(kconfig, "options"); @@ -2307,11 +2315,13 @@ /* Check endpoints are valid */ tresult = cfg_map_get(http, "endpoints", &eps); if (tresult == ISC_R_SUCCESS) { + bool empty = true; for (elt = cfg_list_first(eps); elt != NULL; elt = cfg_list_next(elt)) { const cfg_obj_t *ep = cfg_listelt_value(elt); const char *path = cfg_obj_asstring(ep); + empty = false; if (!isc_nm_http_path_isvalid(path)) { cfg_obj_log(eps, logctx, ISC_LOG_ERROR, "endpoint '%s' is not a " @@ -2322,6 +2332,13 @@ } } } + if (empty) { + cfg_obj_log(eps, logctx, ISC_LOG_ERROR, + "empty 'endpoints' entry"); + if (result == ISC_R_SUCCESS) { + result = ISC_R_FAILURE; + } + } } return result; @@ -2638,9 +2655,8 @@ if (result != ISC_R_SUCCESS) { cfg_obj_log(key, logctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); - } - - if (!lookup_key(voptions, nm)) { + result = ISC_R_FAILURE; + } else if (!lookup_key(voptions, nm)) { if (!lookup_key(config, nm)) { cfg_obj_log(key, logctx, ISC_LOG_ERROR, "key '%s' is not defined", diff -Nru bind9-9.20.26/lib/isccfg/kaspconf.c bind9-9.20.29/lib/isccfg/kaspconf.c --- bind9-9.20.26/lib/isccfg/kaspconf.c 2026-07-20 14:47:54.098850505 +0000 +++ bind9-9.20.29/lib/isccfg/kaspconf.c 2026-09-11 19:41:01.573332721 +0000 @@ -34,11 +34,46 @@ #include #include #include +#include #include #define DEFAULT_NSEC3PARAM_ITER 0 #define DEFAULT_NSEC3PARAM_SALTLEN 0 +static void +kaspcfg_log(const cfg_obj_t *config, isc_log_t *logctx, int level, + const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); + +/* kasp configuration logging */ +static void +kaspcfg_logv(const cfg_obj_t *config, isc_log_t *logctx, int level, + const char *fmt, va_list ap) { + char message[4096]; + + if (!isc_log_wouldlog(logctx, level)) { + return; + } + + vsnprintf(message, sizeof(message), fmt, ap); + + if (config != NULL) { + cfg_obj_log(config, logctx, level, "%s", message); + } else { + isc_log_write(logctx, CFG_LOGCATEGORY_CONFIG, + DNS_LOGMODULE_CONFIG, level, "%s", message); + } +} + +static void +kaspcfg_log(const cfg_obj_t *config, isc_log_t *logctx, int level, + const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + kaspcfg_logv(config, logctx, level, fmt, ap); + va_end(ap); +} + /* * Utility function for getting a configuration option. */ @@ -153,12 +188,11 @@ } else if (strcmp(rolestr, "csk") == 0) { if (offline_ksk) { if (log_errors) { - cfg_obj_log(config, logctx, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "dnssec-policy: csk keys " - "are not " - "allowed when offline-ksk " - "is enabled"); + "are not allowed when " + "offline-ksk is enabled"); } result = ISC_R_FAILURE; goto cleanup; @@ -178,7 +212,7 @@ &key->keystore); if (result == ISC_R_NOTFOUND) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: keystore %s does " "not exist", keydir); @@ -187,7 +221,7 @@ goto cleanup; } else if (result != ISC_R_SUCCESS) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: bad keystore %s", keydir); } @@ -204,11 +238,10 @@ if (key->lifetime > 0) { if (key->lifetime < 30 * (24 * 3600)) { if (log_errors) { - cfg_obj_log(obj, logctx, - ISC_LOG_WARNING, - "dnssec-policy: key " - "lifetime is " - "shorter than 30 days"); + kaspcfg_log( + obj, logctx, ISC_LOG_WARNING, + "dnssec-policy: key lifetime " + "is shorter than 30 days"); } } if ((key->role & DNS_KASP_KEY_ROLE_KSK) != 0 && @@ -223,12 +256,11 @@ } if (error) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, - "dnssec-policy: key " - "lifetime is " - "shorter than the time it " - "takes to " - "do a rollover"); + kaspcfg_log( + obj, logctx, ISC_LOG_ERROR, + "dnssec-policy: key lifetime " + "is shorter than the time it " + "takes to do a rollover"); } result = ISC_R_FAILURE; goto cleanup; @@ -242,7 +274,7 @@ (isc_textregion_t *)&alg); if (result != ISC_R_SUCCESS) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: bad algorithm %s", alg.base); } @@ -255,10 +287,9 @@ key->algorithm == DNS_KEYALG_NSEC3RSASHA1)) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: algorithm %s not " - "supported " - "in FIPS mode", + "supported in FIPS mode", alg.base); } result = DNS_R_BADALG; @@ -269,7 +300,7 @@ !dst_algorithm_supported(key->algorithm)) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: algorithm %s not " "supported", alg.base); @@ -282,11 +313,10 @@ case DST_ALG_RSASHA1: case DST_ALG_NSEC3RSASHA1: if (log_errors) { - cfg_obj_log( - obj, logctx, ISC_LOG_WARNING, - "dnssec-policy: DNSSEC algorithm %s is " - "deprecated", - alg.base); + kaspcfg_log(obj, logctx, ISC_LOG_WARNING, + "dnssec-policy: DNSSEC algorithm " + "%s is deprecated", + alg.base); } break; default: @@ -310,14 +340,13 @@ } if (size < min || size > 4096) { if (log_errors) { - cfg_obj_log(obj, logctx, - ISC_LOG_ERROR, - "dnssec-policy: " - "key with " - "algorithm %s has " - "invalid " - "key length %u", - alg.base, size); + kaspcfg_log( + obj, logctx, + ISC_LOG_ERROR, + "dnssec-policy: key " + "with algorithm %s has " + "invalid key length %u", + alg.base, size); } result = ISC_R_RANGE; goto cleanup; @@ -328,14 +357,12 @@ case DNS_KEYALG_ED25519: case DNS_KEYALG_ED448: if (log_errors) { - cfg_obj_log(obj, logctx, - ISC_LOG_WARNING, - "dnssec-policy: key " - "algorithm %s " - "has predefined length; " - "ignoring " - "length value %u", - alg.base, size); + kaspcfg_log( + obj, logctx, ISC_LOG_WARNING, + "dnssec-policy: key algorithm " + "%s has predefined length; " + "ignoring length value %u", + alg.base, size); } default: break; @@ -351,7 +378,7 @@ tag_min = cfg_obj_asuint32(obj); if (tag_min > 0xffff) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: tag-min " "too big"); } @@ -362,7 +389,7 @@ tag_max = cfg_obj_asuint32(obj); if (tag_max > 0xffff) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: tag-max " "too big"); } @@ -371,7 +398,7 @@ } if (tag_min >= tag_max) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: tag-min >= " "tag_max"); } @@ -432,7 +459,7 @@ char algstr[DNS_SECALG_FORMATSIZE]; dns_secalg_format((dns_secalg_t)badalg, algstr, sizeof(algstr)); if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: cannot use nsec3 with " "algorithm '%s'", algstr); @@ -442,7 +469,7 @@ if (iter != DEFAULT_NSEC3PARAM_ITER) { if (log_errors) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + kaspcfg_log(obj, logctx, ISC_LOG_ERROR, "dnssec-policy: nsec3 iterations value %u " "not allowed, must be zero", iter); @@ -463,7 +490,7 @@ } if (saltlen > 0xff) { if (log_errors) { - cfg_obj_log( + kaspcfg_log( obj, logctx, ISC_LOG_ERROR, "dnssec-policy: nsec3 salt length %u too high", saltlen); @@ -488,23 +515,23 @@ result = dns_dsdigest_fromtext(&alg, &r); if (result != ISC_R_SUCCESS) { if (log_errors) { - cfg_obj_log(digest, logctx, ISC_LOG_ERROR, + kaspcfg_log(digest, logctx, ISC_LOG_ERROR, "dnssec-policy: bad cds digest-type %s", str); } result = DNS_R_BADALG; } else if (!dst_ds_digest_supported(alg)) { if (log_errors) { - cfg_obj_log(digest, logctx, ISC_LOG_ERROR, - "dnssec-policy: unsupported cds " - "digest-type %s", - str); + kaspcfg_log( + digest, logctx, ISC_LOG_ERROR, + "dnssec-policy: unsupported cds digest-type %s", + str); } result = DST_R_UNSUPPORTEDALG; } else { if (alg == DNS_DSDIGEST_SHA1) { if (log_errors) { - cfg_obj_log(digest, logctx, ISC_LOG_WARNING, + kaspcfg_log(digest, logctx, ISC_LOG_WARNING, "dnssec-policy: deprecated CDS " "digest-type %s", str); @@ -550,14 +577,14 @@ kaspname = cfg_obj_asstring(cfg_tuple_get(config, "name")); INSIST(kaspname != NULL); - cfg_obj_log(config, logctx, ISC_LOG_DEBUG(1), + kaspcfg_log(config, logctx, ISC_LOG_DEBUG(1), "dnssec-policy: load policy '%s'", kaspname); result = dns_kasplist_find(kasplist, kaspname, &kasp); if (result == ISC_R_SUCCESS) { if (log_errors) { - cfg_obj_log(config, logctx, ISC_LOG_ERROR, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "dnssec-policy: duplicately named policy " "found '%s'", kaspname); @@ -597,11 +624,10 @@ DNS_KASP_SIG_VALIDITY_DNSKEY); if (sigrefresh >= (sigvalidity * 0.9)) { if (log_errors) { - cfg_obj_log(config, logctx, ISC_LOG_ERROR, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "dnssec-policy: policy '%s' " - "signatures-refresh must be " - "at most 90%% of the " - "signatures-validity-dnskey", + "signatures-refresh must be at most 90%% " + "of the signatures-validity-dnskey", kaspname); } result = ISC_R_FAILURE; @@ -610,10 +636,10 @@ if (sigjitter > sigvalidity) { if (log_errors) { - cfg_obj_log(config, logctx, ISC_LOG_ERROR, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "dnssec-policy: policy '%s' " - "signatures-jitter cannot " - "be larger than signatures-validity-dnskey", + "signatures-jitter cannot be larger than " + "signatures-validity-dnskey", kaspname); } result = ISC_R_FAILURE; @@ -623,10 +649,10 @@ DNS_KASP_SIG_VALIDITY); if (sigrefresh >= (sigvalidity * 0.9)) { if (log_errors) { - cfg_obj_log(config, logctx, ISC_LOG_ERROR, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "dnssec-policy: policy '%s' " - "signatures-refresh must be " - "at most 90%% of the signatures-validity", + "signatures-refresh must be at most 90%% " + "of the signatures-validity", kaspname); } result = ISC_R_FAILURE; @@ -635,7 +661,7 @@ if (sigjitter > sigvalidity) { if (log_errors) { - cfg_obj_log(config, logctx, ISC_LOG_ERROR, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "dnssec-policy: policy '%s' " "signatures-jitter cannot " "be larger than signatures-validity", @@ -748,7 +774,7 @@ ksk_min_lifetime, zsk_min_lifetime); if (result != ISC_R_SUCCESS) { if (log_errors) { - cfg_obj_log(kobj, logctx, ISC_LOG_ERROR, + kaspcfg_log(kobj, logctx, ISC_LOG_ERROR, "dnssec-policy: failed to " "configure keys (%s)", isc_result_totext(result)); @@ -788,7 +814,7 @@ (DNS_KASP_KEY_ROLE_ZSK | DNS_KASP_KEY_ROLE_KSK)) { if (log_errors) { - cfg_obj_log(keys, logctx, ISC_LOG_ERROR, + kaspcfg_log(keys, logctx, ISC_LOG_ERROR, "dnssec-policy: algorithm " "%zu requires both KSK and " "ZSK roles", @@ -797,13 +823,13 @@ result = ISC_R_FAILURE; } if (warn[i][0] && log_errors) { - cfg_obj_log(keys, logctx, ISC_LOG_WARNING, + kaspcfg_log(keys, logctx, ISC_LOG_WARNING, "dnssec-policy: algorithm %zu has " "multiple keys with ZSK role", i); } if (warn[i][1] && log_errors) { - cfg_obj_log(keys, logctx, ISC_LOG_WARNING, + kaspcfg_log(keys, logctx, ISC_LOG_WARNING, "dnssec-policy: algorithm %zu has " "multiple keys with KSK role", i); @@ -846,7 +872,7 @@ &new_key->keystore); if (result != ISC_R_SUCCESS) { if (log_errors) { - cfg_obj_log(config, logctx, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "dnssec-policy: failed to " "find keystore (%s)", @@ -1021,13 +1047,13 @@ result = dns_keystorelist_find(keystorelist, name, &keystore); if (result == ISC_R_SUCCESS) { - cfg_obj_log(config, logctx, ISC_LOG_ERROR, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "key-store: duplicate key-store found '%s'", name); dns_keystore_detach(&keystore); return ISC_R_EXISTS; } if (result != ISC_R_NOTFOUND) { - cfg_obj_log(config, logctx, ISC_LOG_ERROR, + kaspcfg_log(config, logctx, ISC_LOG_ERROR, "key-store: lookup '%s' failed: %s", name, isc_result_totext(result)); return result; diff -Nru bind9-9.20.26/lib/isccfg/parser.c bind9-9.20.29/lib/isccfg/parser.c --- bind9-9.20.26/lib/isccfg/parser.c 2026-07-20 14:47:54.099850520 +0000 +++ bind9-9.20.29/lib/isccfg/parser.c 2026-09-11 19:41:01.574332746 +0000 @@ -3150,7 +3150,7 @@ cfg_obj_t **ret) { cfg_obj_t *obj = NULL; isc_result_t result; - isc_netaddr_t netaddr; + isc_netaddr_t netaddr = { .family = AF_UNSPEC }; unsigned int addrlen = 0, prefixlen; bool expectprefix; diff -Nru bind9-9.20.26/lib/ns/Makefile.in bind9-9.20.29/lib/ns/Makefile.in --- bind9-9.20.26/lib/ns/Makefile.in 2026-07-20 14:49:10.998591015 +0000 +++ bind9-9.20.29/lib/ns/Makefile.in 2026-09-11 19:42:18.966198689 +0000 @@ -322,6 +322,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/lib/ns/client.c bind9-9.20.29/lib/ns/client.c --- bind9-9.20.26/lib/ns/client.c 2026-07-20 14:47:54.100850536 +0000 +++ bind9-9.20.29/lib/ns/client.c 2026-09-11 19:41:01.575332770 +0000 @@ -269,6 +269,7 @@ client->extflags = 0; client->ednsversion = -1; client->additionaldepth = 0; + client->additionaltotal = 0; dns_ecs_init(&client->ecs); dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE); diff -Nru bind9-9.20.26/lib/ns/include/ns/client.h bind9-9.20.29/lib/ns/include/ns/client.h --- bind9-9.20.26/lib/ns/include/ns/client.h 2026-07-20 14:47:54.100850536 +0000 +++ bind9-9.20.29/lib/ns/include/ns/client.h 2026-09-11 19:41:01.575332770 +0000 @@ -185,6 +185,7 @@ uint16_t extflags; int16_t ednsversion; /* -1 noedns */ uint16_t additionaldepth; + uint16_t additionaltotal; void (*cleanup)(ns_client_t *); ns_query_t query; isc_time_t requesttime; diff -Nru bind9-9.20.26/lib/ns/interfacemgr.c bind9-9.20.29/lib/ns/interfacemgr.c --- bind9-9.20.26/lib/ns/interfacemgr.c 2026-07-20 14:47:54.102850567 +0000 +++ bind9-9.20.29/lib/ns/interfacemgr.c 2026-09-11 19:41:01.577332817 +0000 @@ -90,6 +90,7 @@ static void clearlistenon(ns_interfacemgr_t *mgr); +#if defined(RTM_NEWADDR) && defined(RTM_DELADDR) static bool need_rescan(ns_interfacemgr_t *mgr, struct MSGHDR *rtm, size_t len) { if (rtm->MSGTYPE != RTM_NEWADDR && rtm->MSGTYPE != RTM_DELADDR) { @@ -195,6 +196,7 @@ return false; } +#endif /* if defined(RTM_NEWADDR) && defined(RTM_DELADDR) */ static void route_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, @@ -243,9 +245,11 @@ REQUIRE(mgr->route != NULL); +#if defined(RTM_NEWADDR) && defined(RTM_DELADDR) if (need_rescan(mgr, rtm, rtmlen) && mgr->sctx->interface_auto) { ns_interfacemgr_scan(mgr, false, false); } +#endif /* if defined(RTM_NEWADDR) && defined(RTM_DELADDR) */ isc_nm_read(handle, route_recv, mgr); return; diff -Nru bind9-9.20.26/lib/ns/query.c bind9-9.20.29/lib/ns/query.c --- bind9-9.20.26/lib/ns/query.c 2026-07-20 14:47:54.103850583 +0000 +++ bind9-9.20.29/lib/ns/query.c 2026-09-11 19:41:01.579332865 +0000 @@ -1018,86 +1018,27 @@ } static isc_result_t -query_validatezonedb(ns_client_t *client, const dns_name_t *name, - dns_rdatatype_t qtype, dns_getdb_options_t options, - dns_zone_t *zone, dns_db_t *db, - dns_dbversion_t **versionp) { +query_validateacls(ns_client_t *client, const dns_name_t *name, + dns_rdatatype_t qtype, dns_getdb_options_t options, + ns_dbversion_t *dbversion, dns_acl_t *queryacl, + dns_acl_t *queryonacl) { isc_result_t result; - dns_acl_t *queryacl, *queryonacl; - ns_dbversion_t *dbversion; - - REQUIRE(zone != NULL); - REQUIRE(db != NULL); - - /* - * Mirror zone data is treated as cache data. - */ - if (dns_zone_gettype(zone) == dns_zone_mirror) { - return query_checkcacheaccess(client, name, qtype, options); - } - - /* - * This limits our searching to the zone where the first name - * (the query target) was looked for. This prevents following - * CNAMES or DNAMES into other zones and prevents returning - * additional data from other zones. This does not apply if we're - * answering a query where recursion is requested and allowed. - */ - if (client->query.rpz_st == NULL && - !(WANTRECURSION(client) && RECURSIONOK(client)) && - client->query.authdbset && db != client->query.authdb) - { - return DNS_R_REFUSED; - } - - /* - * Non recursive query to a static-stub zone is prohibited; its - * zone content is not public data, but a part of local configuration - * and should not be disclosed. - */ - if (dns_zone_gettype(zone) == dns_zone_staticstub && - !RECURSIONOK(client)) - { - return DNS_R_REFUSED; - } - - /* - * If the zone has an ACL, we'll check it, otherwise - * we use the view's "allow-query" ACL. Each ACL is only checked - * once per query. - * - * Also, get the database version to use. - */ - - /* - * Get the current version of this database. - */ - dbversion = ns_client_findversion(client, db); - if (dbversion == NULL) { - CTRACE(ISC_LOG_ERROR, "unable to get db version"); - return DNS_R_SERVFAIL; - } if (options.ignoreacl) { - goto approved; + return ISC_R_SUCCESS; } if (dbversion->acl_checked) { - if (!dbversion->queryok) { - return DNS_R_REFUSED; - } - goto approved; + return dbversion->queryok ? ISC_R_SUCCESS : DNS_R_REFUSED; } - queryacl = dns_zone_getqueryacl(zone); if (queryacl == NULL) { queryacl = client->view->queryacl; if ((client->query.attributes & NS_QUERYATTR_QUERYOKVALID) != 0) { /* * We've evaluated the view's queryacl already. If - * NS_QUERYATTR_QUERYOK is set, then the client is - * allowed to make queries, otherwise the query should - * be refused. + * queryok is set, then the client is allowed to make + * queries, otherwise the query should be refused. */ dbversion->acl_checked = true; if ((client->query.attributes & NS_QUERYATTR_QUERYOK) == @@ -1107,7 +1048,7 @@ return DNS_R_REFUSED; } dbversion->queryok = true; - goto approved; + return ISC_R_SUCCESS; } } @@ -1138,22 +1079,20 @@ if (queryacl == client->view->queryacl) { if (result == ISC_R_SUCCESS) { /* - * We were allowed by the default - * "allow-query" ACL. Remember this so we - * don't have to check again. + * We were allowed by the default "allow-query" ACL. + * Remember this so we don't have to check again. */ client->query.attributes |= NS_QUERYATTR_QUERYOK; } /* - * We've now evaluated the view's query ACL, and - * the NS_QUERYATTR_QUERYOK attribute is now valid. + * We've now evaluated the view's query ACL, and the queryok + * attribute is now valid. */ client->query.attributes |= NS_QUERYATTR_QUERYOKVALID; } - /* If and only if we've gotten this far, check allow-query-on too */ + /* If and only if we've gotten this far, check allow-query-on too. */ if (result == ISC_R_SUCCESS) { - queryonacl = dns_zone_getqueryonacl(zone); if (queryonacl == NULL) { queryonacl = client->view->queryonacl; } @@ -1177,7 +1116,72 @@ } dbversion->queryok = true; -approved: + return ISC_R_SUCCESS; +} + +static isc_result_t +query_validatezonedb(ns_client_t *client, const dns_name_t *name, + dns_rdatatype_t qtype, dns_getdb_options_t options, + dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t **versionp) { + ns_dbversion_t *dbversion; + + REQUIRE(zone != NULL); + REQUIRE(db != NULL); + + /* + * Mirror zone data is treated as cache data. + */ + if (dns_zone_gettype(zone) == dns_zone_mirror) { + return query_checkcacheaccess(client, name, qtype, options); + } + + /* + * This limits our searching to the zone where the first name + * (the query target) was looked for. This prevents following + * CNAMES or DNAMES into other zones and prevents returning + * additional data from other zones. This does not apply if we're + * answering a query where recursion is requested and allowed. + */ + if (client->query.rpz_st == NULL && + !(WANTRECURSION(client) && RECURSIONOK(client)) && + client->query.authdbset && db != client->query.authdb) + { + return DNS_R_REFUSED; + } + + /* + * Non recursive query to a static-stub zone is prohibited; its + * zone content is not public data, but a part of local configuration + * and should not be disclosed. + */ + if (dns_zone_gettype(zone) == dns_zone_staticstub && + !RECURSIONOK(client)) + { + return DNS_R_REFUSED; + } + + /* + * If the zone has an ACL, we'll check it, otherwise + * we use the view's "allow-query" ACL. Each ACL is only checked + * once per query. + * + * Also, get the database version to use. + */ + + /* + * Get the current version of this database. + */ + dbversion = ns_client_findversion(client, db); + if (dbversion == NULL) { + CTRACE(ISC_LOG_ERROR, "unable to get db version"); + return DNS_R_SERVFAIL; + } + + RETERR(query_validateacls(client, name, qtype, options, dbversion, + dns_zone_getqueryacl(zone), + dns_zone_getqueryonacl(zone))); + /* Transfer ownership, if necessary. */ SET_IF_NOT_NULL(versionp, dbversion->version); return ISC_R_SUCCESS; @@ -1451,10 +1455,10 @@ dns_getdb_options_t options, dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp, bool *is_zonep) { isc_result_t result; - isc_result_t tresult; unsigned int namelabels; unsigned int zonelabels; dns_zone_t *zone = NULL; + dns_view_t *view = client->view; REQUIRE(zonep != NULL && *zonep == NULL); @@ -1475,63 +1479,56 @@ * If # zone labels < # name labels, try to find an even better match * Only try if DLZ drivers are loaded for this view */ - if (zonelabels < namelabels && - !ISC_LIST_EMPTY(client->view->dlz_searched)) - { + if (zonelabels < namelabels && !ISC_LIST_EMPTY(view->dlz_searched)) { dns_clientinfomethods_t cm; dns_clientinfo_t ci; dns_db_t *tdbp; + ns_dbversion_t *dbversion; + isc_result_t tresult; dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, client, NULL); dns_clientinfo_setecs(&ci, &client->ecs); tdbp = NULL; - tresult = dns_view_searchdlz(client->view, name, zonelabels, - &cm, &ci, &tdbp); + /* If we successful, we found a better match. */ + tresult = dns_view_searchdlz(view, name, zonelabels, &cm, &ci, + &tdbp); if (tresult == ISC_R_SUCCESS) { - ns_dbversion_t *dbversion; + /* We found a better match. */ + dbversion = ns_client_findversion(client, tdbp); /* - * If the previous search returned a zone, detach it. + * Discard the database found by the previous search. */ if (zone != NULL) { dns_zone_detach(&zone); } - - /* - * If the previous search returned a database, - * detach it. - */ if (*dbp != NULL) { dns_db_detach(dbp); } - - /* - * If the previous search returned a version, clear it. - */ *versionp = NULL; - dbversion = ns_client_findversion(client, tdbp); - if (dbversion == NULL) { - tresult = ISC_R_NOMEMORY; - } else { - /* - * Be sure to return our database. - */ - *dbp = tdbp; - *versionp = dbversion->version; + tresult = query_validateacls( + client, name, qtype, options, dbversion, + view->queryacl, view->queryonacl); + if (tresult != ISC_R_SUCCESS) { + dns_db_detach(&tdbp); + result = tresult; + goto out; } /* * We return a null zone, No stats for DLZ zones. */ - zone = NULL; - result = tresult; + *dbp = tdbp; + *versionp = dbversion->version; + result = ISC_R_SUCCESS; } } +out: /* If successful, Transfer ownership of zone. */ if (result == ISC_R_SUCCESS) { *zonep = zone; @@ -1786,6 +1783,10 @@ CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb"); + if (client->additionaltotal++ >= DNS_RDATASET_MAXADDITIONAL * 2) { + return DNS_R_TOOMANYRECORDS; + } + dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, client, NULL); @@ -2138,7 +2139,9 @@ cleanup: CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup"); - ns_client_putrdataset(client, &rdataset); + if (rdataset != NULL) { + ns_client_putrdataset(client, &rdataset); + } if (sigrdataset != NULL) { ns_client_putrdataset(client, &sigrdataset); } @@ -2658,7 +2661,7 @@ } static void -query_stale_refresh_ncache(ns_client_t *client) { +query_stale_refresh_ncache(ns_client_t *client, dns_rdataset_t *rdataset) { dns_name_t *qname; if (client->query.origqname != NULL) { @@ -2666,7 +2669,7 @@ } else { qname = client->query.qname; } - query_stale_refresh(client, qname, NULL); + query_stale_refresh(client, qname, rdataset); } static void @@ -3980,7 +3983,8 @@ * With more than one applicable policy, prefer * the earliest configured policy, * client-IP over QNAME over IP over NSDNAME over NSIP, - * and the smallest name. + * and the name that appears last in DNSSEC canonical + * order. * We known st->m.rpz->num >= rpz->num and either * st->m.rpz->num > rpz->num or st->m.type >= rpz_type */ @@ -5012,6 +5016,13 @@ return ISC_R_NOTFOUND; } + result = ns_client_checkaclsilent( + client, &client->destaddr, + dns_zone_getqueryonacl(client->view->redirect), true); + if (result != ISC_R_SUCCESS) { + return ISC_R_NOTFOUND; + } + result = dns_zone_getdb(client->view->redirect, &db); if (result != ISC_R_SUCCESS) { return ISC_R_NOTFOUND; @@ -7680,33 +7691,6 @@ query_addrrset(qctx, &fname, &neg, &negsig, dbuf, DNS_SECTION_AUTHORITY); - if ((qctx->noqname->attributes & DNS_RDATASETATTR_CLOSEST) == 0) { - goto cleanup; - } - - if (fname == NULL) { - dbuf = ns_client_getnamebuf(client); - fname = ns_client_newname(client, dbuf, &b); - } - - if (neg == NULL) { - neg = ns_client_newrdataset(client); - } else if (dns_rdataset_isassociated(neg)) { - dns_rdataset_disassociate(neg); - } - - if (negsig == NULL) { - negsig = ns_client_newrdataset(client); - } else if (dns_rdataset_isassociated(negsig)) { - dns_rdataset_disassociate(negsig); - } - - result = dns_rdataset_getclosest(qctx->noqname, fname, neg, negsig); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - - query_addrrset(qctx, &fname, &neg, &negsig, dbuf, - DNS_SECTION_AUTHORITY); - cleanup: if (neg != NULL) { ns_client_putrdataset(client, &neg); @@ -8039,6 +8023,7 @@ } } else if (qctx->client->query.dns64_aaaaok != NULL) { query_filter64(qctx); + qctx->noqname = NULL; ns_client_putrdataset(qctx->client, &qctx->rdataset); isc_mem_cput(qctx->client->manager->mctx, qctx->client->query.dns64_aaaaok, @@ -8078,9 +8063,10 @@ */ INSIST(qctx->client->query.dns64_aaaaok == NULL); - if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude && - !ISC_LIST_EMPTY(qctx->view->dns64) && + if (qctx->qtype == dns_rdatatype_aaaa && qctx->client->message->rdclass == dns_rdataclass_in && + !ISC_LIST_EMPTY(qctx->view->dns64) && !qctx->dns64_exclude && + qctx->client->query.dns64_aaaa == NULL && !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset)) { /* @@ -10243,7 +10229,7 @@ } if (!qctx->is_zone && RECURSIONOK(qctx->client)) { - query_stale_refresh_ncache(qctx->client); + query_stale_refresh_ncache(qctx->client, qctx->rdataset); } return query_nodata(qctx, result); diff -Nru bind9-9.20.26/srcid bind9-9.20.29/srcid --- bind9-9.20.26/srcid 2026-07-20 14:50:27.513353025 +0000 +++ bind9-9.20.29/srcid 2026-09-11 19:43:34.181022895 +0000 @@ -1 +1 @@ -5a605f8 +c3d4465 diff -Nru bind9-9.20.26/tests/Makefile.in bind9-9.20.29/tests/Makefile.in --- bind9-9.20.26/tests/Makefile.in 2026-07-20 14:49:11.016591428 +0000 +++ bind9-9.20.29/tests/Makefile.in 2026-09-11 19:42:18.984199127 +0000 @@ -279,6 +279,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/tests/bench/Makefile.in bind9-9.20.29/tests/bench/Makefile.in --- bind9-9.20.26/tests/bench/Makefile.in 2026-07-20 14:49:11.049592187 +0000 +++ bind9-9.20.29/tests/bench/Makefile.in 2026-09-11 19:42:19.016199906 +0000 @@ -338,6 +338,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/tests/dns/Makefile.am bind9-9.20.29/tests/dns/Makefile.am --- bind9-9.20.26/tests/dns/Makefile.am 2026-07-20 14:47:54.249852854 +0000 +++ bind9-9.20.29/tests/dns/Makefile.am 2026-09-11 19:41:01.724336338 +0000 @@ -27,11 +27,14 @@ diff_test \ dispatch_test \ dns64_test \ + dnssecsignstats_test \ dst_test \ ede_test \ keytable_test \ + message_test \ name_test \ nametree_test \ + ncache_test \ nsec3_test \ nsec3param_test \ private_test \ diff -Nru bind9-9.20.26/tests/dns/Makefile.in bind9-9.20.29/tests/dns/Makefile.in --- bind9-9.20.26/tests/dns/Makefile.in 2026-07-20 14:49:11.133594116 +0000 +++ bind9-9.20.29/tests/dns/Makefile.in 2026-09-11 19:42:19.101201977 +0000 @@ -102,13 +102,14 @@ check_PROGRAMS = acl_test$(EXEEXT) badcache_test$(EXEEXT) \ db_test$(EXEEXT) dbdiff_test$(EXEEXT) dbiterator_test$(EXEEXT) \ dbversion_test$(EXEEXT) diff_test$(EXEEXT) \ - dispatch_test$(EXEEXT) dns64_test$(EXEEXT) dst_test$(EXEEXT) \ - ede_test$(EXEEXT) keytable_test$(EXEEXT) name_test$(EXEEXT) \ - nametree_test$(EXEEXT) nsec3_test$(EXEEXT) \ - nsec3param_test$(EXEEXT) private_test$(EXEEXT) \ - qp_test$(EXEEXT) qpmulti_test$(EXEEXT) qpdb_test$(EXEEXT) \ - qpzone_test$(EXEEXT) rbt_test$(EXEEXT) rbtdb_test$(EXEEXT) \ - rdata_test$(EXEEXT) rdataset_test$(EXEEXT) \ + dispatch_test$(EXEEXT) dns64_test$(EXEEXT) \ + dnssecsignstats_test$(EXEEXT) dst_test$(EXEEXT) \ + ede_test$(EXEEXT) keytable_test$(EXEEXT) message_test$(EXEEXT) \ + name_test$(EXEEXT) nametree_test$(EXEEXT) ncache_test$(EXEEXT) \ + nsec3_test$(EXEEXT) nsec3param_test$(EXEEXT) \ + private_test$(EXEEXT) qp_test$(EXEEXT) qpmulti_test$(EXEEXT) \ + qpdb_test$(EXEEXT) qpzone_test$(EXEEXT) rbt_test$(EXEEXT) \ + rbtdb_test$(EXEEXT) rdata_test$(EXEEXT) rdataset_test$(EXEEXT) \ rdatasetstats_test$(EXEEXT) resconf_test$(EXEEXT) \ resolver_test$(EXEEXT) rsa_test$(EXEEXT) sigs_test$(EXEEXT) \ skr_test$(EXEEXT) time_test$(EXEEXT) tsig_test$(EXEEXT) \ @@ -225,6 +226,13 @@ $(am__DEPENDENCIES_1) $(LIBDNS_LIBS) \ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_3) +dnssecsignstats_test_SOURCES = dnssecsignstats_test.c +dnssecsignstats_test_OBJECTS = dnssecsignstats_test.$(OBJEXT) +dnssecsignstats_test_LDADD = $(LDADD) +dnssecsignstats_test_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(LIBDNS_LIBS) \ + $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_3) dnstap_test_SOURCES = dnstap_test.c dnstap_test_OBJECTS = dnstap_test-dnstap_test.$(OBJEXT) am__DEPENDENCIES_4 = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ @@ -265,6 +273,13 @@ $(am__DEPENDENCIES_1) $(LIBDNS_LIBS) \ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_3) +message_test_SOURCES = message_test.c +message_test_OBJECTS = message_test.$(OBJEXT) +message_test_LDADD = $(LDADD) +message_test_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(LIBDNS_LIBS) \ + $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_3) name_test_SOURCES = name_test.c name_test_OBJECTS = name_test.$(OBJEXT) name_test_LDADD = $(LDADD) @@ -279,6 +294,13 @@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(LIBDNS_LIBS) \ $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_3) +ncache_test_SOURCES = ncache_test.c +ncache_test_OBJECTS = ncache_test.$(OBJEXT) +ncache_test_LDADD = $(LDADD) +ncache_test_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(LIBDNS_LIBS) \ + $(top_builddir)/tests/libtest/libtest.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_3) nsec3_test_SOURCES = nsec3_test.c nsec3_test_OBJECTS = nsec3_test.$(OBJEXT) nsec3_test_LDADD = $(LDADD) @@ -449,11 +471,13 @@ ./$(DEPDIR)/dbdiff_test.Po ./$(DEPDIR)/dbiterator_test.Po \ ./$(DEPDIR)/dbversion_test.Po ./$(DEPDIR)/diff_test.Po \ ./$(DEPDIR)/dispatch_test.Po ./$(DEPDIR)/dns64_test.Po \ + ./$(DEPDIR)/dnssecsignstats_test.Po \ ./$(DEPDIR)/dnstap_test-dnstap_test.Po \ ./$(DEPDIR)/dst_test-dst_test.Po ./$(DEPDIR)/ede_test.Po \ ./$(DEPDIR)/geoip_test-geoip_test.Po \ ./$(DEPDIR)/keytable_test.Po ./$(DEPDIR)/master_test.Po \ - ./$(DEPDIR)/name_test.Po ./$(DEPDIR)/nametree_test.Po \ + ./$(DEPDIR)/message_test.Po ./$(DEPDIR)/name_test.Po \ + ./$(DEPDIR)/nametree_test.Po ./$(DEPDIR)/ncache_test.Po \ ./$(DEPDIR)/nsec3_test.Po ./$(DEPDIR)/nsec3param_test.Po \ ./$(DEPDIR)/private_test.Po ./$(DEPDIR)/qp_test.Po \ ./$(DEPDIR)/qpdb_test.Po ./$(DEPDIR)/qpmulti_test.Po \ @@ -486,8 +510,9 @@ am__v_CCLD_1 = SOURCES = acl_test.c badcache_test.c db_test.c dbdiff_test.c \ dbiterator_test.c dbversion_test.c diff_test.c dispatch_test.c \ - dns64_test.c dnstap_test.c dst_test.c ede_test.c geoip_test.c \ - keytable_test.c master_test.c name_test.c nametree_test.c \ + dns64_test.c dnssecsignstats_test.c dnstap_test.c dst_test.c \ + ede_test.c geoip_test.c keytable_test.c master_test.c \ + message_test.c name_test.c nametree_test.c ncache_test.c \ nsec3_test.c nsec3param_test.c private_test.c qp_test.c \ qpdb_test.c qpmulti_test.c qpzone_test.c rbt_test.c \ rbtdb_test.c rdata_test.c rdataset_test.c rdatasetstats_test.c \ @@ -496,8 +521,9 @@ zonemgr_test.c zt_test.c DIST_SOURCES = acl_test.c badcache_test.c db_test.c dbdiff_test.c \ dbiterator_test.c dbversion_test.c diff_test.c dispatch_test.c \ - dns64_test.c dnstap_test.c dst_test.c ede_test.c geoip_test.c \ - keytable_test.c master_test.c name_test.c nametree_test.c \ + dns64_test.c dnssecsignstats_test.c dnstap_test.c dst_test.c \ + ede_test.c geoip_test.c keytable_test.c master_test.c \ + message_test.c name_test.c nametree_test.c ncache_test.c \ nsec3_test.c nsec3param_test.c private_test.c qp_test.c \ qpdb_test.c qpmulti_test.c qpzone_test.c rbt_test.c \ rbtdb_test.c rdata_test.c rdataset_test.c rdatasetstats_test.c \ @@ -817,6 +843,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ @@ -1135,6 +1162,10 @@ @rm -f dns64_test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(dns64_test_OBJECTS) $(dns64_test_LDADD) $(LIBS) +dnssecsignstats_test$(EXEEXT): $(dnssecsignstats_test_OBJECTS) $(dnssecsignstats_test_DEPENDENCIES) $(EXTRA_dnssecsignstats_test_DEPENDENCIES) + @rm -f dnssecsignstats_test$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(dnssecsignstats_test_OBJECTS) $(dnssecsignstats_test_LDADD) $(LIBS) + dnstap_test$(EXEEXT): $(dnstap_test_OBJECTS) $(dnstap_test_DEPENDENCIES) $(EXTRA_dnstap_test_DEPENDENCIES) @rm -f dnstap_test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(dnstap_test_OBJECTS) $(dnstap_test_LDADD) $(LIBS) @@ -1159,6 +1190,10 @@ @rm -f master_test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(master_test_OBJECTS) $(master_test_LDADD) $(LIBS) +message_test$(EXEEXT): $(message_test_OBJECTS) $(message_test_DEPENDENCIES) $(EXTRA_message_test_DEPENDENCIES) + @rm -f message_test$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(message_test_OBJECTS) $(message_test_LDADD) $(LIBS) + name_test$(EXEEXT): $(name_test_OBJECTS) $(name_test_DEPENDENCIES) $(EXTRA_name_test_DEPENDENCIES) @rm -f name_test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(name_test_OBJECTS) $(name_test_LDADD) $(LIBS) @@ -1167,6 +1202,10 @@ @rm -f nametree_test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nametree_test_OBJECTS) $(nametree_test_LDADD) $(LIBS) +ncache_test$(EXEEXT): $(ncache_test_OBJECTS) $(ncache_test_DEPENDENCIES) $(EXTRA_ncache_test_DEPENDENCIES) + @rm -f ncache_test$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(ncache_test_OBJECTS) $(ncache_test_LDADD) $(LIBS) + nsec3_test$(EXEEXT): $(nsec3_test_OBJECTS) $(nsec3_test_DEPENDENCIES) $(EXTRA_nsec3_test_DEPENDENCIES) @rm -f nsec3_test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nsec3_test_OBJECTS) $(nsec3_test_LDADD) $(LIBS) @@ -1270,14 +1309,17 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diff_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatch_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns64_test.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnssecsignstats_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnstap_test-dnstap_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dst_test-dst_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ede_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/geoip_test-geoip_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keytable_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/master_test.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/name_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nametree_test.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ncache_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3param_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/private_test.Po@am__quote@ # am--include-marker @@ -1691,6 +1733,13 @@ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +dnssecsignstats_test.log: dnssecsignstats_test$(EXEEXT) + @p='dnssecsignstats_test$(EXEEXT)'; \ + b='dnssecsignstats_test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) dst_test.log: dst_test$(EXEEXT) @p='dst_test$(EXEEXT)'; \ b='dst_test'; \ @@ -1712,6 +1761,13 @@ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +message_test.log: message_test$(EXEEXT) + @p='message_test$(EXEEXT)'; \ + b='message_test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) name_test.log: name_test$(EXEEXT) @p='name_test$(EXEEXT)'; \ b='name_test'; \ @@ -1726,6 +1782,13 @@ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +ncache_test.log: ncache_test$(EXEEXT) + @p='ncache_test$(EXEEXT)'; \ + b='ncache_test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) nsec3_test.log: nsec3_test$(EXEEXT) @p='nsec3_test$(EXEEXT)'; \ b='nsec3_test'; \ @@ -2007,14 +2070,17 @@ -rm -f ./$(DEPDIR)/diff_test.Po -rm -f ./$(DEPDIR)/dispatch_test.Po -rm -f ./$(DEPDIR)/dns64_test.Po + -rm -f ./$(DEPDIR)/dnssecsignstats_test.Po -rm -f ./$(DEPDIR)/dnstap_test-dnstap_test.Po -rm -f ./$(DEPDIR)/dst_test-dst_test.Po -rm -f ./$(DEPDIR)/ede_test.Po -rm -f ./$(DEPDIR)/geoip_test-geoip_test.Po -rm -f ./$(DEPDIR)/keytable_test.Po -rm -f ./$(DEPDIR)/master_test.Po + -rm -f ./$(DEPDIR)/message_test.Po -rm -f ./$(DEPDIR)/name_test.Po -rm -f ./$(DEPDIR)/nametree_test.Po + -rm -f ./$(DEPDIR)/ncache_test.Po -rm -f ./$(DEPDIR)/nsec3_test.Po -rm -f ./$(DEPDIR)/nsec3param_test.Po -rm -f ./$(DEPDIR)/private_test.Po @@ -2095,14 +2161,17 @@ -rm -f ./$(DEPDIR)/diff_test.Po -rm -f ./$(DEPDIR)/dispatch_test.Po -rm -f ./$(DEPDIR)/dns64_test.Po + -rm -f ./$(DEPDIR)/dnssecsignstats_test.Po -rm -f ./$(DEPDIR)/dnstap_test-dnstap_test.Po -rm -f ./$(DEPDIR)/dst_test-dst_test.Po -rm -f ./$(DEPDIR)/ede_test.Po -rm -f ./$(DEPDIR)/geoip_test-geoip_test.Po -rm -f ./$(DEPDIR)/keytable_test.Po -rm -f ./$(DEPDIR)/master_test.Po + -rm -f ./$(DEPDIR)/message_test.Po -rm -f ./$(DEPDIR)/name_test.Po -rm -f ./$(DEPDIR)/nametree_test.Po + -rm -f ./$(DEPDIR)/ncache_test.Po -rm -f ./$(DEPDIR)/nsec3_test.Po -rm -f ./$(DEPDIR)/nsec3param_test.Po -rm -f ./$(DEPDIR)/private_test.Po diff -Nru bind9-9.20.26/tests/dns/badcache_test.c bind9-9.20.29/tests/dns/badcache_test.c --- bind9-9.20.26/tests/dns/badcache_test.c 2026-07-20 14:47:54.249852854 +0000 +++ bind9-9.20.29/tests/dns/badcache_test.c 2026-09-11 19:41:01.724336338 +0000 @@ -140,10 +140,12 @@ dns_badcache_add(bc, name, dns_rdatatype_aaaa, flags, expire); file = fopen("./badcache.out", "w"); + assert_non_null(file); dns_badcache_print(bc, "badcache", file); fclose(file); file = fopen("./badcache.out", "r"); + assert_non_null(file); len = fread(buf, sizeof(buf[0]), ARRAY_SIZE(buf), file); assert_int_equal(len, 68); fclose(file); diff -Nru bind9-9.20.26/tests/dns/db_test.c bind9-9.20.29/tests/dns/db_test.c --- bind9-9.20.26/tests/dns/db_test.c 2026-07-20 14:47:54.251852885 +0000 +++ bind9-9.20.29/tests/dns/db_test.c 2026-09-11 19:41:01.727336409 +0000 @@ -353,6 +353,7 @@ /* Now we create a node with an empty parent */ result = dns_db_newversion(db, &new); + assert_int_equal(result, ISC_R_SUCCESS); dns_test_namefromstring("long.ent.name.test.test.", &fname); result = dns_db_findnode(db, name, true, &node); assert_int_equal(result, ISC_R_SUCCESS); diff -Nru bind9-9.20.26/tests/dns/dnssecsignstats_test.c bind9-9.20.29/tests/dns/dnssecsignstats_test.c --- bind9-9.20.26/tests/dns/dnssecsignstats_test.c 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/tests/dns/dnssecsignstats_test.c 2026-09-11 19:41:01.728336434 +0000 @@ -0,0 +1,217 @@ +/* + * 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. + */ + +#include +#include /* IWYU pragma: keep */ +#include +#include +#include +#include +#include + +#define UNIT_TESTING +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#define DNSSEC_KEY(alg, id) ((uint32_t)(alg) << 16 | (id)) + +typedef struct { + uint32_t key; + uint64_t value; +} dumped_entry_t; + +typedef struct { + dumped_entry_t entries[64]; + size_t count; +} dump_t; + +static void +collect(uint32_t key, uint64_t value, void *arg) { + dump_t *dump = arg; + + assert_true(dump->count < ARRAY_SIZE(dump->entries)); + dump->entries[dump->count++] = (dumped_entry_t){ + .key = key, + .value = value, + }; +} + +static bool +find_value(const dump_t *dump, uint32_t key, uint64_t *valuep) { + for (size_t i = 0; i < dump->count; i++) { + if (dump->entries[i].key == key) { + *valuep = dump->entries[i].value; + return true; + } + } + + return false; +} + +ISC_RUN_TEST_IMPL(basic) { + dns_stats_t *stats = NULL; + dump_t dump = { 0 }; + uint64_t value = 0; + + UNUSED(state); + + dns_dnssecsignstats_create(mctx, &stats); + for (dns_keytag_t id = 1; id <= 40; id++) { + dns_dnssecsignstats_increment(stats, id, 8, + dns_dnssecsignstats_sign); + } + dns_dnssecsignstats_increment(stats, 1, 8, dns_dnssecsignstats_sign); + dns_dnssecsignstats_increment(stats, 1, 8, dns_dnssecsignstats_refresh); + dns_dnssecsignstats_increment(stats, 1, 13, dns_dnssecsignstats_sign); + + dns_dnssecsignstats_dump(stats, dns_dnssecsignstats_sign, collect, + &dump, 0); + assert_int_equal(dump.count, 41); + assert_true(find_value(&dump, DNSSEC_KEY(8, 1), &value)); + assert_int_equal(value, 2); + assert_true(find_value(&dump, DNSSEC_KEY(13, 1), &value)); + assert_int_equal(value, 1); + + dump = (dump_t){ 0 }; + dns_dnssecsignstats_dump(stats, dns_dnssecsignstats_refresh, collect, + &dump, 0); + assert_int_equal(dump.count, 1); + assert_true(find_value(&dump, DNSSEC_KEY(8, 1), &value)); + assert_int_equal(value, 1); + + dump = (dump_t){ 0 }; + dns_dnssecsignstats_dump(stats, dns_dnssecsignstats_refresh, collect, + &dump, ISC_STATSDUMP_VERBOSE); + assert_int_equal(dump.count, 41); + assert_true(find_value(&dump, DNSSEC_KEY(13, 1), &value)); + assert_int_equal(value, 0); + + dns_dnssecsignstats_clear(stats, 1, 8); + dump = (dump_t){ 0 }; + dns_dnssecsignstats_dump(stats, dns_dnssecsignstats_sign, collect, + &dump, 0); + assert_int_equal(dump.count, 40); + assert_false(find_value(&dump, DNSSEC_KEY(8, 1), &value)); + + dns_dnssecsignstats_increment(stats, 1, 8, dns_dnssecsignstats_refresh); + dump = (dump_t){ 0 }; + dns_dnssecsignstats_dump(stats, dns_dnssecsignstats_refresh, collect, + &dump, 0); + assert_true(find_value(&dump, DNSSEC_KEY(8, 1), &value)); + assert_int_equal(value, 1); + + dns_stats_detach(&stats); + rcu_barrier(); +} + +#define STRESS_READER_THREADS 4 +#define STRESS_ITERATIONS 20000 +#define STRESS_KEY_COUNT 64 + +typedef struct { + dns_stats_t *stats; + atomic_uint_fast32_t readers_ready; + atomic_uint_fast64_t dumps; + atomic_bool invalid; + atomic_bool stop; +} stress_test_t; + +static void +stress_dump(uint32_t key, uint64_t value, void *arg) { + stress_test_t *test = arg; + uint8_t alg = key >> 16; + dns_keytag_t id = key; + + if ((alg != 8 && alg != 13) || id == 0 || id > STRESS_KEY_COUNT || + value != 1) + { + atomic_store_relaxed(&test->invalid, true); + } +} + +static void * +stress_reader(void *arg) { + stress_test_t *test = arg; + + atomic_fetch_add_relaxed(&test->readers_ready, 1); + while (!atomic_load_acquire(&test->stop)) { + dns_dnssecsignstats_dump(test->stats, dns_dnssecsignstats_sign, + stress_dump, test, 0); + dns_dnssecsignstats_dump(test->stats, + dns_dnssecsignstats_refresh, + stress_dump, test, 0); + atomic_fetch_add_relaxed(&test->dumps, 1); + } + + return NULL; +} + +ISC_RUN_TEST_IMPL(concurrent_clear_dump) { + dns_stats_t *stats = NULL; + stress_test_t test = { 0 }; + isc_thread_t threads[STRESS_READER_THREADS]; + + UNUSED(state); + + dns_dnssecsignstats_create(mctx, &stats); + test.stats = stats; + atomic_init(&test.readers_ready, 0); + atomic_init(&test.dumps, 0); + atomic_init(&test.invalid, false); + atomic_init(&test.stop, false); + + for (size_t i = 0; i < ARRAY_SIZE(threads); i++) { + isc_thread_create(stress_reader, &test, &threads[i]); + } + while (atomic_load_acquire(&test.readers_ready) < ARRAY_SIZE(threads)) { + isc_thread_yield(); + } + + for (size_t i = 0; i < STRESS_ITERATIONS; i++) { + dns_keytag_t id = i % STRESS_KEY_COUNT + 1; + uint8_t alg = i % 2 == 0 ? 8 : 13; + + dns_dnssecsignstats_increment(stats, id, alg, + dns_dnssecsignstats_sign); + dns_dnssecsignstats_increment(stats, id, alg, + dns_dnssecsignstats_refresh); + dns_dnssecsignstats_clear(stats, id, alg); + } + + atomic_store_release(&test.stop, true); + for (size_t i = 0; i < ARRAY_SIZE(threads); i++) { + isc_thread_join(threads[i], NULL); + } + + assert_false(atomic_load_relaxed(&test.invalid)); + assert_true(atomic_load_relaxed(&test.dumps) > 0); + + dns_stats_detach(&stats); + rcu_barrier(); +} + +ISC_TEST_LIST_START +ISC_TEST_ENTRY(basic) +ISC_TEST_ENTRY(concurrent_clear_dump) +ISC_TEST_LIST_END + +ISC_TEST_MAIN diff -Nru bind9-9.20.26/tests/dns/ede_test.c bind9-9.20.29/tests/dns/ede_test.c --- bind9-9.20.26/tests/dns/ede_test.c 2026-07-20 14:47:54.252852901 +0000 +++ bind9-9.20.29/tests/dns/ede_test.c 2026-09-11 19:41:01.728336434 +0000 @@ -146,7 +146,7 @@ dns_ede_init(mctx, &edectx); dns_ede_add(&edectx, 1, NULL); - expect_assert_failure(dns_ede_add(&edectx, 32, NULL)); + expect_assert_failure(dns_ede_add(&edectx, DNS_EDE_MAX_CODE + 1, NULL)); const ede_test_expected_t expected[] = { { .code = 1, .txt = NULL }, diff -Nru bind9-9.20.26/tests/dns/keytable_test.c bind9-9.20.29/tests/dns/keytable_test.c --- bind9-9.20.26/tests/dns/keytable_test.c 2026-07-20 14:47:54.252852901 +0000 +++ bind9-9.20.29/tests/dns/keytable_test.c 2026-09-11 19:41:01.729336457 +0000 @@ -575,6 +575,8 @@ ISC_LOOP_TEST_IMPL(dump) { FILE *f = fopen("/dev/null", "w"); + assert_non_null(f); + UNUSED(arg); create_tables(); diff -Nru bind9-9.20.26/tests/dns/master_test.c bind9-9.20.29/tests/dns/master_test.c --- bind9-9.20.26/tests/dns/master_test.c 2026-07-20 14:47:54.252852901 +0000 +++ bind9-9.20.29/tests/dns/master_test.c 2026-09-11 19:41:01.729336457 +0000 @@ -179,6 +179,29 @@ } /* + * Embedded NUL test: + * dns_master_loadbuffer() rejects a bare NUL byte with DNS_R_SYNTAX + * instead of acting on the partially-written unknown token + */ +ISC_RUN_TEST_IMPL(nulbyte) { + isc_result_t result; + isc_buffer_t source; + unsigned char data[] = "$INCLUDE \0\n"; + + UNUSED(state); + + result = setup_master(nullmsg, nullmsg); + assert_int_equal(result, ISC_R_SUCCESS); + + isc_buffer_init(&source, data, sizeof(data) - 1); + isc_buffer_add(&source, sizeof(data) - 1); + + result = dns_master_loadbuffer(&source, &dns_origin, &dns_origin, + dns_rdataclass_in, 0, &callbacks, mctx); + assert_int_equal(result, DNS_R_SYNTAX); +} + +/* * Unexpected end of file test: * dns_master_loadfile() returns DNS_R_UNEXPECTED when file ends too soon */ @@ -561,6 +584,7 @@ ISC_TEST_LIST_START ISC_TEST_ENTRY(load) +ISC_TEST_ENTRY(nulbyte) ISC_TEST_ENTRY(unexpected) ISC_TEST_ENTRY(noowner) ISC_TEST_ENTRY(nottl) diff -Nru bind9-9.20.26/tests/dns/message_test.c bind9-9.20.29/tests/dns/message_test.c --- bind9-9.20.26/tests/dns/message_test.c 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/tests/dns/message_test.c 2026-09-11 19:41:01.729336457 +0000 @@ -0,0 +1,219 @@ +/* + * 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. + */ + +#include +#include /* IWYU pragma: keep */ +#include +#include +#include +#include +#include +#include +#include + +#define UNIT_TESTING +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TTL 300 + +/* + * Helpers for assembling a DNS message in wire format by hand, so that + * it can contain things dns_message_rendersection() would never produce, + * such as the same RR listed several times. + */ + +static void +put_name(isc_buffer_t *wire, const char *namestr) { + dns_fixedname_t fname; + isc_region_t r; + + dns_test_namefromstring(namestr, &fname); + dns_name_toregion(dns_fixedname_name(&fname), &r); + isc_buffer_putmem(wire, r.base, r.length); +} + +static void +put_header(isc_buffer_t *wire, unsigned int ancount, unsigned int nscount) { + isc_buffer_putuint16(wire, 0x1234); /* ID */ + isc_buffer_putuint16(wire, DNS_MESSAGEFLAG_QR); + isc_buffer_putuint16(wire, 1); /* QDCOUNT */ + isc_buffer_putuint16(wire, ancount); + isc_buffer_putuint16(wire, nscount); + isc_buffer_putuint16(wire, 0); /* ARCOUNT */ +} + +static void +put_question(isc_buffer_t *wire, const char *qname, dns_rdatatype_t qtype) { + put_name(wire, qname); + isc_buffer_putuint16(wire, qtype); + isc_buffer_putuint16(wire, dns_rdataclass_in); +} + +static void +put_rr_with_ttl(isc_buffer_t *wire, const char *owner, dns_rdatatype_t type, + dns_ttl_t ttl, const char *rdatatext) { + unsigned char rdatabuf[512]; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_result_t result; + + result = dns_test_rdatafromstring(&rdata, dns_rdataclass_in, type, + rdatabuf, sizeof(rdatabuf), rdatatext, + false); + assert_int_equal(result, ISC_R_SUCCESS); + + put_name(wire, owner); + isc_buffer_putuint16(wire, type); + isc_buffer_putuint16(wire, dns_rdataclass_in); + isc_buffer_putuint32(wire, ttl); + isc_buffer_putuint16(wire, rdata.length); + isc_buffer_putmem(wire, rdata.data, rdata.length); +} + +static void +put_rr(isc_buffer_t *wire, const char *owner, dns_rdatatype_t type, + const char *rdatatext) { + put_rr_with_ttl(wire, owner, type, TTL, rdatatext); +} + +static isc_result_t +parse(isc_buffer_t *wire, unsigned int options, dns_message_t **msgp) { + dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, msgp); + return dns_message_parse(*msgp, wire, options); +} + +/* + * Get the rdataset of the given type at 'owner' in 'section'. + */ +static dns_rdataset_t * +get_rdataset(dns_message_t *msg, dns_section_t section, const char *owner, + dns_rdatatype_t type) { + dns_fixedname_t fname; + dns_rdataset_t *rdataset = NULL; + isc_result_t result; + + dns_test_namefromstring(owner, &fname); + result = dns_message_findname(msg, section, dns_fixedname_name(&fname), + type, 0, NULL, &rdataset); + assert_int_equal(result, ISC_R_SUCCESS); + + return rdataset; +} + +/* + * A record of a singleton type repeated with identical RDATA is kept once; + * repeats of other types are all retained, as before. + */ +ISC_RUN_TEST_IMPL(parse_duplicate_singleton) { + unsigned char wirebuf[1024]; + isc_buffer_t wire; + dns_message_t *msg = NULL; + isc_result_t result; + dns_rdataset_t *rdataset = NULL; + + isc_buffer_init(&wire, wirebuf, sizeof(wirebuf)); + put_header(&wire, 4, 2); + put_question(&wire, "dup.example.", dns_rdatatype_a); + put_rr_with_ttl(&wire, "dup.example.", dns_rdatatype_cname, 600, + "target.example."); + put_rr_with_ttl(&wire, "dup.example.", dns_rdatatype_cname, 300, + "target.example."); + put_rr_with_ttl(&wire, "target.example.", dns_rdatatype_a, 600, + "10.0.0.1"); + put_rr_with_ttl(&wire, "target.example.", dns_rdatatype_a, 1200, + "10.0.0.1"); + put_rr_with_ttl(&wire, "example.", dns_rdatatype_soa, 0, + "ns.example. hostmaster.example. 1 3600 600 86400 300"); + put_rr_with_ttl(&wire, "example.", dns_rdatatype_soa, 1200, + "ns.example. hostmaster.example. 1 3600 600 86400 300"); + + result = parse(&wire, 0, &msg); + assert_int_equal(result, ISC_R_SUCCESS); + + rdataset = get_rdataset(msg, DNS_SECTION_ANSWER, "dup.example.", + dns_rdatatype_cname); + assert_non_null(rdataset); + assert_int_equal(dns_rdataset_count(rdataset), 1); + assert_int_equal(rdataset->ttl, 300); + + rdataset = get_rdataset(msg, DNS_SECTION_ANSWER, "target.example.", + dns_rdatatype_a); + assert_non_null(rdataset); + assert_int_equal(dns_rdataset_count(rdataset), 2); + assert_int_equal(rdataset->ttl, 600); + + rdataset = get_rdataset(msg, DNS_SECTION_AUTHORITY, "example.", + dns_rdatatype_soa); + assert_non_null(rdataset); + assert_int_equal(dns_rdataset_count(rdataset), 1); + assert_int_equal(rdataset->ttl, 0); + + dns_message_detach(&msg); +} + +/* + * A singleton type with two different RDATA is still a malformed message. + */ +ISC_RUN_TEST_IMPL(parse_conflicting_singleton) { + unsigned char wirebuf[1024]; + isc_buffer_t wire; + dns_message_t *msg = NULL; + isc_result_t result; + dns_rdataset_t *rdataset = NULL; + + isc_buffer_init(&wire, wirebuf, sizeof(wirebuf)); + put_header(&wire, 2, 0); + put_question(&wire, "dup.example.", dns_rdatatype_a); + put_rr(&wire, "dup.example.", dns_rdatatype_cname, "target.example."); + put_rr(&wire, "dup.example.", dns_rdatatype_cname, "other.example."); + + result = parse(&wire, 0, &msg); + assert_int_equal(result, DNS_R_FORMERR); + dns_message_detach(&msg); + + /* + * With best-effort parsing the problem is reported but the message + * is still usable, and only the first CNAME survives. + */ + isc_buffer_first(&wire); + result = parse(&wire, DNS_MESSAGEPARSE_BESTEFFORT, &msg); + assert_int_equal(result, DNS_R_RECOVERABLE); + + rdataset = get_rdataset(msg, DNS_SECTION_ANSWER, "dup.example.", + dns_rdatatype_cname); + assert_non_null(rdataset); + assert_int_equal(dns_rdataset_count(rdataset), 2); + + dns_message_detach(&msg); +} + +ISC_TEST_LIST_START +ISC_TEST_ENTRY(parse_duplicate_singleton) +ISC_TEST_ENTRY(parse_conflicting_singleton) +ISC_TEST_LIST_END + +ISC_TEST_MAIN diff -Nru bind9-9.20.26/tests/dns/name_test.c bind9-9.20.29/tests/dns/name_test.c --- bind9-9.20.26/tests/dns/name_test.c 2026-07-20 14:47:54.252852901 +0000 +++ bind9-9.20.29/tests/dns/name_test.c 2026-09-11 19:41:01.729336457 +0000 @@ -949,6 +949,148 @@ assert_int_equal(dns_name_countlabels(name), DNS_NAME_MAXLABELS); } +#define VARGC(...) (sizeof((unsigned char[]){ __VA_ARGS__ })) +#define TOTEXT_TEST(flags, text, ...) \ + { { __VA_ARGS__ }, VARGC(__VA_ARGS__), flags, text } + +ISC_RUN_TEST_IMPL(totext) { + isc_result_t result; + struct { + unsigned char data[255]; + size_t length; + int flags; + const char *text; + } totext[] = { + /* Root name tests. */ + TOTEXT_TEST(0, ".", 0x00), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, ".", 0x00), + /* Plain label tests. */ +#define WIRE_DATA 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x00 + TOTEXT_TEST(0, "example.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "example", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "example.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "example", + WIRE_DATA), + /* Embbeded NUL in label tests. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '\0', 'b', 0x00 + TOTEXT_TEST(0, "a\\000b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\000b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a\\000b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a\\000b", + WIRE_DATA), + /* Embbeded period in label tests. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '.', 'b', 0x00 + TOTEXT_TEST(0, "a\\.b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\.b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a\\.b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a\\.b", + WIRE_DATA), + /* Embbeded space in label tests. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', ' ', 'b', 0x00 + TOTEXT_TEST(0, "a\\032b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\032b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a b", + WIRE_DATA), + /* Embbeded semi-colon in label tests. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', ';', 'b', 0x00 + TOTEXT_TEST(0, "a\\;b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\;b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a;b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a;b", + WIRE_DATA), + /* Embeded backslash in label test. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '\\', 'b', 0x00 + TOTEXT_TEST(0, "a\\\\b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\\\b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a\\\\b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a\\\\b", + WIRE_DATA), + /* Embeded double quote in label test. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '"', 'b', 0x00 + TOTEXT_TEST(0, "a\\\"b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\\"b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a\\\"b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a\\\"b", + WIRE_DATA), + /* Embeded commercial at in label test. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '@', 'b', 0x00 + TOTEXT_TEST(0, "a\\@b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\@b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_PRINCIPAL, "a@b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_PRINCIPAL | DNS_NAME_OMITFINALDOT, "a@b", + WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a@b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a@b", + WIRE_DATA), + /* Embeded dollar symbol in label test. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '$', 'b', 0x00 + TOTEXT_TEST(0, "a\\$b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\$b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_PRINCIPAL, "a$b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_PRINCIPAL | DNS_NAME_OMITFINALDOT, "a$b", + WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a$b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a$b", + WIRE_DATA), + /* Embeded left parenthesis label test. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '(', 'b', 0x00 + TOTEXT_TEST(0, "a\\(b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\(b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a(b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a(b", + WIRE_DATA), + /* Embeded right parenthesis label test. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', ')', 'b', 0x00 + TOTEXT_TEST(0, "a\\)b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a\\)b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a)b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a)b", + WIRE_DATA), + /* Embeded left curly bracket label test. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '{', 'b', 0x00 + TOTEXT_TEST(0, "a{b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a{b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a{b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a{b", + WIRE_DATA), + /* Embeded right curly bracket label test. */ +#undef WIRE_DATA +#define WIRE_DATA 0x03, 'a', '}', 'b', 0x00 + TOTEXT_TEST(0, "a}b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_OMITFINALDOT, "a}b", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED, "a}b.", WIRE_DATA), + TOTEXT_TEST(DNS_NAME_QUOTED | DNS_NAME_OMITFINALDOT, "a}b", + WIRE_DATA), + }; + char namebuf[DNS_NAME_FORMATSIZE]; + + for (size_t i = 0; i < ARRAY_SIZE(totext); i++) { + isc_region_t r = { .base = totext[i].data, + .length = totext[i].length }; + isc_buffer_t b; + dns_name_t name = DNS_NAME_INITEMPTY; + + dns_name_fromregion(&name, &r); + isc_buffer_init(&b, namebuf, sizeof(namebuf)); + + result = dns_name_totext(&name, totext[i].flags, &b); + assert_int_equal(result, ISC_R_SUCCESS); + assert_string_equal(namebuf, totext[i].text); + } +} + #ifdef DNS_BENCHMARK_TESTS /* @@ -1031,22 +1173,23 @@ #endif /* DNS_BENCHMARK_TESTS */ ISC_TEST_LIST_START -ISC_TEST_ENTRY(fullcompare) -ISC_TEST_ENTRY(compression) +ISC_TEST_ENTRY(buffer) ISC_TEST_ENTRY(collision) +ISC_TEST_ENTRY(compression) +ISC_TEST_ENTRY(countlabels) ISC_TEST_ENTRY(fromregion) ISC_TEST_ENTRY(fromwire) -ISC_TEST_ENTRY(istat) +ISC_TEST_ENTRY(fullcompare) +ISC_TEST_ENTRY(getlabel) +ISC_TEST_ENTRY(getlabelsequence) +ISC_TEST_ENTRY(hash) ISC_TEST_ENTRY(init) ISC_TEST_ENTRY(invalidate) -ISC_TEST_ENTRY(buffer) ISC_TEST_ENTRY(isabsolute) -ISC_TEST_ENTRY(hash) ISC_TEST_ENTRY(issubdomain) -ISC_TEST_ENTRY(countlabels) -ISC_TEST_ENTRY(getlabel) -ISC_TEST_ENTRY(getlabelsequence) +ISC_TEST_ENTRY(istat) ISC_TEST_ENTRY(maxlabels) +ISC_TEST_ENTRY(totext) #ifdef DNS_BENCHMARK_TESTS ISC_TEST_ENTRY(benchmark) #endif /* DNS_BENCHMARK_TESTS */ diff -Nru bind9-9.20.26/tests/dns/ncache_test.c bind9-9.20.29/tests/dns/ncache_test.c --- bind9-9.20.26/tests/dns/ncache_test.c 1970-01-01 00:00:00.000000000 +0000 +++ bind9-9.20.29/tests/dns/ncache_test.c 2026-09-11 19:41:01.729336457 +0000 @@ -0,0 +1,302 @@ +/* + * 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. + */ + +#include +#include /* IWYU pragma: keep */ +#include +#include +#include +#include +#include +#include + +#define UNIT_TESTING +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * dns_ncache_add() turns every RRset it keeps from the authority section + * into one negative cache record laid out as + * + * owner name | type | trust | count | count * (rdlen | rdata) + * + * The rdata is copied verbatim and never parsed, so the tests below fill + * it from this buffer and only care about its length. + */ +static unsigned char filler[UINT16_MAX]; + +/* + * dns_rdataslab_fromrdataset() stores each record behind a 2-byte length, + * or an 8-byte length, offset and order header with --enable-fixed-rrset, + * and refuses a record that would exceed DNS_RDATA_MAXLENGTH together + * with that header. + */ +#if DNS_RDATASET_FIXED +#define SLAB_OVERHEAD 8 +#else +#define SLAB_OVERHEAD 2 +#endif + +static dns_name_t * +name_fromstring(dns_fixedname_t *fixed, const char *namestr) { + dns_name_t *name = dns_fixedname_initname(fixed); + isc_result_t result; + + result = dns_name_fromstring(name, namestr, dns_rootname, 0, NULL); + assert_int_equal(result, ISC_R_SUCCESS); + + return name; +} + +static dns_message_t * +negative_response(void) { + dns_message_t *msg = NULL; + + dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER, &msg); + msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA; + msg->rcode = dns_rcode_nxdomain; + + return msg; +} + +/* + * Add an RRset of 'count' rdatas to the authority section of 'msg', at + * 'ownerstr', marked for negative caching the way the resolver marks + * them. The rdata lengths are chosen so that the negative cache record + * built from the RRset is exactly 'size' bytes long. + */ +static void +add_rrset(dns_message_t *msg, const char *ownerstr, dns_rdatatype_t type, + dns_rdatatype_t covers, unsigned int count, size_t size) { + dns_name_t *name = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdataset_t *rdataset = NULL; + size_t payload, rdlen; + + dns_message_gettempname(msg, &name); + name_fromstring((dns_fixedname_t *)name, ownerstr); + name->attributes.ncache = true; + + dns_message_gettemprdatalist(msg, &rdatalist); + rdatalist->rdclass = dns_rdataclass_in; + rdatalist->type = type; + rdatalist->covers = covers; + rdatalist->ttl = 3600; + + /* + * Split the rdata bytes evenly, giving the remainder to the first + * rdatas one byte at a time. + */ + assert_true(size >= name->length + 5 + count * 2); + payload = size - name->length - 5 - count * 2; + rdlen = payload / count; + + for (unsigned int i = 0; i < count; i++) { + dns_rdata_t *rdata = NULL; + + dns_message_gettemprdata(msg, &rdata); + rdata->rdclass = dns_rdataclass_in; + rdata->type = type; + rdata->data = filler; + rdata->length = rdlen + (i < payload % count ? 1 : 0); + assert_true(rdata->length <= DNS_RDATA_MAXLENGTH); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + } + + dns_message_gettemprdataset(msg, &rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + rdataset->trust = dns_trust_authauthority; + rdataset->attributes |= DNS_RDATASETATTR_NCACHE; + ISC_LIST_APPEND(name->list, rdataset, link); + + dns_message_addname(msg, name, DNS_SECTION_AUTHORITY); + /* + * dns_ncache_add() skips the section when its count is zero. + */ + msg->counts[DNS_SECTION_AUTHORITY] += count; +} + +/* + * Cache 'msg' as an NXDOMAIN for 'qname' in a fresh cache and return the + * result of dns_ncache_add(), and in 'find_result' what a lookup of + * 'qname' sees afterwards: DNS_R_NCACHENXDOMAIN if the record was stored, + * ISC_R_NOTFOUND if it was rejected. + */ +static isc_result_t +ncache_add(dns_message_t *msg, const dns_name_t *qname, + isc_result_t *find_result) { + isc_stdtime_t now = isc_stdtime_now(); + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + dns_fixedname_t ffound; + dns_name_t *found = dns_fixedname_initname(&ffound); + dns_rdataset_t rdataset = DNS_RDATASET_INIT; + isc_result_t result; + + result = dns_db_create(mctx, CACHEDB_DEFAULT, dns_rootname, + dns_dbtype_cache, dns_rdataclass_in, 0, NULL, + &db); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_db_findnode(db, qname, true, &node); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_ncache_add(msg, db, node, dns_rdatatype_any, now, 0, 3600, + NULL); + + dns_db_detachnode(db, &node); + + *find_result = dns_db_find(db, qname, NULL, dns_rdatatype_a, 0, now, + NULL, found, &rdataset, NULL); + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + + dns_db_detach(&db); + + return result; +} + +/* + * A record that does not fit in dns_rdata_t.length must be rejected. + * Its size used to be truncated to 16 bits instead, so a record of + * exactly 65536 bytes was committed to the cache with a length of zero + * and every subsequent reader of the cache entry failed an assertion. + */ +ISC_LOOP_TEST_IMPL(ncache_add_size) { + struct { + size_t size; + isc_result_t expected; + } tests[] = { + /* + * The largest record that can be stored: the slab needs + * SLAB_OVERHEAD more bytes for its record header. + */ + { DNS_RDATA_MAXLENGTH - SLAB_OVERHEAD, ISC_R_SUCCESS }, + { DNS_RDATA_MAXLENGTH + 1, ISC_R_NOSPACE }, + { 65536, ISC_R_NOSPACE }, + }; + dns_fixedname_t fqname; + dns_name_t *qname = name_fromstring(&fqname, "missing.example."); + + for (size_t i = 0; i < ARRAY_SIZE(tests); i++) { + dns_message_t *msg = negative_response(); + isc_result_t result, find_result; + + /* + * Two RRSIG(NSEC) records, because a single rdata cannot be + * longer than DNS_RDATA_MAXLENGTH. + */ + add_rrset(msg, "example.", dns_rdatatype_rrsig, + dns_rdatatype_nsec, 2, tests[i].size); + + result = ncache_add(msg, qname, &find_result); + assert_int_equal(result, tests[i].expected); + assert_int_equal(find_result, tests[i].expected == ISC_R_SUCCESS + ? DNS_R_NCACHENXDOMAIN + : ISC_R_NOTFOUND); + + dns_message_detach(&msg); + } + + isc_loopmgr_shutdown(loopmgr); +} + +/* + * A negative response holds at most one SOA record. The message parser + * and the resolver enforce that on their own, so exercise the checks in + * dns_ncache_add() with hand-built messages. + */ +ISC_LOOP_TEST_IMPL(ncache_add_soa) { + dns_fixedname_t fqname; + dns_name_t *qname = name_fromstring(&fqname, "missing.example."); + dns_message_t *msg = NULL; + isc_result_t result, find_result; + + /* One SOA is fine. */ + msg = negative_response(); + add_rrset(msg, "example.", dns_rdatatype_soa, dns_rdatatype_none, 1, + 100); + result = ncache_add(msg, qname, &find_result); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(find_result, DNS_R_NCACHENXDOMAIN); + dns_message_detach(&msg); + + /* Two SOA records in one RRset are not. */ + msg = negative_response(); + add_rrset(msg, "example.", dns_rdatatype_soa, dns_rdatatype_none, 2, + 100); + result = ncache_add(msg, qname, &find_result); + assert_int_equal(result, DNS_R_TOOMANYRECORDS); + assert_int_equal(find_result, ISC_R_NOTFOUND); + dns_message_detach(&msg); + + /* Neither are two SOA RRsets. */ + msg = negative_response(); + add_rrset(msg, "example.", dns_rdatatype_soa, dns_rdatatype_none, 1, + 100); + add_rrset(msg, "sub.example.", dns_rdatatype_soa, dns_rdatatype_none, 1, + 100); + result = ncache_add(msg, qname, &find_result); + assert_int_equal(result, DNS_R_TOOMANYRECORDS); + assert_int_equal(find_result, ISC_R_NOTFOUND); + dns_message_detach(&msg); + + isc_loopmgr_shutdown(loopmgr); +} + +/* + * dns_ncache_add() stores at most DNS_NCACHE_RDATA (100) records. + */ +ISC_LOOP_TEST_IMPL(ncache_add_count) { + dns_fixedname_t fqname; + dns_name_t *qname = name_fromstring(&fqname, "missing.example."); + dns_message_t *msg = negative_response(); + isc_result_t result, find_result; + + for (unsigned int i = 0; i < 101; i++) { + char owner[64]; + + snprintf(owner, sizeof(owner), "nsec%u.example.", i); + add_rrset(msg, owner, dns_rdatatype_nsec, dns_rdatatype_none, 1, + 100); + } + + result = ncache_add(msg, qname, &find_result); + assert_int_equal(result, DNS_R_TOOMANYRECORDS); + assert_int_equal(find_result, ISC_R_NOTFOUND); + dns_message_detach(&msg); + + isc_loopmgr_shutdown(loopmgr); +} + +ISC_TEST_LIST_START +ISC_TEST_ENTRY_CUSTOM(ncache_add_size, setup_managers, teardown_managers) +ISC_TEST_ENTRY_CUSTOM(ncache_add_soa, setup_managers, teardown_managers) +ISC_TEST_ENTRY_CUSTOM(ncache_add_count, setup_managers, teardown_managers) +ISC_TEST_LIST_END + +ISC_TEST_MAIN diff -Nru bind9-9.20.26/tests/dns/qp_test.c bind9-9.20.29/tests/dns/qp_test.c --- bind9-9.20.26/tests/dns/qp_test.c 2026-07-20 14:47:54.253852916 +0000 +++ bind9-9.20.29/tests/dns/qp_test.c 2026-09-11 19:41:01.730336481 +0000 @@ -230,7 +230,7 @@ item[ival] = ival; - inserted = n = 0; + inserted = 0; /* randomly insert or remove */ dns_qpkey_t key; diff -Nru bind9-9.20.26/tests/dns/qpdb_test.c bind9-9.20.29/tests/dns/qpdb_test.c --- bind9-9.20.26/tests/dns/qpdb_test.c 2026-07-20 14:47:54.253852916 +0000 +++ bind9-9.20.29/tests/dns/qpdb_test.c 2026-09-11 19:41:01.730336481 +0000 @@ -43,6 +43,28 @@ /* Set to true (or use -v option) for verbose output */ static bool verbose = false; +static void +make_rdatalist(dns_rdatalist_t *rdatalist, dns_rdataset_t *rdataset, + dns_rdata_t *rdata, dns_rdatatype_t type, dns_rdatatype_t covers, + unsigned char *data, size_t length) { + dns_rdata_init(rdata); + rdata->data = data; + rdata->length = length; + rdata->rdclass = dns_rdataclass_in; + rdata->type = type; + + dns_rdatalist_init(rdatalist); + rdatalist->rdclass = dns_rdataclass_in; + rdatalist->type = type; + rdatalist->covers = covers; + rdatalist->ttl = 60; + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + rdataset->trust = dns_trust_answer; +} + /* * Add to a cache DB 'db' an rdataset of type 'rtype' at a name * .example.com. The rdataset would contain one data, and rdata_len is @@ -355,6 +377,113 @@ isc_loopmgr_shutdown(loopmgr); } +/* + * A noqname or closest-encloser proof rdataset is a view into memory owned by + * the slabheader of its parent rdataset. Replacing the parent must not free + * that memory while a proof view or one of its clones remains associated. + */ +ISC_LOOP_TEST_IMPL(proof_rdataset_keeps_slabheader) { + isc_result_t result; + dns_db_t *db = NULL; + isc_mem_t *dbmctx = NULL; + isc_stdtime_t now = isc_stdtime_now(); + dns_fixedname_t fname, fproof, ffound; + dns_name_t *name = NULL, *proofname = NULL; + dns_dbnode_t *node = NULL; + dns_slabheader_t *oldheader = NULL, *newheader = NULL; + dns_rdatalist_t oldlist, newlist, nseclist, siglist; + dns_rdataset_t oldset, newset, nsecset, sigset; + dns_rdataset_t oldbound, newbound; + dns_rdataset_t noqname, noqnamesig, noqnameclone; + dns_rdata_t oldrdata, newrdata, nsecrdata, sigrdata; + unsigned char olddata[] = { 192, 0, 2, 1 }; + unsigned char newdata[] = { 192, 0, 2, 2 }; + unsigned char nsecdata[] = { 0 }; + unsigned char sigdata[] = { 0 }; + + isc_mem_create(&dbmctx); + result = dns_db_create(dbmctx, CACHEDB_DEFAULT, dns_rootname, + dns_dbtype_cache, dns_rdataclass_in, 0, NULL, + &db); + assert_int_equal(result, ISC_R_SUCCESS); + + dns_test_namefromstring("proof.example.", &fname); + name = dns_fixedname_name(&fname); + dns_test_namefromstring("nsec.example.", &fproof); + proofname = dns_fixedname_name(&fproof); + + make_rdatalist(&oldlist, &oldset, &oldrdata, dns_rdatatype_a, 0, + olddata, sizeof(olddata)); + make_rdatalist(&newlist, &newset, &newrdata, dns_rdatatype_a, 0, + newdata, sizeof(newdata)); + make_rdatalist(&nseclist, &nsecset, &nsecrdata, dns_rdatatype_nsec, 0, + nsecdata, sizeof(nsecdata)); + make_rdatalist(&siglist, &sigset, &sigrdata, dns_rdatatype_rrsig, + dns_rdatatype_nsec, sigdata, sizeof(sigdata)); + + ISC_LIST_APPEND(proofname->list, &nsecset, link); + ISC_LIST_APPEND(proofname->list, &sigset, link); + result = dns_rdataset_addnoqname(&oldset, proofname, + dns_rdatatype_nsec); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_db_findnode(db, name, true, &node); + assert_int_equal(result, ISC_R_SUCCESS); + + dns_rdataset_init(&oldbound); + result = dns_db_addrdataset(db, node, NULL, now, &oldset, 0, &oldbound); + assert_int_equal(result, ISC_R_SUCCESS); + oldheader = dns_slabheader_fromrdataset(&oldbound); + + dns_rdataset_init(&noqname); + dns_rdataset_init(&noqnamesig); + result = dns_rdataset_getnoqname(&oldbound, + dns_fixedname_initname(&ffound), + &noqname, &noqnamesig); + assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(noqname.proof.header, oldheader); + assert_ptr_equal(noqnamesig.proof.header, oldheader); + + dns_rdataset_init(&noqnameclone); + dns_rdataset_clone(&noqname, &noqnameclone); + assert_ptr_equal(noqnameclone.proof.header, oldheader); + + /* Leave only the cache and proof views holding the old header. */ + dns_rdataset_disassociate(&oldbound); + assert_int_equal(isc_refcount_current(&oldheader->references), 4); + + /* + * Replace the parent. The old header becomes ancient and loses its + * cache-owned reference, but the five proof views keep it alive. + */ + dns_rdataset_init(&newbound); + result = dns_db_addrdataset(db, node, NULL, now, &newset, 0, &newbound); + assert_int_equal(result, ISC_R_SUCCESS); + newheader = dns_slabheader_fromrdataset(&newbound); + assert_ptr_equal(newheader->down, oldheader); + assert_int_equal(isc_refcount_current(&oldheader->references), 3); + + clean_stale_headers(newheader); + assert_ptr_equal(newheader->down, oldheader); + assert_int_equal(dns_rdataset_count(&noqname), 1); + assert_int_equal(dns_rdataset_count(&noqnamesig), 1); + assert_int_equal(dns_rdataset_count(&noqnameclone), 1); + + dns_rdataset_disassociate(&noqnameclone); + dns_rdataset_disassociate(&noqname); + dns_rdataset_disassociate(&noqnamesig); + assert_int_equal(isc_refcount_current(&oldheader->references), 0); + + clean_stale_headers(newheader); + assert_null(newheader->down); + + dns_rdataset_disassociate(&newbound); + dns_db_detachnode(db, &node); + dns_db_detach(&db); + isc_mem_detach(&dbmctx); + isc_loopmgr_shutdown(loopmgr); +} + ISC_LOOP_TEST_IMPL(overmempurge_bigrdata) { size_t maxcache = 2097152U; /* 2MB - same as DNS_CACHE_MINSIZE */ size_t hiwater = maxcache - (maxcache >> 3); /* borrowed from cache.c */ @@ -463,6 +592,8 @@ teardown_managers) ISC_TEST_ENTRY_CUSTOM(ncache_add_over_ancient_secure, setup_managers, teardown_managers) +ISC_TEST_ENTRY_CUSTOM(proof_rdataset_keeps_slabheader, setup_managers, + teardown_managers) ISC_TEST_LIST_END ISC_TEST_MAIN diff -Nru bind9-9.20.26/tests/dns/qpzone_test.c bind9-9.20.29/tests/dns/qpzone_test.c --- bind9-9.20.26/tests/dns/qpzone_test.c 2026-07-20 14:47:54.253852916 +0000 +++ bind9-9.20.29/tests/dns/qpzone_test.c 2026-09-11 19:41:01.730336481 +0000 @@ -525,10 +525,127 @@ assert_null(db); } +/* + * Add a single record to the database in a new version. + */ +static void +add_record(dns_db_t *db, const char *owner, dns_rdatatype_t rdtype, + const char *text) { + isc_result_t result; + dns_fixedname_t fowner; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned char rdata_data[256]; + + dns_test_namefromstring(owner, &fowner); + result = dns_test_rdatafromstring(&rdata, dns_rdataclass_in, rdtype, + rdata_data, sizeof(rdata_data), text, + false); + assert_int_equal(result, ISC_R_SUCCESS); + + WITH_NEWVERSION(db, newversion, true) { + result = apply_dns_update(db, newversion, + dns_fixedname_name(&fowner), rdtype, + dns_rdataclass_in, 300, rdata.data, + rdata.length, DNS_DIFFOP_ADD); + assert_int_equal(result, ISC_R_SUCCESS); + } +} + +/* + * Look up 'qname'/'rdtype' in the current version of the database and + * return the result, with the found name in 'found'. + */ +static isc_result_t +find_record(dns_db_t *db, const char *qname, dns_rdatatype_t rdtype, + unsigned int options, dns_name_t *found) { + isc_result_t result; + dns_dbversion_t *version = NULL; + dns_fixedname_t fqname; + dns_rdataset_t rdataset; + + dns_test_namefromstring(qname, &fqname); + dns_rdataset_init(&rdataset); + dns_db_currentversion(db, &version); + result = dns_db_find(db, dns_fixedname_name(&fqname), version, rdtype, + options, 0, NULL, found, &rdataset, NULL); + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + dns_db_closeversion(db, &version, false); + + return result; +} + +/* + * Nodes that are not below the zone origin can end up in the database + * (e.g. from a secondary zone file carrying out-of-zone data). They + * must not be visible through lookups: not as zone cuts, DNAMEs or + * wildcards above the apex, nor as answers for names outside the zone. + */ +ISC_RUN_TEST_IMPL(nodes_outside_zone) { + isc_result_t result; + dns_db_t *db = NULL; + dns_fixedname_t ffound, fexpected; + dns_name_t *found = dns_fixedname_initname(&ffound); + dns_name_t *expected = NULL; + + result = dns__qpzone_create(mctx, &example_org_name, dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, NULL, &db); + assert_int_equal(result, ISC_R_SUCCESS); + assert_non_null(db); + + add_record(db, "example.org.", dns_rdatatype_soa, + "ns.example.org. root.example.org. 1 300 300 300 300"); + add_record(db, "example.org.", dns_rdatatype_ns, "ns.example.org."); + add_record(db, "ns.example.org.", dns_rdatatype_a, "10.0.0.2"); + add_record(db, "www.example.org.", dns_rdatatype_a, "10.0.0.1"); + + /* Above the origin. */ + add_record(db, "org.", dns_rdatatype_ns, "ns.attacker."); + add_record(db, "org.", dns_rdatatype_dname, "attacker."); + add_record(db, "*.org.", dns_rdatatype_a, "192.0.2.1"); + + /* Outside the zone altogether. */ + add_record(db, "mail.attacker.", dns_rdatatype_a, "192.0.2.2"); + add_record(db, "*.attacker.", dns_rdatatype_a, "192.0.2.3"); + + /* Names in the zone are answered from the zone. */ + result = find_record(db, "www.example.org.", dns_rdatatype_a, 0, found); + assert_int_equal(result, ISC_R_SUCCESS); + dns_test_namefromstring("www.example.org.", &fexpected); + expected = dns_fixedname_name(&fexpected); + assert_true(dns_name_equal(found, expected)); + + result = find_record(db, "example.org.", dns_rdatatype_soa, 0, found); + assert_int_equal(result, ISC_R_SUCCESS); + assert_true(dns_name_equal(found, &example_org_name)); + + /* The closest encloser of a nonexistent name is in the zone. */ + result = find_record(db, "nx.example.org.", dns_rdatatype_a, 0, found); + assert_int_equal(result, DNS_R_NXDOMAIN); + assert_true(dns_name_equal(found, &example_org_name)); + assert_false(found->attributes.wildcard); + + /* Names outside the zone are not found, with or without glue. */ + result = find_record(db, "mail.attacker.", dns_rdatatype_a, 0, found); + assert_int_equal(result, ISC_R_NOTFOUND); + + result = find_record(db, "attacker.", dns_rdatatype_a, + DNS_DBFIND_GLUEOK, found); + assert_int_equal(result, ISC_R_NOTFOUND); + + result = find_record(db, "org.", dns_rdatatype_ns, 0, found); + assert_int_equal(result, ISC_R_NOTFOUND); + + dns_db_detach(&db); + assert_null(db); +} + ISC_TEST_LIST_START ISC_TEST_ENTRY(ownercase) ISC_TEST_ENTRY(setownercase) ISC_TEST_ENTRY(diffop_add_sub) +ISC_TEST_ENTRY(nodes_outside_zone) ISC_TEST_ENTRY(diffop_addresign) ISC_TEST_LIST_END diff -Nru bind9-9.20.26/tests/dns/rbtdb_test.c bind9-9.20.29/tests/dns/rbtdb_test.c --- bind9-9.20.26/tests/dns/rbtdb_test.c 2026-07-20 14:47:54.254852932 +0000 +++ bind9-9.20.29/tests/dns/rbtdb_test.c 2026-09-11 19:41:01.730336481 +0000 @@ -41,6 +41,28 @@ #include #include +static void +make_rdatalist(dns_rdatalist_t *rdatalist, dns_rdataset_t *rdataset, + dns_rdata_t *rdata, dns_rdatatype_t type, dns_rdatatype_t covers, + unsigned char *data, size_t length) { + dns_rdata_init(rdata); + rdata->data = data; + rdata->length = length; + rdata->rdclass = dns_rdataclass_in; + rdata->type = type; + + dns_rdatalist_init(rdatalist); + rdatalist->rdclass = dns_rdataclass_in; + rdatalist->type = type; + rdatalist->covers = covers; + rdatalist->ttl = 60; + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + rdataset->trust = dns_trust_answer; +} + /* * Add to cache DB 'db' an rdataset of type 'rtype' at 'name', with the single * rdata parsed from the text 'rdatastr', TTL 'ttl' relative to 'now' and @@ -178,9 +200,271 @@ isc_loopmgr_shutdown(loopmgr); } +/* + * A noqname or closest-encloser proof rdataset is a view into memory owned by + * the slabheader of its parent rdataset. Expiring the replacement must not + * reclaim the stale parent while a proof view or one of its clones remains + * associated. + */ +ISC_LOOP_TEST_IMPL(proof_rdataset_survives_expiration_cleanup) { + isc_result_t result; + dns_db_t *db = NULL; + isc_mem_t *dbmctx = NULL; + isc_stdtime_t now = isc_stdtime_now(); + dns_fixedname_t fname, fproof, ffound; + dns_name_t *name = NULL, *proofname = NULL; + dns_dbnode_t *node = NULL; + dns_slabheader_t *oldheader = NULL, *newheader = NULL; + dns_rdatalist_t oldlist, newlist, nseclist, siglist; + dns_rdataset_t oldset, newset, nsecset, sigset; + dns_rdataset_t oldbound, newbound; + dns_rdataset_t noqname, noqnamesig, noqnameclone; + dns_rdata_t oldrdata, newrdata, nsecrdata, sigrdata; + unsigned char olddata[] = { 192, 0, 2, 1 }; + unsigned char newdata[] = { 192, 0, 2, 2 }; + unsigned char nsecdata[] = { 0 }; + unsigned char sigdata[] = { 0 }; + + isc_mem_create(&dbmctx); + result = dns_db_create(dbmctx, "rbt", dns_rootname, dns_dbtype_cache, + dns_rdataclass_in, 0, NULL, &db); + assert_int_equal(result, ISC_R_SUCCESS); + + dns_test_namefromstring("proof.example.", &fname); + name = dns_fixedname_name(&fname); + dns_test_namefromstring("nsec.example.", &fproof); + proofname = dns_fixedname_name(&fproof); + + make_rdatalist(&oldlist, &oldset, &oldrdata, dns_rdatatype_a, 0, + olddata, sizeof(olddata)); + make_rdatalist(&newlist, &newset, &newrdata, dns_rdatatype_a, 0, + newdata, sizeof(newdata)); + make_rdatalist(&nseclist, &nsecset, &nsecrdata, dns_rdatatype_nsec, 0, + nsecdata, sizeof(nsecdata)); + make_rdatalist(&siglist, &sigset, &sigrdata, dns_rdatatype_rrsig, + dns_rdatatype_nsec, sigdata, sizeof(sigdata)); + + ISC_LIST_APPEND(proofname->list, &nsecset, link); + ISC_LIST_APPEND(proofname->list, &sigset, link); + result = dns_rdataset_addnoqname(&oldset, proofname, + dns_rdatatype_nsec); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_db_findnode(db, name, true, &node); + assert_int_equal(result, ISC_R_SUCCESS); + + dns_rdataset_init(&oldbound); + result = dns_db_addrdataset(db, node, NULL, now, &oldset, 0, &oldbound); + assert_int_equal(result, ISC_R_SUCCESS); + oldheader = dns_slabheader_fromrdataset(&oldbound); + + dns_rdataset_init(&noqname); + dns_rdataset_init(&noqnamesig); + result = dns_rdataset_getnoqname(&oldbound, + dns_fixedname_initname(&ffound), + &noqname, &noqnamesig); + assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(noqname.proof.header, oldheader); + assert_ptr_equal(noqnamesig.proof.header, oldheader); + + dns_rdataset_init(&noqnameclone); + dns_rdataset_clone(&noqname, &noqnameclone); + assert_ptr_equal(noqnameclone.proof.header, oldheader); + + /* Leave only the cache and proof views holding the old header. */ + dns_rdataset_disassociate(&oldbound); + assert_int_equal(isc_refcount_current(&oldheader->references), 4); + + dns_rdataset_init(&newbound); + result = dns_db_addrdataset(db, node, NULL, now, &newset, 0, &newbound); + assert_int_equal(result, ISC_R_SUCCESS); + newheader = dns_slabheader_fromrdataset(&newbound); + assert_ptr_equal(newheader->down, oldheader); + assert_int_equal(isc_refcount_current(&oldheader->references), 3); + + /* RBTDB reclaims stale headers immediately when the top is expired. */ + dns_db_expiredata(db, node, newheader); + assert_ptr_equal(newheader->down, oldheader); + assert_int_equal(dns_rdataset_count(&noqname), 1); + assert_int_equal(dns_rdataset_count(&noqnamesig), 1); + assert_int_equal(dns_rdataset_count(&noqnameclone), 1); + + dns_rdataset_disassociate(&noqnameclone); + dns_rdataset_disassociate(&noqname); + dns_rdataset_disassociate(&noqnamesig); + assert_int_equal(isc_refcount_current(&oldheader->references), 0); + + dns_db_locknode(db, node, isc_rwlocktype_write); + dns__rbtdb_clean_stale_headers(newheader); + assert_null(newheader->down); + dns_db_unlocknode(db, node, isc_rwlocktype_write); + + dns_rdataset_disassociate(&newbound); + dns_db_detachnode(db, &node); + dns_db_detach(&db); + isc_mem_detach(&dbmctx); + isc_loopmgr_shutdown(loopmgr); +} + +/* + * Add a single record to the zone database 'db' in a new version. + */ +static void +zone_addrecord(dns_db_t *db, const char *owner, dns_rdatatype_t rtype, + const char *rdatastr) { + isc_result_t result; + dns_fixedname_t fowner; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdatalist_t rdatalist; + dns_rdataset_t rdataset; + dns_dbnode_t *node = NULL; + dns_dbversion_t *version = NULL; + unsigned char rdatabuf[256]; + + dns_test_namefromstring(owner, &fowner); + result = dns_test_rdatafromstring(&rdata, dns_rdataclass_in, rtype, + rdatabuf, sizeof(rdatabuf), rdatastr, + false); + assert_int_equal(result, ISC_R_SUCCESS); + + dns_rdatalist_init(&rdatalist); + rdatalist.rdclass = dns_rdataclass_in; + rdatalist.type = rtype; + rdatalist.ttl = 300; + ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); + + dns_rdataset_init(&rdataset); + dns_rdatalist_tordataset(&rdatalist, &rdataset); + + result = dns_db_newversion(db, &version); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_db_findnode(db, dns_fixedname_name(&fowner), true, &node); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL); + assert_int_equal(result, ISC_R_SUCCESS); + + dns_db_detachnode(db, &node); + dns_db_closeversion(db, &version, true); +} + +/* + * Look up 'qname'/'rtype' in the current version of the zone database + * 'db' and return the result, with the found name in 'found'. + */ +static isc_result_t +zone_findrecord(dns_db_t *db, const char *qname, dns_rdatatype_t rtype, + unsigned int options, dns_name_t *found) { + isc_result_t result; + dns_fixedname_t fqname; + dns_rdataset_t rdataset; + + dns_test_namefromstring(qname, &fqname); + dns_rdataset_init(&rdataset); + result = dns_db_find(db, dns_fixedname_name(&fqname), NULL, rtype, + options, 0, NULL, found, &rdataset, NULL); + if (dns_rdataset_isassociated(&rdataset)) { + dns_rdataset_disassociate(&rdataset); + } + + return result; +} + +/* + * Nodes that are not below the zone origin can end up in the database + * (e.g. from a secondary zone file carrying out-of-zone data). They + * must not be visible through lookups: not as zone cuts, DNAMEs or + * wildcards above the apex, nor as answers for names outside the zone. + */ +ISC_RUN_TEST_IMPL(zone_nodes_outside_zone) { + isc_result_t result; + dns_db_t *db = NULL; + dns_fixedname_t forigin, ffound, fexpected; + dns_name_t *origin = NULL; + dns_name_t *found = dns_fixedname_initname(&ffound); + dns_name_t *expected = NULL; + + dns_test_namefromstring("example.org.", &forigin); + origin = dns_fixedname_name(&forigin); + + result = dns_db_create(mctx, "rbt", origin, dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, &db); + assert_int_equal(result, ISC_R_SUCCESS); + assert_non_null(db); + + zone_addrecord(db, "example.org.", dns_rdatatype_soa, + "ns.example.org. root.example.org. 1 300 300 300 300"); + zone_addrecord(db, "example.org.", dns_rdatatype_ns, "ns.example.org."); + zone_addrecord(db, "ns.example.org.", dns_rdatatype_a, "10.0.0.2"); + zone_addrecord(db, "www.example.org.", dns_rdatatype_a, "10.0.0.1"); + zone_addrecord(db, "sub.example.org.", dns_rdatatype_ns, + "ns.sub.example.org."); + zone_addrecord(db, "ns.sub.example.org.", dns_rdatatype_a, "10.0.0.3"); + + /* Above the origin. */ + zone_addrecord(db, "org.", dns_rdatatype_ns, "ns.attacker."); + zone_addrecord(db, "org.", dns_rdatatype_dname, "attacker."); + zone_addrecord(db, "*.org.", dns_rdatatype_a, "192.0.2.1"); + + /* Outside the zone altogether. */ + zone_addrecord(db, "mail.attacker.", dns_rdatatype_a, "192.0.2.2"); + zone_addrecord(db, "*.attacker.", dns_rdatatype_a, "192.0.2.3"); + + /* Names in the zone are answered from the zone. */ + result = zone_findrecord(db, "www.example.org.", dns_rdatatype_a, 0, + found); + assert_int_equal(result, ISC_R_SUCCESS); + dns_test_namefromstring("www.example.org.", &fexpected); + expected = dns_fixedname_name(&fexpected); + assert_true(dns_name_equal(found, expected)); + + result = zone_findrecord(db, "example.org.", dns_rdatatype_soa, 0, + found); + assert_int_equal(result, ISC_R_SUCCESS); + assert_true(dns_name_equal(found, origin)); + + /* Zone cuts inside the zone still work. */ + result = zone_findrecord(db, "www.sub.example.org.", dns_rdatatype_a, 0, + found); + assert_int_equal(result, DNS_R_DELEGATION); + dns_test_namefromstring("sub.example.org.", &fexpected); + expected = dns_fixedname_name(&fexpected); + assert_true(dns_name_equal(found, expected)); + + result = zone_findrecord(db, "ns.sub.example.org.", dns_rdatatype_a, + DNS_DBFIND_GLUEOK, found); + assert_int_equal(result, DNS_R_GLUE); + + /* The closest encloser of a nonexistent name is in the zone. */ + result = zone_findrecord(db, "nx.example.org.", dns_rdatatype_a, 0, + found); + assert_int_equal(result, DNS_R_NXDOMAIN); + assert_true(dns_name_equal(found, origin)); + assert_false(found->attributes.wildcard); + + /* Names outside the zone are not found, with or without glue. */ + result = zone_findrecord(db, "mail.attacker.", dns_rdatatype_a, 0, + found); + assert_int_equal(result, ISC_R_NOTFOUND); + + result = zone_findrecord(db, "attacker.", dns_rdatatype_a, + DNS_DBFIND_GLUEOK, found); + assert_int_equal(result, ISC_R_NOTFOUND); + + result = zone_findrecord(db, "org.", dns_rdatatype_ns, 0, found); + assert_int_equal(result, ISC_R_NOTFOUND); + + dns_db_detach(&db); + assert_null(db); +} + ISC_TEST_LIST_START ISC_TEST_ENTRY_CUSTOM(ncache_add_over_ancient_secure, setup_managers, teardown_managers) +ISC_TEST_ENTRY_CUSTOM(proof_rdataset_survives_expiration_cleanup, + setup_managers, teardown_managers) +ISC_TEST_ENTRY(zone_nodes_outside_zone) ISC_TEST_LIST_END ISC_TEST_MAIN diff -Nru bind9-9.20.26/tests/dns/rdataset_test.c bind9-9.20.29/tests/dns/rdataset_test.c --- bind9-9.20.26/tests/dns/rdataset_test.c 2026-07-20 14:47:54.254852932 +0000 +++ bind9-9.20.29/tests/dns/rdataset_test.c 2026-09-11 19:41:01.731336505 +0000 @@ -25,8 +25,13 @@ #include +#include +#include +#include +#include #include #include +#include #include @@ -101,8 +106,157 @@ assert_int_equal(sigrdataset.ttl, 0); } +/* + * A rdataset at the NOQNAME proof owner, in wire order. + */ +typedef struct { + dns_rdatatype_t type; + dns_rdatatype_t covers; + dns_ttl_t ttl; +} proofset_t; + +#define ANSWER_TTL 3600 +#define MAXSETS 4 + +static void +addset(dns_name_t *owner, dns_rdatalist_t *rdatalist, dns_rdataset_t *rdataset, + dns_rdatatype_t type, dns_rdatatype_t covers, dns_ttl_t ttl) { + dns_rdatalist_init(rdatalist); + rdatalist->rdclass = dns_rdataclass_in; + rdatalist->type = type; + rdatalist->covers = covers; + rdatalist->ttl = ttl; + + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + if (owner != NULL) { + ISC_LIST_APPEND(owner->list, rdataset, link); + } +} + +/* + * Check that dns_rdataset_addnoqname() selects the proof of 'type' at an + * owner carrying 'sets' in wire order, and that dns_rdataset_getnoqname() + * then returns that same proof rather than one chosen by wire order. + */ +static void +check_noqname(const proofset_t *sets, size_t nsets, dns_rdatatype_t type, + isc_result_t expected) { + dns_fixedname_t fowner; + dns_name_t *owner = dns_fixedname_initname(&fowner); + dns_rdatalist_t rdatalists[MAXSETS], answerlist; + dns_rdataset_t rdatasets[MAXSETS], answer; + dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT; + dns_name_t found = DNS_NAME_INITEMPTY; + dns_ttl_t ttl = ANSWER_TTL; + isc_result_t result; + + assert_true(nsets <= MAXSETS); + result = dns_name_fromstring(owner, "proof.example.", dns_rootname, 0, + NULL); + assert_int_equal(result, ISC_R_SUCCESS); + + for (size_t i = 0; i < nsets; i++) { + addset(owner, &rdatalists[i], &rdatasets[i], sets[i].type, + sets[i].covers, sets[i].ttl); + if (sets[i].type == type || + (sets[i].type == dns_rdatatype_rrsig && + sets[i].covers == type)) + { + ttl = ISC_MIN(ttl, sets[i].ttl); + } + } + addset(NULL, &answerlist, &answer, dns_rdatatype_a, 0, ANSWER_TTL); + + result = dns_rdataset_addnoqname(&answer, owner, type); + assert_int_equal(result, expected); + if (result != ISC_R_SUCCESS) { + assert_false((answer.attributes & DNS_RDATASETATTR_NOQNAME) != + 0); + assert_int_equal(answer.ttl, ANSWER_TTL); + return; + } + assert_true((answer.attributes & DNS_RDATASETATTR_NOQNAME) != 0); + assert_int_equal(answer.ttl, ttl); + + result = dns_rdataset_getnoqname(&answer, &found, &neg, &negsig); + assert_int_equal(result, ISC_R_SUCCESS); + assert_true(dns_name_equal(&found, owner)); + assert_int_equal(neg.type, type); + assert_int_equal(negsig.type, dns_rdatatype_rrsig); + assert_int_equal(negsig.covers, type); + + dns_rdataset_disassociate(&neg); + dns_rdataset_disassociate(&negsig); + dns_rdataset_disassociate(&answer); +} + +#define CHECK_NOQNAME(sets, type, expected) \ + check_noqname(sets, sizeof(sets) / sizeof((sets)[0]), type, expected) + +/* test NOQNAME proof selection by dns_rdataset_{add,get}noqname() */ +ISC_RUN_TEST_IMPL(noqname) { + /* Signed NSEC followed by an unsigned NSEC3 (#5985). */ + const proofset_t nsec_unsigned_nsec3[] = { + { dns_rdatatype_nsec, 0, 300 }, + { dns_rdatatype_rrsig, dns_rdatatype_nsec, 200 }, + { dns_rdatatype_nsec3, 0, 100 }, + }; + /* Signed NSEC3 followed by an unsigned NSEC (#6369). */ + const proofset_t nsec3_unsigned_nsec[] = { + { dns_rdatatype_nsec3, 0, 300 }, + { dns_rdatatype_rrsig, dns_rdatatype_nsec3, 200 }, + { dns_rdatatype_nsec, 0, 100 }, + }; + /* Both denial types signed, in both wire orders. */ + const proofset_t nsec_nsec3[] = { + { dns_rdatatype_nsec, 0, 300 }, + { dns_rdatatype_rrsig, dns_rdatatype_nsec, 300 }, + { dns_rdatatype_nsec3, 0, 200 }, + { dns_rdatatype_rrsig, dns_rdatatype_nsec3, 200 }, + }; + const proofset_t nsec3_nsec[] = { + { dns_rdatatype_nsec3, 0, 200 }, + { dns_rdatatype_rrsig, dns_rdatatype_nsec3, 200 }, + { dns_rdatatype_nsec, 0, 300 }, + { dns_rdatatype_rrsig, dns_rdatatype_nsec, 300 }, + }; + /* RRSIG preceding the rdataset it covers. */ + const proofset_t rrsig_first[] = { + { dns_rdatatype_rrsig, dns_rdatatype_nsec, 300 }, + { dns_rdatatype_nsec, 0, 300 }, + }; + /* No signed denial at all. */ + const proofset_t unsigned_only[] = { + { dns_rdatatype_nsec, 0, 300 }, + { dns_rdatatype_nsec3, 0, 300 }, + }; + + UNUSED(state); + + CHECK_NOQNAME(nsec_unsigned_nsec3, dns_rdatatype_nsec, ISC_R_SUCCESS); + CHECK_NOQNAME(nsec_unsigned_nsec3, dns_rdatatype_nsec3, ISC_R_NOTFOUND); + + CHECK_NOQNAME(nsec3_unsigned_nsec, dns_rdatatype_nsec3, ISC_R_SUCCESS); + CHECK_NOQNAME(nsec3_unsigned_nsec, dns_rdatatype_nsec, ISC_R_NOTFOUND); + + /* The caller's choice wins regardless of wire order. */ + CHECK_NOQNAME(nsec_nsec3, dns_rdatatype_nsec, ISC_R_SUCCESS); + CHECK_NOQNAME(nsec_nsec3, dns_rdatatype_nsec3, ISC_R_SUCCESS); + CHECK_NOQNAME(nsec3_nsec, dns_rdatatype_nsec, ISC_R_SUCCESS); + CHECK_NOQNAME(nsec3_nsec, dns_rdatatype_nsec3, ISC_R_SUCCESS); + + CHECK_NOQNAME(rrsig_first, dns_rdatatype_nsec, ISC_R_SUCCESS); + + CHECK_NOQNAME(unsigned_only, dns_rdatatype_nsec, ISC_R_NOTFOUND); + CHECK_NOQNAME(unsigned_only, dns_rdatatype_nsec3, ISC_R_NOTFOUND); + + check_noqname(NULL, 0, dns_rdatatype_nsec, ISC_R_NOTFOUND); +} + ISC_TEST_LIST_START ISC_TEST_ENTRY(trimttl) +ISC_TEST_ENTRY(noqname) ISC_TEST_LIST_END ISC_TEST_MAIN diff -Nru bind9-9.20.26/tests/dns/skr_test.c bind9-9.20.29/tests/dns/skr_test.c --- bind9-9.20.26/tests/dns/skr_test.c 2026-07-20 14:47:54.255852947 +0000 +++ bind9-9.20.29/tests/dns/skr_test.c 2026-09-11 19:41:01.732336529 +0000 @@ -166,7 +166,6 @@ /* Create a lexer as one is required by dns_rdata_fromtext(). */ isc_lex_create(mctx, 64, &lex); - specials[0] = 1; specials['('] = 1; specials[')'] = 1; specials['"'] = 1; diff -Nru bind9-9.20.26/tests/isc/Makefile.in bind9-9.20.29/tests/isc/Makefile.in --- bind9-9.20.26/tests/isc/Makefile.in 2026-07-20 14:49:11.244596666 +0000 +++ bind9-9.20.29/tests/isc/Makefile.in 2026-09-11 19:42:19.208204583 +0000 @@ -844,6 +844,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/tests/isc/dnsstream_utils_test_data.h bind9-9.20.29/tests/isc/dnsstream_utils_test_data.h --- bind9-9.20.26/tests/isc/dnsstream_utils_test_data.h 2026-07-20 14:47:54.264853087 +0000 +++ bind9-9.20.29/tests/isc/dnsstream_utils_test_data.h 2026-09-11 19:41:01.741336745 +0000 @@ -27,576 +27,528 @@ 0x29, 0x04, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static char request_large[] = { /* Packet 4 */ - 0x00, 0x2a, 0x15, 0x45, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x63, - 0x6d, 0x74, 0x73, 0x31, 0x2d, 0x64, 0x68, 0x63, - 0x70, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x6c, 0x69, - 0x6e, 0x65, 0x73, 0x03, 0x63, 0x6f, 0x6d, 0x00, - 0x00, 0x01, 0x00, 0x01 +static char request_large[] = { + /* Packet 4 */ + 0x00, 0x2a, 0x15, 0x45, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6d, 0x74, 0x73, 0x31, 0x2d, 0x64, + 0x68, 0x63, 0x70, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x6c, 0x69, 0x6e, + 0x65, 0x73, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 +}; +static char response_large[] = { + /* Packet 6 */ + 0x18, 0x1a, 0x15, 0x45, 0x81, 0x80, 0x00, 0x01, 0x01, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x63, 0x6d, 0x74, 0x73, 0x31, 0x2d, 0x64, 0x68, 0x63, + 0x70, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x1c, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x46, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x52, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x15, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x56, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe5, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x1d, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xc9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x57, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0d, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x63, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa9, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xde, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x6f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc1, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x59, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xa2, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x2b, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x65, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x6c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x2e, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5a, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x61, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x79, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x3b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x4a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa6, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x35, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x06, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x49, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x54, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x39, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5e, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x83, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xef, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x91, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3e, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x08, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb5, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x89, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xe2, 0x84, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd3, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc8, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x51, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x69, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x03, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x17, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x15, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc4, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x5b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x94, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xbd, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x2c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x2b, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x09, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x10, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x13, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x48, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x2d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x0b, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4c, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x11, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x13, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5c, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x25, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x0d, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x55, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x1c, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x97, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xe2, 0x82, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x31, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x3f, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xe7, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9d, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x42, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x32, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3d, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe2, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xf9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x76, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb3, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xb4, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x28, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xfa, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xa5, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4f, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb9, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xbf, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4d, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x43, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x14, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x04, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x66, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xd9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x19, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x98, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x37, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x0c, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x4d, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x27, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x58, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x76, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x38, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x4c, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x0a, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xc2, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x55, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9c, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xa1, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x56, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x60, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x8f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x61, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x68, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x81, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x8e, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xad, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x74, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x44, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb7, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x41, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x3a, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3c, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x0e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xdf, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x67, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x99, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x03, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd1, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x70, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x07, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x77, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x7d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x6a, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x7b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x64, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x39, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x60, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x6b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xaf, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa7, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xca, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x73, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x02, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x2f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x45, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x1f, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x2e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x07, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x05, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x79, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x16, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x6d, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x7b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x18, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xfd, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x57, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x1f, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3f, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x46, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x25, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x04, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x5d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf7, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3a, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x8a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0e, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x33, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xe9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x34, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x1e, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x40, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x3d, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x14, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x59, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x01, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x26, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x0f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x71, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x17, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xdb, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4e, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x21, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x7a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x2d, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x33, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x27, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x38, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x53, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xb8, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x32, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x82, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x1a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x02, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x40, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x2c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x2a, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x31, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x1e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x50, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9f, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x8c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x26, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x37, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x4b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x70, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x28, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x23, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x7c, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x67, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x29, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x24, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xfb, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xac, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x50, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x21, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x35, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x53, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x08, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0b, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x65, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x4a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x44, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf3, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x47, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x85, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x6a, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x06, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xe2, 0x85, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x51, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x3c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x18, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0a, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x16, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x64, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x23, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x78, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x22, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5f, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x34, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9a, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x42, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x69, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0f, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x6f, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x3e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x6e, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x75, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x2f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x6b, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5f, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x45, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3b, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x2a, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xe2, 0x86, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x41, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xce, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x19, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5a, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x73, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x0c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf1, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x22, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x30, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x7c, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x4b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x6d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5e, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x43, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x72, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x29, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x12, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x62, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x80, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x4e, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x1b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x87, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x05, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x30, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x52, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x10, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x8b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x90, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x09, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xe2, 0x83, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x20, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x74, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x72, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x71, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x5d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x48, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x63, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x93, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe8, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x7d, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x54, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x92, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x58, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x4f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5c, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa0, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x6e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa4, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x7e, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x66, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x12, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x96, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x6c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x11, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x7e, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xae, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa3, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9e, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x1d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb0, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xbc, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xba, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xaa, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x84, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x47, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x86, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x20, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xcb, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xab, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x36, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xc5, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x88, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb1, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xed, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xbe, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc0, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x77, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xbb, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf8, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xe3, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc7, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x95, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xa8, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x8d, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xea, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x49, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc3, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb2, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xc6, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd4, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xec, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x75, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf4, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd8, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xcc, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd6, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x62, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xda, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb6, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x36, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x7f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe0, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd7, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xd2, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd0, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe6, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0x78, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x1a, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xdc, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xeb, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd5, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xcd, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xe1, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x1b, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xdd, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xe4, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x7a, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xee, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x42, 0xac, 0xdb, 0x24, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf2, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf0, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xcf, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf5, 0xc0, 0x0c, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf6, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, + 0x4a, 0xdd, 0x2f, 0xfc }; -static char response_large - [] = { /* Packet 6 */ - 0x18, 0x1a, 0x15, 0x45, 0x81, 0x80, 0x00, 0x01, 0x01, 0x7f, 0x00, - 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6d, 0x74, 0x73, 0x31, 0x2d, 0x64, - 0x68, 0x63, 0x70, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x6c, 0x69, 0x6e, - 0x65, 0x73, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x1c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x46, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x52, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x15, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x56, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe5, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x1d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc9, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x57, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0d, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x63, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0xa9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xde, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x6f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc1, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x59, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa2, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x2b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x65, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x6c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x2e, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5a, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x61, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x79, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x3b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4a, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xa6, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x35, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x06, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x49, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x54, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x39, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5e, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x83, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xef, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x91, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3e, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x08, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb5, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x89, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xe2, 0x84, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0xd3, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc8, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x51, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x69, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x03, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x17, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x15, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xc4, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5b, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x94, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xbd, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x2c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x2b, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x09, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x10, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x13, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x48, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x2d, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x0b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4c, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, - 0xdb, 0x11, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x13, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x5c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x25, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x0d, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x5b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x55, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x1c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x97, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xe2, 0x82, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x31, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x3f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe7, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x9d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x42, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x32, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x3d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe2, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0xf9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x76, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xb3, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb4, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, - 0xdb, 0x28, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xfa, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0xa5, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4f, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb9, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0xbf, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4d, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x43, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x14, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x04, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x66, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0xd9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x19, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x98, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x37, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x0c, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x4d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x27, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x58, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x76, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x38, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x4c, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, - 0xdb, 0x0a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc2, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x55, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9c, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa1, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x56, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x60, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x8f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x61, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x81, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x8e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xad, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x74, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x44, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb7, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x41, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x3a, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x3c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x0e, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xdf, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x67, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x99, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x03, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0xd1, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x70, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x07, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x77, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x7d, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x6a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x7b, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x64, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x39, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x60, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x6b, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0xaf, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa7, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xca, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x73, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x02, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x2f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x45, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x1f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x2e, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x07, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x05, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x79, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x16, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x6d, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x7b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x18, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0xfd, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x57, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x1f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3f, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x46, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x25, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x04, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5d, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf7, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x3a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x8a, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x0e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x33, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xe9, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x34, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, - 0xdb, 0x1e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x40, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x3d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x14, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x59, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x26, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x0f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x71, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x17, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xdb, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, - 0xdb, 0x4e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x21, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x7a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x2d, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x33, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x27, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x38, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x53, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb8, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x32, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x82, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, - 0xdb, 0x1a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x02, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x40, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x2c, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x2a, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x31, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x1e, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x50, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9f, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x8c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x26, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x37, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x4b, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x70, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x28, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x23, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x7c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x67, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x29, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x24, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xfb, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xac, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x50, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x21, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x35, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x53, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x08, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0b, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x4a, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x44, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf3, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, - 0xdb, 0x47, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x85, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x6a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x06, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xe2, 0x85, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x51, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x3c, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x18, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0a, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x16, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x64, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x23, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x78, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x22, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5f, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x34, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x9a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x42, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x69, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0f, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x6f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x3e, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x6e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x75, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x2f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x6b, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5f, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x45, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x3b, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x2a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xe2, 0x86, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x41, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xce, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x19, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5a, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x73, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x0c, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf1, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x22, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x30, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x7c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x4b, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x6d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x5e, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x43, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x72, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x29, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x12, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x62, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x80, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x4e, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x1b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x87, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x05, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x30, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, - 0xdb, 0x52, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x10, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x8b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x90, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x09, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xe2, 0x83, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x20, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x9b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x74, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, - 0xac, 0xdb, 0x72, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x71, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x5d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x48, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x63, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x93, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe8, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x7d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x54, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x92, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x58, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x4f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x5c, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0xa0, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x6e, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0xa4, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x42, 0xac, 0xdb, 0x7e, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x66, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x12, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x96, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x6c, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x11, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x7e, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xae, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0xa3, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x9e, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x1d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xb0, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xbc, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0xba, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xaa, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x84, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x47, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x86, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, 0x20, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0xcb, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xab, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x42, 0xac, 0xdb, - 0x36, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc5, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x88, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0xb1, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xed, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0xbe, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc0, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0x77, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xbb, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0xf8, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe3, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0xc7, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x95, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xa8, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0x8d, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xea, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x49, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc3, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xb2, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xc6, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0xd4, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xec, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x75, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf4, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd8, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0xcc, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd6, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x62, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xda, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xb6, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x36, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0x7f, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe0, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0xd7, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd2, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd0, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x4a, 0xdd, 0x2f, 0xe6, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0x78, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x4a, 0xdd, 0x2f, 0x1a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xdc, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xeb, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xd5, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0xcd, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe1, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0x1b, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, - 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xdd, 0xc0, 0x0c, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xe4, - 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, - 0x04, 0x42, 0xac, 0xdb, 0x7a, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xee, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, - 0x42, 0xac, 0xdb, 0x24, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf2, 0xc0, 0x0c, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, - 0xdd, 0x2f, 0xf0, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xcf, 0xc0, 0x0c, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, - 0x2f, 0xf5, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, - 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, 0xf6, 0xc0, 0x0c, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x04, 0x4a, 0xdd, 0x2f, - 0xfc - }; diff -Nru bind9-9.20.26/tests/isc/doh_test.c bind9-9.20.29/tests/isc/doh_test.c --- bind9-9.20.26/tests/isc/doh_test.c 2026-07-20 14:47:54.264853087 +0000 +++ bind9-9.20.29/tests/isc/doh_test.c 2026-09-11 19:41:01.741336745 +0000 @@ -73,21 +73,11 @@ static atomic_int_fast64_t ctimeouts = 0; static atomic_int_fast64_t total_sends = 0; -static int expected_ssends; -static int expected_sreads; static int expected_csends; -static int expected_cconnects; static int expected_creads; -static int expected_ctimeouts; -#define have_expected_ssends(v) ((v) >= expected_ssends && expected_ssends >= 0) -#define have_expected_sreads(v) ((v) >= expected_sreads && expected_sreads >= 0) #define have_expected_csends(v) ((v) >= expected_csends && expected_csends >= 0) -#define have_expected_cconnects(v) \ - ((v) >= expected_cconnects && expected_cconnects >= 0) #define have_expected_creads(v) ((v) >= expected_creads && expected_creads >= 0) -#define have_expected_ctimeouts(v) \ - ((v) >= expected_ctimeouts && expected_ctimeouts >= 0) static bool noanswer = false; @@ -305,7 +295,6 @@ return -1; } close(tcp_listen_sock); - tcp_listen_sock = -1; if (env_workers != NULL) { workers = atoi(env_workers); @@ -324,12 +313,8 @@ atomic_store(&ctimeouts, 0); atomic_store(&active_cconnects, 0); - expected_cconnects = -1; expected_csends = -1; expected_creads = -1; - expected_sreads = -1; - expected_ssends = -1; - expected_ctimeouts = -1; atomic_store(&POST, false); atomic_store(&use_TLS, false); diff -Nru bind9-9.20.26/tests/isc/lex_test.c bind9-9.20.29/tests/isc/lex_test.c --- bind9-9.20.26/tests/isc/lex_test.c 2026-07-20 14:47:54.266853118 +0000 +++ bind9-9.20.29/tests/isc/lex_test.c 2026-09-11 19:41:01.743336793 +0000 @@ -32,6 +32,151 @@ #define AS_STR(x) (x).value.as_textregion.base +/* check handling of 0x00 */ +ISC_RUN_TEST_IMPL(lex_0x00) { + isc_result_t result; + isc_lex_t *lex = NULL; + isc_buffer_t buf; + isc_token_t token; + + unsigned char nul_then_A[] = { '\0', 'A' }; + unsigned char embedded_null[] = { '"', 'a', '\0', 'b', '"' }; + unsigned char escaped_null[] = { 'a', '\\', '\0', 'b' }; + + UNUSED(state); + + isc_lex_create(mctx, 1024, &lex); + + isc_buffer_init(&buf, &nul_then_A[0], sizeof(nul_then_A)); + isc_buffer_add(&buf, sizeof(nul_then_A)); + + result = isc_lex_openbuffer(lex, &buf); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_lex_gettoken(lex, 0, &token); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(token.type, isc_tokentype_unknown); + + result = isc_lex_gettoken(lex, 0, &token); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(token.type, isc_tokentype_string); + + isc_lex_close(lex); + + /* + * Check that an embedded NUL is preserved in a quoted string. + */ + isc_buffer_init(&buf, &embedded_null[0], sizeof(embedded_null)); + isc_buffer_add(&buf, sizeof(embedded_null)); + + result = isc_lex_openbuffer(lex, &buf); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_lex_gettoken(lex, ISC_LEXOPT_QSTRING, &token); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(token.type, isc_tokentype_qstring); + assert_int_equal(token.value.as_textregion.length, 3); + assert_memory_equal(token.value.as_textregion.base, "a\0b", 3); + + isc_lex_close(lex); + + /* + * Check that an escaped NUL is preserved. + */ + isc_buffer_init(&buf, &escaped_null[0], sizeof(escaped_null)); + isc_buffer_add(&buf, sizeof(escaped_null)); + + result = isc_lex_openbuffer(lex, &buf); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_lex_gettoken(lex, ISC_LEXOPT_ESCAPE, &token); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(token.type, isc_tokentype_string); + assert_int_equal(token.value.as_textregion.length, 4); + assert_memory_equal(token.value.as_textregion.base, "a\\\0b", 4); + + isc_lex_destroy(&lex); +} + +/* + * A NUL token must not preserve a stale beginning-of-line state: + * whitespace following the NUL is not initial whitespace. + */ +ISC_RUN_TEST_IMPL(lex_0x00_initialws) { + isc_result_t result; + isc_lex_t *lex = NULL; + isc_buffer_t buf; + isc_token_t token; + + unsigned char nul_then_ws[] = { 'a', '\n', '\0', ' ', 'b' }; + + UNUSED(state); + + isc_lex_create(mctx, 1024, &lex); + + isc_buffer_init(&buf, &nul_then_ws[0], sizeof(nul_then_ws)); + isc_buffer_add(&buf, sizeof(nul_then_ws)); + + result = isc_lex_openbuffer(lex, &buf); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_lex_gettoken(lex, ISC_LEXOPT_INITIALWS, &token); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(token.type, isc_tokentype_string); + + result = isc_lex_gettoken(lex, ISC_LEXOPT_INITIALWS, &token); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(token.type, isc_tokentype_unknown); + /* + * The unknown token must not leave the previous token's text + * region pointer behind for a caller to dereference. + */ + assert_null(token.value.as_textregion.base); + assert_int_equal(token.value.as_textregion.length, 0); + + result = isc_lex_gettoken(lex, ISC_LEXOPT_INITIALWS, &token); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(token.type, isc_tokentype_string); + assert_string_equal(AS_STR(token), "b"); + + isc_lex_destroy(&lex); +} + +/* + * A NUL inside brace-delimited text is corruption and must yield an + * unknown token instead of being embedded in the btext token. + */ +ISC_RUN_TEST_IMPL(lex_0x00_btext) { + isc_result_t result; + isc_lex_t *lex = NULL; + isc_buffer_t buf; + isc_token_t token; + isc_lexspecials_t specials; + + unsigned char btext_null[] = { '{', 'a', '\0', 'b', '}' }; + + UNUSED(state); + + isc_lex_create(mctx, 1024, &lex); + + memset(specials, 0, sizeof(specials)); + specials['{'] = 1; + specials['}'] = 1; + isc_lex_setspecials(lex, specials); + + isc_buffer_init(&buf, &btext_null[0], sizeof(btext_null)); + isc_buffer_add(&buf, sizeof(btext_null)); + + result = isc_lex_openbuffer(lex, &buf); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_lex_gettoken(lex, ISC_LEXOPT_BTEXT, &token); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(token.type, isc_tokentype_unknown); + + isc_lex_destroy(&lex); +} + /* check handling of 0xff */ ISC_RUN_TEST_IMPL(lex_0xff) { isc_result_t result; @@ -71,8 +216,8 @@ isc_lex_create(mctx, 1024, &lex); - isc_buffer_init(&buf, &text[0], sizeof(text)); - isc_buffer_add(&buf, sizeof(text)); + isc_buffer_init(&buf, &text[0], sizeof(text) - 1); + isc_buffer_add(&buf, sizeof(text) - 1); result = isc_lex_openbuffer(lex, &buf); assert_int_equal(result, ISC_R_SUCCESS); @@ -339,6 +484,9 @@ } ISC_TEST_LIST_START +ISC_TEST_ENTRY(lex_0x00) +ISC_TEST_ENTRY(lex_0x00_initialws) +ISC_TEST_ENTRY(lex_0x00_btext) ISC_TEST_ENTRY(lex_0xff) ISC_TEST_ENTRY(lex_keypair) ISC_TEST_ENTRY(lex_setline) diff -Nru bind9-9.20.26/tests/isc/proxyheader_test.c bind9-9.20.29/tests/isc/proxyheader_test.c --- bind9-9.20.26/tests/isc/proxyheader_test.c 2026-07-20 14:47:54.267853134 +0000 +++ bind9-9.20.29/tests/isc/proxyheader_test.c 2026-09-11 19:41:01.744336817 +0000 @@ -433,6 +433,18 @@ assert_true(cbarg.no_more_calls == 0); verify_proxy_v2_header(NULL, &cbarg); + uint8_t proxy_v2_header_misaligned[sizeof(proxy_v2_header) + 1]; + memmove(&proxy_v2_header_misaligned[1], proxy_v2_header, + sizeof(proxy_v2_header)); + cbarg = (dummy_handler_cbarg_t){ 0 }; + region.base = (uint8_t *)&proxy_v2_header_misaligned[1]; + region.length = sizeof(proxy_v2_header); + result = isc_proxy2_header_handle_directly( + ®ion, proxy2_handler_dummy, &cbarg); + assert_true(result == ISC_R_SUCCESS); + assert_true(cbarg.no_more_calls == 0); + verify_proxy_v2_header(NULL, &cbarg); + cbarg = (dummy_handler_cbarg_t){ 0 }; region.base = (uint8_t *)proxy_v2_header_with_TLS; region.length = sizeof(proxy_v2_header_with_TLS); @@ -1169,6 +1181,7 @@ region.length = sizeof(zerodata); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_NOOP, ®ion); + assert_int_equal(result, ISC_R_SUCCESS); isc_buffer_subtract(&databuf, region.length / 2); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); diff -Nru bind9-9.20.26/tests/isc/stats_test.c bind9-9.20.29/tests/isc/stats_test.c --- bind9-9.20.26/tests/isc/stats_test.c 2026-07-20 14:47:54.269853165 +0000 +++ bind9-9.20.29/tests/isc/stats_test.c 2026-09-11 19:41:01.746336865 +0000 @@ -71,21 +71,9 @@ assert_int_equal(isc_stats_get_counter(stats, i), i + 1); } - /* Test resize. */ - isc_stats_resize(&stats, 3); - assert_int_equal(isc_stats_ncounters(stats), 4); - isc_stats_resize(&stats, 4); - assert_int_equal(isc_stats_ncounters(stats), 4); - isc_stats_resize(&stats, 5); - assert_int_equal(isc_stats_ncounters(stats), 5); - - /* Existing counters are retained */ + /* Counter values can be retrieved. */ for (int i = 0; i < isc_stats_ncounters(stats); i++) { - uint32_t expect = i + 1; - if (i == 4) { - expect = 0; - } - assert_int_equal(isc_stats_get_counter(stats, i), expect); + assert_int_equal(isc_stats_get_counter(stats, i), i + 1); } isc_stats_detach(&stats); diff -Nru bind9-9.20.26/tests/isc/tcpdns_test.c bind9-9.20.29/tests/isc/tcpdns_test.c --- bind9-9.20.26/tests/isc/tcpdns_test.c 2026-07-20 14:47:54.269853165 +0000 +++ bind9-9.20.29/tests/isc/tcpdns_test.c 2026-09-11 19:41:01.746336865 +0000 @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -66,6 +67,41 @@ NULL, NULL, NULL, get_proxy_type(), NULL); } +static isc_job_t trailing_job = ISC_JOB_INITIALIZER; + +static void +trailing_cb(void *arg) { + UNUSED(arg); +} + +static void +double_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + uint64_t magic = 0; + + UNUSED(cbarg); + + assert_int_equal(eresult, ISC_R_SUCCESS); + assert_true(region->length >= sizeof(magic)); + memmove(&magic, region->base, sizeof(magic)); + assert_int_equal(magic, send_magic); + atomic_fetch_add(&creads, 1); + + /* + * Both calls take the asynchronous path because this callback is still + * processing the previous message. They must share one pending job. + */ + isc_nm_read(handle, double_read_cb, NULL); + isc_nm_read(handle, double_read_cb, NULL); + isc_job_run(isc_loop(), &trailing_job, trailing_cb, NULL); + assert_ptr_not_equal(handle->sock->job.link.prev, &handle->sock->job); + + isc_loopmgr_shutdown(loopmgr); + isc_nmhandle_close(handle); + isc_refcount_decrement(&active_creads); + isc_nmhandle_detach(&handle); +} + ISC_LOOP_TEST_IMPL(tcpdns_noop) { start_listening(ISC_NM_LISTEN_ONE, noop_accept_cb, noop_recv_cb); @@ -110,6 +146,14 @@ isc_async_current(stream_recv_send_connect, tcpdns_connect); } +ISC_LOOP_TEST_IMPL(tcpdns_double_read) { + start_listening(ISC_NM_LISTEN_ONE, listen_accept_cb, listen_read_cb); + + atomic_store(&nsends, 1); + connect_readcb = double_read_cb; + isc_async_current(stream_recv_send_connect, tcpdns_connect); +} + ISC_LOOP_TEST_IMPL(tcpdns_recv_two) { start_listening(ISC_NM_LISTEN_ONE, listen_accept_cb, listen_read_cb); @@ -154,6 +198,8 @@ stream_timeout_recovery_teardown) ISC_TEST_ENTRY_CUSTOM(tcpdns_recv_one, stream_recv_one_setup, stream_recv_one_teardown) +ISC_TEST_ENTRY_CUSTOM(tcpdns_double_read, stream_recv_one_setup, + stream_recv_one_teardown) ISC_TEST_ENTRY_CUSTOM(tcpdns_recv_two, stream_recv_two_setup, stream_recv_two_teardown) ISC_TEST_ENTRY_CUSTOM(tcpdns_recv_send, stream_recv_send_setup, diff -Nru bind9-9.20.26/tests/isc/time_test.c bind9-9.20.29/tests/isc/time_test.c --- bind9-9.20.26/tests/isc/time_test.c 2026-07-20 14:47:54.269853165 +0000 +++ bind9-9.20.29/tests/isc/time_test.c 2026-09-11 19:41:01.746336865 +0000 @@ -32,8 +32,96 @@ #include +#define MAX_S UINT_MAX #define MAX_NS (NS_PER_SEC - 1) +ISC_RUN_TEST_IMPL(isc_interval_basic_test) { + isc_interval_t i = { 0, 0 }; + + assert_true(isc_interval_iszero(&i)); + + isc_interval_set(&i, MAX_S, MAX_NS); + assert_int_equal(i.seconds, MAX_S); + assert_int_equal(i.nanoseconds, MAX_NS); + + isc_interval_set(&i, 1, NS_PER_MS * 2); + assert_int_equal(isc_interval_ms(&i), MS_PER_SEC + 2); + + expect_assert_failure(isc_interval_set(NULL, 0, 0)); + expect_assert_failure(isc_interval_set(&i, 0, MAX_NS + 1)); + + expect_assert_failure(isc_interval_iszero(NULL)); +} + +ISC_RUN_TEST_IMPL(isc_time_basic_test) { + isc_time_t t = { 0, 0 }; + + assert_true(isc_time_isepoch(&t)); + + isc_time_set(&t, MAX_S, MAX_NS); + assert_int_equal(t.seconds, MAX_S); + assert_int_equal(t.nanoseconds, MAX_NS); + + assert_int_equal(isc_time_seconds(&t), t.seconds); + assert_int_equal(isc_time_nanoseconds(&t), t.nanoseconds); + + isc_time_settoepoch(&t); + assert_int_equal(t.seconds, 0); + assert_int_equal(t.nanoseconds, 0); + assert_true(isc_time_isepoch(&t)); + + expect_assert_failure(isc_time_set(NULL, 0, 0)); + expect_assert_failure(isc_time_set(&t, 0, MAX_NS + 1)); + + expect_assert_failure(isc_time_settoepoch(NULL)); + expect_assert_failure(isc_time_isepoch(NULL)); + expect_assert_failure(isc_time_isepoch(&(isc_time_t){ 0, MAX_NS + 1 })); + + expect_assert_failure(isc_time_seconds(NULL)); + expect_assert_failure(isc_time_seconds(&(isc_time_t){ 0, MAX_NS + 1 })); + + expect_assert_failure(isc_time_nanoseconds(NULL)); + expect_assert_failure( + isc_time_nanoseconds(&(isc_time_t){ 0, MAX_NS + 1 })); +} + +ISC_RUN_TEST_IMPL(isc_time_now_test) { + isc_time_t t1 = { 0, 0 }; + isc_time_t t2 = { 0, 0 }; + time_t tm; + + tm = time(NULL); + t1 = isc_time_now(); + nanosleep(&(struct timespec){ 1, 0 }, NULL); + t2 = isc_time_now(); + + assert_true(t1.seconds >= (unsigned int)tm); + assert_true(t2.seconds >= (unsigned int)tm); + + assert_int_not_equal(t1.seconds, 0); + assert_int_not_equal(t2.seconds, 0); + assert_int_equal(isc_time_compare(&t2, &t1), 1); + /* + * The coarse clock readings may lag real time by a scheduler tick + * and nanosleep() may overshoot, hence the tolerance in both + * directions. + */ + assert_true(isc_time_microdiff(&t2, &t1) > + US_PER_SEC - 100 * US_PER_MS); + assert_true(isc_time_microdiff(&t2, &t1) < + US_PER_SEC + 100 * US_PER_MS); + + tm = time(NULL); + t1 = isc_time_now_hires(); + nanosleep(&(struct timespec){ 0, NS_PER_US }, NULL); + t2 = isc_time_now_hires(); + + assert_true(t1.seconds >= (unsigned int)tm); + assert_true(t2.seconds >= (unsigned int)tm); + assert_true(isc_time_microdiff(&t2, &t1) >= 1); + assert_true(isc_time_microdiff(&t2, &t1) < US_PER_SEC); +} + struct time_vectors { isc_time_t a; isc_interval_t b; @@ -65,16 +153,14 @@ { 0, MAX_NS }, { 0, NS_PER_SEC / 2 + 1 }, ISC_R_SUCCESS }, - { { UINT_MAX, MAX_NS }, { UINT_MAX, 0 }, { 0, MAX_NS }, ISC_R_SUCCESS }, + { { MAX_S, MAX_NS }, { MAX_S, 0 }, { 0, MAX_NS }, ISC_R_SUCCESS }, { { 0, 0 }, { 1, 0 }, { 0, 0 }, ISC_R_RANGE }, { { 0, 0 }, { 0, MAX_NS }, { 0, 0 }, ISC_R_RANGE }, }; ISC_RUN_TEST_IMPL(isc_time_add_test) { - UNUSED(state); - for (size_t i = 0; i < ARRAY_SIZE(vectors_add); i++) { - isc_time_t r = { UINT_MAX, UINT_MAX }; + isc_time_t r = { MAX_S, MAX_S }; isc_result_t result = isc_time_add(&(vectors_add[i].a), &(vectors_add[i].b), &r); assert_int_equal(result, vectors_add[i].result); @@ -104,8 +190,6 @@ } ISC_RUN_TEST_IMPL(isc_time_sub_test) { - UNUSED(state); - for (size_t i = 0; i < ARRAY_SIZE(vectors_sub); i++) { isc_time_t r = { UINT_MAX, UINT_MAX }; isc_result_t result = isc_time_subtract( @@ -135,41 +219,187 @@ &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, 0 }, NULL)); } -/* parse http time stamp */ +struct compare_vectors { + isc_time_t a; + isc_time_t b; + int64_t r; +}; + +const struct compare_vectors vectors_compare[] = { + { { 0, 0 }, { 0, 0 }, 0 }, + { { 1, 0 }, { 0, 0 }, 1 }, + { { 0, 0 }, { 1, 0 }, -1 }, + + { { 0, 1 }, { 0, 1 }, 0 }, + { { 0, 1 }, { 0, 0 }, 1 }, + { { 0, 0 }, { 0, 1 }, -1 }, + + { { 0, 0 }, { MAX_S, MAX_NS }, -1 }, + { { MAX_S, MAX_NS }, { 0, 0 }, 1 }, + { { MAX_S, MAX_NS }, { MAX_S, MAX_NS }, 0 }, + + { { 1, 0 }, { 0, MAX_NS }, 1 }, + { { 0, MAX_NS }, { 1, 0 }, -1 } +}; + +ISC_RUN_TEST_IMPL(isc_time_compare_test) { + for (size_t i = 0; i < ARRAY_SIZE(vectors_compare); i++) { + int r = isc_time_compare(&(vectors_compare[i].a), + &(vectors_compare[i].b)); + assert_int_equal(vectors_compare[i].r, r); + } + + /* Invalid first argument */ + expect_assert_failure((void)isc_time_compare((isc_time_t *)NULL, + &(isc_time_t){ 0, 0 })); + + expect_assert_failure((void)isc_time_compare( + &(isc_time_t){ 0, MAX_NS + 1 }, &(isc_time_t){ 0, 0 })); + + /* Invalid second argument */ + expect_assert_failure((void)isc_time_compare(&(isc_time_t){ 0, 0 }, + (isc_time_t *)NULL)); + + expect_assert_failure((void)isc_time_compare( + &(isc_time_t){ 0, 0 }, &(isc_time_t){ 0, MAX_NS + 1 })); +} + +#define MAX_NS_PER_US (MAX_NS / NS_PER_US) +#define MAX_MICRODIFF_N (MAX_S + 0LL) +#define MAX_MICRODIFF_US (MAX_S + 0LL) * US_PER_SEC + +const struct compare_vectors vectors_microdiff[] = { + { { 0, 0 }, { 0, 0 }, 0 }, + { { 1, 0 }, { 0, 0 }, 1 * US_PER_SEC }, + { { 0, 0 }, { 1, 0 }, 0 }, + + { { 0, 1 }, { 0, 1 }, 0 }, + { { 0, 1 }, { 0, 0 }, 0 }, + { { 0, 0 }, { 0, 1 }, 0 }, + + { { 0, NS_PER_US }, { 0, NS_PER_US }, 0 }, + { { 0, NS_PER_US }, { 0, 0 }, 1 }, + { { 0, 0 }, { 0, NS_PER_US }, 0 }, + + { { 0, 0 }, { MAX_MICRODIFF_N, MAX_NS }, 0 }, + { { MAX_MICRODIFF_N, MAX_NS }, + { 0, 0 }, + MAX_MICRODIFF_US + MAX_NS_PER_US }, + { { MAX_MICRODIFF_N, MAX_NS }, { MAX_MICRODIFF_N, MAX_NS }, 0 }, + + { { 1, 0 }, { 0, MAX_NS }, 0 }, + { { 0, MAX_NS }, { 1, 0 }, 0 } +}; + +ISC_RUN_TEST_IMPL(isc_time_microdiff_test) { + for (size_t i = 0; i < ARRAY_SIZE(vectors_microdiff); i++) { + int64_t r = isc_time_microdiff(&(vectors_microdiff[i].a), + &(vectors_microdiff[i].b)); + assert_int_equal(vectors_microdiff[i].r, r); + } + + /* Invalid first argument */ + expect_assert_failure((void)isc_time_microdiff((isc_time_t *)NULL, + &(isc_time_t){ 0, 0 })); + + expect_assert_failure((void)isc_time_microdiff( + &(isc_time_t){ 0, MAX_NS + 1 }, &(isc_time_t){ 0, 0 })); + + /* Invalid second argument */ + expect_assert_failure((void)isc_time_microdiff(&(isc_time_t){ 0, 0 }, + (isc_time_t *)NULL)); + + expect_assert_failure((void)isc_time_microdiff( + &(isc_time_t){ 0, 0 }, &(isc_time_t){ 0, MAX_NS + 1 })); +} + +ISC_RUN_TEST_IMPL(isc_time_formattimestamp_test) { + isc_time_t t = { 0, 0 }; + char buf[ISC_FORMATTIMESTAMP_SIZE]; + + /* + * The second least population is at UTC+08:45 that covers village of + * Eucla and other villages in Australia with a population of around + * 200. The area is surrounded by signs to remind you to turn your + * clocks, but it is unofficial so it might not comply either. + */ + setenv("TZ", "Australia/Eucla", 1); + t = isc_time_now(); + + memset(buf, 'X', sizeof(buf)); + isc_time_formattimestamp(&t, buf, sizeof(buf)); + assert_int_equal(strlen(buf), sizeof(buf) - 1); + + memset(buf, 'X', sizeof(buf)); + isc_time_settoepoch(&t); + isc_time_formattimestamp(&t, buf, sizeof(buf)); + assert_string_equal(buf, "01-Jan-1970 08:45:00.000"); + + memset(buf, 'X', sizeof(buf)); + isc_time_set(&t, 1450000000, 123000000); + isc_time_formattimestamp(&t, buf, sizeof(buf)); + assert_string_equal(buf, "13-Dec-2015 18:31:40.123"); + + expect_assert_failure(isc_time_formattimestamp(NULL, buf, sizeof(buf))); + expect_assert_failure(isc_time_formattimestamp( + &(isc_time_t){ 0, MAX_NS + 1 }, buf, sizeof(buf))); + expect_assert_failure(isc_time_formattimestamp(&t, NULL, 0)); + expect_assert_failure( + isc_time_formattimestamp(&t, buf, sizeof(buf) - 1)); +} +/* parse http time stamp */ ISC_RUN_TEST_IMPL(isc_time_parsehttptimestamp_test) { - isc_result_t result; isc_time_t t, x; char buf[ISC_FORMATHTTPTIMESTAMP_SIZE]; - UNUSED(state); - - setenv("TZ", "America/Los_Angeles", 1); + setenv("TZ", "Australia/Eucla", 1); tzset(); t = isc_time_now(); isc_time_formathttptimestamp(&t, buf, sizeof(buf)); - result = isc_time_parsehttptimestamp(buf, &x); - assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(isc_time_parsehttptimestamp(buf, &x), ISC_R_SUCCESS); + assert_int_equal(isc_time_seconds(&t), isc_time_seconds(&x)); + + memset(buf, 'X', sizeof(buf)); + isc_time_settoepoch(&t); + isc_time_formathttptimestamp(&t, buf, sizeof(buf)); + assert_string_equal(buf, "Thu, 01 Jan 1970 00:00:00 GMT"); + assert_int_equal(isc_time_parsehttptimestamp(buf, &x), ISC_R_SUCCESS); assert_int_equal(isc_time_seconds(&t), isc_time_seconds(&x)); + + memset(buf, 'X', sizeof(buf)); + isc_time_set(&t, 1450000000, 123000000); + isc_time_formathttptimestamp(&t, buf, sizeof(buf)); + assert_string_equal(buf, "Sun, 13 Dec 2015 09:46:40 GMT"); + assert_int_equal(isc_time_parsehttptimestamp(buf, &x), ISC_R_SUCCESS); + assert_int_equal(isc_time_seconds(&t), isc_time_seconds(&x)); + + expect_assert_failure( + isc_time_formathttptimestamp(NULL, buf, sizeof(buf))); + expect_assert_failure(isc_time_formathttptimestamp( + &(isc_time_t){ 0, MAX_NS + 1 }, buf, sizeof(buf))); + expect_assert_failure(isc_time_formathttptimestamp(&t, NULL, 0)); + expect_assert_failure( + isc_time_formathttptimestamp(&t, buf, sizeof(buf) - 1)); + + expect_assert_failure(isc_time_parsehttptimestamp(buf, NULL)); + expect_assert_failure(isc_time_parsehttptimestamp(NULL, &t)); } /* print UTC in ISO8601 */ - ISC_RUN_TEST_IMPL(isc_time_formatISO8601_test) { - isc_time_t t; - char buf[64]; + isc_time_t t = { 0, 0 }; + char buf[ISC_FORMATISO8601_SIZE]; - UNUSED(state); - - setenv("TZ", "America/Los_Angeles", 1); + setenv("TZ", "Australia/Eucla", 1); tzset(); t = isc_time_now(); /* check formatting: yyyy-mm-ddThh:mm:ssZ */ memset(buf, 'X', sizeof(buf)); isc_time_formatISO8601(&t, buf, sizeof(buf)); - assert_int_equal(strlen(buf), 20); + assert_int_equal(strlen(buf), sizeof(buf) - 1); assert_int_equal(buf[4], '-'); assert_int_equal(buf[7], '-'); assert_int_equal(buf[10], 'T'); @@ -187,24 +417,27 @@ isc_time_set(&t, 1450000000, 123000000); isc_time_formatISO8601(&t, buf, sizeof(buf)); assert_string_equal(buf, "2015-12-13T09:46:40Z"); + + expect_assert_failure(isc_time_formatISO8601(NULL, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatISO8601( + &(isc_time_t){ 0, MAX_NS + 1 }, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatISO8601(&t, NULL, 0)); + expect_assert_failure(isc_time_formatISO8601(&t, buf, sizeof(buf) - 1)); } /* print UTC in ISO8601 with milliseconds */ - ISC_RUN_TEST_IMPL(isc_time_formatISO8601ms_test) { - isc_time_t t; - char buf[64]; - - UNUSED(state); + isc_time_t t = { 0, 0 }; + char buf[ISC_FORMATISO8601MS_SIZE]; - setenv("TZ", "America/Los_Angeles", 1); + setenv("TZ", "Australia/Eucla", 1); tzset(); t = isc_time_now(); /* check formatting: yyyy-mm-ddThh:mm:ss.sssZ */ memset(buf, 'X', sizeof(buf)); isc_time_formatISO8601ms(&t, buf, sizeof(buf)); - assert_int_equal(strlen(buf), 24); + assert_int_equal(strlen(buf), sizeof(buf) - 1); assert_int_equal(buf[4], '-'); assert_int_equal(buf[7], '-'); assert_int_equal(buf[10], 'T'); @@ -223,24 +456,28 @@ isc_time_set(&t, 1450000000, 123000000); isc_time_formatISO8601ms(&t, buf, sizeof(buf)); assert_string_equal(buf, "2015-12-13T09:46:40.123Z"); + + expect_assert_failure(isc_time_formatISO8601ms(NULL, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatISO8601ms( + &(isc_time_t){ 0, MAX_NS + 1 }, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatISO8601ms(&t, NULL, 0)); + expect_assert_failure( + isc_time_formatISO8601ms(&t, buf, sizeof(buf) - 1)); } /* print UTC in ISO8601 with microseconds */ - ISC_RUN_TEST_IMPL(isc_time_formatISO8601us_test) { - isc_time_t t; - char buf[64]; - - UNUSED(state); + isc_time_t t = { 0, 0 }; + char buf[ISC_FORMATISO8601US_SIZE]; - setenv("TZ", "America/Los_Angeles", 1); + setenv("TZ", "Australia/Eucla", 1); tzset(); t = isc_time_now_hires(); /* check formatting: yyyy-mm-ddThh:mm:ss.ssssssZ */ memset(buf, 'X', sizeof(buf)); isc_time_formatISO8601us(&t, buf, sizeof(buf)); - assert_int_equal(strlen(buf), 27); + assert_int_equal(strlen(buf), sizeof(buf) - 1); assert_int_equal(buf[4], '-'); assert_int_equal(buf[7], '-'); assert_int_equal(buf[10], 'T'); @@ -259,6 +496,13 @@ isc_time_set(&t, 1450000000, 123456000); isc_time_formatISO8601us(&t, buf, sizeof(buf)); assert_string_equal(buf, "2015-12-13T09:46:40.123456Z"); + + expect_assert_failure(isc_time_formatISO8601us(NULL, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatISO8601us( + &(isc_time_t){ 0, MAX_NS + 1 }, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatISO8601us(&t, NULL, 0)); + expect_assert_failure( + isc_time_formatISO8601us(&t, buf, sizeof(buf) - 1)); } /* print local time in ISO8601 */ @@ -296,21 +540,18 @@ } /* print local time in ISO8601 with milliseconds */ - ISC_RUN_TEST_IMPL(isc_time_formatISO8601Lms_test) { - isc_time_t t; - char buf[64]; - - UNUSED(state); + isc_time_t t = { 0, 0 }; + char buf[ISC_FORMATISO8601LMS_SIZE]; - setenv("TZ", "America/Los_Angeles", 1); + setenv("TZ", "Australia/Eucla", 1); tzset(); t = isc_time_now(); /* check formatting: yyyy-mm-ddThh:mm:ss.sss */ memset(buf, 'X', sizeof(buf)); isc_time_formatISO8601Lms(&t, buf, sizeof(buf)); - assert_int_equal(strlen(buf), 23); + assert_int_equal(strlen(buf), sizeof(buf) - 1); assert_int_equal(buf[4], '-'); assert_int_equal(buf[7], '-'); assert_int_equal(buf[10], 'T'); @@ -322,12 +563,20 @@ memset(buf, 'X', sizeof(buf)); isc_time_settoepoch(&t); isc_time_formatISO8601Lms(&t, buf, sizeof(buf)); - assert_string_equal(buf, "1969-12-31T16:00:00.000"); + assert_string_equal(buf, "1970-01-01T08:45:00.000"); memset(buf, 'X', sizeof(buf)); isc_time_set(&t, 1450000000, 123000000); isc_time_formatISO8601Lms(&t, buf, sizeof(buf)); - assert_string_equal(buf, "2015-12-13T01:46:40.123"); + assert_string_equal(buf, "2015-12-13T18:31:40.123"); + + expect_assert_failure( + isc_time_formatISO8601Lms(NULL, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatISO8601Lms( + &(isc_time_t){ 0, MAX_NS + 1 }, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatISO8601Lms(&t, NULL, 0)); + expect_assert_failure( + isc_time_formatISO8601Lms(&t, buf, sizeof(buf) - 1)); } /* print local time in ISO8601 with microseconds */ @@ -366,21 +615,18 @@ } /* print UTC time as yyyymmddhhmmsssss */ - ISC_RUN_TEST_IMPL(isc_time_formatshorttimestamp_test) { - isc_time_t t; - char buf[64]; - - UNUSED(state); + isc_time_t t = { 0, 0 }; + char buf[ISC_FORMATSHORTTIMESTAMP_SIZE]; - setenv("TZ", "America/Los_Angeles", 1); + setenv("TZ", "Australia/Eucla", 1); tzset(); t = isc_time_now(); /* check formatting: yyyymmddhhmmsssss */ memset(buf, 'X', sizeof(buf)); isc_time_formatshorttimestamp(&t, buf, sizeof(buf)); - assert_int_equal(strlen(buf), 17); + assert_int_equal(strlen(buf), sizeof(buf) - 1); /* check time conversion correctness */ memset(buf, 'X', sizeof(buf)); @@ -392,10 +638,21 @@ isc_time_set(&t, 1450000000, 123000000); isc_time_formatshorttimestamp(&t, buf, sizeof(buf)); assert_string_equal(buf, "20151213094640123"); + + expect_assert_failure( + isc_time_formatshorttimestamp(NULL, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatshorttimestamp( + &(isc_time_t){ 0, MAX_NS + 1 }, buf, sizeof(buf))); + expect_assert_failure(isc_time_formatshorttimestamp(&t, NULL, 0)); + expect_assert_failure( + isc_time_formatshorttimestamp(&t, buf, sizeof(buf) - 1)); } ISC_TEST_LIST_START +ISC_TEST_ENTRY(isc_interval_basic_test) +ISC_TEST_ENTRY(isc_time_basic_test) +ISC_TEST_ENTRY(isc_time_now_test) ISC_TEST_ENTRY(isc_time_add_test) ISC_TEST_ENTRY(isc_time_sub_test) ISC_TEST_ENTRY(isc_time_parsehttptimestamp_test) @@ -406,6 +663,9 @@ ISC_TEST_ENTRY(isc_time_formatISO8601Lms_test) ISC_TEST_ENTRY(isc_time_formatISO8601Lus_test) ISC_TEST_ENTRY(isc_time_formatshorttimestamp_test) +ISC_TEST_ENTRY(isc_time_formattimestamp_test) +ISC_TEST_ENTRY(isc_time_microdiff_test) +ISC_TEST_ENTRY(isc_time_compare_test) ISC_TEST_LIST_END diff -Nru bind9-9.20.26/tests/isc/work_test.c bind9-9.20.29/tests/isc/work_test.c --- bind9-9.20.26/tests/isc/work_test.c 2026-07-20 14:47:54.270853181 +0000 +++ bind9-9.20.29/tests/isc/work_test.c 2026-09-11 19:41:01.747336888 +0000 @@ -38,17 +38,20 @@ static atomic_uint scheduled = 0; -static void +static isc_result_t work_cb(void *arg) { UNUSED(arg); atomic_fetch_add(&scheduled, 1); assert_int_equal(isc_tid(), UINT32_MAX); + + return ISC_R_ALREADYRUNNING; /* mock result code */ } static void -after_work_cb(void *arg ISC_ATTR_UNUSED, isc_result_t result ISC_ATTR_UNUSED) { +after_work_cb(void *arg ISC_ATTR_UNUSED, isc_result_t result) { + assert_int_equal(result, ISC_R_ALREADYRUNNING); assert_int_equal(atomic_load(&scheduled), 1); isc_loopmgr_shutdown(loopmgr); } diff -Nru bind9-9.20.26/tests/isccfg/Makefile.in bind9-9.20.29/tests/isccfg/Makefile.in --- bind9-9.20.26/tests/isccfg/Makefile.in 2026-07-20 14:49:11.285597608 +0000 +++ bind9-9.20.29/tests/isccfg/Makefile.in 2026-09-11 19:42:19.246205509 +0000 @@ -508,6 +508,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/tests/isccfg/duration_test.c bind9-9.20.29/tests/isccfg/duration_test.c --- bind9-9.20.26/tests/isccfg/duration_test.c 2026-07-20 14:47:54.270853181 +0000 +++ bind9-9.20.29/tests/isccfg/duration_test.c 2026-09-11 19:41:01.747336888 +0000 @@ -208,6 +208,7 @@ kopts = cfg_tuple_get(kconf, "options"); result = cfg_map_get(kopts, "keys", &keys); + assert_int_equal(result, ISC_R_SUCCESS); key_element = cfg_list_first(keys); assert_non_null(key_element); diff -Nru bind9-9.20.26/tests/libtest/Makefile.in bind9-9.20.29/tests/libtest/Makefile.in --- bind9-9.20.26/tests/libtest/Makefile.in 2026-07-20 14:49:11.319598389 +0000 +++ bind9-9.20.29/tests/libtest/Makefile.in 2026-09-11 19:42:19.279206312 +0000 @@ -491,6 +491,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/tests/libtest/dns.c bind9-9.20.29/tests/libtest/dns.c --- bind9-9.20.26/tests/libtest/dns.c 2026-07-20 14:47:54.271853196 +0000 +++ bind9-9.20.29/tests/libtest/dns.c 2026-09-11 19:41:01.748336913 +0000 @@ -368,7 +368,6 @@ * delimiters while reading the source string. These should match * specials from lib/dns/master.c. */ - specials[0] = 1; specials['('] = 1; specials[')'] = 1; specials['"'] = 1; diff -Nru bind9-9.20.26/tests/ns/Makefile.in bind9-9.20.29/tests/ns/Makefile.in --- bind9-9.20.26/tests/ns/Makefile.in 2026-07-20 14:49:11.359599308 +0000 +++ bind9-9.20.29/tests/ns/Makefile.in 2026-09-11 19:42:19.321207335 +0000 @@ -518,6 +518,7 @@ LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIBSCF_LIBS = @LIBSCF_LIBS@ LIBTOOL = @LIBTOOL@ LIBURCU_CFLAGS = @LIBURCU_CFLAGS@ LIBURCU_LIBS = @LIBURCU_LIBS@ diff -Nru bind9-9.20.26/util/check-make-install.sh.in bind9-9.20.29/util/check-make-install.sh.in --- bind9-9.20.26/util/check-make-install.sh.in 2026-07-20 14:47:54.273853227 +0000 +++ bind9-9.20.29/util/check-make-install.sh.in 2026-09-11 19:41:01.750336960 +0000 @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # Copyright (C) Internet Systems Consortium, Inc. ("ISC") # @@ -11,17 +11,30 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. +set -euo pipefail + abs_top_srcdir=@abs_top_srcdir@ abs_builddir=@abs_builddir@ +# configure expands the directory variables below into references to +# prefix, exec_prefix and datarootdir, which shellcheck cannot see. +# shellcheck disable=SC2034 prefix=@prefix@ +# shellcheck disable=SC2034 +exec_prefix=@exec_prefix@ +# shellcheck disable=SC2034 +datarootdir=@datarootdir@ includedir=@includedir@ -install_dir="${DESTDIR}@prefix@" +install_dir="${DESTDIR:-}@prefix@" +bindir="${DESTDIR:-}@bindir@" +libdir="${DESTDIR:-}@libdir@" +mandir="${DESTDIR:-}@mandir@" +sbindir="${DESTDIR:-}@sbindir@" headers_to_install() { find "${abs_top_srcdir}/lib" -name "*.h" -or -name "*.h.in" \ | sed -n \ -e "s|\.h\.in$|\.h|" \ - -e "s|.*include/|${DESTDIR}${includedir}/|p" \ + -e "s|.*include/|${DESTDIR:-}${includedir}/|p" \ | sort -u } @@ -34,19 +47,31 @@ fi done -named_binary_path="${install_dir}/sbin/named" +named_binary_path="${sbindir}/named" if [ ! -x "${named_binary_path}" ]; then echo "ERROR: ${named_binary_path} does not exist or is not executable" status=1 fi -named_man_page_path="${install_dir}/share/man/man8/named.8" +named_man_page_path="${mandir}/man8/named.8" if [ ! -f "${named_man_page_path}" ]; then echo "ERROR: ${named_man_page_path} does not exist" status=1 fi -if [ -n "${DESTDIR}" ]; then +# Every installed program must have a manual page installed with it. +shopt -s nullglob + +for program in "${bindir}"/* "${sbindir}"/* "${libdir}"/bind/*.so; do + name=$(basename "${program}" .so) + man_pages=("${mandir}"/man*/"${name}".?) + if [ ${#man_pages[@]} -eq 0 ]; then + echo "ERROR: no manual page was installed for ${name}" + status=1 + fi +done + +if [ -n "${DESTDIR:-}" ]; then for expected_subdir in bin include lib sbin share; do echo "${install_dir}/${expected_subdir}" >>"${abs_builddir}/expected_dirs" done @@ -58,4 +83,4 @@ rm -f "${abs_builddir}/expected_dirs" "${abs_builddir}/existing_dirs" fi -exit $status +exit "$status"