Compare commits
232
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f089e25217 | ||
|
|
1fa199fba2 | ||
|
|
29cef34a34 | ||
|
|
25ec1d79e4 | ||
|
|
79573f1390 | ||
|
|
042bb98846 | ||
|
|
f30008a71c | ||
|
|
b5478654a2 | ||
|
|
4a3f7fe1ef | ||
|
|
9d1a8a98c6 | ||
|
|
657ee2b997 | ||
|
|
6c54337f52 | ||
|
|
7e6be9f1b5 | ||
|
|
7d289e5333 | ||
|
|
6f4ef40ccd | ||
|
|
237123e500 | ||
|
|
b1b1ca8ca4 | ||
|
|
66dbff596b | ||
|
|
2dff926624 | ||
|
|
b1184d916d | ||
|
|
84180c8ee1 | ||
|
|
1359694267 | ||
|
|
9305ebdabe | ||
|
|
d69cd51f91 | ||
|
|
0f86976672 | ||
|
|
2b348a5daa | ||
|
|
ed77b61599 | ||
|
|
e6984e5c07 | ||
|
|
7a13fcd601 | ||
|
|
7d7fc8cb2d | ||
|
|
254ba1b051 | ||
|
|
63b93ccda2 | ||
|
|
580c41de0d | ||
|
|
4f7947c583 | ||
|
|
f454fa6dea | ||
|
|
7107c44c7c | ||
|
|
abbc59a270 | ||
|
|
141e4c9805 | ||
|
|
6708da3112 | ||
|
|
53cc00ee3f | ||
|
|
932665410d | ||
|
|
6cb6b99ae7 | ||
|
|
26375bdcf2 | ||
|
|
970ac03196 | ||
|
|
6a045cd8ec | ||
|
|
c35f00e48a | ||
|
|
49f9487577 | ||
|
|
b53c03d98e | ||
|
|
afda87cb08 | ||
|
|
7007025302 | ||
|
|
d9c947c57d | ||
|
|
cdf0fd2e5e | ||
|
|
83da52d6e4 | ||
|
|
efe4fa6fc7 | ||
|
|
46785dc71e | ||
|
|
e7525cab4f | ||
|
|
695be761b0 | ||
|
|
887fa0ddc9 | ||
|
|
31521fade2 | ||
|
|
2bf03ab7df | ||
|
|
852ba174dd | ||
|
|
1b39172ee7 | ||
|
|
22a4bd5bbe | ||
|
|
ed9704fcda | ||
|
|
e033e58a85 | ||
|
|
7508534789 | ||
|
|
a3915e535a | ||
|
|
bc31575899 | ||
|
|
1cb345fa95 | ||
|
|
77d4afba1b | ||
|
|
2ca6bcc99a | ||
|
|
620cce8f7e | ||
|
|
e4793242eb | ||
|
|
cbbc0051a3 | ||
|
|
24ae1157e8 | ||
|
|
e13728413a | ||
|
|
5d4233c2c2 | ||
|
|
3b9ea189b2 | ||
|
|
903af2e1de | ||
|
|
da607d6a06 | ||
|
|
bbb2741de8 | ||
|
|
fbea3bb255 | ||
|
|
c7ed858c6e | ||
|
|
23835c4afe | ||
|
|
950f828cd2 | ||
|
|
f8a09fd91a | ||
|
|
c3d8932f79 | ||
|
|
8b7785bc23 | ||
|
|
67f403a423 | ||
|
|
0438d3655b | ||
|
|
50bd729019 | ||
|
|
2a4daaedca | ||
|
|
c9ff77c067 | ||
|
|
9360d90bf2 | ||
|
|
36c11d9180 | ||
|
|
bf70d4840c | ||
|
|
fcf2919c93 | ||
|
|
d2fd97f4da | ||
|
|
eb1829b970 | ||
|
|
4ef755ffb0 | ||
|
|
90b0038ea0 | ||
|
|
7f805659c3 | ||
|
|
381273f89f | ||
|
|
9cc6b4a68a | ||
|
|
7c369ea3d9 | ||
|
|
40fd4cd407 | ||
|
|
9c712eff0a | ||
|
|
d2fa9a642b | ||
|
|
c13e8e1859 | ||
|
|
2c88946590 | ||
|
|
480126919a | ||
|
|
1341a1a734 | ||
|
|
b0b4ea3975 | ||
|
|
3c0eaff4c6 | ||
|
|
dc9d9a8fdf | ||
|
|
03c9e0b753 | ||
|
|
4c0db2ee3c | ||
|
|
e4344b7d1a | ||
|
|
3989b99a0b | ||
|
|
1076bd3c78 | ||
|
|
bf92e16c0e | ||
|
|
ae2b59bfe7 | ||
|
|
792ac13d60 | ||
|
|
304b5ec1ad | ||
|
|
bf538b63a8 | ||
|
|
dfefc89b7e | ||
|
|
7c96bf3e71 | ||
|
|
b7b69d9cf0 | ||
|
|
88d826ac5d | ||
|
|
a5ea7bcd25 | ||
|
|
a6c6ad048d | ||
|
|
424cb59a43 | ||
|
|
cad6292fc4 | ||
|
|
63659e2e3a | ||
|
|
c47fa689d4 | ||
|
|
f95b890759 | ||
|
|
ea6659a5e9 | ||
|
|
b4cc46de07 | ||
|
|
183b3cb6aa | ||
|
|
40a6efae01 | ||
|
|
86d5981dcd | ||
|
|
a7ece8e0bd | ||
|
|
8c2503947f | ||
|
|
1335e139f2 | ||
|
|
7b5b3a842b | ||
|
|
2789906ce4 | ||
|
|
0371223343 | ||
|
|
d6df757fdc | ||
|
|
f0800501c7 | ||
|
|
aba16af556 | ||
|
|
af220a5b72 | ||
|
|
77d4bb9751 | ||
|
|
2a724a808d | ||
|
|
948a89d591 | ||
|
|
5e02a007ca | ||
|
|
0ba29730f7 | ||
|
|
82cfb48295 | ||
|
|
087e7b590f | ||
|
|
d1f1b6a934 | ||
|
|
3712a219cb | ||
|
|
da39dffd08 | ||
|
|
a061fd67f6 | ||
|
|
32e7e0a8ee | ||
|
|
86a192cece | ||
|
|
b1ebd49f3a | ||
|
|
a4e9ce500a | ||
|
|
225d986cdf | ||
|
|
05b09f2b5b | ||
|
|
ab441581b5 | ||
|
|
ad083897cc | ||
|
|
c8efe7fe1d | ||
|
|
ecb043fc7b | ||
|
|
d12c238750 | ||
|
|
49561277de | ||
|
|
22591ae0a7 | ||
|
|
13c6f25abb | ||
|
|
673387c4d5 | ||
|
|
6c010a5644 | ||
|
|
d3172cb47c | ||
|
|
4d2d80f534 | ||
|
|
e790b0cba1 | ||
|
|
69d3efed89 | ||
|
|
9950f6d651 | ||
|
|
c252ca2ce5 | ||
|
|
7a161f615a | ||
|
|
686033e48d | ||
|
|
5af3b713af | ||
|
|
db272a4968 | ||
|
|
f90a772298 | ||
|
|
67087b6c43 | ||
|
|
9019985d2d | ||
|
|
0906848ae9 | ||
|
|
b41d1820d2 | ||
|
|
8babbd09a1 | ||
|
|
d74bba4fae | ||
|
|
cbc121ce9a | ||
|
|
176bf877e1 | ||
|
|
f7f7b09d98 | ||
|
|
6a301c1d35 | ||
|
|
4be1db6e82 | ||
|
|
52b053537d | ||
|
|
120b4a9ef9 | ||
|
|
1f67a3f474 | ||
|
|
17186e06bb | ||
|
|
c0fcc2899e | ||
|
|
8b67476249 | ||
|
|
f908d358c4 | ||
|
|
78aa2fb64c | ||
|
|
ad33a73f83 | ||
|
|
8d3f601a6b | ||
|
|
5b5f43babc | ||
|
|
4d560d5ffd | ||
|
|
659fa0cbc3 | ||
|
|
1102c5d552 | ||
|
|
bc600ae2a1 | ||
|
|
e39de45adc | ||
|
|
fd49abf254 | ||
|
|
6a91862ac5 | ||
|
|
229bf863e2 | ||
|
|
40816e4e35 | ||
|
|
5a17764a77 | ||
|
|
b3c8b5cfb2 | ||
|
|
29f1c93734 | ||
|
|
f0b164430a | ||
|
|
41eed193b2 | ||
|
|
228cc557fe | ||
|
|
377bd35574 | ||
|
|
32e43764dd | ||
|
|
0aac81cf80 | ||
|
|
03c040da53 | ||
|
|
33bdbfe2f5 | ||
|
|
df0229e7ee |
@@ -75,6 +75,7 @@ doc/man/dnssec-importkey.8in
|
||||
doc/man/dnssec-keyfromlabel.8in
|
||||
doc/man/dnssec-keygen.8in
|
||||
doc/man/dnssec-keymgr.8in
|
||||
doc/man/dnssec-ksr.8in
|
||||
doc/man/dnssec-revoke.8in
|
||||
doc/man/dnssec-settime.8in
|
||||
doc/man/dnssec-signzone.8in
|
||||
|
||||
+74
-96
@@ -15,7 +15,7 @@ variables:
|
||||
TEST_PARALLEL_JOBS: 4
|
||||
|
||||
CONFIGURE: ./configure
|
||||
CLANG_VERSION: 17
|
||||
CLANG_VERSION: 18
|
||||
CLANG: "clang-${CLANG_VERSION}"
|
||||
SCAN_BUILD: "scan-build-${CLANG_VERSION}"
|
||||
LLVM_SYMBOLIZER: "/usr/lib/llvm-${CLANG_VERSION}/bin/llvm-symbolizer"
|
||||
@@ -71,6 +71,7 @@ stages:
|
||||
- performance
|
||||
- docs
|
||||
- postcheck
|
||||
- postmerge
|
||||
- release
|
||||
|
||||
### Runner Tag Templates
|
||||
@@ -80,14 +81,6 @@ stages:
|
||||
- libvirt
|
||||
- amd64
|
||||
|
||||
# Jobs with these tags do not run on AWS but on permanent OVH systems.
|
||||
|
||||
.linux-respdiff-amd64: &linux_respdiff_amd64
|
||||
tags:
|
||||
- linux
|
||||
- ovh
|
||||
- amd64
|
||||
|
||||
# Autoscaling GitLab Runner on AWS EC2 (amd64)
|
||||
|
||||
.linux-amd64: &linux_amd64
|
||||
@@ -147,10 +140,6 @@ stages:
|
||||
image: "$CI_REGISTRY_IMAGE:debian-bullseye-amd64"
|
||||
<<: *linux_amd64
|
||||
|
||||
.respdiff-debian-bookworm-amd64: &respdiff_debian_bookworm_amd64_image
|
||||
image: "$CI_REGISTRY_IMAGE:debian-bookworm-amd64"
|
||||
<<: *linux_respdiff_amd64
|
||||
|
||||
.debian-bookworm-amd64: &debian_bookworm_amd64_image
|
||||
image: "$CI_REGISTRY_IMAGE:debian-bookworm-amd64"
|
||||
<<: *linux_amd64
|
||||
@@ -206,7 +195,7 @@ stages:
|
||||
### QCOW2 Image Templates
|
||||
|
||||
.freebsd-13-amd64: &freebsd_13_amd64_image
|
||||
image: "freebsd-13.2-x86_64"
|
||||
image: "freebsd-13.3-x86_64"
|
||||
<<: *libvirt_amd64
|
||||
|
||||
.freebsd-14-amd64: &freebsd_14_amd64_image
|
||||
@@ -219,17 +208,19 @@ stages:
|
||||
|
||||
### Job Templates
|
||||
|
||||
.api-schedules-tags-triggers-web-triggering-rules: &api_schedules_tags_triggers_web_triggering_rules
|
||||
.api-pipelines-schedules-tags-triggers-web-triggering-rules: &api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
only:
|
||||
- api
|
||||
- pipelines
|
||||
- schedules
|
||||
- tags
|
||||
- triggers
|
||||
- web
|
||||
|
||||
.api-schedules-triggers-web-triggering-rules: &api_schedules_triggers_web_triggering_rules
|
||||
.api-pipelines-schedules-triggers-web-triggering-rules: &api_pipelines_schedules_triggers_web_triggering_rules
|
||||
only:
|
||||
- api
|
||||
- pipelines
|
||||
- schedules
|
||||
- triggers
|
||||
- web
|
||||
@@ -238,6 +229,7 @@ stages:
|
||||
only:
|
||||
- api
|
||||
- merge_requests
|
||||
- pipelines
|
||||
- schedules
|
||||
- tags
|
||||
- triggers
|
||||
@@ -344,7 +336,7 @@ stages:
|
||||
|
||||
.shotgun: &shotgun_job
|
||||
<<: *base_image
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
stage: performance
|
||||
script:
|
||||
- if [ -z "$CI_COMMIT_TAG" ]; then export SHOTGUN_ROUNDS=1; else export SHOTGUN_ROUNDS=3; fi
|
||||
@@ -479,14 +471,14 @@ stages:
|
||||
- *configure
|
||||
- make -j${BUILD_PARALLEL_JOBS:-1} V=1
|
||||
- *setup_interfaces
|
||||
- git clone --depth 1 https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.isc.org/isc-private/bind-qa.git
|
||||
- cd bind-qa/bind9/respdiff
|
||||
- git clone --depth 1 https://gitlab.isc.org/isc-projects/bind9-qa.git
|
||||
- cd bind9-qa/respdiff
|
||||
needs: []
|
||||
artifacts:
|
||||
paths:
|
||||
- bind-qa/bind9/respdiff
|
||||
- bind9-qa/respdiff
|
||||
exclude:
|
||||
- bind-qa/bind9/respdiff/rspworkdir/data.mdb # Exclude a 10 GB file.
|
||||
- bind9-qa/respdiff/rspworkdir/data.mdb # Exclude a 10 GB file.
|
||||
untracked: true
|
||||
when: always
|
||||
|
||||
@@ -501,15 +493,6 @@ misc:
|
||||
<<: *precheck_job
|
||||
script:
|
||||
- sh util/checklibs.sh > checklibs.out
|
||||
- sh util/tabify-changes < CHANGES > CHANGES.tmp
|
||||
- diff -urNap CHANGES CHANGES.tmp
|
||||
- perl util/check-changes CHANGES
|
||||
- sh util/check-line-length.sh CHANGES
|
||||
- test ! -f CHANGES.SE || sh util/tabify-changes < CHANGES.SE > CHANGES.tmp
|
||||
- test ! -f CHANGES.SE || diff -urNap CHANGES.SE CHANGES.tmp
|
||||
- test ! -f CHANGES.SE || perl util/check-changes master=0 CHANGES.SE
|
||||
- test ! -f CHANGES.SE || sh util/check-line-length.sh CHANGES.SE
|
||||
- rm CHANGES.tmp
|
||||
- sh util/check-categories.sh
|
||||
- sh util/check-gitignore.sh
|
||||
- sh util/check-trailing-whitespace.sh
|
||||
@@ -522,6 +505,18 @@ misc:
|
||||
- checklibs.out
|
||||
when: on_failure
|
||||
|
||||
changes:
|
||||
<<: *precheck_job
|
||||
except:
|
||||
- pipelines
|
||||
script:
|
||||
- sh util/tabify-changes < CHANGES > CHANGES.tmp
|
||||
- diff -urNap CHANGES CHANGES.tmp
|
||||
- perl util/check-changes CHANGES
|
||||
- sh util/check-line-length.sh CHANGES
|
||||
- rm CHANGES.tmp
|
||||
needs: []
|
||||
|
||||
black:
|
||||
<<: *precheck_job
|
||||
needs: []
|
||||
@@ -800,12 +795,12 @@ gcc:8fips:amd64:
|
||||
EXTRA_CONFIGURE: "--with-libidn2 --enable-fips-mode --disable-tracing"
|
||||
<<: *oraclelinux_8fips_amd64_image
|
||||
<<: *build_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
|
||||
system:gcc:8fips:amd64:
|
||||
<<: *oraclelinux_8fips_amd64_image
|
||||
<<: *system_test_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
needs:
|
||||
- job: gcc:8fips:amd64
|
||||
artifacts: true
|
||||
@@ -813,7 +808,7 @@ system:gcc:8fips:amd64:
|
||||
unit:gcc:8fips:amd64:
|
||||
<<: *oraclelinux_8fips_amd64_image
|
||||
<<: *unit_test_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
needs:
|
||||
- job: gcc:8fips:amd64
|
||||
artifacts: true
|
||||
@@ -825,12 +820,12 @@ gcc:9fips:amd64:
|
||||
EXTRA_CONFIGURE: "--with-libidn2 --enable-fips-mode --disable-leak-detection --disable-tracing"
|
||||
<<: *oraclelinux_9fips_amd64_image
|
||||
<<: *build_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
|
||||
system:gcc:9fips:amd64:
|
||||
<<: *oraclelinux_9fips_amd64_image
|
||||
<<: *system_test_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
needs:
|
||||
- job: gcc:9fips:amd64
|
||||
artifacts: true
|
||||
@@ -838,7 +833,7 @@ system:gcc:9fips:amd64:
|
||||
unit:gcc:9fips:amd64:
|
||||
<<: *oraclelinux_9fips_amd64_image
|
||||
<<: *unit_test_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
needs:
|
||||
- job: gcc:9fips:amd64
|
||||
artifacts: true
|
||||
@@ -1008,7 +1003,7 @@ system:gcc:out-of-tree:
|
||||
artifacts: true
|
||||
<<: *base_image
|
||||
<<: *system_test_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
|
||||
unit:gcc:out-of-tree:
|
||||
variables:
|
||||
@@ -1018,7 +1013,7 @@ unit:gcc:out-of-tree:
|
||||
artifacts: true
|
||||
<<: *base_image
|
||||
<<: *unit_test_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
|
||||
# Jobs for tarball GCC builds on Debian 12 "bookworm" (amd64)
|
||||
|
||||
@@ -1038,7 +1033,7 @@ gcc:tarball:
|
||||
system:gcc:tarball:
|
||||
<<: *base_image
|
||||
<<: *system_test_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
before_script:
|
||||
- cd bind-*
|
||||
- *setup_interfaces
|
||||
@@ -1052,7 +1047,7 @@ system:gcc:tarball:
|
||||
unit:gcc:tarball:
|
||||
<<: *base_image
|
||||
<<: *unit_test_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
|
||||
before_script:
|
||||
- cd bind-*
|
||||
needs:
|
||||
@@ -1331,7 +1326,9 @@ unit:clang:bookworm:amd64:
|
||||
clang:freebsd13:amd64:
|
||||
variables:
|
||||
CFLAGS: "${CFLAGS_COMMON}"
|
||||
EXTRA_CONFIGURE: "${WITH_READLINE_LIBEDIT}"
|
||||
# Use MIT Kerberos5 for BIND 9 GSS-API support because of FreeBSD Heimdal
|
||||
# incompatibility; see https://bugs.freebsd.org/275241.
|
||||
EXTRA_CONFIGURE: "${WITH_READLINE_LIBEDIT} --with-gssapi=/usr/local/bin/krb5-config"
|
||||
USER: gitlab-runner
|
||||
<<: *freebsd_13_amd64_image
|
||||
<<: *build_job
|
||||
@@ -1357,7 +1354,9 @@ unit:clang:freebsd13:amd64:
|
||||
clang:freebsd14:amd64:
|
||||
variables:
|
||||
CFLAGS: "${CFLAGS_COMMON}"
|
||||
EXTRA_CONFIGURE: "${WITH_READLINE_EDITLINE}"
|
||||
# Use MIT Kerberos5 for BIND 9 GSS-API support because of FreeBSD Heimdal
|
||||
# incompatibility; see https://bugs.freebsd.org/275241.
|
||||
EXTRA_CONFIGURE: "${WITH_READLINE_EDITLINE} --with-gssapi=/usr/local/bin/krb5-config"
|
||||
USER: gitlab-runner
|
||||
<<: *freebsd_14_amd64_image
|
||||
<<: *build_job
|
||||
@@ -1524,51 +1523,10 @@ coverity:
|
||||
|
||||
# Respdiff tests
|
||||
|
||||
respdiff-short:
|
||||
respdiff:
|
||||
<<: *respdiff_job
|
||||
<<: *default_triggering_rules
|
||||
<<: *debian_bookworm_amd64_image
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -Og -DISC_TRACK_PTHREADS_OBJECTS"
|
||||
MAX_DISAGREEMENTS_PERCENTAGE: "0.5"
|
||||
script:
|
||||
- bash respdiff.sh -m /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 -s named -q "${PWD}/10k_a.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named"
|
||||
|
||||
respdiff-short:asan:
|
||||
<<: *respdiff_job
|
||||
<<: *default_triggering_rules
|
||||
<<: *debian_bookworm_amd64_image
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -Og -fsanitize=address,undefined"
|
||||
LDFLAGS: "-fsanitize=address,undefined"
|
||||
EXTRA_CONFIGURE: "--disable-dnsrps --without-jemalloc"
|
||||
MAX_DISAGREEMENTS_PERCENTAGE: "0.5"
|
||||
script:
|
||||
- bash respdiff.sh -s named -q "${PWD}/10k_a.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named"
|
||||
|
||||
respdiff-short:tsan:
|
||||
<<: *respdiff_job
|
||||
<<: *default_triggering_rules
|
||||
<<: *tsan_debian_bookworm_amd64_image
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -Og -fsanitize=thread"
|
||||
LDFLAGS: "-fsanitize=thread"
|
||||
EXTRA_CONFIGURE: "--disable-dnsrps --enable-pthread-rwlock --without-jemalloc"
|
||||
MAX_DISAGREEMENTS_PERCENTAGE: "0.5"
|
||||
TSAN_OPTIONS: "${TSAN_OPTIONS_DEBIAN}"
|
||||
script:
|
||||
- bash respdiff.sh -s named -q "${PWD}/10k_a.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named"
|
||||
after_script:
|
||||
- *find_python
|
||||
- *parse_tsan
|
||||
|
||||
respdiff-long:
|
||||
<<: *respdiff_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *respdiff_debian_bookworm_amd64_image
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -Og -DISC_TRACK_PTHREADS_OBJECTS"
|
||||
@@ -1576,9 +1534,9 @@ respdiff-long:
|
||||
script:
|
||||
- bash respdiff.sh -m /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 -s named -q "${PWD}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named"
|
||||
|
||||
respdiff-long:asan:
|
||||
respdiff:asan:
|
||||
<<: *respdiff_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *default_triggering_rules
|
||||
<<: *debian_bookworm_amd64_image
|
||||
variables:
|
||||
CC: gcc
|
||||
@@ -1589,9 +1547,9 @@ respdiff-long:asan:
|
||||
script:
|
||||
- bash respdiff.sh -s named -q "${PWD}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named"
|
||||
|
||||
respdiff-long:tsan:
|
||||
respdiff:tsan:
|
||||
<<: *respdiff_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *default_triggering_rules
|
||||
<<: *tsan_debian_bookworm_amd64_image
|
||||
variables:
|
||||
CC: gcc
|
||||
@@ -1605,11 +1563,10 @@ respdiff-long:tsan:
|
||||
after_script:
|
||||
- *find_python
|
||||
- *parse_tsan
|
||||
allow_failure: true # affected by GL #4475
|
||||
|
||||
respdiff-long-third-party:
|
||||
respdiff-third-party:
|
||||
<<: *respdiff_job
|
||||
<<: *api_schedules_tags_triggers_web_triggering_rules
|
||||
<<: *default_triggering_rules
|
||||
<<: *debian_bookworm_amd64_image
|
||||
variables:
|
||||
CC: gcc
|
||||
@@ -1656,8 +1613,8 @@ shotgun:dot:
|
||||
- *setup_interfaces
|
||||
- make -k all V=1
|
||||
- make DESTDIR="${INSTALL_PATH}" install
|
||||
- git clone --depth 1 https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.isc.org/isc-private/bind-qa.git
|
||||
- cd bind-qa/bind9/stress
|
||||
- git clone --depth 1 https://gitlab.isc.org/isc-projects/bind9-qa.git
|
||||
- cd bind9-qa/stress
|
||||
- LD_LIBRARY_PATH="${INSTALL_PATH}/usr/local/lib" BIND_INSTALL_PATH="${INSTALL_PATH}/usr/local" WORKSPACE="${CI_PROJECT_DIR}" bash stress.sh
|
||||
needs:
|
||||
- job: autoreconf
|
||||
@@ -1758,7 +1715,7 @@ stress:rpz:fedora:39:arm64:
|
||||
variables:
|
||||
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /rpz/i && $BIND_STRESS_TEST_ARCH =~ /arm64/i)
|
||||
|
||||
stress:authoritative:freebsd12:amd64:
|
||||
stress:authoritative:freebsd13:amd64:
|
||||
<<: *freebsd_stress_amd64
|
||||
<<: *stress_job
|
||||
variables:
|
||||
@@ -1772,7 +1729,7 @@ stress:authoritative:freebsd12:amd64:
|
||||
variables:
|
||||
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /freebsd/i && $BIND_STRESS_TEST_MODE =~ /authoritative/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i)
|
||||
|
||||
stress:recursive:freebsd12:amd64:
|
||||
stress:recursive:freebsd13:amd64:
|
||||
<<: *freebsd_stress_amd64
|
||||
<<: *stress_job
|
||||
variables:
|
||||
@@ -1786,7 +1743,7 @@ stress:recursive:freebsd12:amd64:
|
||||
variables:
|
||||
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /freebsd/i && $BIND_STRESS_TEST_MODE =~ /recursive/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i)
|
||||
|
||||
stress:rpz:freebsd12:amd64:
|
||||
stress:rpz:freebsd13:amd64:
|
||||
<<: *freebsd_stress_amd64
|
||||
<<: *stress_job
|
||||
variables:
|
||||
@@ -1868,3 +1825,24 @@ pairwise:
|
||||
only:
|
||||
variables:
|
||||
- $PAIRWISE_TESTING
|
||||
|
||||
backports:
|
||||
<<: *base_image
|
||||
stage: postmerge
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "push" && ($CI_COMMIT_REF_NAME =~ /^bind-9.[0-9]+$/ || $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH)'
|
||||
variables:
|
||||
# automated commits will inherit identification from the user who pressed Merge button
|
||||
GIT_COMMITTER_NAME: $GITLAB_USER_NAME
|
||||
GIT_COMMITTER_EMAIL: $GITLAB_USER_EMAIL
|
||||
# avoid leftover branches from previous jobs
|
||||
GIT_STRATEGY: clone
|
||||
# assumed max depth of a MR for backport
|
||||
GIT_DEPTH: 200
|
||||
script:
|
||||
# CI job token is not sufficient for push operations
|
||||
- git remote get-url origin | sed -e "s/gitlab-ci-token:$CI_JOB_TOKEN/oauth2:$BACKPORT_GITLAB_API_TOKEN/" | xargs git remote set-url --push origin
|
||||
# force-pushing is disabled so we have to have merge request on top
|
||||
- MERGE_REQUEST_ID="$(git log -1 --format='%b' | sed --silent -e 's/^See merge request [^!]\+!//p')"
|
||||
- git clone --depth 1 https://gitlab.isc.org/isc-projects/bind9-qa.git
|
||||
- bind9-qa/releng/backport_mr.py $CI_PROJECT_ID "$MERGE_REQUEST_ID"
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
## Release Schedule
|
||||
|
||||
**Code Freeze:**
|
||||
|
||||
**Tagging Deadline:**
|
||||
|
||||
**Public Release:**
|
||||
|
||||
## Documentation Review Links
|
||||
|
||||
**Closed issues assigned to the milestone without a release note:**
|
||||
|
||||
- []()
|
||||
- []()
|
||||
- []()
|
||||
|
||||
**Merge requests merged into the milestone without a release note:**
|
||||
|
||||
- []()
|
||||
- []()
|
||||
- []()
|
||||
|
||||
**Merge requests merged into the milestone without a `CHANGES` entry:**
|
||||
|
||||
- []()
|
||||
- []()
|
||||
- []()
|
||||
|
||||
## Release Checklist
|
||||
|
||||
### Before the Code Freeze
|
||||
|
||||
- [ ] ***(QA)*** Rebase -S editions on top of current open-source versions: `git checkout bind-9.18-sub && git rebase origin/bind-9.18`
|
||||
- [ ] ***(QA)*** [Inform](https://gitlab.isc.org/isc-private/bind-qa/-/blob/master/bind9/releng/inform_supp_marketing.py) Support and Marketing of impending release (and give estimated release dates).
|
||||
- [ ] ***(QA)*** Ensure there are no permanent test failures on any platform. Check [public](https://gitlab.isc.org/isc-projects/bind9/-/pipelines?scope=all&source=schedule) and [private](https://gitlab.isc.org/isc-private/bind9/-/pipelines?scope=all&source=schedule) scheduled pipelines.
|
||||
- [ ] ***(QA)*** Check charts from `shotgun:*` jobs in the scheduled pipelines to verify there is no unexplained performance drop for any protocol.
|
||||
- [ ] ***(QA)*** Check [Perflab](https://perflab.isc.org/) to ensure there has been no unexplained drop in performance for the versions being released.
|
||||
- [ ] ***(QA)*** Check whether all issues assigned to the release milestone are resolved[^1].
|
||||
- [ ] ***(QA)*** Ensure that there are no outstanding [merge requests in the private repository](https://gitlab.isc.org/isc-private/bind9/-/merge_requests/)[^1] (Subscription Edition only).
|
||||
- [ ] ***(QA)*** [Ensure](https://gitlab.isc.org/isc-private/bind-qa/-/blob/master/bind9/releng/check_backports.py) all merge requests marked for backporting have been indeed backported.
|
||||
- [ ] ***(QA)*** [Announce](https://gitlab.isc.org/isc-private/bind-qa/-/blob/master/bind9/releng/inform_code_freeze.py) (on Mattermost) that the code freeze is in effect.
|
||||
|
||||
### Before the Tagging Deadline
|
||||
|
||||
- [ ] ***(QA)*** Inspect the current output of the `cross-version-config-tests` job to verify that no unexpected backward-incompatible change was introduced in the current release cycle.
|
||||
- [ ] ***(QA)*** Ensure release notes are correct, ask Support and Marketing to check them as well. [Example](https://gitlab.isc.org/isc-private/bind9/-/merge_requests/510)
|
||||
- [ ] ***(QA)*** Add a release marker to `CHANGES`. Examples: [9.18](https://gitlab.isc.org/isc-projects/bind9/-/commit/f14d8ad78c0506fd4247187f2177f8eceeb6b3b9), [9.16](https://gitlab.isc.org/isc-projects/bind9/-/commit/1bcdf21874f99a00da389d723e0ad07dfd70f9f1)
|
||||
- [ ] ***(QA)*** Add a release marker to `CHANGES.SE` (Subscription Edition only). [Example](https://gitlab.isc.org/isc-private/bind9/-/commit/0f03d5737bcbdaa1bf713c6db1887b14938c3421)
|
||||
- [ ] ***(QA)*** Update BIND 9 version in `configure.ac` ([9.18+](https://gitlab.isc.org/isc-projects/bind9/-/commit/3c85ab7f4c35e6d8acef1393606002a0a8730100)) or `version` ([9.16](https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/7692/diffs?commit_id=1bcdf21874f99a00da389d723e0ad07dfd70f9f1)).
|
||||
- [ ] ***(QA)*** Rebuild `configure` using Autoconf on `docs.isc.org` (9.16).
|
||||
- [ ] ***(QA)*** Update GitLab settings for all maintained branches to disallow merging to them: [public](https://gitlab.isc.org/isc-projects/bind9/-/settings/repository), [private](https://gitlab.isc.org/isc-private/bind9/-/settings/repository)
|
||||
- [ ] ***(QA)*** Tag the releases in the private repository (`git tag -s -m "BIND 9.x.y" v9.x.y`).
|
||||
|
||||
### Before the ASN Deadline (for ASN Releases) or the Public Release Date (for Regular Releases)
|
||||
|
||||
- [ ] ***(QA)*** Check that the formatting is correct for the HTML version of release notes.
|
||||
- [ ] ***(QA)*** Check that the formatting of the generated man pages is correct.
|
||||
- [ ] ***(QA)*** Verify GitLab CI results [for the tags](https://gitlab.isc.org/isc-private/bind9/-/pipelines?scope=tags) created and sign off on the releases to be published.
|
||||
- [ ] ***(QA)*** Update GitLab settings for all maintained branches to allow merging to them again: [public](https://gitlab.isc.org/isc-projects/bind9/-/settings/repository), [private](https://gitlab.isc.org/isc-private/bind9/-/settings/repository)
|
||||
- [ ] ***(QA)*** Prepare (using [`version_bump.py`](https://gitlab.isc.org/isc-private/bind-qa/-/blob/master/bind9/releng/version_bump.py)) and merge MRs resetting the release notes and updating the version string for each maintained branch.
|
||||
- [ ] ***(QA)*** Rebase the Subscription Edition branches (including recent release prep commits) on top of the open source branches with updated version strings.
|
||||
- [ ] ***(QA)*** Announce (on Mattermost) that the code freeze is over.
|
||||
- [ ] ***(QA)*** Request signatures for the tarballs, providing their location and checksums. Ask [signers on Mattermost](https://mattermost.isc.org/isc/channels/bind-9-qa).
|
||||
- [ ] ***(Signers)*** Ensure that the contents of tarballs and tags are identical.
|
||||
- [ ] ***(Signers)*** Validate tarball checksums, sign tarballs, and upload signatures.
|
||||
- [ ] ***(QA)*** Verify tarball signatures and check tarball checksums again: Run `publish_bind.sh` on repo.isc.org to pre-publish.
|
||||
- [ ] ***(QA)*** Prepare the `patches/` subdirectory for each security release (if applicable).
|
||||
- [ ] ***(QA)*** Pre-publish ASN and/or Subscription Edition tarballs so that packages can be built.
|
||||
- [ ] ***(QA)*** Build and test ASN and/or Subscription Edition packages (in [cloudsmith branch in private repo](https://gitlab.isc.org/isc-private/rpms/bind/-/tree/cloudsmith)). [Example](https://gitlab.isc.org/isc-private/rpms/bind/-/commit/e2512f4cfaf991827a635e374e7e93b27a5f38ba)
|
||||
- [ ] ***(Marketing)*** Prepare and send out ASN emails (as outlined in the CVE checklist; if applicable).
|
||||
|
||||
### On the Day of Public Release
|
||||
|
||||
- [ ] ***(QA)*** Wait for clearance from Security Officer to proceed with the public release (if applicable).
|
||||
- [ ] ***(QA)*** Place tarballs in public location on FTP site.
|
||||
- [ ] ***(QA)*** Inform Marketing of the release, providing FTP links for the published tarballs.
|
||||
- [ ] ***(QA)*** Use the [Printing Press project](https://gitlab.isc.org/isc-private/printing-press/-/wikis/home#adding-new-documents) to prepare a release announcement email.
|
||||
- [ ] ***(Marketing)*** Publish links to downloads on ISC website. [Example](https://gitlab.isc.org/website/theme-staging-site/-/commit/1ac7b30b73cb03228df4cd5651fa4e774ac35625)
|
||||
- [ ] ***(Marketing)*** Update the BIND -S information document in SF with download links to the new versions. (If this is a security release, this will have already been done as part of the ASN process.)
|
||||
- [ ] ***(Marketing)*** Update the Current Software Versions document in the SF portal if any stable versions were released.
|
||||
- [ ] ***(Marketing)*** Send the release announcement email to the *bind-announce* mailing list (and to *bind-users* if a major release - [example](https://lists.isc.org/pipermail/bind-users/2022-January/105624.html)).
|
||||
- [ ] ***(Marketing)*** Announce release on social media sites.
|
||||
- [ ] ***(Marketing)*** Update [Wikipedia entry for BIND](https://en.wikipedia.org/wiki/BIND).
|
||||
- [ ] ***(Support)*** Add the new releases to the [vulnerability matrix in the Knowledge Base](https://kb.isc.org/docs/aa-00913).
|
||||
- [ ] ***(Support)*** Update tickets in case of waiting support customers.
|
||||
- [ ] ***(QA)*** Build and test any outstanding private packages in [private repo](https://gitlab.isc.org/isc-private/rpms/bind/-/tree/cloudsmith). [Example](https://gitlab.isc.org/isc-private/rpms/bind/-/commit/2007d566db81dd9dfd79e571e2f600a3bc284da4)
|
||||
- [ ] ***(QA)*** Build [public RPMs](https://gitlab.isc.org/isc-packages/rpms/bind). [Example commit](https://gitlab.isc.org/isc-packages/rpms/bind/-/commit/3b5e851ea7c4e3570371a4878b5461f02a44f8cc) which triggers [Copr builds](https://copr.fedorainfracloud.org/coprs/isc/) automatically
|
||||
- [ ] ***(SwEng)*** Build Debian/Ubuntu packages.
|
||||
- [ ] ***(SwEng)*** Update Docker files [here](https://gitlab.isc.org/isc-projects/bind9-docker/-/branches) and make sure push is synchronized to [GitHub](https://github.com/isc-projects/bind9-docker). [Docker Hub](https://hub.docker.com/r/internetsystemsconsortium/bind9) should pick it up automatically. [Example](https://gitlab.isc.org/isc-projects/bind9-docker/-/commit/cada7e10e9af951595c98bfffc4bd42512faac05)
|
||||
- [ ] ***(QA)*** Ensure all new tags are annotated and signed. `git show --show-signature v9.19.12`
|
||||
- [ ] ***(QA)*** Push tags for the published releases to the public repository.
|
||||
- [ ] ***(QA)*** Using [`merge_tag.py`](https://gitlab.isc.org/isc-private/bind-qa/-/blob/master/bind9/releng/merge_tag.py), merge published release tags back into the their relevant development/maintenance branches.
|
||||
- [ ] ***(QA)*** Ensure `allow_failure: true` is removed from the `cross-version-config-tests` job if it was set during the current release cycle.
|
||||
- [ ] ***(QA)*** Sanitize confidential issues which are assigned to the current release milestone and do not describe a security vulnerability, then make them public.
|
||||
- [ ] ***(QA)*** Sanitize [confidential issues](https://gitlab.isc.org/isc-projects/bind9/-/issues/?sort=milestone_due_desc&state=opened&confidential=yes) which are assigned to older release milestones and describe security vulnerabilities, then make them public if appropriate[^2].
|
||||
- [ ] ***(QA)*** Update QA tools used in GitLab CI (e.g. Black, PyLint, Sphinx) by modifying the relevant [`Dockerfile`](https://gitlab.isc.org/isc-projects/images/-/merge_requests/228/diffs).
|
||||
- [ ] ***(QA)*** Run a pipeline to rebuild all [images](https://gitlab.isc.org/isc-projects/images) used in GitLab CI.
|
||||
- [ ] ***(QA)*** Update [`metadata.json`](https://gitlab.isc.org/isc-private/bind-qa/-/blob/master/bind9/releng/metadata.json) with the upcoming release information.
|
||||
|
||||
[^1]: If not, use the time remaining until the tagging deadline to ensure all outstanding issues are either resolved or moved to a different milestone.
|
||||
[^2]: As a rule of thumb, security vulnerabilities which have reproducers merged to the public repository are considered okay for full disclosure.
|
||||
@@ -1,3 +1,75 @@
|
||||
6380. [func] Queries and responses now emit distinct dnstap entries
|
||||
for DoT and DoH. [GL #4523]
|
||||
|
||||
6379. [bug] A QP iterator bug could result in DNSSEC validation
|
||||
failing because the wrong NSEC was returned. [GL #4659]
|
||||
|
||||
6378. [func] The option to specify the number of UDP dispatches was
|
||||
previously removed. An attempt to use the option now
|
||||
prints a warning. [GL #1879]
|
||||
|
||||
6377. [func] Introduce 'dnssec-ksr', a DNSSEC tool to create
|
||||
Key Signing Requests (KSRs) and Signed Key Responses
|
||||
(SKRs). [GL #1128]
|
||||
|
||||
6376. [func] Allow 'dnssec-keygen' options '-f' and '-k' to be used
|
||||
together to create a subset of keys from the DNSSEC
|
||||
policy. [GL !8188]
|
||||
|
||||
6375. [func] Allow multiple RNDC message to be processed from
|
||||
a single TCP read. [GL #4416]
|
||||
|
||||
6374. [func] Don't count expired / future RRSIGs in verification
|
||||
failure quota. [GL #4586]
|
||||
|
||||
6373. [func] Offload the isc_http response processing to worker
|
||||
thread. [GL #4680]
|
||||
|
||||
6372. [func] Implement signature jitter for dnssec-policy. [GL #4554]
|
||||
|
||||
6371. [bug] Access to the trust bytes in the ncache data needed to
|
||||
be made thread safe. [GL #4475]
|
||||
|
||||
6370. [bug] Wrong source address used for IPv6 notify messages.
|
||||
[GL #4669]
|
||||
|
||||
--- 9.19.23 released ---
|
||||
|
||||
6369. [func] The 'fixed' value for the 'rrset-order' option has
|
||||
been marked and documented as deprecated. [GL #4446]
|
||||
|
||||
6368. [func] The 'sortlist' option has been marked and documented
|
||||
as deprecated. [GL #4593]
|
||||
|
||||
6367. [bug] Since the dns_validator_destroy() function doesn't
|
||||
guarantee that it destroys the validator, rename it to
|
||||
dns_validator_shutdown() and require explicit
|
||||
dns_validator_detach() to follow. Implement an expected
|
||||
behavior of the function to release a name associated
|
||||
with the validator. [GL #4654]
|
||||
|
||||
6366. [bug] An assertion could be triggered in the QPDB cache when
|
||||
encountering a delegation below a DNAME. [GL #4652]
|
||||
|
||||
6365. [placeholder]
|
||||
|
||||
6364. [protocol] Add RESOLVER.ARPA to the built in empty zones.
|
||||
[GL #4580]
|
||||
|
||||
6363. [bug] dig/mdig +ednsflags=<non-zero-value> did not re-enable
|
||||
EDNS if it had been disabled. [GL #4641]
|
||||
|
||||
6362. [bug] Reduce memory consumption of QP-trie based databases
|
||||
by dynamically allocating the nodenames. [GL #4614]
|
||||
|
||||
6361. [bug] Some invalid ISO 8601 durations were accepted
|
||||
erroneously. [GL #4624]
|
||||
|
||||
6360. [bug] Don't return static-stub synthesised NS RRset.
|
||||
[GL #4608]
|
||||
|
||||
6359. [bug] Fix bug in Depends (keymgr_dep) function. [GL #4552]
|
||||
|
||||
--- 9.19.22 released ---
|
||||
|
||||
6358. [bug] Fix validate_dnskey_dsset when KSK is not signing,
|
||||
|
||||
+5
-6
@@ -2103,9 +2103,8 @@ sendquery(void *arg) {
|
||||
|
||||
dns_view_attach(view, &(dns_view_t *){ NULL });
|
||||
CHECK(dns_request_create(requestmgr, message, NULL, &peer, NULL, NULL,
|
||||
DNS_REQUESTOPT_TCP, NULL, 1, 0, 0,
|
||||
isc_loop_current(loopmgr), recvresponse,
|
||||
message, &request));
|
||||
DNS_REQUESTOPT_TCP, NULL, 1, 0, 0, isc_loop(),
|
||||
recvresponse, message, &request));
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
@@ -2167,8 +2166,8 @@ run_server(void *arg) {
|
||||
dns_view_initsecroots(view);
|
||||
CHECK(setup_dnsseckeys(NULL, view));
|
||||
|
||||
CHECK(dns_view_createresolver(view, loopmgr, netmgr, 0,
|
||||
tlsctx_client_cache, dispatch, NULL));
|
||||
CHECK(dns_view_createresolver(view, netmgr, 0, tlsctx_client_cache,
|
||||
dispatch, NULL));
|
||||
|
||||
isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
|
||||
dns_resolver_setstats(view->resolver, resstats);
|
||||
@@ -2187,7 +2186,7 @@ run_server(void *arg) {
|
||||
NULL, NULL, ISC_NM_PROXY_NONE,
|
||||
&ifp->tcplistensocket));
|
||||
ifp->flags |= NS_INTERFACEFLAG_LISTENING;
|
||||
isc_async_current(loopmgr, sendquery, ifp->tcplistensocket);
|
||||
isc_async_current(sendquery, ifp->tcplistensocket);
|
||||
|
||||
return;
|
||||
|
||||
|
||||
@@ -1797,6 +1797,10 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
|
||||
"ednsflags");
|
||||
goto exit_or_usage;
|
||||
}
|
||||
if (lookup->edns == -1) {
|
||||
lookup->edns =
|
||||
DEFAULT_EDNS_VERSION;
|
||||
}
|
||||
lookup->ednsflags = num;
|
||||
break;
|
||||
case 'n':
|
||||
|
||||
@@ -2,6 +2,7 @@ dnssec-cds
|
||||
dnssec-dsfromkey
|
||||
dnssec-keyfromlabel
|
||||
dnssec-keygen
|
||||
dnssec-ksr
|
||||
dnssec-makekeyset
|
||||
dnssec-revoke
|
||||
dnssec-settime
|
||||
|
||||
@@ -2,6 +2,7 @@ include $(top_srcdir)/Makefile.top
|
||||
|
||||
AM_CPPFLAGS += \
|
||||
$(LIBISC_CFLAGS) \
|
||||
$(LIBISCCFG_CFLAGS) \
|
||||
$(LIBDNS_CFLAGS)
|
||||
|
||||
AM_CPPFLAGS += \
|
||||
@@ -12,6 +13,7 @@ noinst_LTLIBRARIES = libdnssectool.la
|
||||
LDADD += \
|
||||
libdnssectool.la \
|
||||
$(LIBISC_LIBS) \
|
||||
$(LIBISCCFG_LIBS) \
|
||||
$(LIBDNS_LIBS) \
|
||||
$(OPENSSL_LIBS)
|
||||
|
||||
@@ -21,6 +23,7 @@ bin_PROGRAMS = \
|
||||
dnssec-importkey \
|
||||
dnssec-keyfromlabel \
|
||||
dnssec-keygen \
|
||||
dnssec-ksr \
|
||||
dnssec-revoke \
|
||||
dnssec-settime \
|
||||
dnssec-signzone \
|
||||
@@ -32,20 +35,16 @@ libdnssectool_la_SOURCES = \
|
||||
|
||||
dnssec_keygen_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(LIBISCCFG_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
||||
dnssec_keygen_LDADD = \
|
||||
$(LDADD) \
|
||||
$(LIBISCCFG_LIBS) \
|
||||
$(OPENSSL_LIBS)
|
||||
|
||||
dnssec_signzone_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(LIBISCCFG_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
||||
dnssec_signzone_LDADD = \
|
||||
$(LDADD) \
|
||||
$(LIBISCCFG_LIBS) \
|
||||
$(OPENSSL_LIBS)
|
||||
|
||||
@@ -54,6 +54,7 @@ static dns_name_t *name = NULL;
|
||||
static isc_mem_t *mctx = NULL;
|
||||
static uint32_t ttl;
|
||||
static bool emitttl = false;
|
||||
static unsigned int split_width = 0;
|
||||
|
||||
static isc_result_t
|
||||
initname(char *setname) {
|
||||
@@ -279,8 +280,8 @@ emit(dns_dsdigest_t dt, bool showall, bool cds, dns_rdata_t *rdata) {
|
||||
fatal("can't print name");
|
||||
}
|
||||
|
||||
result = dns_rdata_tofmttext(&ds, (dns_name_t *)NULL, 0, 0, 0, "",
|
||||
&textb);
|
||||
result = dns_rdata_tofmttext(&ds, (dns_name_t *)NULL, 0, 0, split_width,
|
||||
"", &textb);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("can't print rdata");
|
||||
@@ -347,6 +348,7 @@ usage(void) {
|
||||
" -f zonefile: read keys from a zone file\n"
|
||||
" -h: print help information\n"
|
||||
" -K directory: where to find key or keyset files\n"
|
||||
" -w split base64 rdata text into chunks\n"
|
||||
" -s: read keys from keyset-<dnsname> file\n"
|
||||
" -T: TTL of output records (omitted by default)\n"
|
||||
" -v level: verbosity\n"
|
||||
@@ -380,7 +382,7 @@ main(int argc, char **argv) {
|
||||
|
||||
isc_commandline_errprint = false;
|
||||
|
||||
#define OPTIONS "12Aa:Cc:d:Ff:K:l:sT:v:hV"
|
||||
#define OPTIONS "12Aa:Cc:d:Ff:K:l:sT:v:whV"
|
||||
while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) {
|
||||
switch (ch) {
|
||||
case '1':
|
||||
@@ -432,6 +434,9 @@ main(int argc, char **argv) {
|
||||
fatal("-v must be followed by a number");
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
split_width = UINT_MAX;
|
||||
break;
|
||||
case 'F':
|
||||
/* Reserved for FIPS mode */
|
||||
FALLTHROUGH;
|
||||
|
||||
+28
-112
@@ -56,10 +56,6 @@
|
||||
|
||||
#include <dst/dst.h>
|
||||
|
||||
#include <isccfg/cfg.h>
|
||||
#include <isccfg/grammar.h>
|
||||
#include <isccfg/kaspconf.h>
|
||||
#include <isccfg/namedconf.h>
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/provider.h>
|
||||
@@ -67,9 +63,6 @@
|
||||
|
||||
#include "dnssectool.h"
|
||||
|
||||
#define MAX_RSA 4096 /* should be long enough... */
|
||||
#define MAX_DH 4096 /* should be long enough... */
|
||||
|
||||
const char *program = "dnssec-keygen";
|
||||
|
||||
/*
|
||||
@@ -103,8 +96,9 @@ struct keygen_ctx {
|
||||
int options;
|
||||
int dbits;
|
||||
dns_ttl_t ttl;
|
||||
uint16_t kskflag;
|
||||
uint16_t revflag;
|
||||
bool wantzsk;
|
||||
bool wantksk;
|
||||
bool wantrev;
|
||||
dns_secalg_t alg;
|
||||
/* timing data */
|
||||
int prepub;
|
||||
@@ -184,7 +178,7 @@ usage(void) {
|
||||
fprintf(stderr, " -d <digest bits> (0 => max, default)\n");
|
||||
fprintf(stderr, " -E <engine>:\n");
|
||||
fprintf(stderr, " name of an OpenSSL engine to use\n");
|
||||
fprintf(stderr, " -f <keyflag>: KSK | REVOKE\n");
|
||||
fprintf(stderr, " -f <keyflag>: ZSK | KSK | REVOKE\n");
|
||||
fprintf(stderr, " -F: FIPS mode\n");
|
||||
fprintf(stderr, " -L <ttl>: default key TTL\n");
|
||||
fprintf(stderr, " -p <protocol>: (default: 3 [dnssec])\n");
|
||||
@@ -254,90 +248,6 @@ progress(int p) {
|
||||
(void)fflush(stderr);
|
||||
}
|
||||
|
||||
static void
|
||||
kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name,
|
||||
const char *keydir, const char *engine, dns_kasp_t **kaspp) {
|
||||
isc_result_t result = ISC_R_NOTFOUND;
|
||||
const cfg_listelt_t *element;
|
||||
const cfg_obj_t *kasps = NULL;
|
||||
dns_kasp_t *kasp = NULL, *kasp_next;
|
||||
dns_kasplist_t kasplist;
|
||||
const cfg_obj_t *keystores = NULL;
|
||||
dns_keystore_t *ks = NULL, *ks_next;
|
||||
dns_keystorelist_t kslist;
|
||||
|
||||
ISC_LIST_INIT(kasplist);
|
||||
ISC_LIST_INIT(kslist);
|
||||
|
||||
(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) {
|
||||
fatal("failed to configure key-store '%s': %s",
|
||||
cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
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 */
|
||||
dns_keystore_setdirectory(ks, keydir);
|
||||
}
|
||||
dns_keystore_detach(&ks);
|
||||
|
||||
(void)cfg_map_get(config, "dnssec-policy", &kasps);
|
||||
for (element = cfg_list_first(kasps); element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
kasp = NULL;
|
||||
if (strcmp(cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
name) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = cfg_kasp_fromconfig(kconfig, NULL, true, mctx, lctx,
|
||||
&kslist, &kasplist, &kasp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("failed to configure dnssec-policy '%s': %s",
|
||||
cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
isc_result_totext(result));
|
||||
}
|
||||
INSIST(kasp != NULL);
|
||||
dns_kasp_freeze(kasp);
|
||||
break;
|
||||
}
|
||||
|
||||
*kaspp = kasp;
|
||||
|
||||
/*
|
||||
* Cleanup kasp list.
|
||||
*/
|
||||
for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
|
||||
kasp_next = ISC_LIST_NEXT(kasp, link);
|
||||
ISC_LIST_UNLINK(kasplist, kasp, link);
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup keystore list.
|
||||
*/
|
||||
for (ks = ISC_LIST_HEAD(kslist); ks != NULL; ks = ks_next) {
|
||||
ks_next = ISC_LIST_NEXT(ks, link);
|
||||
ISC_LIST_UNLINK(kslist, ks, link);
|
||||
dns_keystore_detach(&ks);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
|
||||
char filename[255];
|
||||
@@ -645,8 +555,12 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
|
||||
if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */
|
||||
flags |= ctx->signatory;
|
||||
} else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */
|
||||
flags |= ctx->kskflag;
|
||||
flags |= ctx->revflag;
|
||||
if (ctx->ksk || ctx->wantksk) {
|
||||
flags |= DNS_KEYFLAG_KSK;
|
||||
}
|
||||
if (ctx->wantrev) {
|
||||
flags |= DNS_KEYFLAG_REVOKE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->protocol == -1) {
|
||||
@@ -769,7 +683,7 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
|
||||
}
|
||||
|
||||
if (ctx->setrev) {
|
||||
if (ctx->kskflag == 0) {
|
||||
if (!ctx->wantksk) {
|
||||
fprintf(stderr,
|
||||
"%s: warning: Key is "
|
||||
"not flagged as a KSK, but -R "
|
||||
@@ -1013,9 +927,11 @@ main(int argc, char **argv) {
|
||||
case 'f':
|
||||
c = (unsigned char)(isc_commandline_argument[0]);
|
||||
if (toupper(c) == 'K') {
|
||||
ctx.kskflag = DNS_KEYFLAG_KSK;
|
||||
ctx.wantksk = true;
|
||||
} else if (toupper(c) == 'Z') {
|
||||
ctx.wantzsk = true;
|
||||
} else if (toupper(c) == 'R') {
|
||||
ctx.revflag = DNS_KEYFLAG_REVOKE;
|
||||
ctx.wantrev = true;
|
||||
} else {
|
||||
fatal("unknown flag '%s'",
|
||||
isc_commandline_argument);
|
||||
@@ -1289,8 +1205,8 @@ main(int argc, char **argv) {
|
||||
if (ctx.size != -1) {
|
||||
fatal("-k and -b cannot be used together");
|
||||
}
|
||||
if (ctx.kskflag || ctx.revflag) {
|
||||
fatal("-k and -f cannot be used together");
|
||||
if (ctx.wantrev) {
|
||||
fatal("-k and -fR cannot be used together");
|
||||
}
|
||||
if (ctx.options & DST_TYPE_KEY) {
|
||||
fatal("-k and -T KEY cannot be used together");
|
||||
@@ -1305,7 +1221,6 @@ main(int argc, char **argv) {
|
||||
ctx.use_nsec3 = false;
|
||||
ctx.alg = DST_ALG_ECDSA256;
|
||||
ctx.size = 0;
|
||||
ctx.kskflag = DNS_KEYFLAG_KSK;
|
||||
ctx.ttl = 3600;
|
||||
ctx.setttl = true;
|
||||
ctx.ksk = true;
|
||||
@@ -1330,8 +1245,8 @@ main(int argc, char **argv) {
|
||||
ctx.policy, ctx.configfile);
|
||||
}
|
||||
|
||||
kasp_from_conf(config, mctx, ctx.policy, ctx.directory,
|
||||
engine, &kasp);
|
||||
kasp_from_conf(config, mctx, lctx, ctx.policy,
|
||||
ctx.directory, engine, &kasp);
|
||||
if (kasp == NULL) {
|
||||
fatal("failed to load dnssec-policy '%s'",
|
||||
ctx.policy);
|
||||
@@ -1345,15 +1260,13 @@ main(int argc, char **argv) {
|
||||
ctx.ttl = dns_kasp_dnskeyttl(kasp);
|
||||
ctx.setttl = true;
|
||||
|
||||
kaspkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
|
||||
while (kaspkey != NULL) {
|
||||
for (kaspkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
kaspkey != NULL;
|
||||
kaspkey = ISC_LIST_NEXT(kaspkey, link))
|
||||
{
|
||||
ctx.use_nsec3 = false;
|
||||
ctx.alg = dns_kasp_key_algorithm(kaspkey);
|
||||
ctx.size = dns_kasp_key_size(kaspkey);
|
||||
ctx.kskflag = dns_kasp_key_ksk(kaspkey)
|
||||
? DNS_KEYFLAG_KSK
|
||||
: 0;
|
||||
ctx.ksk = dns_kasp_key_ksk(kaspkey);
|
||||
ctx.zsk = dns_kasp_key_zsk(kaspkey);
|
||||
ctx.lifetime = dns_kasp_key_lifetime(kaspkey);
|
||||
@@ -1361,9 +1274,12 @@ main(int argc, char **argv) {
|
||||
if (ctx.keystore != NULL) {
|
||||
check_keystore_options(&ctx);
|
||||
}
|
||||
if ((ctx.ksk && !ctx.wantksk && ctx.wantzsk) ||
|
||||
(ctx.zsk && !ctx.wantzsk && ctx.wantksk))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
keygen(&ctx, mctx, argc, argv);
|
||||
|
||||
kaspkey = ISC_LIST_NEXT(kaspkey, link);
|
||||
}
|
||||
|
||||
dns_kasp_detach(&kasp);
|
||||
|
||||
@@ -105,7 +105,13 @@ Options
|
||||
.. option:: -f flag
|
||||
|
||||
This option sets the specified flag in the flag field of the KEY/DNSKEY record.
|
||||
The only recognized flags are KSK (Key-Signing Key) and REVOKE.
|
||||
The only recognized flags are ZSK (Zone-Signing Key), KSK (Key-Signing Key)
|
||||
and REVOKE.
|
||||
|
||||
Note that ZSK is not a physical flag in the DNSKEY record, it is merely used
|
||||
to explicitly tell that you want to create a ZSK. Setting :option:`-f` in
|
||||
conjunction with :option:`-k` will result in generating keys that only
|
||||
match the given role set with this option.
|
||||
|
||||
.. option:: -F
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,159 @@
|
||||
.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
..
|
||||
.. SPDX-License-Identifier: MPL-2.0
|
||||
..
|
||||
.. This Source Code Form is subject to the terms of the Mozilla Public
|
||||
.. License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
..
|
||||
.. See the COPYRIGHT file distributed with this work for additional
|
||||
.. information regarding copyright ownership.
|
||||
|
||||
.. highlight: console
|
||||
|
||||
.. iscman:: dnssec-ksr
|
||||
.. program:: dnssec-ksr
|
||||
.. _man_dnssec-ksr:
|
||||
|
||||
dnssec-ksr - Create signed key response (SKR) files for offline KSK setups
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Synopsis
|
||||
~~~~~~~~
|
||||
|
||||
:program:`dnssec-ksr` [**-E** engine] [**-e** date/offset] [**-F**] [**-h**] [**-i** date/offset] [**-K** directory] [**-k** policy] [**-l** file] [**-V**] [**-v** level] {command} {zone}
|
||||
|
||||
Description
|
||||
~~~~~~~~~~~
|
||||
|
||||
The :program:`dnssec-ksr` can be used to issue several commands that are needed
|
||||
to generate presigned RRsets for a zone where the private key file of the Key
|
||||
Signing Key (KSK) is typically offline. This requires Zone Signing Keys
|
||||
(ZSKs) to be pregenerated, and the DNSKEY, CDNSKEY, and CDS RRsets to be
|
||||
already signed in advance.
|
||||
|
||||
The latter is done by creating Key Signing Requests (KSRs) that can be imported
|
||||
to the environment where the KSK is available. Once there, this program can
|
||||
create Signed Key Responses (SKRs) that can be loaded by an authoritative DNS
|
||||
server.
|
||||
|
||||
Options
|
||||
~~~~~~~
|
||||
|
||||
.. option:: -E engine
|
||||
|
||||
This option specifies the cryptographic hardware to use, when applicable.
|
||||
|
||||
When BIND 9 is built with OpenSSL, this needs to be set to the OpenSSL
|
||||
engine identifier that drives the cryptographic accelerator or
|
||||
hardware service module (usually ``pkcs11``).
|
||||
|
||||
.. option:: -e date/offset
|
||||
|
||||
This option sets the end date for which keys or SKRs need to be generated
|
||||
(depending on the command).
|
||||
|
||||
.. option:: -F
|
||||
|
||||
This options turns on FIPS (US Federal Information Processing Standards)
|
||||
mode if the underlying crytographic library supports running in FIPS
|
||||
mode.
|
||||
|
||||
.. option:: -h
|
||||
|
||||
This option prints a short summary of the options and arguments to
|
||||
:program:`dnssec-ksr`.
|
||||
|
||||
.. option:: -i date/offset
|
||||
|
||||
This option sets the start date for which keys or SKRs need to be generated
|
||||
(depending on the command).
|
||||
|
||||
.. option:: -K directory
|
||||
|
||||
This option sets the directory in which the key files are to be read or
|
||||
written (depending on the command).
|
||||
|
||||
.. option:: -k policy
|
||||
|
||||
This option sets the specific ``dnssec-policy`` for which keys need to
|
||||
be generated, or signed.
|
||||
|
||||
.. option:: -l file
|
||||
|
||||
This option provides a configuration file that contains a ``dnssec-policy``
|
||||
statement (matching the policy set with :option:`-k`).
|
||||
|
||||
.. option:: -V
|
||||
|
||||
This option prints version information.
|
||||
|
||||
.. option:: -v level
|
||||
|
||||
This option sets the debugging level. Level 1 is intended to be usefully
|
||||
verbose for general users; higher levels are intended for developers.
|
||||
|
||||
``command``
|
||||
|
||||
The KSR command to be executed. See below for the available commands.
|
||||
|
||||
``zone``
|
||||
|
||||
The name of the zone for which the KSR command is being executed.
|
||||
|
||||
Commands
|
||||
~~~~~~~~
|
||||
|
||||
.. option:: keygen
|
||||
|
||||
Pregenerate a number of zone signing keys (ZSKs), given a DNSSEC policy and
|
||||
an interval. The number of generated keys depends on the interval and the
|
||||
ZSK lifetime.
|
||||
|
||||
.. option:: request
|
||||
|
||||
Create a Key Signing Request (KSR), given a DNSSEC policy and an interval.
|
||||
|
||||
.. option:: sign
|
||||
|
||||
Sign a Key Signing Request (KSR), given a DNSSEC policy and an interval,
|
||||
creating a Signed Key Response (SKR).
|
||||
|
||||
Exit Status
|
||||
~~~~~~~~~~~
|
||||
|
||||
The :program:`dnssec-ksr` command exits 0 on success, or non-zero if an error
|
||||
occurred.
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
When you need to generate keys for the zone "example.com" for the next year,
|
||||
given a ``dnssec-policy`` named "mypolicy":
|
||||
|
||||
::
|
||||
|
||||
dnssec-ksr -i now -e +1y -k mypolicy -l named.conf keygen example.com
|
||||
|
||||
Creating a KSR for the same zone and period can be done with:
|
||||
|
||||
::
|
||||
|
||||
dnssec-ksr -i now -e +1y -k mypolicy -l named.conf request example.com > ksr.txt
|
||||
|
||||
Typically you would now transfer the KSR to the system that has access to the KSK.
|
||||
|
||||
Signing the KSR created above can be done with:
|
||||
|
||||
::
|
||||
|
||||
dnssec-ksr -i now -e +1y -k kskpolicy -l named.conf -f ksr.txt sign example.com
|
||||
|
||||
Make sure that the DNSSEC parameters in ``kskpolicy`` match those in ``mypolicy``.
|
||||
|
||||
See Also
|
||||
~~~~~~~~
|
||||
|
||||
:iscman:`dnssec-keygen(8) <dnssec-keygen>`,
|
||||
:iscman:`dnssec-signzone(8) <dnssec-signzone>`,
|
||||
BIND 9 Administrator Reference Manual.
|
||||
@@ -1674,7 +1674,7 @@ assignwork(void *arg) {
|
||||
lock_and_dumpnode(dns_fixedname_name(&fname), node);
|
||||
dns_db_detachnode(gdb, &node);
|
||||
|
||||
isc_async_current(loopmgr, assignwork, NULL);
|
||||
isc_async_current(assignwork, NULL);
|
||||
}
|
||||
|
||||
/*%
|
||||
|
||||
@@ -602,3 +602,88 @@ loadjournal(isc_mem_t *mctx, dns_db_t *db, const char *file) {
|
||||
cleanup:
|
||||
dns_journal_destroy(&jnl);
|
||||
}
|
||||
|
||||
void
|
||||
kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, isc_log_t *lctx,
|
||||
const char *name, const char *keydir, const char *engine,
|
||||
dns_kasp_t **kaspp) {
|
||||
isc_result_t result = ISC_R_NOTFOUND;
|
||||
const cfg_listelt_t *element;
|
||||
const cfg_obj_t *kasps = NULL;
|
||||
dns_kasp_t *kasp = NULL, *kasp_next;
|
||||
dns_kasplist_t kasplist;
|
||||
const cfg_obj_t *keystores = NULL;
|
||||
dns_keystore_t *ks = NULL, *ks_next;
|
||||
dns_keystorelist_t kslist;
|
||||
|
||||
ISC_LIST_INIT(kasplist);
|
||||
ISC_LIST_INIT(kslist);
|
||||
|
||||
(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) {
|
||||
fatal("failed to configure key-store '%s': %s",
|
||||
cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
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 */
|
||||
dns_keystore_setdirectory(ks, keydir);
|
||||
}
|
||||
dns_keystore_detach(&ks);
|
||||
|
||||
(void)cfg_map_get(config, "dnssec-policy", &kasps);
|
||||
for (element = cfg_list_first(kasps); element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
kasp = NULL;
|
||||
if (strcmp(cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
name) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = cfg_kasp_fromconfig(kconfig, NULL, true, mctx, lctx,
|
||||
&kslist, &kasplist, &kasp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("failed to configure dnssec-policy '%s': %s",
|
||||
cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
isc_result_totext(result));
|
||||
}
|
||||
INSIST(kasp != NULL);
|
||||
dns_kasp_freeze(kasp);
|
||||
break;
|
||||
}
|
||||
|
||||
*kaspp = kasp;
|
||||
|
||||
/*
|
||||
* Cleanup kasp list.
|
||||
*/
|
||||
for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
|
||||
kasp_next = ISC_LIST_NEXT(kasp, link);
|
||||
ISC_LIST_UNLINK(kasplist, kasp, link);
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup keystore list.
|
||||
*/
|
||||
for (ks = ISC_LIST_HEAD(kslist); ks != NULL; ks = ks_next) {
|
||||
ks_next = ISC_LIST_NEXT(ks, link);
|
||||
ISC_LIST_UNLINK(kslist, ks, link);
|
||||
dns_keystore_detach(&ks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,18 @@
|
||||
#include <isc/log.h>
|
||||
#include <isc/stdtime.h>
|
||||
|
||||
#include <dns/kasp.h>
|
||||
#include <dns/rdatastruct.h>
|
||||
|
||||
#include <dst/dst.h>
|
||||
|
||||
#include <isccfg/cfg.h>
|
||||
#include <isccfg/kaspconf.h>
|
||||
#include <isccfg/namedconf.h>
|
||||
|
||||
#define MAX_RSA 4096 /* should be long enough... */
|
||||
#define MAX_DH 4096 /* should be long enough... */
|
||||
|
||||
/*! verbosity: set by -v and -q option in each program, defined in dnssectool.c
|
||||
*/
|
||||
extern int verbose;
|
||||
@@ -108,3 +116,8 @@ isoptarg(const char *arg, char **argv, void (*usage)(void));
|
||||
|
||||
void
|
||||
loadjournal(isc_mem_t *mctx, dns_db_t *db, const char *journal);
|
||||
|
||||
void
|
||||
kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, isc_log_t *lctx,
|
||||
const char *name, const char *keydir, const char *engine,
|
||||
dns_kasp_t **kaspp);
|
||||
|
||||
@@ -298,6 +298,7 @@ dnssec-policy \"default\" {\n\
|
||||
publish-safety " DNS_KASP_PUBLISH_SAFETY "; \n\
|
||||
retire-safety " DNS_KASP_RETIRE_SAFETY "; \n\
|
||||
purge-keys " DNS_KASP_PURGE_KEYS "; \n\
|
||||
signatures-jitter " DNS_KASP_SIG_JITTER "; \n\
|
||||
signatures-refresh " DNS_KASP_SIG_REFRESH "; \n\
|
||||
signatures-validity " DNS_KASP_SIG_VALIDITY "; \n\
|
||||
signatures-validity-dnskey " DNS_KASP_SIG_VALIDITY_DNSKEY "; \n\
|
||||
|
||||
@@ -949,6 +949,7 @@ parse_command_line(int argc, char *argv[]) {
|
||||
break;
|
||||
case 'U':
|
||||
/* Obsolete. No longer in use. Ignore. */
|
||||
named_main_earlywarning("option '-U' has been removed");
|
||||
break;
|
||||
case 'u':
|
||||
named_g_username = isc_commandline_argument;
|
||||
|
||||
+2
-9
@@ -21,7 +21,7 @@ named - Internet domain name server
|
||||
Synopsis
|
||||
~~~~~~~~
|
||||
|
||||
:program:`named` [ [**-4**] | [**-6**] ] [**-c** config-file] [**-C**] [**-d** debug-level] [**-D** string] [**-E** engine-name] [**-f**] [**-g**] [**-L** logfile] [**-M** option] [**-m** flag] [**-n** #cpus] [**-p** port] [**-s**] [**-t** directory] [**-U** #listeners] [**-u** user] [**-v**] [**-V**] ]
|
||||
:program:`named` [ [**-4**] | [**-6**] ] [**-c** config-file] [**-C**] [**-d** debug-level] [**-D** string] [**-E** engine-name] [**-f**] [**-g**] [**-L** logfile] [**-M** option] [**-m** flag] [**-n** #cpus] [**-p** port] [**-s**] [**-t** directory] [**-u** user] [**-v**] [**-V**] ]
|
||||
|
||||
Description
|
||||
~~~~~~~~~~~
|
||||
@@ -163,14 +163,7 @@ Options
|
||||
|
||||
.. option:: -U #listeners
|
||||
|
||||
This option tells :program:`named` the number of ``#listeners`` worker threads to listen on, for incoming UDP packets on
|
||||
each address. If not specified, :program:`named` calculates a default
|
||||
value based on the number of detected CPUs: 1 for 1 CPU, and the
|
||||
number of detected CPUs minus one for machines with more than 1 CPU.
|
||||
This cannot be increased to a value higher than the number of CPUs.
|
||||
If :option:`-n` has been set to a higher value than the number of detected
|
||||
CPUs, then :option:`-U` may be increased as high as that value, but no
|
||||
higher.
|
||||
This option has been removed. Attempts to use it now result in a warning.
|
||||
|
||||
.. option:: -u user
|
||||
|
||||
|
||||
+18
-19
@@ -152,11 +152,11 @@
|
||||
#endif /* HAVE_LMDB */
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#define SIZE_MAX ((size_t) - 1)
|
||||
#endif /* ifndef SIZE_MAX */
|
||||
|
||||
#ifndef SIZE_AS_PERCENT
|
||||
#define SIZE_AS_PERCENT ((size_t)-2)
|
||||
#define SIZE_AS_PERCENT ((size_t) - 2)
|
||||
#endif /* ifndef SIZE_AS_PERCENT */
|
||||
|
||||
/* RFC7828 defines timeout as 16-bit value specified in units of 100
|
||||
@@ -400,6 +400,9 @@ const char *empty_zones[] = {
|
||||
/* RFC 8375 */
|
||||
"HOME.ARPA",
|
||||
|
||||
/* RFC 9462 */
|
||||
"RESOLVER.ARPA",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -4698,9 +4701,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
CHECK(dns_view_createresolver(
|
||||
view, named_g_loopmgr, named_g_netmgr, resopts,
|
||||
named_g_server->tlsctx_client_cache, dispatch4, dispatch6));
|
||||
CHECK(dns_view_createresolver(view, named_g_netmgr, resopts,
|
||||
named_g_server->tlsctx_client_cache,
|
||||
dispatch4, dispatch6));
|
||||
|
||||
if (resstats == NULL) {
|
||||
isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
|
||||
@@ -8184,7 +8187,7 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
/*
|
||||
* Require the reconfiguration to happen always on the main loop
|
||||
*/
|
||||
REQUIRE(isc_loop_current(named_g_loopmgr) == named_g_mainloop);
|
||||
REQUIRE(isc_loop() == named_g_mainloop);
|
||||
|
||||
ISC_LIST_INIT(kasplist);
|
||||
ISC_LIST_INIT(keystorelist);
|
||||
@@ -9835,8 +9838,7 @@ run_server(void *arg) {
|
||||
named_server_t *server = (named_server_t *)arg;
|
||||
dns_geoip_databases_t *geoip = NULL;
|
||||
|
||||
dns_zonemgr_create(named_g_mctx, named_g_loopmgr, named_g_netmgr,
|
||||
&server->zonemgr);
|
||||
dns_zonemgr_create(named_g_mctx, named_g_netmgr, &server->zonemgr);
|
||||
|
||||
CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_loopmgr,
|
||||
named_g_netmgr, &named_g_dispatchmgr),
|
||||
@@ -15079,29 +15081,26 @@ named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
|
||||
{
|
||||
dns_name_t *name;
|
||||
dns_fixedname_t fixed;
|
||||
dns_rdataset_t next;
|
||||
isc_stdtime_t resign;
|
||||
dns_typepair_t typepair;
|
||||
|
||||
dns_rdataset_init(&next);
|
||||
name = dns_fixedname_initname(&fixed);
|
||||
|
||||
result = dns_db_getsigningtime(db, &next, name);
|
||||
result = dns_db_getsigningtime(db, &resign, name, &typepair);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
char typebuf[DNS_RDATATYPE_FORMATSIZE];
|
||||
|
||||
resign -= dns_zone_getsigresigninginterval(zone);
|
||||
|
||||
dns_name_format(name, namebuf, sizeof(namebuf));
|
||||
dns_rdatatype_format(next.covers, typebuf,
|
||||
sizeof(typebuf));
|
||||
dns_rdatatype_format(DNS_TYPEPAIR_COVERS(typepair),
|
||||
typebuf, sizeof(typebuf));
|
||||
snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
|
||||
typebuf);
|
||||
isc_time_set(
|
||||
&resigntime,
|
||||
next.resign -
|
||||
dns_zone_getsigresigninginterval(zone),
|
||||
0);
|
||||
isc_time_set(&resigntime, resign, 0);
|
||||
isc_time_formathttptimestamp(&resigntime, rtbuf,
|
||||
sizeof(rtbuf));
|
||||
dns_rdataset_disassociate(&next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2484,7 +2484,7 @@ static void
|
||||
done_update(void) {
|
||||
ddebug("done_update()");
|
||||
|
||||
isc_async_current(loopmgr, getinput, NULL);
|
||||
isc_async_current(getinput, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+2
-4
@@ -305,8 +305,7 @@ rndc_recvdone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
||||
fatal("recv failed: %s", isc_result_totext(result));
|
||||
}
|
||||
|
||||
source.rstart = isc_buffer_base(ccmsg->buffer);
|
||||
source.rend = isc_buffer_used(ccmsg->buffer);
|
||||
isccc_ccmsg_toregion(ccmsg, &source);
|
||||
|
||||
DO("parse message",
|
||||
isccc_cc_fromwire(&source, &response, algorithm, &secret));
|
||||
@@ -381,8 +380,7 @@ rndc_recvnonce(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
|
||||
fatal("recv failed: %s", isc_result_totext(result));
|
||||
}
|
||||
|
||||
source.rstart = isc_buffer_base(ccmsg->buffer);
|
||||
source.rend = isc_buffer_used(ccmsg->buffer);
|
||||
isccc_ccmsg_toregion(ccmsg, &source);
|
||||
|
||||
DO("parse message",
|
||||
isccc_cc_fromwire(&source, &response, algorithm, &secret));
|
||||
|
||||
@@ -128,6 +128,7 @@ TESTS = \
|
||||
kasp \
|
||||
keepalive \
|
||||
keyfromlabel \
|
||||
ksr \
|
||||
legacy \
|
||||
limits \
|
||||
logfileconfig \
|
||||
|
||||
@@ -87,6 +87,7 @@ dnssec-policy "jitter" {
|
||||
signatures-validity P10D;
|
||||
signatures-validity-dnskey P10D;
|
||||
signatures-refresh P2D;
|
||||
signatures-jitter P8D;
|
||||
};
|
||||
|
||||
# Jitter, NSEC3
|
||||
|
||||
@@ -91,10 +91,10 @@ checkjitter() {
|
||||
|
||||
_count=0
|
||||
# Check if we have at least 4 days
|
||||
# This number has been tuned for `signatures-validity 10d; signatures-refresh 2d`, as
|
||||
# 1 signature expiration dates should be spread out across at most 8 (10-2) days
|
||||
# 2. we remove first and last day to remove frequency outlier, we are left with 6 (8-2) days
|
||||
# 3. we subtract two more days to allow test pass on day boundaries, etc. leaving us with 4 (6-2)
|
||||
# This number has been tuned for `signatures-validity 10d; signatures-jitter 8d`, as
|
||||
# 1. signature expiration dates should be spread out across at most 8 days
|
||||
# 2. we remove first and last day to remove frequency outlier, we are left with 6 days
|
||||
# 3. we subtract two more days to allow test pass on day boundaries, etc. leaving us with 4 days
|
||||
for _num in $_expiretimes; do
|
||||
_count=$((_count + 1))
|
||||
done
|
||||
|
||||
@@ -10,5 +10,9 @@
|
||||
# information regarding copyright ownership.
|
||||
|
||||
|
||||
import isctest.mark
|
||||
|
||||
|
||||
@isctest.mark.flaky(max_runs=2)
|
||||
def test_autosign(run_tests_sh):
|
||||
run_tests_sh()
|
||||
|
||||
@@ -120,7 +120,8 @@ A.E.F.IP6.ARPA
|
||||
B.E.F.IP6.ARPA
|
||||
8.B.D.0.1.0.0.2.IP6.ARPA
|
||||
EMPTY.AS112.ARPA
|
||||
HOME.ARPA"
|
||||
HOME.ARPA
|
||||
RESOLVER.ARPA"
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
@@ -134,7 +135,7 @@ for zone in ${emptyzones}; do
|
||||
count=$((count + 1))
|
||||
done
|
||||
lines=$(grep "automatic empty zone: " ns1/named.run | wc -l)
|
||||
test $count -eq $lines -a $count -eq 99 || {
|
||||
test $count -eq $lines -a $count -eq 100 || {
|
||||
ret=1
|
||||
echo_i "failed (count mismatch)"
|
||||
}
|
||||
|
||||
@@ -51,22 +51,22 @@ sub reply_handler {
|
||||
STDOUT->flush();
|
||||
|
||||
if ($qname eq "example.broken") {
|
||||
if ($qtype eq "SOA") {
|
||||
if ($qtype eq "SOA") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass SOA . . 0 0 0 0 0");
|
||||
push @ans, $rr;
|
||||
} elsif ($qtype eq "NS") {
|
||||
} elsif ($qtype eq "NS") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass NS $nsname");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("$nsname $ttl $qclass A $localaddr");
|
||||
push @add, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "cname-to-$synth2") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.$synth2");
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.$synth2");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("name.$synth2 $ttl $qclass CNAME name");
|
||||
$rr = new Net::DNS::RR("name.$synth2 $ttl $qclass CNAME name");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME .");
|
||||
$rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME .");
|
||||
push @ans, $rr;
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "$synth" || $qname eq "$synth2") {
|
||||
@@ -115,6 +115,30 @@ sub reply_handler {
|
||||
push @ans, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
# The next few branches produce a zone with an illegal NS below a DNAME.
|
||||
} elsif ($qname eq "jeff.dname") {
|
||||
if ($qtype eq "SOA") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass SOA . . 0 0 0 0 0");
|
||||
push @ans, $rr;
|
||||
} elsif ($qtype eq "NS") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass NS ns.jeff.dname.");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("$nsname $ttl $qclass A $localaddr");
|
||||
push @add, $rr;
|
||||
} elsif ($qtype eq "DNAME") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass DNAME mutt.example.");
|
||||
push @ans, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "ns.jeff.dname") {
|
||||
if ($qtype eq "A") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass A 10.53.0.3");
|
||||
push @ans, $rr;
|
||||
} elsif ($qtype eq "AAAA") {
|
||||
my $rr = new Net::DNS::RR("jeff.dname. $ttl $qclass SOA . . 0 0 0 0 $ttl");
|
||||
push @auth, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
} else {
|
||||
$rcode = "REFUSED";
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ ns3.example.broken. A 10.53.0.3
|
||||
example.dname. NS ns3.example.dname.
|
||||
ns3.example.dname. A 10.53.0.3
|
||||
|
||||
; regression test for illegal NS below DNAME
|
||||
jeff.dname. NS ns.jeff.dname.
|
||||
ns.jeff.dname. A 10.53.0.3
|
||||
|
||||
domain0.nil. NS ns2.domain0.nil
|
||||
domain1.nil. NS ns2.domain0.nil
|
||||
domain2.nil. NS ns2.domain0.nil
|
||||
|
||||
@@ -48,6 +48,9 @@ signed-sub2 NS ns2.sub2
|
||||
signed-sub2 DS 44137 8 2 1CB4F54E0B4F4F85109143113A3C679716A2377D86EB0907846A03FB 0C0A3927
|
||||
d CNAME d.signed-sub2
|
||||
|
||||
mutt NS ns5.mutt
|
||||
ns5.mutt A 10.53.0.5
|
||||
|
||||
; long CNAME loop
|
||||
loop CNAME goop
|
||||
goop CNAME boop
|
||||
|
||||
@@ -40,3 +40,8 @@ zone "signed-sub5.example" {
|
||||
type primary;
|
||||
file "sub.db";
|
||||
};
|
||||
|
||||
zone "mutt.example" {
|
||||
type primary;
|
||||
file "mutt.db";
|
||||
};
|
||||
|
||||
@@ -626,5 +626,16 @@ grep 'status: NOERROR' dig.out.7.$n >/dev/null 2>&1 || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
# Regression test for GL #4652
|
||||
n=$((n + 1))
|
||||
echo_i "checking handling of illegal NS below DNAME ($n)"
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.7 DNAME jeff.dname. >dig.out.ns7.1.$n 2>&1
|
||||
grep 'status: NOERROR' dig.out.ns7.1.$n >/dev/null 2>&1 || ret=1
|
||||
$DIG $DIGOPTS @10.53.0.7 NS jeff.dname. >dig.out.ns7.2.$n 2>&1
|
||||
grep 'status: SERVFAIL' dig.out.ns7.2.$n >/dev/null 2>&1 || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you 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 "invalid-sigrefresh" {
|
||||
keys {
|
||||
csk lifetime unlimited algorithm 13;
|
||||
};
|
||||
signatures-refresh P7.5D;
|
||||
};
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
file "example.db";
|
||||
dnssec-policy "invalid-sigrefresh";
|
||||
};
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The dnssec-policy jitter is more than signatures-validity,
|
||||
* which is not allowed.
|
||||
*/
|
||||
dnssec-policy high-jitter {
|
||||
signatures-jitter P8DT1S;
|
||||
signatures-validity P8D;
|
||||
};
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
file "example.db";
|
||||
dnssec-policy high-jitter;
|
||||
};
|
||||
@@ -28,6 +28,12 @@ options {
|
||||
avoid-v6-udp-ports { range 1 1023; };
|
||||
|
||||
dnssec-must-be-secure mustbesecure.example yes;
|
||||
|
||||
sortlist { };
|
||||
|
||||
rrset-order {
|
||||
name "fixed.example" order fixed;
|
||||
};
|
||||
};
|
||||
|
||||
trusted-keys {
|
||||
|
||||
@@ -34,6 +34,7 @@ dnssec-policy "test" {
|
||||
parent-propagation-delay PT1H;
|
||||
publish-safety PT3600S;
|
||||
retire-safety PT3600S;
|
||||
signatures-jitter PT12H;
|
||||
signatures-refresh P3D;
|
||||
signatures-validity P2W;
|
||||
signatures-validity-dnskey P14D;
|
||||
|
||||
@@ -34,6 +34,7 @@ dnssec-policy "test" {
|
||||
publish-safety PT3600S;
|
||||
purge-keys P90D;
|
||||
retire-safety PT3600S;
|
||||
signatures-jitter PT12H;
|
||||
signatures-refresh P3D;
|
||||
signatures-validity P2W;
|
||||
signatures-validity-dnskey P14D;
|
||||
|
||||
@@ -165,6 +165,12 @@ warnings=$(grep "'notify' is disabled" <checkconf.out$n | wc -l)
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
if grep "^#define DNS_RDATASET_FIXED" "$TOP_BUILDDIR/config.h" >/dev/null 2>&1; then
|
||||
test_fixed=true
|
||||
else
|
||||
test_fixed=false
|
||||
fi
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking named-checkconf deprecate warnings ($n)"
|
||||
ret=0
|
||||
@@ -179,12 +185,18 @@ grep "option 'avoid-v6-udp-ports' is deprecated" <checkconf.out$n.1 >/dev/null |
|
||||
grep "option 'dialup' is deprecated" <checkconf.out$n.1 >/dev/null || ret=1
|
||||
grep "option 'heartbeat-interval' is deprecated" <checkconf.out$n.1 >/dev/null || ret=1
|
||||
grep "option 'dnssec-must-be-secure' is deprecated" <checkconf.out$n.1 >/dev/null || ret=1
|
||||
grep "option 'sortlist' is deprecated" <checkconf.out$n.1 >/dev/null || ret=1
|
||||
grep "token 'port' is deprecated" <checkconf.out$n.1 >/dev/null || ret=1
|
||||
if $test_fixed; then
|
||||
grep "rrset-order: order 'fixed' is deprecated" <checkconf.out$n.1 >/dev/null || ret=1
|
||||
else
|
||||
grep "rrset-order: order 'fixed' was disabled at compilation time" <checkconf.out$n.1 >/dev/null || ret=1
|
||||
fi
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
# set -i to ignore deprecate warnings
|
||||
$CHECKCONF -i deprecated.conf >checkconf.out$n.2 2>&1
|
||||
grep '.*' <checkconf.out$n.2 >/dev/null && ret=1
|
||||
$CHECKCONF -i deprecated.conf 2>&1 | grep_v "rrset-order: order 'fixed' was disabled at compilation time" >checkconf.out$n.2
|
||||
grep '^.+$' <checkconf.out$n.2 >/dev/null && ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ status=$((status + ret))
|
||||
|
||||
echo_i "checking with max ttl (text) ($n)"
|
||||
ret=0
|
||||
$CHECKZONE -l 300 example zones/good1.db >test.out1.$n 2>&1 && ret=1
|
||||
$CHECKZONE -l 600 example zones/good1.db >test.out2.$n 2>&1 || ret=1
|
||||
$CHECKZONE -i local -l 300 example zones/good1.db >test.out1.$n 2>&1 && ret=1
|
||||
$CHECKZONE -i local -l 600 example zones/good1.db >test.out2.$n 2>&1 || ret=1
|
||||
n=$((n + 1))
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
@@ -650,3 +650,5 @@ parse_openssl_config() {
|
||||
esac
|
||||
done < "$OPENSSL_CONF"
|
||||
}
|
||||
|
||||
grep_v() { grep -v "$@" || test $? = 1; }
|
||||
|
||||
@@ -42,6 +42,7 @@ export IMPORTKEY=$TOP_BUILDDIR/bin/dnssec/dnssec-importkey
|
||||
export JOURNALPRINT=$TOP_BUILDDIR/bin/tools/named-journalprint
|
||||
export KEYFRLAB=$TOP_BUILDDIR/bin/dnssec/dnssec-keyfromlabel
|
||||
export KEYGEN=$TOP_BUILDDIR/bin/dnssec/dnssec-keygen
|
||||
export KSR=$TOP_BUILDDIR/bin/dnssec/dnssec-ksr
|
||||
export MDIG=$TOP_BUILDDIR/bin/tools/mdig
|
||||
export NAMED=$TOP_BUILDDIR/bin/named/named
|
||||
export NSEC3HASH=$TOP_BUILDDIR/bin/tools/nsec3hash
|
||||
@@ -68,6 +69,8 @@ export KRB5_CONFIG=/dev/null
|
||||
# use local keytab instead of default /etc/krb5.keytab
|
||||
export KRB5_KTNAME=dns.keytab
|
||||
|
||||
export ANS_LOG_LEVEL=debug
|
||||
|
||||
#
|
||||
# Programs detected by configure
|
||||
# Variables will be empty if no program was found by configure
|
||||
|
||||
@@ -30,6 +30,9 @@ import isctest
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
|
||||
isctest.log.init_conftest_logger()
|
||||
isctest.log.avoid_duplicated_logs()
|
||||
|
||||
# ----------------- Older pytest / xdist compatibility -------------------
|
||||
# As of 2023-01-11, the minimal supported pytest / xdist versions are
|
||||
# determined by what is available in EL8/EPEL8:
|
||||
|
||||
@@ -6,7 +6,7 @@ scriptversion=2021-09-20.08 # UTC
|
||||
|
||||
# Copyright (C) 2011-2020 Free Software Foundation, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-Automake-exception-2.0
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later WITH Autoconf-exception-generic
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -20,7 +20,7 @@ import dns.message
|
||||
def test_dialup_zone_transfer(named_port, servers, ns):
|
||||
msg = dns.message.make_query("example.", "SOA")
|
||||
# Drop the RD flag from the query
|
||||
msg.flags -= dns.flags.RD
|
||||
msg.flags &= ~dns.flags.RD
|
||||
ns1response = isctest.query.tcp(msg, "10.53.0.1")
|
||||
with servers[f"ns{ns}"].watch_log_from_start() as watcher:
|
||||
watcher.wait_for_line(
|
||||
|
||||
@@ -1117,6 +1117,14 @@ if [ -x "$DIG" ]; then
|
||||
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=<nonzero> 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))
|
||||
else
|
||||
echo_i "$DIG is needed, so skipping these dig tests"
|
||||
fi
|
||||
|
||||
@@ -363,14 +363,13 @@ setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
|
||||
dns_name_t *name DNS__DB_FLARG) {
|
||||
getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *name,
|
||||
dns_typepair_t *type) {
|
||||
sampledb_t *sampledb = (sampledb_t *)db;
|
||||
|
||||
REQUIRE(VALID_SAMPLEDB(sampledb));
|
||||
|
||||
return (dns__db_getsigningtime(sampledb->rbtdb, rdataset,
|
||||
name DNS__DB_FLARG_PASS));
|
||||
return (dns_db_getsigningtime(sampledb->rbtdb, resign, name, type));
|
||||
}
|
||||
|
||||
static dns_stats_t *
|
||||
@@ -614,7 +613,7 @@ create_db(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
|
||||
isc_mem_attach(mctx, &sampledb->common.mctx);
|
||||
dns_name_init(&sampledb->common.origin, NULL);
|
||||
|
||||
CHECK(dns_name_dupwithoffsets(origin, mctx, &sampledb->common.origin));
|
||||
dns_name_dupwithoffsets(origin, mctx, &sampledb->common.origin);
|
||||
|
||||
isc_refcount_init(&sampledb->common.references, 1);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
. ../conf.sh
|
||||
|
||||
[ "prereq/var/tmp/etc/openssl-provider.cnf" -eq "prereq${OPENSSL_CONF}" ] || {
|
||||
[ "prereq/var/tmp/etc/openssl-provider.cnf" = "prereq${OPENSSL_CONF}" ] || {
|
||||
echo_i "skip: pkcs11-provider not enabled"
|
||||
exit 255
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import isctest.mark
|
||||
|
||||
|
||||
@isctest.mark.flaky(max_runs=3) # GL#4605
|
||||
def test_enginepkcs11(run_tests_sh):
|
||||
run_tests_sh()
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
rm -f */named.conf
|
||||
rm -f */named.memstats
|
||||
rm -f */named.run
|
||||
rm -f dig.out
|
||||
rm -f ns*/K*
|
||||
rm -f ns*/dsset-*
|
||||
rm -f ns*/managed-keys.bind*
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
; <<>> DiG 9.0 <<>> +norec @10.53.0.1 -p 5300 foo.bar.fi. A
|
||||
;; global options: printcmd
|
||||
;; Got answer:
|
||||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58772
|
||||
;; flags: qr ad; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 7
|
||||
|
||||
;; QUESTION SECTION:
|
||||
;foo.bar.fi. IN A
|
||||
|
||||
;; AUTHORITY SECTION:
|
||||
fi. 172800 IN NS NS.EU.NET.
|
||||
fi. 172800 IN NS NS.TELE.fi.
|
||||
fi. 172800 IN NS PRIFI.EUNET.fi.
|
||||
fi. 172800 IN NS NS.UU.NET.
|
||||
fi. 172800 IN NS T.NS.VERIO.NET.
|
||||
fi. 172800 IN NS HYDRA.HELSINKI.fi.
|
||||
|
||||
;; ADDITIONAL SECTION:
|
||||
NS.TELE.fi. 172800 IN A 193.210.19.19
|
||||
NS.TELE.fi. 172800 IN A 193.210.18.18
|
||||
PRIFI.EUNET.fi. 172800 IN A 193.66.1.146
|
||||
NS.UU.NET. 172800 IN A 137.39.1.3
|
||||
T.NS.VERIO.NET. 172800 IN A 192.67.14.16
|
||||
HYDRA.HELSINKI.fi. 172800 IN A 128.214.4.29
|
||||
NS.EU.NET. 172800 IN A 192.16.202.11
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
; <<>> DiG 9.0 <<>> @10.53.0.1 -p 5300 example.net a
|
||||
;; global options: printcmd
|
||||
;; Got answer:
|
||||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29409
|
||||
;; flags: qr rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 0
|
||||
|
||||
;; QUESTION SECTION:
|
||||
;example.net. IN A
|
||||
|
||||
;; AUTHORITY SECTION:
|
||||
example.net. 300 IN NS ns2.example.
|
||||
example.net. 300 IN NS ns1.example.
|
||||
|
||||
@@ -1,90 +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
|
||||
|
||||
. ../conf.sh
|
||||
|
||||
dig_with_opts() {
|
||||
"$DIG" +norec -p "${PORT}" "$@"
|
||||
}
|
||||
|
||||
status=0
|
||||
n=0
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "testing that a ccTLD referral gets a full glue set from the root zone ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 foo.bar.fi. A >dig.out.$n || ret=1
|
||||
digcomp --lc fi.good dig.out.$n || ret=1
|
||||
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "testing that we don't find out-of-zone glue ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 example.net. A >dig.out.$n || ret=1
|
||||
digcomp noglue.good dig.out.$n || ret=1
|
||||
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "testing truncation for unsigned referrals close to UDP packet size limit (A glue) ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 +ignore +noedns foo.subdomain-a.tc-test-unsigned. >dig.out.$n || ret=1
|
||||
grep -q "flags:[^;]* tc" dig.out.$n || ret=1
|
||||
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "testing truncation for unsigned referrals close to UDP packet size limit (AAAA glue) ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 +ignore +noedns foo.subdomain-aaaa.tc-test-unsigned. >dig.out.$n || ret=1
|
||||
grep -q "flags:[^;]* tc" dig.out.$n || ret=1
|
||||
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "testing truncation for unsigned referrals close to UDP packet size limit (A+AAAA glue) ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 +ignore +noedns foo.subdomain-both.tc-test-unsigned. >dig.out.$n || ret=1
|
||||
grep -q "flags:[^;]* tc" dig.out.$n || ret=1
|
||||
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "testing truncation for signed referrals close to UDP packet size limit (A glue) ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 +ignore +dnssec +bufsize=512 foo.subdomain-a.tc-test-signed. >dig.out.$n || ret=1
|
||||
grep -q "flags:[^;]* tc" dig.out.$n || ret=1
|
||||
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "testing truncation for signed referrals close to UDP packet size limit (AAAA glue) ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 +ignore +dnssec +bufsize=512 foo.subdomain-aaaa.tc-test-signed. >dig.out.$n || ret=1
|
||||
grep -q "flags:[^;]* tc" dig.out.$n || ret=1
|
||||
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "testing truncation for signed referrals close to UDP packet size limit (A+AAAA glue) ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 +ignore +dnssec +bufsize=512 foo.subdomain-both.tc-test-signed. >dig.out.$n || ret=1
|
||||
grep -q "flags:[^;]* tc" dig.out.$n || ret=1
|
||||
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
@@ -0,0 +1,104 @@
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you 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 isctest
|
||||
|
||||
import pytest
|
||||
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
|
||||
def test_glue_full_glue_set():
|
||||
"""test that a ccTLD referral gets a full glue set from the root zone"""
|
||||
msg = dns.message.make_query("foo.bar.fi", "A")
|
||||
msg.flags &= ~dns.flags.RD
|
||||
res = isctest.query.udp(msg, "10.53.0.1")
|
||||
|
||||
answer = """;ANSWER
|
||||
;AUTHORITY
|
||||
fi. 172800 IN NS HYDRA.HELSINKI.fi.
|
||||
fi. 172800 IN NS NS.EU.NET.
|
||||
fi. 172800 IN NS NS.UU.NET.
|
||||
fi. 172800 IN NS NS.TELE.fi.
|
||||
fi. 172800 IN NS T.NS.VERIO.NET.
|
||||
fi. 172800 IN NS PRIFI.EUNET.fi.
|
||||
;ADDITIONAL
|
||||
NS.TELE.fi. 172800 IN A 193.210.18.18
|
||||
NS.TELE.fi. 172800 IN A 193.210.19.19
|
||||
PRIFI.EUNET.fi. 172800 IN A 193.66.1.146
|
||||
HYDRA.HELSINKI.fi. 172800 IN A 128.214.4.29
|
||||
NS.EU.NET. 172800 IN A 192.16.202.11
|
||||
T.NS.VERIO.NET. 172800 IN A 192.67.14.16
|
||||
NS.UU.NET. 172800 IN A 137.39.1.3
|
||||
"""
|
||||
expected_answer = dns.message.from_text(answer)
|
||||
|
||||
isctest.check.noerror(res)
|
||||
isctest.check.rrsets_equal(res.answer, expected_answer.answer)
|
||||
isctest.check.rrsets_equal(res.authority, expected_answer.authority)
|
||||
isctest.check.rrsets_equal(res.additional, expected_answer.additional)
|
||||
|
||||
|
||||
def test_glue_no_glue_set():
|
||||
"""test that out-of-zone glue is not found"""
|
||||
msg = dns.message.make_query("example.net.", "A")
|
||||
msg.flags &= ~dns.flags.RD
|
||||
res = isctest.query.udp(msg, "10.53.0.1")
|
||||
|
||||
answer = """;ANSWER
|
||||
;AUTHORITY
|
||||
example.net. 300 IN NS ns2.example.
|
||||
example.net. 300 IN NS ns1.example.
|
||||
;ADDITIONAL
|
||||
"""
|
||||
expected_answer = dns.message.from_text(answer)
|
||||
|
||||
isctest.check.noerror(res)
|
||||
isctest.check.rrsets_equal(res.answer, expected_answer.answer)
|
||||
isctest.check.rrsets_equal(res.authority, expected_answer.authority)
|
||||
isctest.check.rrsets_equal(res.additional, expected_answer.additional)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"qname,dnssec",
|
||||
[
|
||||
# test truncation for unsigned referrals close to UDP packet size limit (A glue)
|
||||
("foo.subdomain-a.tc-test-unsigned.", False),
|
||||
# test truncation for unsigned referrals close to UDP packet size limit (AAAA glue)
|
||||
("foo.subdomain-aaaa.tc-test-unsigned.", False),
|
||||
# test truncation for unsigned referrals close to UDP packet size limit (A+AAAA glue)
|
||||
("foo.subdomain-both.tc-test-unsigned.", False),
|
||||
# test truncation for signed referrals close to UDP packet size limit (A glue)
|
||||
("foo.subdomain-a.tc-test-signed.", True),
|
||||
# test truncation for signed referrals close to UDP packet size limit (AAAA glue)
|
||||
("foo.subdomain-aaaa.tc-test-signed.", True),
|
||||
# test truncation for signed referrals close to UDP packet size limit (A+AAAA glue)
|
||||
("foo.subdomain-both.tc-test-signed.", True),
|
||||
],
|
||||
)
|
||||
def test_glue_truncation(qname, dnssec):
|
||||
msg = dns.message.make_query(qname, "A")
|
||||
msg.flags &= ~dns.flags.RD
|
||||
if dnssec:
|
||||
msg.use_edns(
|
||||
payload=512,
|
||||
# Zones used in this test were created with dig in mind that, unlike dnspython,
|
||||
# by default, sets a cookie. Given that the message size must be close to the
|
||||
# truncation limit, we also need to set a cookie here.
|
||||
options=[dns.edns.GenericOption(dns.edns.OptionType.COOKIE, b"0xda13cc")],
|
||||
)
|
||||
msg.want_dnssec(wanted=True)
|
||||
res = isctest.query.udp(msg, "10.53.0.1")
|
||||
|
||||
isctest.check.noerror(res)
|
||||
assert res.flags & dns.flags.TC
|
||||
@@ -0,0 +1,799 @@
|
||||
"""
|
||||
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, you 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 dataclasses import dataclass, field
|
||||
from typing import (
|
||||
Any,
|
||||
AsyncGenerator,
|
||||
Callable,
|
||||
Coroutine,
|
||||
List,
|
||||
Optional,
|
||||
Tuple,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
|
||||
import abc
|
||||
import asyncio
|
||||
import enum
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import signal
|
||||
import struct
|
||||
import sys
|
||||
|
||||
import dns.flags
|
||||
import dns.message
|
||||
import dns.name
|
||||
import dns.node
|
||||
import dns.rcode
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
import dns.rrset
|
||||
import dns.zone
|
||||
|
||||
try:
|
||||
RdataType = dns.rdatatype.RdataType
|
||||
RdataClass = dns.rdataclass.RdataClass
|
||||
except AttributeError: # dnspython < 2.0.0 compat
|
||||
RdataType = int # type: ignore
|
||||
RdataClass = int # type: ignore
|
||||
|
||||
|
||||
_UdpHandler = Callable[
|
||||
[bytes, Tuple[str, int], asyncio.DatagramTransport], Coroutine[Any, Any, None]
|
||||
]
|
||||
|
||||
|
||||
_TcpHandler = Callable[
|
||||
[asyncio.StreamReader, asyncio.StreamWriter], Coroutine[Any, Any, None]
|
||||
]
|
||||
|
||||
|
||||
class _AsyncUdpHandler(asyncio.DatagramProtocol):
|
||||
"""
|
||||
Protocol implementation for handling UDP traffic using asyncio.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
handler: _UdpHandler,
|
||||
) -> None:
|
||||
self._transport: Optional[asyncio.DatagramTransport] = None
|
||||
self._handler: _UdpHandler = handler
|
||||
|
||||
def connection_made(self, transport: asyncio.BaseTransport) -> None:
|
||||
"""
|
||||
Called by asyncio when a connection is made.
|
||||
"""
|
||||
self._transport = cast(asyncio.DatagramTransport, transport)
|
||||
|
||||
def datagram_received(self, data: bytes, addr: Tuple[str, int]) -> None:
|
||||
"""
|
||||
Called by asyncio when a datagram is received.
|
||||
"""
|
||||
assert self._transport
|
||||
handler_coroutine = self._handler(data, addr, self._transport)
|
||||
try:
|
||||
# Python >= 3.7
|
||||
asyncio.create_task(handler_coroutine)
|
||||
except AttributeError:
|
||||
# Python < 3.7
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task(handler_coroutine)
|
||||
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
class AsyncServer:
|
||||
"""
|
||||
A generic asynchronous server which may handle UDP and/or TCP traffic.
|
||||
|
||||
Once the server is executed as asyncio coroutine, it will keep running
|
||||
until a SIGINT/SIGTERM signal is received.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
udp_handler: Optional[_UdpHandler],
|
||||
tcp_handler: Optional[_TcpHandler],
|
||||
pidfile: Optional[str] = None,
|
||||
) -> None:
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s %(levelname)8s %(message)s",
|
||||
level=os.environ.get("ANS_LOG_LEVEL", "INFO").upper(),
|
||||
)
|
||||
try:
|
||||
ipv4_address = sys.argv[1]
|
||||
except IndexError:
|
||||
ipv4_address = self._get_ipv4_address_from_directory_name()
|
||||
|
||||
last_ipv4_address_octet = ipv4_address.split(".")[-1]
|
||||
ipv6_address = f"fd92:7065:b8e:ffff::{last_ipv4_address_octet}"
|
||||
|
||||
try:
|
||||
port = int(sys.argv[2])
|
||||
except IndexError:
|
||||
port = int(os.environ.get("PORT", 5300))
|
||||
|
||||
logging.info("Setting up IPv4 listener at %s:%d", ipv4_address, port)
|
||||
logging.info("Setting up IPv6 listener at [%s]:%d", ipv6_address, port)
|
||||
|
||||
self._ip_addresses: Tuple[str, str] = (ipv4_address, ipv6_address)
|
||||
self._port: int = port
|
||||
self._udp_handler: Optional[_UdpHandler] = udp_handler
|
||||
self._tcp_handler: Optional[_TcpHandler] = tcp_handler
|
||||
self._pidfile: Optional[str] = pidfile
|
||||
self._work_done: Optional[asyncio.Future] = None
|
||||
|
||||
def _get_ipv4_address_from_directory_name(self) -> str:
|
||||
containing_directory = pathlib.Path().absolute().stem
|
||||
match_result = re.match(r"ans(?P<index>\d+)", containing_directory)
|
||||
if not match_result:
|
||||
raise RuntimeError("Unable to auto-determine the IPv4 address to use")
|
||||
|
||||
return f"10.53.0.{match_result.group('index')}"
|
||||
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Start the server in an asynchronous coroutine.
|
||||
"""
|
||||
coroutine = self._run
|
||||
try:
|
||||
# Python >= 3.7
|
||||
asyncio.run(coroutine())
|
||||
except AttributeError:
|
||||
# Python < 3.7
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(coroutine())
|
||||
|
||||
async def _run(self) -> None:
|
||||
self._setup_signals()
|
||||
assert self._work_done
|
||||
await self._listen_udp()
|
||||
await self._listen_tcp()
|
||||
self._write_pidfile()
|
||||
await self._work_done
|
||||
self._cleanup_pidfile()
|
||||
|
||||
def _get_asyncio_loop(self) -> asyncio.AbstractEventLoop:
|
||||
try:
|
||||
# Python >= 3.7
|
||||
loop = asyncio.get_running_loop()
|
||||
except AttributeError:
|
||||
# Python < 3.7
|
||||
loop = asyncio.get_event_loop()
|
||||
return loop
|
||||
|
||||
def _setup_signals(self) -> None:
|
||||
loop = self._get_asyncio_loop()
|
||||
self._work_done = loop.create_future()
|
||||
loop.add_signal_handler(signal.SIGINT, functools.partial(self._signal_done))
|
||||
loop.add_signal_handler(signal.SIGTERM, functools.partial(self._signal_done))
|
||||
|
||||
def _signal_done(self) -> None:
|
||||
assert self._work_done
|
||||
self._work_done.set_result(True)
|
||||
|
||||
async def _listen_udp(self) -> None:
|
||||
if not self._udp_handler:
|
||||
return
|
||||
loop = self._get_asyncio_loop()
|
||||
for ip_address in self._ip_addresses:
|
||||
await loop.create_datagram_endpoint(
|
||||
lambda: _AsyncUdpHandler(cast(_UdpHandler, self._udp_handler)),
|
||||
(ip_address, self._port),
|
||||
)
|
||||
|
||||
async def _listen_tcp(self) -> None:
|
||||
if not self._tcp_handler:
|
||||
return
|
||||
for ip_address in self._ip_addresses:
|
||||
await asyncio.start_server(
|
||||
self._tcp_handler, host=ip_address, port=self._port
|
||||
)
|
||||
|
||||
def _write_pidfile(self) -> None:
|
||||
if not self._pidfile:
|
||||
return
|
||||
logging.info("Writing PID to %s", self._pidfile)
|
||||
with open(self._pidfile, "w", encoding="ascii") as pidfile:
|
||||
print(f"{os.getpid()}", file=pidfile)
|
||||
|
||||
def _cleanup_pidfile(self) -> None:
|
||||
if not self._pidfile:
|
||||
return
|
||||
logging.info("Removing %s", self._pidfile)
|
||||
os.unlink(self._pidfile)
|
||||
|
||||
|
||||
class DnsProtocol(enum.Enum):
|
||||
UDP = enum.auto()
|
||||
TCP = enum.auto()
|
||||
|
||||
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
@dataclass
|
||||
class QueryContext:
|
||||
"""
|
||||
Context for the incoming query which may be used for preparing the response.
|
||||
"""
|
||||
|
||||
query: dns.message.Message
|
||||
response: dns.message.Message
|
||||
peer: Tuple[str, int]
|
||||
protocol: DnsProtocol
|
||||
zone: Optional[dns.zone.Zone] = None
|
||||
soa: Optional[dns.rrset.RRset] = None
|
||||
node: Optional[dns.node.Node] = None
|
||||
answer: Optional[dns.rdataset.Rdataset] = None
|
||||
|
||||
@property
|
||||
def qname(self) -> dns.name.Name:
|
||||
return self.query.question[0].name
|
||||
|
||||
@property
|
||||
def qclass(self) -> RdataClass:
|
||||
return self.query.question[0].rdclass
|
||||
|
||||
@property
|
||||
def qtype(self) -> RdataType:
|
||||
return self.query.question[0].rdtype
|
||||
|
||||
|
||||
@dataclass
|
||||
class ResponseAction(abc.ABC):
|
||||
"""
|
||||
Base class for actions that can be taken in response to a query.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
async def perform(self) -> Optional[Union[dns.message.Message, bytes]]:
|
||||
"""
|
||||
This method is expected to carry out arbitrary actions (e.g. wait for a
|
||||
specific amount of time, modify the answer, etc.) and then return the
|
||||
DNS response to send (a dns.message.Message, a raw bytes object, or
|
||||
None, which prevents any response from being sent).
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@dataclass
|
||||
class DnsResponseSend(ResponseAction):
|
||||
"""
|
||||
Action which yields a dns.message.Message response.
|
||||
|
||||
The response may be sent with a delay if requested.
|
||||
|
||||
Depending on the value of the `authoritative` property, this class may set
|
||||
the AA bit in the response (True), clear it (False), or not touch it at all
|
||||
(None).
|
||||
"""
|
||||
|
||||
response: dns.message.Message
|
||||
authoritative: Optional[bool] = None
|
||||
delay: float = 0.0
|
||||
|
||||
async def perform(self) -> Optional[Union[dns.message.Message, bytes]]:
|
||||
"""
|
||||
Yield a potentially delayed response that is a dns.message.Message.
|
||||
"""
|
||||
assert isinstance(self.response, dns.message.Message)
|
||||
if self.authoritative is not None:
|
||||
if self.authoritative:
|
||||
self.response.flags |= dns.flags.AA
|
||||
else:
|
||||
self.response.flags &= ~dns.flags.AA
|
||||
if self.delay > 0:
|
||||
logging.info(
|
||||
"Delaying response (ID=%d) by %d ms",
|
||||
self.response.id,
|
||||
self.delay * 1000,
|
||||
)
|
||||
await asyncio.sleep(self.delay)
|
||||
return self.response
|
||||
|
||||
|
||||
@dataclass
|
||||
class BytesResponseSend(ResponseAction):
|
||||
"""
|
||||
Action which yields a raw response that is a sequence of bytes.
|
||||
|
||||
The response may be sent with a delay if requested.
|
||||
"""
|
||||
|
||||
response: bytes
|
||||
delay: float = 0.0
|
||||
|
||||
async def perform(self) -> Optional[Union[dns.message.Message, bytes]]:
|
||||
"""
|
||||
Yield a potentially delayed response that is a sequence of bytes.
|
||||
"""
|
||||
assert isinstance(self.response, bytes)
|
||||
if self.delay > 0:
|
||||
logging.info("Delaying raw response by %d ms", self.delay * 1000)
|
||||
await asyncio.sleep(self.delay)
|
||||
return self.response
|
||||
|
||||
|
||||
@dataclass
|
||||
class ResponseDrop(ResponseAction):
|
||||
"""
|
||||
Action which does nothing - as if a packet was dropped.
|
||||
"""
|
||||
|
||||
async def perform(self) -> Optional[Union[dns.message.Message, bytes]]:
|
||||
return None
|
||||
|
||||
|
||||
class ResponseHandler(abc.ABC):
|
||||
"""
|
||||
Base class for generic response handlers.
|
||||
|
||||
If a query passes the `match()` function logic, then it is handled by this
|
||||
response handler and response(s) may be generated by the `get_responses()`
|
||||
method.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def match(self, qctx: QueryContext) -> bool:
|
||||
"""
|
||||
Matching logic - query is handled when it returns True.
|
||||
"""
|
||||
return True
|
||||
|
||||
@abc.abstractmethod
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[ResponseAction, None]:
|
||||
"""
|
||||
Custom handler which may produce response(s) to matching queries.
|
||||
|
||||
The response prepared from zone data is passed to this method in
|
||||
qctx.response.
|
||||
"""
|
||||
yield DnsResponseSend(qctx.response)
|
||||
|
||||
|
||||
class DomainHandler(ResponseHandler):
|
||||
"""
|
||||
Base class used for deriving custom domain handlers.
|
||||
|
||||
The derived class must specify a list of `domains` that it wants to handle.
|
||||
Queries for any of these domains (and their subdomains) will then be passed
|
||||
to the `get_response()` method in the derived class.
|
||||
"""
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def domains(self) -> List[str]:
|
||||
"""
|
||||
A list of domain names handled by this class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._domains: List[dns.name.Name] = [
|
||||
dns.name.from_text(d) for d in self.domains
|
||||
]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.__class__.__name__}(domains: {', '.join(self.domains)})"
|
||||
|
||||
def match(self, qctx: QueryContext) -> bool:
|
||||
"""
|
||||
Handle queries whose QNAME matches any of the domains handled by this
|
||||
class.
|
||||
"""
|
||||
for domain in self._domains:
|
||||
if qctx.qname.is_subdomain(domain):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@dataclass
|
||||
class _ZoneTreeNode:
|
||||
"""
|
||||
A node representing a zone with one origin.
|
||||
"""
|
||||
|
||||
zone: Optional[dns.zone.Zone]
|
||||
children: List["_ZoneTreeNode"] = field(default_factory=list)
|
||||
|
||||
|
||||
class _ZoneTree:
|
||||
"""
|
||||
Tree with independent zones.
|
||||
|
||||
This zone tree is used as a backing structure for the DNS server. The
|
||||
individual zones are independent to allow the (single) server to serve both
|
||||
the parent zone and a child zone if needed.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._root: _ZoneTreeNode = _ZoneTreeNode(None)
|
||||
|
||||
def add(self, zone: dns.zone.Zone) -> None:
|
||||
"""
|
||||
Add a zone to the tree and rearrange sub-zones if necessary.
|
||||
"""
|
||||
assert zone.origin
|
||||
best_match = self._find_best_match(zone.origin, self._root)
|
||||
added_node = _ZoneTreeNode(zone)
|
||||
self._move_children(best_match, added_node)
|
||||
best_match.children.append(added_node)
|
||||
|
||||
def _find_best_match(
|
||||
self, name: dns.name.Name, start_node: _ZoneTreeNode
|
||||
) -> _ZoneTreeNode:
|
||||
for child in start_node.children:
|
||||
assert child.zone
|
||||
assert child.zone.origin
|
||||
if name.is_subdomain(child.zone.origin):
|
||||
return self._find_best_match(name, child)
|
||||
return start_node
|
||||
|
||||
def _move_children(self, node_from: _ZoneTreeNode, node_to: _ZoneTreeNode) -> None:
|
||||
assert node_to.zone
|
||||
assert node_to.zone.origin
|
||||
|
||||
children_to_move = []
|
||||
for child in node_from.children:
|
||||
assert child.zone
|
||||
assert child.zone.origin
|
||||
if child.zone.origin.is_subdomain(node_to.zone.origin):
|
||||
children_to_move.append(child)
|
||||
|
||||
for child in children_to_move:
|
||||
node_from.children.remove(child)
|
||||
node_to.children.append(child)
|
||||
|
||||
def find_best_zone(self, name: dns.name.Name) -> Optional[dns.zone.Zone]:
|
||||
"""
|
||||
Return the closest matching zone (if any) for the domain name.
|
||||
"""
|
||||
node = self._find_best_match(name, self._root)
|
||||
return node.zone if node != self._root else None
|
||||
|
||||
|
||||
class AsyncDnsServer(AsyncServer):
|
||||
"""
|
||||
DNS server which responds to queries based on zone data and/or custom
|
||||
handlers.
|
||||
|
||||
The server may use custom handlers which allow arbitrary query processing.
|
||||
These don't need to be standards-compliant and can be used for testing all
|
||||
sorts of scenarios, including delaying responses, synthesizing them based
|
||||
on query contents etc.
|
||||
|
||||
The server also loads any zone files (*.db) found in its directory and
|
||||
serves them. Responses prepared using zone data can then be modified,
|
||||
replaced, or suppressed by query handlers. Query handlers can also generate
|
||||
response from scratch, without using zone data at all.
|
||||
"""
|
||||
|
||||
def __init__(self, load_zones: bool = True):
|
||||
super().__init__(self._handle_udp, self._handle_tcp, "ans.pid")
|
||||
|
||||
self._zone_tree: _ZoneTree = _ZoneTree()
|
||||
self._response_handlers: List[ResponseHandler] = []
|
||||
|
||||
if load_zones:
|
||||
self._load_zones()
|
||||
|
||||
def install_response_handler(self, handler: ResponseHandler) -> None:
|
||||
"""
|
||||
Add a response handler which will be used to handle matching queries.
|
||||
|
||||
Response handlers can modify, replace, or suppress the answers prepared
|
||||
from zone file contents.
|
||||
"""
|
||||
logging.info("Installing response handler: %s", handler)
|
||||
self._response_handlers.append(handler)
|
||||
|
||||
def _load_zones(self) -> None:
|
||||
for entry in os.scandir():
|
||||
entry_path = pathlib.Path(entry.path)
|
||||
if entry_path.suffix != ".db":
|
||||
continue
|
||||
origin = dns.name.from_text(entry_path.stem)
|
||||
logging.info("Loading zone file %s", entry_path)
|
||||
zone = dns.zone.from_file(entry.path, origin, relativize=False)
|
||||
self._zone_tree.add(zone)
|
||||
|
||||
async def _handle_udp(
|
||||
self, wire: bytes, peer: Tuple[str, int], transport: asyncio.DatagramTransport
|
||||
) -> None:
|
||||
logging.debug("Received UDP message: %s", wire.hex())
|
||||
responses = self._handle_query(wire, peer, DnsProtocol.UDP)
|
||||
async for response in responses:
|
||||
transport.sendto(response, peer)
|
||||
|
||||
async def _handle_tcp(
|
||||
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
|
||||
) -> None:
|
||||
wire_length_bytes = await reader.read(2)
|
||||
(wire_length,) = struct.unpack("!H", wire_length_bytes)
|
||||
logging.debug("Receiving TCP message (%d octets)...", wire_length)
|
||||
|
||||
wire = await reader.read(wire_length)
|
||||
full_message = wire_length_bytes + wire
|
||||
logging.debug("Received complete TCP message: %s", full_message.hex())
|
||||
|
||||
peer = writer.get_extra_info("peername")
|
||||
responses = self._handle_query(wire, peer, DnsProtocol.TCP)
|
||||
async for response in responses:
|
||||
writer.write(response)
|
||||
try:
|
||||
await writer.drain()
|
||||
except ConnectionResetError:
|
||||
logging.error(
|
||||
"TCP connection from %s reset by peer", self._format_peer(peer)
|
||||
)
|
||||
return
|
||||
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
|
||||
def _format_peer(self, peer: Tuple[str, int]) -> str:
|
||||
host = peer[0]
|
||||
port = peer[1]
|
||||
if "::" in host:
|
||||
host = f"[{host}]"
|
||||
return f"{host}:{port}"
|
||||
|
||||
def _log_query(
|
||||
self, qctx: QueryContext, peer: Tuple[str, int], protocol: DnsProtocol
|
||||
) -> None:
|
||||
logging.info(
|
||||
"Received %s/%s/%s (ID=%d) query from %s (%s)",
|
||||
qctx.qname.to_text(omit_final_dot=True),
|
||||
dns.rdataclass.to_text(qctx.qclass),
|
||||
dns.rdatatype.to_text(qctx.qtype),
|
||||
qctx.query.id,
|
||||
self._format_peer(peer),
|
||||
protocol.name,
|
||||
)
|
||||
logging.debug(
|
||||
"\n".join([f"[IN] {l}" for l in [""] + str(qctx.query).splitlines()])
|
||||
)
|
||||
|
||||
def _log_response(
|
||||
self,
|
||||
qctx: QueryContext,
|
||||
response: Optional[Union[dns.message.Message, bytes]],
|
||||
peer: Tuple[str, int],
|
||||
protocol: DnsProtocol,
|
||||
) -> None:
|
||||
if not response:
|
||||
logging.info(
|
||||
"Not sending a response to query (ID=%d) from %s (%s)",
|
||||
qctx.query.id,
|
||||
self._format_peer(peer),
|
||||
protocol.name,
|
||||
)
|
||||
return
|
||||
|
||||
if isinstance(response, dns.message.Message):
|
||||
try:
|
||||
qname = response.question[0].name.to_text(omit_final_dot=True)
|
||||
qclass = dns.rdataclass.to_text(response.question[0].rdclass)
|
||||
qtype = dns.rdatatype.to_text(response.question[0].rdtype)
|
||||
except IndexError:
|
||||
qname = "<empty>"
|
||||
qclass = "-"
|
||||
qtype = "-"
|
||||
|
||||
logging.info(
|
||||
"Sending %s/%s/%s (ID=%d) response (%d/%d/%d/%d) to a query (ID=%d) from %s (%s)",
|
||||
qname,
|
||||
qclass,
|
||||
qtype,
|
||||
response.id,
|
||||
len(response.question),
|
||||
len(response.answer),
|
||||
len(response.authority),
|
||||
len(response.additional),
|
||||
qctx.query.id,
|
||||
self._format_peer(peer),
|
||||
protocol.name,
|
||||
)
|
||||
logging.debug(
|
||||
"\n".join([f"[OUT] {l}" for l in [""] + str(response).splitlines()])
|
||||
)
|
||||
return
|
||||
|
||||
logging.info(
|
||||
"Sending response (%d bytes) to a query (ID=%d) from %s (%s)",
|
||||
len(response),
|
||||
qctx.query.id,
|
||||
self._format_peer(peer),
|
||||
protocol.name,
|
||||
)
|
||||
logging.debug("[OUT] %s", response.hex())
|
||||
|
||||
async def _handle_query(
|
||||
self, wire: bytes, peer: Tuple[str, int], protocol: DnsProtocol
|
||||
) -> AsyncGenerator[bytes, None]:
|
||||
"""
|
||||
Yield wire data to send as a response over the established transport.
|
||||
"""
|
||||
query = dns.message.from_wire(wire)
|
||||
response_stub = dns.message.make_response(query)
|
||||
qctx = QueryContext(query, response_stub, peer, protocol)
|
||||
self._log_query(qctx, peer, protocol)
|
||||
responses = self._prepare_responses(qctx)
|
||||
async for response in responses:
|
||||
self._log_response(qctx, response, peer, protocol)
|
||||
if response:
|
||||
if isinstance(response, dns.message.Message):
|
||||
response = response.to_wire(max_size=65535)
|
||||
if protocol == DnsProtocol.UDP:
|
||||
yield response
|
||||
else:
|
||||
response_length = struct.pack("!H", len(response))
|
||||
yield response_length + response
|
||||
|
||||
async def _prepare_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[Optional[Union[dns.message.Message, bytes]], None]:
|
||||
"""
|
||||
Yield response(s) either from response handlers or zone data.
|
||||
"""
|
||||
self._prepare_response_from_zone_data(qctx)
|
||||
|
||||
response_handled = False
|
||||
async for action in self._run_response_handlers(qctx):
|
||||
yield await action.perform()
|
||||
response_handled = True
|
||||
|
||||
if not response_handled:
|
||||
yield qctx.response
|
||||
|
||||
def _prepare_response_from_zone_data(self, qctx: QueryContext) -> None:
|
||||
"""
|
||||
Prepare a response to the query based on the available zone data.
|
||||
|
||||
The functionality is split across smaller functions that modify the
|
||||
query context until a proper response is formed.
|
||||
"""
|
||||
if self._refused_response(qctx):
|
||||
return
|
||||
|
||||
if self._delegation_response(qctx):
|
||||
return
|
||||
|
||||
qctx.response.flags |= dns.flags.AA
|
||||
|
||||
if self._ent_response(qctx):
|
||||
return
|
||||
|
||||
if self._nxdomain_response(qctx):
|
||||
return
|
||||
|
||||
if self._nodata_response(qctx):
|
||||
return
|
||||
|
||||
self._noerror_response(qctx)
|
||||
|
||||
def _refused_response(self, qctx: QueryContext) -> bool:
|
||||
qctx.zone = self._zone_tree.find_best_zone(qctx.qname)
|
||||
if qctx.zone:
|
||||
return False
|
||||
|
||||
qctx.response.set_rcode(dns.rcode.REFUSED)
|
||||
return True
|
||||
|
||||
def _delegation_response(self, qctx: QueryContext) -> bool:
|
||||
assert qctx.zone
|
||||
|
||||
name = qctx.qname
|
||||
delegation = None
|
||||
|
||||
while name != qctx.zone.origin:
|
||||
node = qctx.zone.get_node(name)
|
||||
if node:
|
||||
delegation = node.get_rdataset(qctx.qclass, dns.rdatatype.NS)
|
||||
if delegation:
|
||||
break
|
||||
name = name.parent()
|
||||
|
||||
if not delegation:
|
||||
return False
|
||||
|
||||
delegation_rrset = dns.rrset.RRset(name, qctx.qclass, dns.rdatatype.NS)
|
||||
delegation_rrset.update(delegation)
|
||||
|
||||
qctx.response.set_rcode(dns.rcode.NOERROR)
|
||||
qctx.response.authority.append(delegation_rrset)
|
||||
|
||||
self._delegation_response_additional(qctx)
|
||||
|
||||
return True
|
||||
|
||||
def _delegation_response_additional(self, qctx: QueryContext) -> None:
|
||||
assert qctx.zone
|
||||
assert qctx.response.authority[0]
|
||||
|
||||
for nameserver in qctx.response.authority[0]:
|
||||
if not nameserver.target.is_subdomain(qctx.response.authority[0].name):
|
||||
continue
|
||||
glue_a = qctx.zone.get_rrset(nameserver.target, dns.rdatatype.A)
|
||||
if glue_a:
|
||||
qctx.response.additional.append(glue_a)
|
||||
glue_aaaa = qctx.zone.get_rrset(nameserver.target, dns.rdatatype.AAAA)
|
||||
if glue_aaaa:
|
||||
qctx.response.additional.append(glue_aaaa)
|
||||
|
||||
def _ent_response(self, qctx: QueryContext) -> bool:
|
||||
assert qctx.zone
|
||||
assert qctx.zone.origin
|
||||
|
||||
qctx.soa = qctx.zone.find_rrset(qctx.zone.origin, dns.rdatatype.SOA)
|
||||
assert qctx.soa
|
||||
|
||||
qctx.node = qctx.zone.get_node(qctx.qname)
|
||||
if qctx.node or not any(
|
||||
n for n in qctx.zone.nodes if n.is_subdomain(qctx.qname)
|
||||
):
|
||||
return False
|
||||
|
||||
qctx.response.set_rcode(dns.rcode.NOERROR)
|
||||
qctx.response.authority.append(qctx.soa)
|
||||
return True
|
||||
|
||||
def _nxdomain_response(self, qctx: QueryContext) -> bool:
|
||||
assert qctx.soa
|
||||
|
||||
if qctx.node:
|
||||
return False
|
||||
|
||||
qctx.response.set_rcode(dns.rcode.NXDOMAIN)
|
||||
qctx.response.authority.append(qctx.soa)
|
||||
return True
|
||||
|
||||
def _nodata_response(self, qctx: QueryContext) -> bool:
|
||||
assert qctx.node
|
||||
assert qctx.soa
|
||||
|
||||
qctx.answer = qctx.node.get_rdataset(qctx.qclass, qctx.qtype)
|
||||
if qctx.answer:
|
||||
return False
|
||||
|
||||
qctx.response.set_rcode(dns.rcode.NOERROR)
|
||||
qctx.response.authority.append(qctx.soa)
|
||||
return True
|
||||
|
||||
def _noerror_response(self, qctx: QueryContext) -> None:
|
||||
assert qctx.answer
|
||||
|
||||
answer_rrset = dns.rrset.RRset(qctx.qname, qctx.qclass, qctx.qtype)
|
||||
answer_rrset.update(qctx.answer)
|
||||
|
||||
qctx.response.set_rcode(dns.rcode.NOERROR)
|
||||
qctx.response.answer.append(answer_rrset)
|
||||
|
||||
async def _run_response_handlers(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[ResponseAction, None]:
|
||||
"""
|
||||
Yield response(s) to the query from a matching query handler.
|
||||
"""
|
||||
for handler in self._response_handlers:
|
||||
if handler.match(qctx):
|
||||
async for response in handler.get_responses(qctx):
|
||||
yield response
|
||||
return
|
||||
@@ -9,11 +9,13 @@
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from typing import Any
|
||||
from typing import Any, Optional
|
||||
|
||||
import dns.rcode
|
||||
import dns.message
|
||||
import dns.zone
|
||||
|
||||
import isctest.log
|
||||
|
||||
# compatiblity with dnspython<2.0.0
|
||||
try:
|
||||
@@ -38,8 +40,58 @@ def servfail(message: dns.message.Message) -> None:
|
||||
rcode(message, dns_rcode.SERVFAIL)
|
||||
|
||||
|
||||
def rrsets_equal(first_rrset: dns.rrset.RRset, second_rrset: dns.rrset.RRset) -> None:
|
||||
def rrsets_equal(
|
||||
first_rrset: dns.rrset.RRset,
|
||||
second_rrset: dns.rrset.RRset,
|
||||
compare_ttl: Optional[bool] = False,
|
||||
) -> None:
|
||||
"""Compare two RRset (optionally including TTL)"""
|
||||
|
||||
def compare_rrs(rr1, rrset):
|
||||
rr2 = next((other_rr for other_rr in rrset if rr1 == other_rr), None)
|
||||
assert rr2 is not None, f"No corresponding RR found for: {rr1}"
|
||||
if compare_ttl:
|
||||
assert rr1.ttl == rr2.ttl
|
||||
|
||||
isctest.log.debug(
|
||||
"%s() first RRset:\n%s",
|
||||
rrsets_equal.__name__,
|
||||
"\n".join([str(rr) for rr in first_rrset]),
|
||||
)
|
||||
isctest.log.debug(
|
||||
"%s() second RRset:\n%s",
|
||||
rrsets_equal.__name__,
|
||||
"\n".join([str(rr) for rr in second_rrset]),
|
||||
)
|
||||
for rr in first_rrset:
|
||||
assert rr in second_rrset
|
||||
compare_rrs(rr, second_rrset)
|
||||
for rr in second_rrset:
|
||||
assert rr in first_rrset
|
||||
compare_rrs(rr, first_rrset)
|
||||
|
||||
|
||||
def zones_equal(
|
||||
first_zone: dns.zone.Zone,
|
||||
second_zone: dns.zone.Zone,
|
||||
compare_ttl: Optional[bool] = False,
|
||||
) -> None:
|
||||
"""Compare two zones (optionally including TTL)"""
|
||||
|
||||
isctest.log.debug(
|
||||
"%s() first zone:\n%s",
|
||||
zones_equal.__name__,
|
||||
first_zone.to_text(relativize=False),
|
||||
)
|
||||
isctest.log.debug(
|
||||
"%s() second zone:\n%s",
|
||||
zones_equal.__name__,
|
||||
second_zone.to_text(relativize=False),
|
||||
)
|
||||
assert first_zone == second_zone
|
||||
if compare_ttl:
|
||||
for name, node in first_zone.nodes.items():
|
||||
for rdataset in node:
|
||||
found_rdataset = second_zone.find_rdataset(
|
||||
name=name, rdtype=rdataset.rdtype
|
||||
)
|
||||
assert found_rdataset
|
||||
assert found_rdataset.ttl == rdataset.ttl
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from .basic import (
|
||||
avoid_duplicated_logs,
|
||||
deinit_module_logger,
|
||||
deinit_test_logger,
|
||||
init_conftest_logger,
|
||||
init_module_logger,
|
||||
init_test_logger,
|
||||
debug,
|
||||
|
||||
@@ -53,10 +53,6 @@ def avoid_duplicated_logs():
|
||||
logging.root.handlers.remove(handler)
|
||||
|
||||
|
||||
init_conftest_logger()
|
||||
avoid_duplicated_logs()
|
||||
|
||||
|
||||
def init_module_logger(system_test_name: str, testdir: Path):
|
||||
logger = logging.getLogger(system_test_name)
|
||||
logger.handlers.clear()
|
||||
|
||||
@@ -11,4 +11,21 @@
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
rm -f classlist.out privatelist.out typelist.out tempzone checkzone.out* checker.out
|
||||
set -e
|
||||
|
||||
rm -f ./*.ksk*
|
||||
rm -f ./*.zsk*
|
||||
rm -f ./created.out
|
||||
rm -f ./footer.*
|
||||
rm -f ./keygen.out.*
|
||||
rm -f ./named.conf
|
||||
rm -f ./now.out
|
||||
rm -rf ./offline
|
||||
rm -f ./python.out
|
||||
rm -f ./settime.out.*
|
||||
rm -f ./K*
|
||||
rm -rf ./keydir
|
||||
rm -f ./ksr.*.err.*
|
||||
rm -f ./ksr.*.expect
|
||||
rm -f ./ksr.*.expect.*
|
||||
rm -f ./ksr.*.out.*
|
||||
@@ -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 "common" {
|
||||
keys {
|
||||
ksk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
zsk lifetime P6M algorithm @DEFAULT_ALGORITHM@;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "csk" {
|
||||
keys {
|
||||
csk lifetime P6M algorithm @DEFAULT_ALGORITHM@;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "unlimited" {
|
||||
keys {
|
||||
ksk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
zsk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "no-cdnskey" {
|
||||
keys {
|
||||
ksk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
zsk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
};
|
||||
cdnskey no;
|
||||
cds-digest-types { SHA-1; SHA-256; SHA-384; };
|
||||
};
|
||||
|
||||
dnssec-policy "no-cds" {
|
||||
keys {
|
||||
ksk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
zsk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
};
|
||||
cds-digest-types { };
|
||||
};
|
||||
|
||||
dnssec-policy "two-tone" {
|
||||
keys {
|
||||
ksk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
ksk lifetime unlimited algorithm @ALTERNATIVE_ALGORITHM@;
|
||||
zsk lifetime P3M algorithm @DEFAULT_ALGORITHM@;
|
||||
zsk lifetime P5M algorithm @ALTERNATIVE_ALGORITHM@;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/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.
|
||||
|
||||
# shellcheck source=conf.sh
|
||||
. ../conf.sh
|
||||
|
||||
set -e
|
||||
|
||||
$SHELL clean.sh
|
||||
|
||||
mkdir keydir
|
||||
mkdir offline
|
||||
|
||||
copy_setports named.conf.in named.conf
|
||||
|
||||
# Create KSK for the various policies.
|
||||
create_ksk() {
|
||||
KSK=$($KEYGEN -l named.conf -fK -k $2 $1 2>keygen.out.$1)
|
||||
num=0
|
||||
for ksk in $KSK; do
|
||||
num=$(($num + 1))
|
||||
echo $ksk >"${1}.ksk${num}.id"
|
||||
cat "${ksk}.key" | grep -v ";.*" >"$1.ksk$num"
|
||||
cp "${ksk}.key" offline/
|
||||
cp "${ksk}.private" offline/
|
||||
done
|
||||
}
|
||||
create_ksk common.test common
|
||||
create_ksk unlimited.test unlimited
|
||||
create_ksk two-tone.test two-tone
|
||||
@@ -0,0 +1,806 @@
|
||||
#!/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 source=conf.sh
|
||||
. ../conf.sh
|
||||
# shellcheck source=kasp.sh
|
||||
. ../kasp.sh
|
||||
|
||||
set -e
|
||||
|
||||
CDS_SHA1="no"
|
||||
CDS_SHA256="yes"
|
||||
CDS_SHA384="no"
|
||||
CDNSKEY="yes"
|
||||
|
||||
status=0
|
||||
n=0
|
||||
|
||||
# Get timing metadata from a value plus additional time.
|
||||
# $1: Value
|
||||
# $2: Additional time
|
||||
addtime() {
|
||||
if [ -x "$PYTHON" ]; then
|
||||
# Convert "%Y%m%d%H%M%S" format to epoch seconds.
|
||||
# Then, add the additional time (can be negative).
|
||||
_value=$1
|
||||
_plus=$2
|
||||
$PYTHON >python.out <<EOF
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
_now = datetime.strptime("$_value", "%Y%m%d%H%M%S")
|
||||
_delta = timedelta(seconds=$_plus)
|
||||
_then = _now + _delta
|
||||
print(_then.strftime("%Y%m%d%H%M%S"));
|
||||
EOF
|
||||
cat python.out
|
||||
fi
|
||||
}
|
||||
|
||||
# Check keys that were created. The keys created are listed in the latest ksr
|
||||
# output file, ksr.keygen.out.$n.
|
||||
# $1: zone name
|
||||
# $2: key directory
|
||||
check_keys() (
|
||||
zone=$1
|
||||
dir=$2
|
||||
lifetime=$LIFETIME
|
||||
alg=$ALG
|
||||
size=$SIZE
|
||||
inception=0
|
||||
pad=$(printf "%03d" "$alg")
|
||||
|
||||
num=0
|
||||
for key in $(grep "K${zone}.+$pad+" ksr.keygen.out.$n); do
|
||||
grep "; Created:" "${dir}/${key}.key" >created.out || return 1
|
||||
created=$(awk '{print $3}' <created.out)
|
||||
test "$num" -eq 0 && retired=$created
|
||||
# active: retired previous key
|
||||
active=$retired
|
||||
# published: 2h5m (dnskey-ttl + publish-safety + propagation)
|
||||
published=$(addtime $active -7500)
|
||||
# retired: zsk-lifetime
|
||||
retired=$(addtime $active $lifetime)
|
||||
# removed: 10d1h5m (ttlsig + retire-safety + sign-delay + propagation)
|
||||
removed=$(addtime $retired 867900)
|
||||
|
||||
echo_i "check metadata on $key"
|
||||
statefile="${dir}/${key}.state"
|
||||
grep "Algorithm: $alg" $statefile >/dev/null || return 1
|
||||
grep "Length: $size" $statefile >/dev/null || return 1
|
||||
grep "Lifetime: $lifetime" $statefile >/dev/null || return 1
|
||||
grep "KSK: no" $statefile >/dev/null || return 1
|
||||
grep "ZSK: yes" $statefile >/dev/null || return 1
|
||||
grep "Published: $published" $statefile >/dev/null || return 1
|
||||
grep "Active: $active" $statefile >/dev/null || return 1
|
||||
grep "Retired: $retired" $statefile >/dev/null || return 1
|
||||
grep "Removed: $removed" $statefile >/dev/null || return 1
|
||||
|
||||
inception=$((inception + lifetime))
|
||||
num=$((num + 1))
|
||||
|
||||
# Save some information for testing
|
||||
cp ${dir}/${key}.key ${key}.key.expect
|
||||
cp ${dir}/${key}.private ${key}.private.expect
|
||||
cp ${dir}/${key}.state ${key}.state.expect
|
||||
cat ${dir}/${key}.key | grep -v ";.*" >"${zone}.${alg}.zsk${num}"
|
||||
echo $key >"${zone}.${alg}.zsk${num}.id"
|
||||
done
|
||||
|
||||
return 0
|
||||
)
|
||||
|
||||
# Print the DNSKEY records for zone $1, which have keys listed in file $5
|
||||
# that match the keys with numbers $2 and $3, and match algorithm number $4,
|
||||
# sorted by keytag.
|
||||
print_dnskeys() {
|
||||
for key in $(cat $5 | sort); do
|
||||
for num in $2 $3; do
|
||||
zsk=$(cat $1.$4.zsk$num.id)
|
||||
if [ "$key" = "$zsk" ]; then
|
||||
cat $1.$4.zsk$num >>ksr.request.expect.$n
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
# Call the dnssec-ksr command:
|
||||
# ksr <policy> [options] <command> <zone>
|
||||
ksr() {
|
||||
$KSR -l named.conf -k "$@"
|
||||
}
|
||||
|
||||
# Unknown action.
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr' errors on unknown action ($n)"
|
||||
ret=0
|
||||
ksr common foobar common.test >ksr.foobar.out.$n 2>&1 && ret=1
|
||||
grep "dnssec-ksr: fatal: unknown command 'foobar'" ksr.foobar.out.$n >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Key generation: common
|
||||
set_zsk() {
|
||||
ALG=$1
|
||||
SIZE=$2
|
||||
LIFETIME=$3
|
||||
}
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr keygen' errors on missing end date ($n)"
|
||||
ret=0
|
||||
ksr common keygen common.test >ksr.keygen.out.$n 2>&1 && ret=1
|
||||
grep "dnssec-ksr: fatal: keygen requires an end date" ksr.keygen.out.$n >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr keygen' pregenerates right amount of keys in the common case ($n)"
|
||||
ret=0
|
||||
ksr common -i now -e +1y keygen common.test >ksr.keygen.out.$n 2>&1 || ret=1
|
||||
num=$(cat ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 2 ] || ret=1
|
||||
set_zsk $DEFAULT_ALGORITHM_NUMBER $DEFAULT_BITS 16070400
|
||||
check_keys common.test "." || ret=1
|
||||
cp ksr.keygen.out.$n ksr.keygen.out.expect
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
# save now time
|
||||
key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id)
|
||||
grep "; Created:" "${key}.key" >now.out || ret=1
|
||||
now=$(awk '{print $3}' <now.out)
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr keygen' selects pregenerated keys for the same time bundle ($n)"
|
||||
ret=0
|
||||
ksr common -e +1y keygen common.test >ksr.keygen.out.$n 2>&1 || ret=1
|
||||
diff -w ksr.keygen.out.expect ksr.keygen.out.$n >/dev/null || ret=1
|
||||
for key in $(cat ksr.keygen.out.$n); do
|
||||
# Ensure the files are not modified.
|
||||
diff ${key}.key ${key}.key.expect >/dev/null || ret=1
|
||||
diff ${key}.private ${key}.private.expect >/dev/null || ret=1
|
||||
diff ${key}.state ${key}.state.expect >/dev/null || ret=1
|
||||
done
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Create request: common
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr request' errors on missing end date ($n)"
|
||||
ret=0
|
||||
ksr common request common.test >ksr.request.out.$n 2>&1 && ret=1
|
||||
grep "dnssec-ksr: fatal: request requires an end date" ksr.request.out.$n >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr request' creates correct KSR in the common case ($n)"
|
||||
ret=0
|
||||
ksr common -i $now -e +1y request common.test >ksr.request.out.$n 2>&1 || ret=1
|
||||
# Bundle 1: KSK + ZSK1
|
||||
key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id)
|
||||
inception=$(cat $key.state | grep "Generated" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >ksr.request.expect.$n
|
||||
cat common.test.ksk1 >>ksr.request.expect.$n
|
||||
cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n
|
||||
# Bundle 2: KSK + ZSK1 + ZSK2
|
||||
key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk2.id)
|
||||
inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat common.test.ksk1 >>ksr.request.expect.$n
|
||||
print_dnskeys common.test 1 2 $DEFAULT_ALGORITHM_NUMBER ksr.keygen.out.expect
|
||||
# Bundle 3: KSK + ZSK2
|
||||
key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id)
|
||||
inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat common.test.ksk1 >>ksr.request.expect.$n
|
||||
cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n
|
||||
# Footer
|
||||
cp ksr.request.expect.$n ksr.request.expect.base
|
||||
grep ";; KeySigningRequest generated at" ksr.request.out.$n >footer.$n || ret=1
|
||||
cat footer.$n >>ksr.request.expect.$n
|
||||
# Check if request output is the same as expected.
|
||||
diff -w ksr.request.out.$n ksr.request.expect.$n >/dev/null || ret=1
|
||||
# Save request for ksr sign operation.
|
||||
cp ksr.request.expect.$n ksr.request.expect
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Sign request: common
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr sign' errors on missing KSR file ($n)"
|
||||
ret=0
|
||||
ksr common -i $now -e +1y sign common.test >ksr.sign.out.$n 2>&1 && ret=1
|
||||
grep "dnssec-ksr: fatal: 'sign' requires a KSR file" ksr.sign.out.$n >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr sign' creates correct SKR in the common case ($n)"
|
||||
ret=0
|
||||
ksr common -i $now -e +1y -K offline -f ksr.request.expect sign common.test >ksr.sign.out.$n 2>&1 || ret=1
|
||||
|
||||
_update_expected_zsks() {
|
||||
zsk=$((zsk + 1))
|
||||
next=$((next + 1))
|
||||
inception=$rollover_done
|
||||
if [ "$next" -le "$numzsks" ]; then
|
||||
key1="${zone}.${DEFAULT_ALGORITHM_NUMBER}.zsk${zsk}"
|
||||
key2="${zone}.${DEFAULT_ALGORITHM_NUMBER}.zsk${next}"
|
||||
zsk1=$(cat $key1.id)
|
||||
zsk2=$(cat $key2.id)
|
||||
rollover_start=$(cat $zsk2.state | grep "Published" | awk '{print $2}')
|
||||
rollover_done=$(cat $zsk1.state | grep "Removed" | awk '{print $2}')
|
||||
else
|
||||
# No more expected rollovers.
|
||||
key1="${zone}.${DEFAULT_ALGORITHM_NUMBER}.zsk${zsk}"
|
||||
zsk1=$(cat $key1.id)
|
||||
rollover_start=$((end + 1))
|
||||
rollover_done=$((end + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
check_ksr() {
|
||||
_ret=0
|
||||
zone=$1
|
||||
file=$2
|
||||
start=$3
|
||||
end=$4
|
||||
numzsks=$5
|
||||
cds1=$($DSFROMKEY -T 3600 -a SHA-1 -C -w $(cat "${zone}.ksk1.id"))
|
||||
cds2=$($DSFROMKEY -T 3600 -a SHA-256 -C -w $(cat "${zone}.ksk1.id"))
|
||||
cds4=$($DSFROMKEY -T 3600 -a SHA-384 -C -w $(cat "${zone}.ksk1.id"))
|
||||
cdnskey=$(awk '{sub(/DNSKEY/,"CDNSKEY")}1' <${zone}.ksk1)
|
||||
|
||||
echo_i "check ksr: zone $1 file $2 from $3 to $4 num-zsk $5"
|
||||
|
||||
# Initial state: not in a rollover, expect a SignedKeyResponse header
|
||||
# on the first line, start with the first ZSK (set zsk=0 so when we
|
||||
# call _update_expected_zsks, zsk is set to 1.
|
||||
rollover=0
|
||||
expect="header"
|
||||
zsk=0
|
||||
next=1
|
||||
rollover_done=$start
|
||||
_update_expected_zsks
|
||||
|
||||
echo_i "check ksr: inception $inception rollover-start $rollover_start rollover-done $rollover_done"
|
||||
|
||||
lineno=0
|
||||
complete=0
|
||||
while IFS= read -r line; do
|
||||
# A single signed key response may consist of:
|
||||
# ;; SignedKeyResponse (header)
|
||||
# ;; DNSKEY 257 (ksk)
|
||||
# ;; one or two (during rollover) DNSKEY 256 (zsk1, zsk2)
|
||||
# ;; RRSIG(DNSKEY) (rrsig-dnskey)
|
||||
# ;; CDNSKEY (cdnskey)
|
||||
# ;; RRSIG(CDNSKEY) (rrsig-cdnskey)
|
||||
# ;; CDS (cds)
|
||||
# ;; RRSIG(CDS) (rrsig-cds)
|
||||
err=0
|
||||
lineno=$((lineno + 1))
|
||||
|
||||
# skip empty lines
|
||||
if [ -z "$line" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$expect" = "header" ]; then
|
||||
expected=";; SignedKeyResponse 1.0 $inception"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
next_inception=$(addtime $inception 777600)
|
||||
expect="ksk"
|
||||
elif [ "$expect" = "ksk" ]; then
|
||||
expected="$(cat ${zone}.ksk1)"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
expect="zsk1"
|
||||
elif [ "$expect" = "cdnskey" ]; then
|
||||
expected="$cdnskey"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
expect="rrsig-cdnskey"
|
||||
elif [ "$expect" = "cds1" ]; then
|
||||
expected="$cds1"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
if [ "$CDS_SHA256" = "yes" ]; then
|
||||
expect="cds2"
|
||||
elif [ "$CDS_SHA384" = "yes" ]; then
|
||||
expect="cds4"
|
||||
else
|
||||
expect="rrsig-cds"
|
||||
fi
|
||||
elif [ "$expect" = "cds2" ]; then
|
||||
expected="$cds2"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
if [ "$CDS_SHA384" = "yes" ]; then
|
||||
expect="cds4"
|
||||
else
|
||||
expect="rrsig-cds"
|
||||
fi
|
||||
elif [ "$expect" = "cds4" ]; then
|
||||
expected="$cds4"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
expect="rrsig-cds"
|
||||
elif [ "$expect" = "zsk1" ]; then
|
||||
expected="$(cat $key1)"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
expect="rrsig-dnskey"
|
||||
[ "$rollover" -eq 1 ] && expect="zsk2"
|
||||
elif [ "$expect" = "zsk2" ]; then
|
||||
expected="$(cat $key2)"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
expect="rrsig-dnskey"
|
||||
elif [ "$expect" = "rrsig-dnskey" ]; then
|
||||
exp=$(addtime $inception 1209600) # signature-validity 14 days
|
||||
inc=$(addtime $inception -3600) # adjust for one hour clock skew
|
||||
expected="${zone}. 3600 IN RRSIG DNSKEY 13 2 3600 $exp $inc"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
if [ "$CDNSKEY" = "yes" ]; then
|
||||
expect="cdnskey"
|
||||
elif [ "$CDS_SHA1" = "yes" ]; then
|
||||
expect="cds1"
|
||||
elif [ "$CDS_SHA256" = "yes" ]; then
|
||||
expect="cds2"
|
||||
elif [ "$CDS_SHA384" = "yes" ]; then
|
||||
expect="cds4"
|
||||
else
|
||||
complete=1
|
||||
fi
|
||||
elif [ "$expect" = "rrsig-cdnskey" ]; then
|
||||
exp=$(addtime $inception 1209600) # signature-validity 14 days
|
||||
inc=$(addtime $inception -3600) # adjust for one hour clock skew
|
||||
expected="${zone}. 3600 IN RRSIG CDNSKEY 13 2 3600 $exp $inc"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
if [ "$CDS_SHA1" = "yes" ]; then
|
||||
expect="cds1"
|
||||
elif [ "$CDS_SHA256" = "yes" ]; then
|
||||
expect="cds2"
|
||||
elif [ "$CDS_SHA384" = "yes" ]; then
|
||||
expect="cds4"
|
||||
else
|
||||
complete=1
|
||||
fi
|
||||
elif [ "$expect" = "rrsig-cds" ]; then
|
||||
exp=$(addtime $inception 1209600) # signature-validity 14 days
|
||||
inc=$(addtime $inception -3600) # adjust for one hour clock skew
|
||||
expected="${zone}. 3600 IN RRSIG CDS 13 2 3600 $exp $inc"
|
||||
echo $line | grep "$expected" >/dev/null || err=1
|
||||
complete=1
|
||||
elif [ "$expect" = "footer" ]; then
|
||||
expected=";; SignedKeyResponse 1.0 generated at"
|
||||
echo "$(echo $line | tr -s ' ')" | grep "$expected" >/dev/null || err=1
|
||||
|
||||
expect="eof"
|
||||
elif [ "$expect" = "eof" ]; then
|
||||
expected="EOF"
|
||||
echo_i "failed: expected EOF"
|
||||
err=1
|
||||
else
|
||||
echo_i "failed: bad expect value $expect"
|
||||
err=1
|
||||
fi
|
||||
|
||||
echo "$(echo $line | tr -s ' ')" | grep "$expected" >/dev/null || err=1
|
||||
if [ "$err" -ne 0 ]; then
|
||||
echo_i "unexpected data on line $lineno:"
|
||||
echo_i "line: $(echo $line | tr -s ' ')"
|
||||
echo_i "expected: $expected"
|
||||
fi
|
||||
|
||||
if [ "$complete" -eq 1 ]; then
|
||||
inception=$next_inception
|
||||
expect="header"
|
||||
|
||||
# Update rollover status if required.
|
||||
if [ "$inception" -ge "$end" ]; then
|
||||
expect="footer"
|
||||
elif [ "$inception" -ge "$rollover_done" ]; then
|
||||
[ "$rollover" -eq 1 ] && inception=$rollover_done
|
||||
rollover=0
|
||||
_update_expected_zsks
|
||||
elif [ "$inception" -ge "$rollover_start" ]; then
|
||||
[ "$rollover" -eq 0 ] && inception=$rollover_start
|
||||
rollover=1
|
||||
# Keys will be sorted, so during a rollover a key with a
|
||||
# lower keytag will be printed first. Update key1/key2 and
|
||||
# zsk1/zsk2 accordingly.
|
||||
id1=$(keyfile_to_key_id "$zsk1")
|
||||
id2=$(keyfile_to_key_id "$zsk2")
|
||||
if [ $id1 -gt $id2 ]; then
|
||||
key1="${zone}.${DEFAULT_ALGORITHM_NUMBER}.zsk${next}"
|
||||
key2="${zone}.${DEFAULT_ALGORITHM_NUMBER}.zsk${zsk}"
|
||||
zsk1=$(cat $key1.id)
|
||||
zsk2=$(cat $key2.id)
|
||||
fi
|
||||
fi
|
||||
complete=0
|
||||
fi
|
||||
|
||||
_ret=$((_ret + err))
|
||||
test "$_ret" -eq 0 || exit $_ret
|
||||
done <$file
|
||||
|
||||
return $_ret
|
||||
}
|
||||
|
||||
zsk1=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id)
|
||||
start=$(cat $zsk1.state | grep "Generated" | awk '{print $2}')
|
||||
end=$(addtime $start 31536000) # one year
|
||||
check_ksr "common.test" "ksr.sign.out.$n" $start $end 2 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Key generation: common (2)
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr keygen' pregenerates keys in the given key-directory ($n)"
|
||||
ret=0
|
||||
ksr common -e +1y -K keydir keygen common.test >ksr.keygen.out.$n 2>&1 || ret=1
|
||||
num=$(cat ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 2 ] || ret=1
|
||||
set_zsk $DEFAULT_ALGORITHM_NUMBER $DEFAULT_BITS 16070400
|
||||
check_keys common.test keydir || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr keygen' selects generates only necessary keys for overlapping time bundle ($n)"
|
||||
ret=0
|
||||
ksr common -e +2y -v 1 keygen common.test >ksr.keygen.out.$n 2>&1 || ret=1
|
||||
num=$(cat ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 4 ] || ret=1
|
||||
# 2 selected, 2 generated
|
||||
num=$(grep "Selecting" ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 2 ] || ret=1
|
||||
num=$(grep "Generating" ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 2 ] || ret=1
|
||||
cp ksr.keygen.out.$n ksr.keygen.out.expect
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "run 'dnssec-ksr keygen' again with verbosity 0 ($n)"
|
||||
ret=0
|
||||
ksr common -i $now -e +2y keygen common.test >ksr.keygen.out.$n 2>&1 || ret=1
|
||||
num=$(cat ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 4 ] || ret=1
|
||||
set_zsk $DEFAULT_ALGORITHM_NUMBER $DEFAULT_BITS 16070400
|
||||
check_keys common.test "." || ret=1
|
||||
cp ksr.keygen.out.$n ksr.keygen.out.expect
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Create request: common (2)
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr request' creates correct KSR if the interval is shorter ($n)"
|
||||
ret=0
|
||||
ksr common -i $now -e +1y request common.test >ksr.request.out.$n 2>&1 || ret=1
|
||||
# Same as earlier.
|
||||
cp ksr.request.expect.base ksr.request.expect.$n
|
||||
grep ";; KeySigningRequest generated at" ksr.request.out.$n >footer.$n || ret=1
|
||||
cat footer.$n >>ksr.request.expect.$n
|
||||
diff -w ksr.request.out.$n ksr.request.expect.$n >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr request' creates correct KSR with new interval ($n)"
|
||||
ret=0
|
||||
ksr common -i $now -e +2y request common.test >ksr.request.out.$n 2>&1 || ret=1
|
||||
cp ksr.request.expect.base ksr.request.expect.$n
|
||||
# Bundle 4: KSK + ZSK2 + ZSK3
|
||||
key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk3.id)
|
||||
inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat common.test.ksk1 >>ksr.request.expect.$n
|
||||
print_dnskeys common.test 2 3 $DEFAULT_ALGORITHM_NUMBER ksr.keygen.out.expect
|
||||
# Bundle 5: KSK + ZSK3
|
||||
key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk2.id)
|
||||
inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat common.test.ksk1 >>ksr.request.expect.$n
|
||||
cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk3 >>ksr.request.expect.$n
|
||||
# Bundle 6: KSK + ZSK3 + ZSK4
|
||||
key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk4.id)
|
||||
inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat common.test.ksk1 >>ksr.request.expect.$n
|
||||
print_dnskeys common.test 3 4 $DEFAULT_ALGORITHM_NUMBER ksr.keygen.out.expect
|
||||
# Bundle 7: KSK + ZSK4
|
||||
key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk3.id)
|
||||
inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat common.test.ksk1 >>ksr.request.expect.$n
|
||||
cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk4 >>ksr.request.expect.$n
|
||||
# Footer
|
||||
cp ksr.request.expect.$n ksr.request.expect.base
|
||||
grep ";; KeySigningRequest generated at" ksr.request.out.$n >footer.$n || ret=1
|
||||
cat footer.$n >>ksr.request.expect.$n
|
||||
diff -w ksr.request.out.$n ksr.request.expect.$n >/dev/null || ret=1
|
||||
# Save request for ksr sign operation.
|
||||
cp ksr.request.expect.$n ksr.request.expect
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr request' errors if there are not enough keys ($n)"
|
||||
ret=0
|
||||
ksr common -i $now -e +3y request common.test >ksr.request.out.$n 2>ksr.request.err.$n && ret=1
|
||||
grep "dnssec-ksr: fatal: no common.test/ECDSAP256SHA256 zsk key pair found for bundle" ksr.request.err.$n >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Sign request: common (2)
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr sign' creates correct SKR with the new interval ($n)"
|
||||
ret=0
|
||||
ksr common -i $now -e +2y -K offline -f ksr.request.expect sign common.test >ksr.sign.out.$n 2>&1 || ret=1
|
||||
start=$(cat $zsk1.state | grep "Generated" | awk '{print $2}')
|
||||
end=$(addtime $start 63072000) # two years
|
||||
check_ksr "common.test" "ksr.sign.out.$n" $start $end 4 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Key generation: csk
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr keygen' creates no keys for policy with csk ($n)"
|
||||
ret=0
|
||||
ksr csk -e +2y keygen csk.test >ksr.keygen.out.$n 2>&1 && ret=1
|
||||
grep "dnssec-ksr: fatal: policy 'csk' has no zsks" ksr.keygen.out.$n >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Key generation: unlimited
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr keygen' creates only one key for zsk with unlimited lifetime ($n)"
|
||||
ret=0
|
||||
ksr unlimited -e +2y keygen unlimited.test >ksr.keygen.out.$n 2>&1 || ret=1
|
||||
num=$(cat ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 1 ] || ret=1
|
||||
key=$(cat ksr.keygen.out.$n)
|
||||
grep "; Created:" "${key}.key" >created.out || ret=1
|
||||
created=$(awk '{print $3}' <created.out)
|
||||
active=$created
|
||||
published=$(addtime $active -7500)
|
||||
echo_i "check metadata on $key"
|
||||
grep "Algorithm: $DEFAULT_ALGORITHM_NUMBER" ${key}.state >/dev/null || ret=1
|
||||
grep "Length: $DEFAULT_BITS" ${key}.state >/dev/null || ret=1
|
||||
grep "Lifetime: 0" ${key}.state >/dev/null || ret=1
|
||||
grep "KSK: no" ${key}.state >/dev/null || ret=1
|
||||
grep "ZSK: yes" ${key}.state >/dev/null || ret=1
|
||||
grep "Published: $published" ${key}.state >/dev/null || ret=1
|
||||
grep "Active: $active" ${key}.state >/dev/null || ret=1
|
||||
grep "Retired:" ${key}.state >/dev/null && ret=1
|
||||
grep "Removed:" ${key}.state >/dev/null && ret=1
|
||||
cat ${key}.key | grep -v ";.*" >unlimited.test.$DEFAULT_ALGORITHM_NUMBER.zsk1
|
||||
echo $key >"unlimited.test.${DEFAULT_ALGORITHM_NUMBER}.zsk1.id"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Create request: unlimited
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr request' creates correct KSR with unlimited zsk ($n)"
|
||||
ret=0
|
||||
ksr unlimited -i $created -e +4y request unlimited.test >ksr.request.out.$n 2>&1 || ret=1
|
||||
# Only one bundle: KSK + ZSK
|
||||
inception=$(cat $key.state | grep "Generated" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >ksr.request.expect.$n
|
||||
cat unlimited.test.ksk1 >>ksr.request.expect.$n
|
||||
cat unlimited.test.$DEFAULT_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n
|
||||
# Footer
|
||||
grep ";; KeySigningRequest generated at" ksr.request.out.$n >footer.$n || ret=1
|
||||
cat footer.$n >>ksr.request.expect.$n
|
||||
diff -w ksr.request.out.$n ksr.request.expect.$n >/dev/null || ret=1
|
||||
# Save request for ksr sign operation.
|
||||
cp ksr.request.expect.$n ksr.request.expect
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Sign request: unlimited
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr sign' creates correct SKR with unlimited zsk ($n)"
|
||||
ret=0
|
||||
ksr unlimited -i $created -e +4y -K offline -f ksr.request.expect sign unlimited.test >ksr.sign.out.$n 2>&1 || ret=1
|
||||
start=$(cat $key.state | grep "Generated" | awk '{print $2}')
|
||||
end=$(addtime $start 126144000) # four years
|
||||
check_ksr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Sign request: unlimited (no-cdnskey)
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr sign' creates correct SKR with unlimited zsk, no cdnskey ($n)"
|
||||
ret=0
|
||||
ksr no-cdnskey -i $created -e +4y -K offline -f ksr.request.expect sign unlimited.test >ksr.sign.out.$n 2>&1 || ret=1
|
||||
start=$(cat $key.state | grep "Generated" | awk '{print $2}')
|
||||
end=$(addtime $start 126144000) # four years
|
||||
CDNSKEY="no"
|
||||
CDS_SHA1="yes"
|
||||
CDS_SHA256="yes"
|
||||
CDS_SHA384="yes"
|
||||
check_ksr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Sign request: unlimited (no-cds)
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr sign' creates correct SKR with unlimited zsk, no cds ($n)"
|
||||
ret=0
|
||||
ksr no-cds -i $created -e +4y -K offline -f ksr.request.expect sign unlimited.test >ksr.sign.out.$n 2>&1 || ret=1
|
||||
start=$(cat $key.state | grep "Generated" | awk '{print $2}')
|
||||
end=$(addtime $start 126144000) # four years
|
||||
CDNSKEY="yes"
|
||||
CDS_SHA1="no"
|
||||
CDS_SHA256="no"
|
||||
CDS_SHA384="no"
|
||||
check_ksr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Reset CDS and CDNSKEY to default values
|
||||
CDNSKEY="yes"
|
||||
CDS_SHA1="no"
|
||||
CDS_SHA256="yes"
|
||||
CDS_SHA384="no"
|
||||
|
||||
# Key generation: two-tone
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr keygen' creates keys for different algorithms ($n)"
|
||||
ret=0
|
||||
ksr two-tone -e +1y keygen two-tone.test >ksr.keygen.out.$n 2>&1 || ret=1
|
||||
# First algorithm keys have a lifetime of 3 months, so there should be 4 created keys.
|
||||
alg=$(printf "%03d" "$DEFAULT_ALGORITHM_NUMBER")
|
||||
num=$(grep "Ktwo-tone.test.+$alg+" ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 4 ] || ret=1
|
||||
set_zsk $DEFAULT_ALGORITHM_NUMBER $DEFAULT_BITS 8035200
|
||||
check_keys two-tone.test "." || ret=1
|
||||
cp ksr.keygen.out.$n ksr.keygen.out.expect.$DEFAULT_ALGORITHM_NUMBER
|
||||
# Second algorithm keys have a lifetime of 5 months, so there should be 3 created keys.
|
||||
# While only two time bundles of 5 months fit into one year, we need to create an
|
||||
# extra key for the remainder of the bundle.
|
||||
alg=$(printf "%03d" "$ALTERNATIVE_ALGORITHM_NUMBER")
|
||||
num=$(grep "Ktwo-tone.test.+$alg+" ksr.keygen.out.$n | wc -l)
|
||||
[ $num -eq 3 ] || ret=1
|
||||
set_zsk $ALTERNATIVE_ALGORITHM_NUMBER $ALTERNATIVE_BITS 13392000
|
||||
check_keys two-tone.test "." $ALTERNATIVE_ALGORITHM_NUMBER 13392000 || ret=1
|
||||
cp ksr.keygen.out.$n ksr.keygen.out.expect.$ALTERNATIVE_ALGORITHM_NUMBER
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Create request: two-tone
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr request' creates correct KSR with multiple algorithms ($n)"
|
||||
ret=0
|
||||
key=$(cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id)
|
||||
grep "; Created:" "${key}.key" >created.out || ret=1
|
||||
created=$(awk '{print $3}' <created.out)
|
||||
ksr two-tone -i $created -e +6mo request two-tone.test >ksr.request.out.$n 2>&1 || ret=1
|
||||
# The two-tone policy uses two sets of KSK/ZSK with different algorithms. One
|
||||
# set uses the default algorithm (denoted as A below), the other is using the
|
||||
# alternative algorithm (denoted as B). The A-ZSKs roll every three months,
|
||||
# so in the second bundle there should be a new DNSKEY prepublished, and the
|
||||
# predecessor is removed in the third bundle. Then, after five months the
|
||||
# ZSK for the B set is rolled, adding the successor in bundle 4 and removing
|
||||
# its predecessor in bundle 5.
|
||||
#
|
||||
# Bundle 1: KSK-A1, KSK-B1, ZSK-A1, ZSK-B1
|
||||
key=$(cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id)
|
||||
inception=$(cat $key.state | grep "Generated" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >ksr.request.expect.$n
|
||||
cat two-tone.test.ksk1 >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk2 >>ksr.request.expect.$n
|
||||
cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n
|
||||
cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n
|
||||
# Bundle 2: KSK-A1, KSK-B1, ZSK-A1 + ZSK-A2, ZSK-B1
|
||||
key=$(cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk2.id)
|
||||
inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk1 >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk2 >>ksr.request.expect.$n
|
||||
print_dnskeys two-tone.test 1 2 $DEFAULT_ALGORITHM_NUMBER ksr.keygen.out.expect.$DEFAULT_ALGORITHM_NUMBER >>ksr.request.expect.$n
|
||||
cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n
|
||||
# Bundle 3: KSK-A1, KSK-B1, ZSK-A2, ZSK-B1
|
||||
key=$(cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id)
|
||||
inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk1 >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk2 >>ksr.request.expect.$n
|
||||
cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n
|
||||
cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n
|
||||
# Bundle 4: KSK-A1, KSK-B1, ZSK-A2, ZSK-B1 + ZSK-B2
|
||||
key=$(cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk2.id)
|
||||
inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk1 >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk2 >>ksr.request.expect.$n
|
||||
cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n
|
||||
print_dnskeys two-tone.test 1 2 $ALTERNATIVE_ALGORITHM_NUMBER ksr.keygen.out.expect.$ALTERNATIVE_ALGORITHM_NUMBER >>ksr.request.expect.$n
|
||||
# Bundle 5: KSK-A1, KSK-B1, ZSK-A2, ZSK-B2
|
||||
key=$(cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk1.id)
|
||||
inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-)
|
||||
echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk1 >>ksr.request.expect.$n
|
||||
cat two-tone.test.ksk2 >>ksr.request.expect.$n
|
||||
cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n
|
||||
cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n
|
||||
# Footer
|
||||
grep ";; KeySigningRequest generated at" ksr.request.out.$n >footer.$n || ret=1
|
||||
cat footer.$n >>ksr.request.expect.$n
|
||||
# Check the KSR request against the expected request.
|
||||
diff -w ksr.request.out.$n ksr.request.expect.$n >/dev/null || ret=1
|
||||
# Save request for ksr sign operation.
|
||||
cp ksr.request.expect.$n ksr.request.expect
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
num_occurrences() {
|
||||
count="$1"
|
||||
file="$2"
|
||||
line="$3"
|
||||
exclude="$4"
|
||||
|
||||
if [ -z "$exclude" ]; then
|
||||
lines=$(cat "$file" | while read line; do echo $line; done | grep "$line" | wc -l)
|
||||
echo_i "$lines occurrences: $1 $2 $3"
|
||||
else
|
||||
lines=$(cat "$file" | while read line; do echo $line; done | grep -v "$exclude" | grep "$line" | wc -l)
|
||||
echo_i "$lines occurrences: $1 $2 $3 (exclude $4)"
|
||||
fi
|
||||
|
||||
test "$lines" -eq "$count" || return 1
|
||||
}
|
||||
|
||||
# Sign request: two-tone
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-ksr sign' creates correct SKR with multiple algorithms ($n)"
|
||||
ret=0
|
||||
ksr two-tone -i $created -e +6mo -K offline -f ksr.request.expect sign two-tone.test >ksr.sign.out.$n 2>&1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
# Weak testing:
|
||||
zone="two-tone.test"
|
||||
# expect 24 headers (including the footer)
|
||||
num_occurrences 24 ksr.sign.out.$n ";; SignedKeyResponse 1.0" || ret=1
|
||||
# expect 23 KSKs and its signatures (for each header one)
|
||||
num_occurrences 23 ksr.sign.out.$n "DNSKEY 257 3 8" "CDNSKEY" || ret=1 # exclude CDNSKEY lines
|
||||
test "$ret" -eq 0 || echo_i "2 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "DNSKEY 257 3 13" "CDNSKEY" || ret=1 # exclude CDNSKEY lines
|
||||
test "$ret" -eq 0 || echo_i "3 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "RRSIG DNSKEY 8" "CDNSKEY" || ret=1 # exclude CDNSKEY lines
|
||||
test "$ret" -eq 0 || echo_i "4 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "RRSIG DNSKEY 13" "CDNSKEY" || ret=1 # exclude CDNSKEY lines
|
||||
test "$ret" -eq 0 || echo_i "5 failed"
|
||||
# ... 23 CDNSKEY records and its signatures
|
||||
num_occurrences 23 ksr.sign.out.$n "CDNSKEY 257 3 8" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "6 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "CDNSKEY 257 3 13" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "7 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "RRSIG CDNSKEY 8" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "8 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "RRSIG CDNSKEY 13" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "9 failed"
|
||||
# ... 23 CDS records and its signatures
|
||||
num_occurrences 23 ksr.sign.out.$n "CDS 8 2" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "10 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "CDS 13 2" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "11 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "RRSIG CDS 8" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "12 failed"
|
||||
num_occurrences 23 ksr.sign.out.$n "RRSIG CDS 13" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "13 failed"
|
||||
# expect 25 ZSK (two more for double keys during the rollover)
|
||||
num_occurrences 25 ksr.sign.out.$n "DNSKEY 256 3 8" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "14 failed"
|
||||
num_occurrences 25 ksr.sign.out.$n "DNSKEY 256 3 13" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "15 failed"
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
@@ -10,5 +10,5 @@
|
||||
# information regarding copyright ownership.
|
||||
|
||||
|
||||
def test_glue(run_tests_sh):
|
||||
def test_ksr(run_tests_sh):
|
||||
run_tests_sh()
|
||||
@@ -14,7 +14,6 @@
|
||||
#
|
||||
# Clean up after limits tests.
|
||||
#
|
||||
rm -f dig.out.*
|
||||
rm -f */named.memstats
|
||||
rm -f */named.conf
|
||||
rm -f */named.run
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -19019,94 +19019,94 @@ a-maximum-rrset A 10.0.0.0
|
||||
A 10.0.15.157
|
||||
A 10.0.15.158
|
||||
A 10.0.15.159
|
||||
A 10.1.0.0
|
||||
A 10.1.0.1
|
||||
A 10.1.0.2
|
||||
A 10.1.0.3
|
||||
A 10.1.0.4
|
||||
A 10.1.0.5
|
||||
A 10.1.0.6
|
||||
A 10.1.0.7
|
||||
A 10.1.0.8
|
||||
A 10.1.0.9
|
||||
A 10.1.0.10
|
||||
A 10.1.0.11
|
||||
A 10.1.0.12
|
||||
A 10.1.0.13
|
||||
A 10.1.0.14
|
||||
A 10.1.0.15
|
||||
A 10.1.0.16
|
||||
A 10.1.0.17
|
||||
A 10.1.0.18
|
||||
A 10.1.0.19
|
||||
A 10.1.0.20
|
||||
A 10.1.0.21
|
||||
A 10.1.0.22
|
||||
A 10.1.0.23
|
||||
A 10.1.0.24
|
||||
A 10.1.0.25
|
||||
A 10.1.0.26
|
||||
A 10.1.0.27
|
||||
A 10.1.0.28
|
||||
A 10.1.0.29
|
||||
A 10.1.0.30
|
||||
A 10.1.0.31
|
||||
A 10.1.0.32
|
||||
A 10.1.0.33
|
||||
A 10.1.0.34
|
||||
A 10.1.0.35
|
||||
A 10.1.0.36
|
||||
A 10.1.0.37
|
||||
A 10.1.0.38
|
||||
A 10.1.0.39
|
||||
A 10.1.0.40
|
||||
A 10.1.0.41
|
||||
A 10.1.0.42
|
||||
A 10.1.0.43
|
||||
A 10.1.0.44
|
||||
A 10.1.0.45
|
||||
A 10.1.0.46
|
||||
A 10.1.0.47
|
||||
A 10.1.0.48
|
||||
A 10.1.0.49
|
||||
A 10.1.0.50
|
||||
A 10.1.0.51
|
||||
A 10.1.0.52
|
||||
A 10.1.0.53
|
||||
A 10.1.0.54
|
||||
A 10.1.0.55
|
||||
A 10.1.0.56
|
||||
A 10.1.0.57
|
||||
A 10.1.0.58
|
||||
A 10.1.0.59
|
||||
A 10.1.0.60
|
||||
A 10.1.0.61
|
||||
A 10.1.0.62
|
||||
A 10.1.0.63
|
||||
A 10.1.0.64
|
||||
A 10.1.0.65
|
||||
A 10.1.0.66
|
||||
A 10.1.0.67
|
||||
A 10.1.0.68
|
||||
A 10.1.0.69
|
||||
A 10.1.0.70
|
||||
A 10.1.0.71
|
||||
A 10.1.0.72
|
||||
A 10.1.0.73
|
||||
A 10.1.0.74
|
||||
A 10.1.0.75
|
||||
A 10.1.0.76
|
||||
A 10.1.0.77
|
||||
A 10.1.0.78
|
||||
A 10.1.0.79
|
||||
A 10.1.0.80
|
||||
A 10.1.0.81
|
||||
A 10.1.0.82
|
||||
A 10.1.0.83
|
||||
A 10.1.0.84
|
||||
A 10.1.0.85
|
||||
A 10.1.0.86
|
||||
A 10.1.0.87
|
||||
A 10.1.0.88
|
||||
A 10.1.0.89
|
||||
A 10.1.0.90
|
||||
A 10.0.15.160
|
||||
A 10.0.15.161
|
||||
A 10.0.15.162
|
||||
A 10.0.15.163
|
||||
A 10.0.15.164
|
||||
A 10.0.15.165
|
||||
A 10.0.15.166
|
||||
A 10.0.15.167
|
||||
A 10.0.15.168
|
||||
A 10.0.15.169
|
||||
A 10.0.15.170
|
||||
A 10.0.15.171
|
||||
A 10.0.15.172
|
||||
A 10.0.15.173
|
||||
A 10.0.15.174
|
||||
A 10.0.15.175
|
||||
A 10.0.15.176
|
||||
A 10.0.15.177
|
||||
A 10.0.15.178
|
||||
A 10.0.15.179
|
||||
A 10.0.15.180
|
||||
A 10.0.15.181
|
||||
A 10.0.15.182
|
||||
A 10.0.15.183
|
||||
A 10.0.15.184
|
||||
A 10.0.15.185
|
||||
A 10.0.15.186
|
||||
A 10.0.15.187
|
||||
A 10.0.15.188
|
||||
A 10.0.15.189
|
||||
A 10.0.15.190
|
||||
A 10.0.15.191
|
||||
A 10.0.15.192
|
||||
A 10.0.15.193
|
||||
A 10.0.15.194
|
||||
A 10.0.15.195
|
||||
A 10.0.15.196
|
||||
A 10.0.15.197
|
||||
A 10.0.15.198
|
||||
A 10.0.15.199
|
||||
A 10.0.15.200
|
||||
A 10.0.15.201
|
||||
A 10.0.15.202
|
||||
A 10.0.15.203
|
||||
A 10.0.15.204
|
||||
A 10.0.15.205
|
||||
A 10.0.15.206
|
||||
A 10.0.15.207
|
||||
A 10.0.15.208
|
||||
A 10.0.15.209
|
||||
A 10.0.15.210
|
||||
A 10.0.15.211
|
||||
A 10.0.15.212
|
||||
A 10.0.15.213
|
||||
A 10.0.15.214
|
||||
A 10.0.15.215
|
||||
A 10.0.15.216
|
||||
A 10.0.15.217
|
||||
A 10.0.15.218
|
||||
A 10.0.15.219
|
||||
A 10.0.15.220
|
||||
A 10.0.15.221
|
||||
A 10.0.15.222
|
||||
A 10.0.15.223
|
||||
A 10.0.15.224
|
||||
A 10.0.15.225
|
||||
A 10.0.15.226
|
||||
A 10.0.15.227
|
||||
A 10.0.15.228
|
||||
A 10.0.15.229
|
||||
A 10.0.15.230
|
||||
A 10.0.15.231
|
||||
A 10.0.15.232
|
||||
A 10.0.15.233
|
||||
A 10.0.15.234
|
||||
A 10.0.15.235
|
||||
A 10.0.15.236
|
||||
A 10.0.15.237
|
||||
A 10.0.15.238
|
||||
A 10.0.15.239
|
||||
A 10.0.15.240
|
||||
A 10.0.15.241
|
||||
A 10.0.15.242
|
||||
A 10.0.15.243
|
||||
A 10.0.15.244
|
||||
A 10.0.15.245
|
||||
A 10.0.15.246
|
||||
A 10.0.15.247
|
||||
A 10.0.15.248
|
||||
A 10.0.15.249
|
||||
A 10.0.15.250
|
||||
@@ -1,57 +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
|
||||
|
||||
. ../conf.sh
|
||||
|
||||
DIGOPTS="-p ${PORT}"
|
||||
|
||||
status=0
|
||||
|
||||
echo_i "1000 A records"
|
||||
$DIG $DIGOPTS +tcp +norec 1000.example. @10.53.0.1 a >dig.out.1000 || status=1
|
||||
# $DIG $DIGOPTS 1000.example. @10.53.0.1 a > knowngood.dig.out.1000
|
||||
digcomp knowngood.dig.out.1000 dig.out.1000 || status=1
|
||||
|
||||
echo_i "2000 A records"
|
||||
$DIG $DIGOPTS +tcp +norec 2000.example. @10.53.0.1 a >dig.out.2000 || status=1
|
||||
# $DIG $DIGOPTS 2000.example. @10.53.0.1 a > knowngood.dig.out.2000
|
||||
digcomp knowngood.dig.out.2000 dig.out.2000 || status=1
|
||||
|
||||
echo_i "3000 A records"
|
||||
$DIG $DIGOPTS +tcp +norec 3000.example. @10.53.0.1 a >dig.out.3000 || status=1
|
||||
# $DIG $DIGOPTS 3000.example. @10.53.0.1 a > knowngood.dig.out.3000
|
||||
digcomp knowngood.dig.out.3000 dig.out.3000 || status=1
|
||||
|
||||
echo_i "4000 A records"
|
||||
$DIG $DIGOPTS +tcp +norec 4000.example. @10.53.0.1 a >dig.out.4000 || status=1
|
||||
# $DIG $DIGOPTS 4000.example. @10.53.0.1 a > knowngood.dig.out.4000
|
||||
digcomp knowngood.dig.out.4000 dig.out.4000 || status=1
|
||||
|
||||
echo_i "exactly maximum rrset"
|
||||
$DIG $DIGOPTS +tcp +norec +noedns a-maximum-rrset.example. @10.53.0.1 a >dig.out.a-maximum-rrset \
|
||||
|| status=1
|
||||
# $DIG $DIGOPTS a-maximum-rrset.example. @10.53.0.1 a > knowngood.dig.out.a-maximum-rrset
|
||||
digcomp knowngood.dig.out.a-maximum-rrset dig.out.a-maximum-rrset || status=1
|
||||
|
||||
echo_i "exceed maximum rrset (5000 A records)"
|
||||
$DIG $DIGOPTS +tcp +norec +noadd 5000.example. @10.53.0.1 a >dig.out.exceed || status=1
|
||||
# Look for truncation bit (tc).
|
||||
grep 'flags: .*tc.*;' dig.out.exceed >/dev/null || {
|
||||
echo_i "TC bit was not set"
|
||||
status=1
|
||||
}
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
@@ -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.
|
||||
|
||||
import itertools
|
||||
|
||||
import isctest
|
||||
import pytest
|
||||
|
||||
import dns.message
|
||||
|
||||
# Everything from getting a big answer to creating an RR set with thousands
|
||||
# of records takes minutes of CPU and real time with dnspython < 2.0.0.
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"name,limit",
|
||||
[
|
||||
("1000", 1000),
|
||||
("2000", 2000),
|
||||
("3000", 3000),
|
||||
("4000", 4000),
|
||||
("a-maximum-rrset", 4091),
|
||||
],
|
||||
)
|
||||
def test_limits(name, limit):
|
||||
msg_query = dns.message.make_query(f"{name}.example.", "A")
|
||||
res = isctest.query.tcp(msg_query, "10.53.0.1")
|
||||
|
||||
iplist = [
|
||||
f"10.0.{x}.{y}"
|
||||
for x, y in itertools.islice(itertools.product(range(256), repeat=2), limit)
|
||||
]
|
||||
|
||||
msg_rrset = [dns.rrset.from_text_list(f"{name}.example.", "5M", "IN", "A", iplist)]
|
||||
|
||||
assert res.answer == msg_rrset
|
||||
|
||||
|
||||
def test_limit_exceeded():
|
||||
msg_query = dns.message.make_query("5000.example.", "A")
|
||||
res = isctest.query.tcp(msg_query, "10.53.0.1")
|
||||
|
||||
assert res.flags & dns.flags.TC, "TC flag was not set"
|
||||
@@ -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.
|
||||
|
||||
|
||||
def test_limits(run_tests_sh):
|
||||
run_tests_sh()
|
||||
@@ -11,9 +11,7 @@
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
rm -f dig.out.*
|
||||
rm -f */named.memstats
|
||||
rm -f */named.conf
|
||||
rm -f */named.run
|
||||
rm -f checkzone.out*
|
||||
rm -f ns*/managed-keys.bind*
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
include. 300 IN SOA ns.include. hostmaster.include. 1 3600 1800 1814400 3600
|
||||
include. 300 IN NS ns.include.
|
||||
a.include. 300 IN A 10.0.0.1
|
||||
a.include. 300 IN A 10.0.0.99
|
||||
a.a.include. 300 IN A 10.0.1.1
|
||||
b.foo.a.include. 300 IN A 10.0.2.2
|
||||
b.include. 300 IN A 10.0.0.2
|
||||
a.b.include. 300 IN A 10.0.1.1
|
||||
c.b.include. 300 IN A 10.0.0.3
|
||||
b.foo.b.include. 300 IN A 10.0.2.2
|
||||
ns.include. 300 IN A 127.0.0.1
|
||||
include. 300 IN SOA ns.include. hostmaster.include. 1 3600 1800 1814400 3600
|
||||
@@ -1,10 +0,0 @@
|
||||
ttl1. 3 IN SOA ns.ttl1. hostmaster.ttl1. 1 3600 1800 1814400 3
|
||||
ttl1. 3 IN NS ns.ttl1.
|
||||
a.ttl1. 3 IN TXT "soa minttl 3"
|
||||
b.ttl1. 2 IN TXT "explicit ttl 2"
|
||||
c.ttl1. 3 IN TXT "soa minttl 3"
|
||||
d.ttl1. 1 IN TXT "default ttl 1"
|
||||
e.ttl1. 4 IN TXT "explicit ttl 4"
|
||||
f.ttl1. 1 IN TXT "default ttl 1"
|
||||
ns.ttl1. 3 IN A 10.53.0.1
|
||||
ttl1. 3 IN SOA ns.ttl1. hostmaster.ttl1. 1 3600 1800 1814400 3
|
||||
@@ -1,10 +0,0 @@
|
||||
ttl2. 1 IN SOA ns.ttl2. hostmaster.ttl2. 1 3600 1800 1814400 3
|
||||
ttl2. 1 IN NS ns.ttl2.
|
||||
a.ttl2. 1 IN TXT "inherited ttl 1"
|
||||
b.ttl2. 2 IN TXT "explicit ttl 2"
|
||||
c.ttl2. 2 IN TXT "inherited ttl 2"
|
||||
d.ttl2. 3 IN TXT "default ttl 3"
|
||||
e.ttl2. 2 IN TXT "explicit ttl 2"
|
||||
f.ttl2. 3 IN TXT "default ttl 3"
|
||||
ns.ttl2. 1 IN A 10.53.0.1
|
||||
ttl2. 1 IN SOA ns.ttl2. hostmaster.ttl2. 1 3600 1800 1814400 3
|
||||
@@ -1,75 +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
|
||||
|
||||
. ../conf.sh
|
||||
|
||||
DIGOPTS="-p ${PORT}"
|
||||
|
||||
status=0
|
||||
n=0
|
||||
|
||||
ret=0
|
||||
n=$((n + 1))
|
||||
echo_i "test master file \$INCLUDE semantics ($n)"
|
||||
$DIG $DIGOPTS +nostats +nocmd include. axfr @10.53.0.1 >dig.out.$n || ret=1
|
||||
|
||||
diff dig.out.$n knowngood.include || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
ret=0
|
||||
n=$((n + 1))
|
||||
echo_i "test master file BIND 8 compatibility TTL and \$TTL semantics ($n)"
|
||||
$DIG $DIGOPTS +nostats +nocmd ttl1. axfr @10.53.0.1 >dig.out.$n || ret=1
|
||||
|
||||
diff dig.out.$n knowngood.ttl1 || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
ret=0
|
||||
n=$((n + 1))
|
||||
echo_i "test of master file RFC1035 TTL and \$TTL semantics ($n)"
|
||||
$DIG $DIGOPTS +nostats +nocmd ttl2. axfr @10.53.0.1 >dig.out.$n || ret=1
|
||||
|
||||
diff dig.out.$n knowngood.ttl2 || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
ret=0
|
||||
n=$((n + 1))
|
||||
echo_i "test that the nameserver is running with a missing master file ($n)"
|
||||
$DIG $DIGOPTS +tcp +noall +answer example soa @10.53.0.2 >dig.out.$n || ret=1
|
||||
grep SOA dig.out.$n >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
ret=0
|
||||
n=$((n + 1))
|
||||
echo_i "test that the nameserver returns SERVFAIL for a missing master file ($n)"
|
||||
$DIG $DIGOPTS +tcp +all missing soa @10.53.0.2 >dig.out.$n || ret=1
|
||||
grep "status: SERVFAIL" dig.out.$n >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
ret=0
|
||||
n=$((n + 1))
|
||||
echo_i "test owner inheritance after "'$INCLUDE'" ($n)"
|
||||
$CHECKZONE -Dq example zone/inheritownerafterinclude.db >checkzone.out$n
|
||||
diff checkzone.out$n zone/inheritownerafterinclude.good || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
@@ -0,0 +1,119 @@
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you 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.message
|
||||
import dns.zone
|
||||
|
||||
import isctest
|
||||
|
||||
|
||||
def test_masterfile_include_semantics():
|
||||
"""Test master file $INCLUDE semantics"""
|
||||
msg_axfr = dns.message.make_query("include.", "AXFR")
|
||||
res_axfr = isctest.query.tcp(msg_axfr, "10.53.0.1")
|
||||
axfr_include_semantics = """;ANSWER
|
||||
include. 300 IN SOA ns.include. hostmaster.include. 1 3600 1800 1814400 3600
|
||||
include. 300 IN NS ns.include.
|
||||
a.include. 300 IN A 10.0.0.1
|
||||
a.include. 300 IN A 10.0.0.99
|
||||
a.a.include. 300 IN A 10.0.1.1
|
||||
b.foo.a.include. 300 IN A 10.0.2.2
|
||||
b.include. 300 IN A 10.0.0.2
|
||||
a.b.include. 300 IN A 10.0.1.1
|
||||
c.b.include. 300 IN A 10.0.0.3
|
||||
b.foo.b.include. 300 IN A 10.0.2.2
|
||||
ns.include. 300 IN A 127.0.0.1
|
||||
"""
|
||||
expected = dns.message.from_text(axfr_include_semantics)
|
||||
isctest.check.rrsets_equal(res_axfr.answer, expected.answer, compare_ttl=True)
|
||||
|
||||
|
||||
def test_masterfile_bind_8_compat_semantics():
|
||||
"""Test master file BIND 8 TTL and $TTL semantics compatibility"""
|
||||
msg_axfr = dns.message.make_query("ttl1.", "AXFR")
|
||||
res_axfr = isctest.query.tcp(msg_axfr, "10.53.0.1")
|
||||
axfr_ttl_semantics = """;ANSWER
|
||||
ttl1. 3 IN SOA ns.ttl1. hostmaster.ttl1. 1 3600 1800 1814400 3
|
||||
ttl1. 3 IN NS ns.ttl1.
|
||||
a.ttl1. 3 IN TXT "soa minttl 3"
|
||||
b.ttl1. 2 IN TXT "explicit ttl 2"
|
||||
c.ttl1. 3 IN TXT "soa minttl 3"
|
||||
d.ttl1. 1 IN TXT "default ttl 1"
|
||||
e.ttl1. 4 IN TXT "explicit ttl 4"
|
||||
f.ttl1. 1 IN TXT "default ttl 1"
|
||||
ns.ttl1. 3 IN A 10.53.0.1
|
||||
"""
|
||||
expected = dns.message.from_text(axfr_ttl_semantics)
|
||||
isctest.check.rrsets_equal(res_axfr.answer, expected.answer, compare_ttl=True)
|
||||
|
||||
|
||||
def test_masterfile_rfc_1035_semantics():
|
||||
"""Test master file RFC1035 TTL and $TTL semantics"""
|
||||
msg_axfr = dns.message.make_query("ttl2.", "AXFR")
|
||||
res_axfr = isctest.query.tcp(msg_axfr, "10.53.0.1")
|
||||
axfr_ttl_semantics = """;ANSWER
|
||||
ttl2. 1 IN SOA ns.ttl2. hostmaster.ttl2. 1 3600 1800 1814400 3
|
||||
ttl2. 1 IN NS ns.ttl2.
|
||||
a.ttl2. 1 IN TXT "inherited ttl 1"
|
||||
b.ttl2. 2 IN TXT "explicit ttl 2"
|
||||
c.ttl2. 2 IN TXT "inherited ttl 2"
|
||||
d.ttl2. 3 IN TXT "default ttl 3"
|
||||
e.ttl2. 2 IN TXT "explicit ttl 2"
|
||||
f.ttl2. 3 IN TXT "default ttl 3"
|
||||
ns.ttl2. 1 IN A 10.53.0.1
|
||||
"""
|
||||
expected = dns.message.from_text(axfr_ttl_semantics)
|
||||
isctest.check.rrsets_equal(res_axfr.answer, expected.answer, compare_ttl=True)
|
||||
|
||||
|
||||
def test_masterfile_missing_master_file():
|
||||
"""Test nameserver running with a missing master file"""
|
||||
msg_soa = dns.message.make_query("example.", "SOA")
|
||||
res_soa = isctest.query.tcp(msg_soa, "10.53.0.2")
|
||||
expected_soa_rr = """;ANSWER
|
||||
example. 300 IN SOA mname1. . 2010042407 20 20 1814400 3600
|
||||
"""
|
||||
expected = dns.message.from_text(expected_soa_rr)
|
||||
isctest.check.rrsets_equal(res_soa.answer, expected.answer, compare_ttl=True)
|
||||
|
||||
|
||||
def test_masterfile_missing_master_file_servfail():
|
||||
"""Test nameserver returning SERVFAIL for a missing master file"""
|
||||
msg_soa = dns.message.make_query("missing.", "SOA")
|
||||
res_soa = isctest.query.tcp(msg_soa, "10.53.0.2")
|
||||
isctest.check.servfail(res_soa)
|
||||
|
||||
|
||||
def test_masterfile_owner_inheritance():
|
||||
"""Test owner inheritance after $INCLUDE"""
|
||||
checker_output = subprocess.run(
|
||||
[
|
||||
os.environ["CHECKZONE"],
|
||||
"-D",
|
||||
"-q",
|
||||
"example",
|
||||
"zone/inheritownerafterinclude.db",
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
check=True,
|
||||
).stdout.decode("utf-8")
|
||||
owner_inheritance_zone = """
|
||||
example. 0 IN SOA . . 0 0 0 0 0
|
||||
example. 0 IN TXT "this should be at the zone apex"
|
||||
example. 0 IN NS .
|
||||
"""
|
||||
checker_zone = dns.zone.from_text(checker_output, origin="example.")
|
||||
expected = dns.zone.from_text(owner_inheritance_zone, origin="example.")
|
||||
isctest.check.zones_equal(checker_zone, expected, compare_ttl=True)
|
||||
@@ -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.
|
||||
|
||||
|
||||
def test_masterfile(run_tests_sh):
|
||||
run_tests_sh()
|
||||
@@ -1,3 +0,0 @@
|
||||
example. 0 IN SOA . . 0 0 0 0 0
|
||||
example. 0 IN NS .
|
||||
example. 0 IN TXT "this should be at the zone apex"
|
||||
@@ -14,6 +14,8 @@
|
||||
options {
|
||||
query-source address 10.53.0.1;
|
||||
notify-source 10.53.0.1;
|
||||
# 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";
|
||||
|
||||
@@ -19,6 +19,9 @@ $TTL 300
|
||||
)
|
||||
. NS a.root-servers.nil.
|
||||
a.root-servers.nil. A 10.53.0.1
|
||||
; sends NOTIFY using invalid notify-source-v6 address
|
||||
. NS other.root-servers.nil.
|
||||
other.root-servers.nil. AAAA fd92:7065:b8e:fffe::a35:4
|
||||
|
||||
example. NS ns2.example.
|
||||
ns2.example. A 10.53.0.2
|
||||
|
||||
@@ -22,6 +22,7 @@ example. NS ns2.example.
|
||||
ns2.example. A 10.53.0.2
|
||||
example. NS ns3.example.
|
||||
ns3.example. A 10.53.0.3
|
||||
ns3.example. AAAA fd92:7065:b8e:ffff::3
|
||||
|
||||
$ORIGIN example.
|
||||
a A 10.0.0.2
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
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";
|
||||
|
||||
@@ -18,7 +18,7 @@ options {
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.3; };
|
||||
listen-on-v6 { none; };
|
||||
listen-on-v6 { fd92:7065:b8e:ffff::3; };
|
||||
recursion yes;
|
||||
notify yes;
|
||||
dnssec-validation no;
|
||||
|
||||
@@ -98,6 +98,12 @@ END {
|
||||
}' ns2/named.run >awk.out.ns2.test$n || ret=1
|
||||
test_end
|
||||
|
||||
# See [GL#4689]
|
||||
test_start "checking server behaviour with invalid notify-source-v6 address"
|
||||
grep "zone ./IN: sending notify to fd92:7065:b8e:fffe::a35:4#" ns1/named.run >/dev/null || ret=1
|
||||
grep "dns_request_create: failed address not available" ns1/named.run >/dev/null || ret=1
|
||||
test_end
|
||||
|
||||
nextpart ns3/named.run >/dev/null
|
||||
|
||||
sleep 1 # make sure filesystem time stamp is newer for reload.
|
||||
@@ -109,6 +115,7 @@ wait_for_log_re 45 "transfer of 'example/IN' from 10.53.0.2#.*success" ns3/named
|
||||
|
||||
test_start "checking notify message was logged"
|
||||
grep 'notify from 10.53.0.2#[0-9][0-9]*: serial 2$' ns3/named.run >/dev/null || ret=1
|
||||
grep 'refused notify from non-primary: fd92:7065:b8e:ffff::2#[0-9][0-9]*$' ns3/named.run >/dev/null || ret=1
|
||||
test_end
|
||||
|
||||
test_start "checking example2 loaded"
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
$TTL 300
|
||||
@ IN SOA a.root-servers.nil. hostmaster.example.net. 0 0 0 0 0
|
||||
@ IN NS a.root-servers.nil.
|
||||
10.in-addr.arpa TXT turn off redirect
|
||||
* IN A 100.100.100.1
|
||||
* IN AAAA 2001:ffff:ffff::100.100.100.1
|
||||
|
||||
@@ -518,6 +518,14 @@ n=$((n + 1))
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "checking nxdomain-redirect against built-in RFC-1918 zone ($n)"
|
||||
ret=0
|
||||
$DIG $DIGOPTS -x 10.0.0.1 @10.53.0.4 -b 10.53.0.2 >dig.out.ns4.test$n || ret=1
|
||||
grep "status: NXDOMAIN" dig.out.ns4.test$n >/dev/null || ret=1
|
||||
n=$((n + 1))
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "checking tld nxdomain-redirect against signed root zone ($n)"
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.5 asdfasdfasdf >dig.out.ns5.test$n || ret=1
|
||||
|
||||
@@ -505,9 +505,21 @@ n=$((n + 1))
|
||||
echo_i "check that '-t aaaa' in .digrc does not have unexpected side effects ($n)"
|
||||
ret=0
|
||||
echo "-t aaaa" >.digrc
|
||||
(HOME="$(pwd)" dig_with_opts @10.53.0.4 . >dig.out.1.${n}) || ret=1
|
||||
(HOME="$(pwd)" dig_with_opts @10.53.0.4 . A >dig.out.2.${n}) || ret=1
|
||||
(HOME="$(pwd)" dig_with_opts @10.53.0.4 -x 127.0.0.1 >dig.out.3.${n}) || ret=1
|
||||
(
|
||||
HOME="$(pwd)"
|
||||
export HOME
|
||||
dig_with_opts @10.53.0.4 . >dig.out.1.${n}
|
||||
) || ret=1
|
||||
(
|
||||
HOME="$(pwd)"
|
||||
export HOME
|
||||
dig_with_opts @10.53.0.4 . A >dig.out.2.${n}
|
||||
) || ret=1
|
||||
(
|
||||
HOME="$(pwd)"
|
||||
export HOME
|
||||
dig_with_opts @10.53.0.4 -x 127.0.0.1 >dig.out.3.${n}
|
||||
) || ret=1
|
||||
grep ';\..*IN.*AAAA$' dig.out.1.${n} >/dev/null || ret=1
|
||||
grep ';\..*IN.*A$' dig.out.2.${n} >/dev/null || ret=1
|
||||
grep 'extra type option' dig.out.2.${n} >/dev/null && ret=1
|
||||
|
||||
@@ -436,7 +436,7 @@ n=$((n + 1))
|
||||
echo_i "testing automatic zones are reported ($n)"
|
||||
ret=0
|
||||
$RNDC -s 10.53.0.4 -p ${EXTRAPORT6} -c ns4/key6.conf status >rndc.out.1.test$n || ret=1
|
||||
grep "number of zones: 199 (198 automatic)" rndc.out.1.test$n >/dev/null || ret=1
|
||||
grep "number of zones: 201 (200 automatic)" rndc.out.1.test$n >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
IN
|
||||
CH
|
||||
HS
|
||||
@@ -1,98 +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
|
||||
|
||||
. ../conf.sh
|
||||
|
||||
status=0
|
||||
n=0
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "class list ($n)"
|
||||
$RRCHECKER -C >classlist.out
|
||||
diff classlist.out classlist.good || {
|
||||
echo_i "failed"
|
||||
status=$((status + 1))
|
||||
}
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "type list ($n)"
|
||||
$RRCHECKER -T >typelist.out
|
||||
diff typelist.out typelist.good || {
|
||||
echo_i "failed"
|
||||
status=$((status + 1))
|
||||
}
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "private type list ($n)"
|
||||
$RRCHECKER -P >privatelist.out
|
||||
diff privatelist.out privatelist.good || {
|
||||
echo_i "failed"
|
||||
status=$((status + 1))
|
||||
}
|
||||
|
||||
myecho() {
|
||||
cat <<EOF
|
||||
$*
|
||||
EOF
|
||||
}
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check conversions to canonical format ($n)"
|
||||
ret=0
|
||||
$SHELL ${TOP_SRCDIR}/bin/tests/system/genzone.sh 0 >tempzone
|
||||
$CHECKZONE -Dq . tempzone | sed '/^;/d' >checkzone.out$n
|
||||
while read -r name tt cl ty rest; do
|
||||
myecho "$cl $ty $rest" | $RRCHECKER -p >checker.out || {
|
||||
ret=1
|
||||
echo_i "'$cl $ty $rest' not handled."
|
||||
}
|
||||
read -r cl0 ty0 rest0 <checker.out
|
||||
test "$cl $ty $rest" = "$cl0 $ty0 $rest0" || {
|
||||
ret=1
|
||||
echo_i "'$cl $ty $rest' != '$cl0 $ty0 $rest0'"
|
||||
}
|
||||
done <checkzone.out$n
|
||||
test $ret -eq 0 || {
|
||||
echo_i "failed"
|
||||
status=$((status + 1))
|
||||
}
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check conversions to and from unknown record format ($n)"
|
||||
ret=0
|
||||
$CHECKZONE -Dq . tempzone | sed '/^;/d' >checkzone.out$n
|
||||
while read -r name tt cl ty rest; do
|
||||
myecho "$cl $ty $rest" | $RRCHECKER -u >checker.out || {
|
||||
ret=1
|
||||
echo_i "'$cl $ty $rest' not converted to unknown record format"
|
||||
}
|
||||
read -r clu tyu restu <checker.out
|
||||
myecho "$clu $tyu $restu" | $RRCHECKER -p >checker.out || {
|
||||
ret=1
|
||||
echo_i "'$cl $ty $rest' not converted back to canonical format"
|
||||
}
|
||||
read -r cl0 ty0 rest0 <checker.out
|
||||
test "$cl $ty $rest" = "$cl0 $ty0 $rest0" || {
|
||||
ret=1
|
||||
echo_i "'$cl $ty $rest' != '$cl0 $ty0 $rest0'"
|
||||
}
|
||||
done <checkzone.out$n
|
||||
test $ret -eq 0 || {
|
||||
echo_i "failed"
|
||||
status=$((status + 1))
|
||||
}
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
@@ -0,0 +1,188 @@
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you 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 pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"option,expected_result",
|
||||
[
|
||||
("-C", ["HS", "CH", "IN"]),
|
||||
(
|
||||
"-T",
|
||||
[
|
||||
"A",
|
||||
"A6",
|
||||
"AAAA",
|
||||
"AFSDB",
|
||||
"AMTRELAY",
|
||||
"APL",
|
||||
"ATMA",
|
||||
"AVC",
|
||||
"CAA",
|
||||
"CDNSKEY",
|
||||
"CDS",
|
||||
"CERT",
|
||||
"CNAME",
|
||||
"CSYNC",
|
||||
"DHCID",
|
||||
"DLV",
|
||||
"DNAME",
|
||||
"DNSKEY",
|
||||
"DOA",
|
||||
"DS",
|
||||
"EID",
|
||||
"EUI48",
|
||||
"EUI64",
|
||||
"GID",
|
||||
"GPOS",
|
||||
"HINFO",
|
||||
"HIP",
|
||||
"HTTPS",
|
||||
"IPSECKEY",
|
||||
"ISDN",
|
||||
"KEY",
|
||||
"KX",
|
||||
"L32",
|
||||
"L64",
|
||||
"LOC",
|
||||
"LP",
|
||||
"MB",
|
||||
"MD",
|
||||
"MF",
|
||||
"MG",
|
||||
"MINFO",
|
||||
"MR",
|
||||
"MX",
|
||||
"NAPTR",
|
||||
"NID",
|
||||
"NIMLOC",
|
||||
"NINFO",
|
||||
"NS",
|
||||
"NSAP",
|
||||
"NSAP-PTR",
|
||||
"NSEC",
|
||||
"NSEC3",
|
||||
"NSEC3PARAM",
|
||||
"NULL",
|
||||
"NXT",
|
||||
"OPENPGPKEY",
|
||||
"PTR",
|
||||
"PX",
|
||||
"RESINFO",
|
||||
"RKEY",
|
||||
"RP",
|
||||
"RRSIG",
|
||||
"RT",
|
||||
"SIG",
|
||||
"SINK",
|
||||
"SMIMEA",
|
||||
"SOA",
|
||||
"SPF",
|
||||
"SRV",
|
||||
"SSHFP",
|
||||
"SVCB",
|
||||
"TA",
|
||||
"TALINK",
|
||||
"TLSA",
|
||||
"TXT",
|
||||
"UID",
|
||||
"UINFO",
|
||||
"UNSPEC",
|
||||
"URI",
|
||||
"WKS",
|
||||
"X25",
|
||||
"ZONEMD",
|
||||
],
|
||||
),
|
||||
("-P", []),
|
||||
],
|
||||
)
|
||||
def test_rrchecker_list_standard_names(option, expected_result):
|
||||
stdout = subprocess.run(
|
||||
[
|
||||
os.environ["RRCHECKER"],
|
||||
option,
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
check=True,
|
||||
).stdout.decode("utf-8")
|
||||
values = [line for line in stdout.split("\n") if line.strip()]
|
||||
|
||||
assert sorted(values) == sorted(expected_result)
|
||||
|
||||
|
||||
def run_rrchecker(option, rr_class, rr_type, rr_rest):
|
||||
with subprocess.Popen(
|
||||
[os.environ["RRCHECKER"], option],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
) as process:
|
||||
rrchecker_output, _ = process.communicate(
|
||||
f"{rr_class} {rr_type} {rr_rest}".encode("utf-8")
|
||||
)
|
||||
return rrchecker_output.decode("utf-8").split()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("option", ["-p", "-u"])
|
||||
def test_rrchecker_conversions(option):
|
||||
tempzone_file = "tempzone"
|
||||
with open(tempzone_file, "w", encoding="utf-8") as file:
|
||||
subprocess.run(
|
||||
[
|
||||
os.environ["SHELL"],
|
||||
os.environ["TOP_SRCDIR"] + "/bin/tests/system/genzone.sh",
|
||||
"0",
|
||||
],
|
||||
stdout=file,
|
||||
stderr=subprocess.PIPE,
|
||||
check=True,
|
||||
)
|
||||
checkzone_output = subprocess.run(
|
||||
[
|
||||
os.environ["CHECKZONE"],
|
||||
"-D",
|
||||
"-q",
|
||||
".",
|
||||
tempzone_file,
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
check=True,
|
||||
).stdout.decode("utf-8")
|
||||
checkzone_output = [
|
||||
line for line in checkzone_output.splitlines() if not line.startswith(";")
|
||||
]
|
||||
|
||||
for rr in checkzone_output:
|
||||
rr_parts_orig = rr.split()
|
||||
assert len(rr_parts_orig) >= 4, f"invalid rr: {rr}"
|
||||
rr_class_orig, rr_type_orig, rr_rest_orig = (
|
||||
rr_parts_orig[2],
|
||||
rr_parts_orig[3],
|
||||
" ".join(rr_parts_orig[4:]),
|
||||
)
|
||||
rr_class, rr_type, rr_rest = rr_class_orig, rr_type_orig, rr_rest_orig
|
||||
if option == "-u":
|
||||
rr_class, rr_type, *rr_rest = run_rrchecker(
|
||||
"-u", rr_class_orig, rr_type_orig, rr_rest_orig
|
||||
)
|
||||
rr_rest = " ".join(rr_rest)
|
||||
|
||||
rr_class, rr_type, *rr_rest = run_rrchecker("-p", rr_class, rr_type, rr_rest)
|
||||
|
||||
assert rr_class_orig == rr_class
|
||||
assert rr_type_orig == rr_type
|
||||
assert rr_rest_orig == " ".join(rr_rest)
|
||||
@@ -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.
|
||||
|
||||
|
||||
def test_rrchecker(run_tests_sh):
|
||||
run_tests_sh()
|
||||
@@ -1,82 +0,0 @@
|
||||
A
|
||||
NS
|
||||
MD
|
||||
MF
|
||||
CNAME
|
||||
SOA
|
||||
MB
|
||||
MG
|
||||
MR
|
||||
NULL
|
||||
WKS
|
||||
PTR
|
||||
HINFO
|
||||
MINFO
|
||||
MX
|
||||
TXT
|
||||
RP
|
||||
AFSDB
|
||||
X25
|
||||
ISDN
|
||||
RT
|
||||
NSAP
|
||||
NSAP-PTR
|
||||
SIG
|
||||
KEY
|
||||
PX
|
||||
GPOS
|
||||
AAAA
|
||||
LOC
|
||||
NXT
|
||||
EID
|
||||
NIMLOC
|
||||
SRV
|
||||
ATMA
|
||||
NAPTR
|
||||
KX
|
||||
CERT
|
||||
A6
|
||||
DNAME
|
||||
SINK
|
||||
APL
|
||||
DS
|
||||
SSHFP
|
||||
IPSECKEY
|
||||
RRSIG
|
||||
NSEC
|
||||
DNSKEY
|
||||
DHCID
|
||||
NSEC3
|
||||
NSEC3PARAM
|
||||
TLSA
|
||||
SMIMEA
|
||||
HIP
|
||||
NINFO
|
||||
RKEY
|
||||
TALINK
|
||||
CDS
|
||||
CDNSKEY
|
||||
OPENPGPKEY
|
||||
CSYNC
|
||||
ZONEMD
|
||||
SVCB
|
||||
HTTPS
|
||||
SPF
|
||||
UINFO
|
||||
UID
|
||||
GID
|
||||
UNSPEC
|
||||
NID
|
||||
L32
|
||||
L64
|
||||
LP
|
||||
EUI48
|
||||
EUI64
|
||||
URI
|
||||
CAA
|
||||
AVC
|
||||
DOA
|
||||
AMTRELAY
|
||||
RESINFO
|
||||
TA
|
||||
DLV
|
||||
@@ -323,6 +323,7 @@ sub construct_ans_command {
|
||||
}
|
||||
|
||||
if (-e "$testdir/$server/ans.py") {
|
||||
$ENV{'PYTHONPATH'} = $testdir . ":" . $ENV{'srcdir'};
|
||||
$command = "$PYTHON -u ans.py 10.53.0.$n $queryport";
|
||||
} elsif (-e "$testdir/$server/ans.pl") {
|
||||
$command = "$PERL ans.pl";
|
||||
|
||||
@@ -17,3 +17,6 @@ a.root-servers.nil. A 10.53.0.1
|
||||
example.com. NS example.
|
||||
|
||||
ns.example.net. A 10.53.0.3
|
||||
|
||||
unsigned. NS ns.unsigned.
|
||||
ns.unsigned. A 10.53.0.3
|
||||
|
||||
@@ -33,6 +33,7 @@ options {
|
||||
recursion yes;
|
||||
dnssec-validation yes;
|
||||
notify no;
|
||||
minimal-responses no;
|
||||
};
|
||||
|
||||
zone "." {
|
||||
@@ -60,3 +61,8 @@ zone "undelegated" {
|
||||
type static-stub;
|
||||
server-addresses { 10.53.0.3; };
|
||||
};
|
||||
|
||||
zone "unsigned" {
|
||||
type static-stub;
|
||||
server-addresses { 10.53.0.3; };
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user