diff --git a/.clang-format b/.clang-format
index 124d82a269..54a39fdb4d 100644
--- a/.clang-format
+++ b/.clang-format
@@ -78,4 +78,4 @@ PenaltyBreakString: 80
PenaltyExcessCharacter: 100
Standard: Cpp11
ContinuationIndentWidth: 8
-ForEachMacros: [ 'cds_lfs_for_each', 'cds_lfs_for_each_safe', 'cds_list_for_each_entry_safe', 'ISC_LIST_FOREACH', 'ISC_LIST_FOREACH_SAFE' ]
+ForEachMacros: [ 'cds_lfs_for_each', 'cds_lfs_for_each_safe', 'cds_list_for_each_entry_safe', 'ISC_LIST_FOREACH', 'ISC_LIST_FOREACH_SAFE', 'ISC_LIST_FOREACH_REV', 'ISC_LIST_FOREACH_REV_SAFE' ]
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..6191af8065
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,5 @@
+[*.sh{,.in}]
+indent_style = space
+indent_size = 2
+binary_next_line = true
+switch_case_indent = true
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index ad3c2b1e98..57b9988e37 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -1534,3 +1534,9 @@ ffbe6b95371c99b7fb05e6de17a8d6b7bf4f629f
1436025e20ae13cfe55df14d62f5812c0cea2ee9
# subshell notation in system tests
05baf7206b7baaf91cb8e049ad13e413c52cdf3f
+# reformat shell scripts with shfmt
+4cb8b13987b930952238cc88e84272b8cf911933
+# Reformat sources with up-to-date clang-format-17
+79d93600116faabd89798522817ad95a69684fff
+# Reformat sources with up-to-date clang-format-18
+b7de2c7cb959fa35099d72c3f9b13938348c74e6
diff --git a/.gitignore b/.gitignore
index 3edbde71e7..242bd0efdb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 594a2dfbf5..0396e175db 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -15,7 +15,7 @@ variables:
TEST_PARALLEL_JOBS: 4
CONFIGURE: ./configure
- CLANG_VERSION: 16
+ CLANG_VERSION: 18
CLANG: "clang-${CLANG_VERSION}"
SCAN_BUILD: "scan-build-${CLANG_VERSION}"
LLVM_SYMBOLIZER: "/usr/lib/llvm-${CLANG_VERSION}/bin/llvm-symbolizer"
@@ -34,8 +34,6 @@ variables:
UBSAN_OPTIONS: "halt_on_error=1:abort_on_error=1:disable_coredump=0"
- TARBALL_EXTENSION: xz
-
AM_COLOR_TESTS: always
WITHOUT_READLINE: "--without-readline"
@@ -57,6 +55,8 @@ variables:
BIND_STRESS_TEST_OS: linux
BIND_STRESS_TEST_ARCH: amd64
+ HYPOTHESIS_PROFILE: "ci"
+
default:
# Allow all running CI jobs to be automatically canceled when a new
# version of a branch is pushed.
@@ -73,6 +73,7 @@ stages:
- performance
- docs
- postcheck
+ - postmerge
- release
### Runner Tag Templates
@@ -82,15 +83,7 @@ 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
+# Autoscaling GitLab Runner on AWS EC2 (amd64)
.linux-amd64: &linux_amd64
tags:
@@ -99,35 +92,32 @@ stages:
- runner-manager
- amd64
-# Stress-testing runners
+# Autoscaling GitLab Runner on AWS EC2 (arm64)
-.linux-stress-amd64: &linux_stress_amd64
+.linux-arm64: &linux_arm64
tags:
- - amd64
+ - linux
- aws
- - linux-stress
- - stress
-
-.linux-stress-arm64: &linux_stress_arm64
- tags:
+ - runner-manager
- aarch64
- - aws
- - linux-stress
- - stress
+
+# Autoscaling GitLab Runner on AWS EC2 (FreeBSD)
.freebsd-stress-amd64: &freebsd_stress_amd64
tags:
- - amd64
+ - bsd-stress-test
- aws
- - bsd-stress
- - stress
+ - autoscaler
+ - shell
+ - stress-test
+ - amd64
### Docker Image Templates
# Alpine Linux
-.alpine-3.18-amd64: &alpine_3_18_amd64_image
- image: "$CI_REGISTRY_IMAGE:alpine-3.18-amd64"
+.alpine-3.20-amd64: &alpine_3_20_amd64_image
+ image: "$CI_REGISTRY_IMAGE:alpine-3.20-amd64"
<<: *linux_amd64
# Oracle Linux
@@ -154,10 +144,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
@@ -182,17 +168,17 @@ stages:
# Fedora
-.tsan-fedora-38-amd64: &tsan_fedora_38_amd64_image
- image: "$CI_REGISTRY_IMAGE:tsan-fedora-38-amd64"
+.tsan-fedora-40-amd64: &tsan_fedora_40_amd64_image
+ image: "$CI_REGISTRY_IMAGE:tsan-fedora-40-amd64"
<<: *linux_amd64
-.fedora-38-amd64: &fedora_38_amd64_image
- image: "$CI_REGISTRY_IMAGE:fedora-38-amd64"
+.fedora-40-amd64: &fedora_40_amd64_image
+ image: "$CI_REGISTRY_IMAGE:fedora-40-amd64"
<<: *linux_amd64
-.fedora-38-arm64: &fedora_38_arm64_image
- image: "$CI_REGISTRY_IMAGE:fedora-38-arm64"
- <<: *linux_stress_arm64
+.fedora-40-arm64: &fedora_40_arm64_image
+ image: "$CI_REGISTRY_IMAGE:fedora-40-arm64"
+ <<: *linux_arm64
# Ubuntu
@@ -204,6 +190,10 @@ stages:
image: "$CI_REGISTRY_IMAGE:ubuntu-jammy-amd64"
<<: *linux_amd64
+.ubuntu-noble-amd64: &ubuntu_noble_amd64_image
+ image: "$CI_REGISTRY_IMAGE:ubuntu-noble-amd64"
+ <<: *linux_amd64
+
# Base image
# This is a meta image that is used as a base for non-specific jobs
@@ -212,31 +202,33 @@ stages:
### QCOW2 Image Templates
-.freebsd-12-amd64: &freebsd_12_amd64_image
- image: "freebsd-12.4-x86_64"
+.freebsd-13-amd64: &freebsd_13_amd64_image
+ image: "freebsd-13.3-x86_64"
<<: *libvirt_amd64
-.freebsd-13-amd64: &freebsd_13_amd64_image
- image: "freebsd-13.2-x86_64"
+.freebsd-14-amd64: &freebsd_14_amd64_image
+ image: "freebsd-14.0-x86_64"
<<: *libvirt_amd64
.openbsd-amd64: &openbsd_amd64_image
- image: "openbsd-7.3-x86_64"
+ image: "openbsd-7.5-x86_64"
<<: *libvirt_amd64
### 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
@@ -245,6 +237,7 @@ stages:
only:
- api
- merge_requests
+ - pipelines
- schedules
- tags
- triggers
@@ -280,11 +273,11 @@ stages:
# change directory to the workspace before including this
.find_python: &find_python
- - PYTHON="$(source bin/tests/system/conf.sh; echo $PYTHON)"
+ - PYTHON="$(cat bin/tests/system/isctest/vars/.ac_vars/PYTHON)"
- test -x "$PYTHON"
.find_pytest: &find_pytest
- - PYTEST="$(source bin/tests/system/conf.sh; echo $PYTEST)"
+ - PYTEST="$(cat bin/tests/system/isctest/vars/.ac_vars/PYTEST)"
- test -x "$PYTEST"
.parse_tsan: &parse_tsan
@@ -307,8 +300,8 @@ stages:
# Unpack release tarball and continue work in the extracted directory.
.unpack_release_tarball: &unpack_release_tarball
- - tar --extract --file bind-*.tar.${TARBALL_EXTENSION}
- - rm -f bind-*.tar.${TARBALL_EXTENSION}
+ - tar --extract --file bind-*.tar.xz
+ - rm -f bind-*.tar.xz
- cd bind-*
.build: &build_job
@@ -345,53 +338,29 @@ stages:
sudo sh -x bin/tests/system/ifconfig.sh up;
fi
-cross-version-config-tests:
- stage: system
+.display_pytest_failures: &display_pytest_failures
+ - awk '/^=+ FAILURES =+/{flag=1;next}/^=+.*=+$/{flag=0}flag' bin/tests/system/pytest.out.txt || true
+ - awk '/^=+ ERRORS =+/{flag=1;next}/^=+.*=+$/{flag=0}flag' bin/tests/system/pytest.out.txt || true
+
+.shotgun: &shotgun_job
<<: *base_image
- <<: *default_triggering_rules
- variables:
- CC: gcc
- CFLAGS: "${CFLAGS_COMMON}"
- # Disable option checking to prevent problems with new default options in
- # the &configure anchor.
- EXTRA_CONFIGURE: "--disable-option-checking"
+ <<: *api_pipelines_schedules_tags_triggers_web_triggering_rules
+ stage: performance
script:
- - *configure
- - *setup_interfaces
- - make -j${BUILD_PARALLEL_JOBS:-1}
- # Build system test binaries.
- - make -C bin/tests/system -j${TEST_PARALLEL_JOBS:-1} check TESTS=""
- - export BIND_BRANCH="$(sed -n -E "s|^m4_define\(\[bind_VERSION_MINOR\], ([0-9]+)\)dnl$|\1|p" configure.ac)"
- # When testing a .0 release, compare it against the previous development
- # release (e.g., 9.19.0 and 9.18.0 should both be compared against 9.17.22).
- - if [ "$(sed -n -E "s|^m4_define\(\[bind_VERSION_PATCH\], ([0-9]+)\)dnl$|\1|p" configure.ac)" = "0" ]; then export BIND_BRANCH=$((BIND_BRANCH - 1 - (BIND_BRANCH % 2))); fi
- - BASELINE="$(curl -s "https://gitlab.isc.org/api/v4/projects/1/repository/tags?search=^v9.${BIND_BRANCH}&order_by=version" | jq -r ".[0].name")"
- - git clone --branch "${BASELINE}" --depth 1 https://gitlab.isc.org/isc-projects/bind9.git "bind-${BASELINE}"
- - cd "bind-${BASELINE}"
- - autoreconf -fi
- - *configure
- - make -j${BUILD_PARALLEL_JOBS:-1}
- - *find_pytest
- - cd bin/tests/system
- # Run the setup phase of all system tests in the most recently tagged BIND 9
- # release using the binaries built for the current BIND 9 version. This
- # intends to detect obvious backward compatibility issues with the latter.
- - sed -i -E "s|(export TOP_BUILDDIR)=.*|\1=${CI_PROJECT_DIR}|" conf.sh
- - >
- "$PYTEST" --setup-only -n "${TEST_PARALLEL_JOBS:-1}"
+ - if [ -z "$CI_COMMIT_TAG" ]; then export SHOTGUN_ROUNDS=1; else export SHOTGUN_ROUNDS=3; fi
+ - PIPELINE_ID=$(curl -s -X POST --fail
+ -F "token=$CI_JOB_TOKEN"
+ -F ref=main
+ -F "variables[SHOTGUN_TEST_VERSION]=['$CI_COMMIT_REF_NAME', '$BIND_BASELINE_VERSION']"
+ -F "variables[SHOTGUN_DURATION]=300"
+ -F "variables[SHOTGUN_ROUNDS]=$SHOTGUN_ROUNDS"
+ -F "variables[SHOTGUN_TRAFFIC_MULTIPLIER]=$SHOTGUN_TRAFFIC_MULTIPLIER"
+ -F "variables[SHOTGUN_SCENARIO]=$SHOTGUN_SCENARIO"
+ https://gitlab.isc.org/api/v4/projects/188/trigger/pipeline | jq .id)
+ - util/ci-wait-shotgun.py $PIPELINE_ID
needs:
- - job: autoreconf
+ - job: ci-variables
artifacts: true
- artifacts:
- paths:
- - bind-*
- untracked: true
- expire_in: "1 day"
- when: on_failure
-
-.display_pytest_failures: &display_pytest_failures
- - awk '/^=+ FAILURES =+/{flag=1;next}/^=+.*=+$/{flag=0}flag' bin/tests/system/pytest.out.txt || true
- - awk '/^=+ ERRORS =+/{flag=1;next}/^=+.*=+$/{flag=0}flag' bin/tests/system/pytest.out.txt || true
.system_test_common: &system_test_common
<<: *default_triggering_rules
@@ -401,6 +370,8 @@ cross-version-config-tests:
- *setup_interfaces
script:
- *find_pytest
+ - *find_python
+ - ( if [ "${CI_DISPOSABLE_ENVIRONMENT}" = "true" ]; then sleep 3000; "$PYTHON" "${CI_PROJECT_DIR}/util/get-running-system-tests.py"; fi ) &
- cd bin/tests/system
- >
"$PYTEST" --junit-xml="$CI_PROJECT_DIR"/junit.xml -n "$TEST_PARALLEL_JOBS" | tee pytest.out.txt
@@ -419,6 +390,14 @@ cross-version-config-tests:
reports:
junit: junit.xml
+.system_test_make_check: &system_test_make_check_job
+ <<: *system_test_common
+ script:
+ - cd bin/tests/system
+ - make -j${TEST_PARALLEL_JOBS:-1} check
+ after_script:
+ - cat bin/tests/system/test-suite.log || true
+
.system_test_gcov: &system_test_gcov_job
<<: *system_test_common
artifacts:
@@ -491,7 +470,6 @@ cross-version-config-tests:
script:
- *configure
- make -j${BUILD_PARALLEL_JOBS:-1} -k doc V=1
- - qpdf --check doc/arm/_build/latex/Bv9ARM.pdf
- find doc/man/ -maxdepth 1 -name "*.[0-9]" -exec mandoc -T lint "{}" \; | ( ! grep -v -e "skipping paragraph macro. sp after" -e "unknown font, skipping request. ft C" -e "input text line longer than 80 bytes" )
.respdiff: &respdiff_job
@@ -501,14 +479,14 @@ cross-version-config-tests:
- *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
@@ -523,15 +501,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
@@ -544,6 +513,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: []
@@ -557,6 +538,23 @@ black:
expire_in: "1 week"
when: on_failure
+ci-variables:
+ stage: precheck
+ <<: *precheck_job
+ script:
+ - export BIND_BASELINE_BRANCH="$(sed -n -E "s|^m4_define\(\[bind_VERSION_MINOR\], ([0-9]+)\)dnl$|\1|p" configure.ac)"
+ # When testing a .0 release, compare it against the previous development
+ # release (e.g., 9.19.0 and 9.18.0 should both be compared against 9.17.22).
+ - if [ "$(sed -n -E "s|^m4_define\(\[bind_VERSION_PATCH\], ([0-9]+)\)dnl$|\1|p" configure.ac)" = "0" ]; then export BIND_BASELINE_BRANCH=$((BIND_BASELINE_BRANCH - 1 - (BIND_BASELINE_BRANCH % 2))); fi
+ - BIND_BASELINE_VERSION="$(curl -s "https://gitlab.isc.org/api/v4/projects/1/repository/tags?search=^v9.${BIND_BASELINE_BRANCH}&order_by=version" | jq -r ".[0].name")"
+ - echo "BIND_BASELINE_VERSION=$BIND_BASELINE_VERSION" >> ci_vars.env
+ needs:
+ - job: autoreconf
+ artifacts: true
+ artifacts:
+ reports:
+ dotenv: ci_vars.env
+
clang-format:
<<: *precheck_job
needs: []
@@ -580,6 +578,8 @@ coccinelle:
pylint:
<<: *precheck_job
needs: []
+ variables:
+ PYTHONPATH: "${CI_PROJECT_DIR}/bin/tests/system"
script:
- pylint --rcfile $CI_PROJECT_DIR/.pylintrc $(git ls-files '*.py' | grep -vE '(ans\.py|dangerfile\.py|^bin/tests/system/)')
# Ignore Pylint wrong-import-position error in system test to enable use of pytest.importorskip
@@ -594,16 +594,33 @@ reuse:
script:
- reuse lint
+shfmt:
+ <<: *precheck_job
+ needs: []
+ script:
+ - shfmt -w -i 2 -ci -bn . $(find . -name "*.sh.in")
+ - git diff > shfmt.patch
+ - if test "$(git status --porcelain | grep -Ev '\?\?' | wc -l)" -gt "0"; then git status --short; exit 1; fi
+ artifacts:
+ paths:
+ - shfmt.patch
+ expire_in: "1 week"
+ when: on_failure
+
danger:
<<: *precheck_job
+ # Keep the GIT_DEPTH environment variable set to a "high number" before
+ # https://github.com/libgit2/libgit2/pull/6662 is addressed and integrated
+ # into pygit2.
+ variables:
+ GIT_DEPTH: 1000
needs: []
script:
- - danger-python ci -f
+ - pip install git+https://gitlab.isc.org/isc-projects/hazard.git
+ - hazard
only:
refs:
- merge_requests
- variables:
- - $DANGER_GITLAB_API_TOKEN
checkbashisms:
<<: *precheck_job
@@ -611,6 +628,11 @@ checkbashisms:
script:
- checkbashisms $(find . -path './.git' -prune -o -type f -exec sh -c 'head -n 1 "{}" | grep -qsF "#!/bin/sh"' \; -print)
+mypy:
+ <<: *precheck_job
+ script:
+ - mypy "bin/tests/system/isctest/"
+
tarball-create:
stage: precheck
<<: *base_image
@@ -626,7 +648,7 @@ tarball-create:
artifacts:
paths:
- diff.patch
- - bind-*.tar.${TARBALL_EXTENSION}
+ - bind-*.tar.xz
when: always
needs:
- job: autoreconf
@@ -654,28 +676,77 @@ docs:tarball:
- job: tarball-create
artifacts: true
-# Jobs for regular GCC builds on Alpine Linux 3.18 (amd64)
+# Job detecting named.conf breakage introduced since the previous point release
-gcc:alpine3.18:amd64:
+cross-version-config-tests:
+ stage: system
+ <<: *base_image
+ <<: *default_triggering_rules
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON}"
+ # Disable option checking to prevent problems with new default options in
+ # the &configure anchor.
+ EXTRA_CONFIGURE: "--disable-option-checking"
+ PYTEST: "/usr/bin/pytest-3"
+ script:
+ - *configure
+ - *setup_interfaces
+ - make -j${BUILD_PARALLEL_JOBS:-1}
+ - git clone --branch "${BIND_BASELINE_VERSION}" --depth 1 https://gitlab.isc.org/isc-projects/bind9.git "bind-${BIND_BASELINE_VERSION}"
+ - cd "bind-${BIND_BASELINE_VERSION}"
+ - autoreconf -fi
+ - *configure
+ - make -j${BUILD_PARALLEL_JOBS:-1}
+ - cd bin/tests/system
+ # Run the setup phase of all system tests in the most recently tagged BIND 9
+ # release using the binaries built for the current BIND 9 version. This
+ # intends to detect obvious backward compatibility issues with the latter.
+ - >
+ if [ -f isctest/vars/autoconf.py ]; then
+ echo "${CI_PROJECT_DIR}" > isctest/vars/.ac_vars/TOP_BUILDDIR
+ else
+ sed -i -E "s|(export TOP_BUILDDIR)=.*|\1=${CI_PROJECT_DIR}|" conf.sh;
+ fi
+ - >
+ "$PYTEST" --setup-only --junit-xml="$CI_PROJECT_DIR"/junit.xml -n "${TEST_PARALLEL_JOBS:-1}"
+ needs:
+ - job: autoreconf
+ artifacts: true
+ - job: ci-variables
+ artifacts: true
+ artifacts:
+ reports:
+ junit: junit.xml
+ paths:
+ - bind-*
+ - junit.xml
+ untracked: true
+ expire_in: "1 day"
+ when: always
+
+# Jobs for regular GCC builds on Alpine Linux 3.20 (amd64)
+
+gcc:alpine3.20:amd64:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON}"
EXTRA_CONFIGURE: "${WITHOUT_READLINE}"
- <<: *alpine_3_18_amd64_image
+ <<: *alpine_3_20_amd64_image
<<: *build_job
-system:gcc:alpine3.18:amd64:
- <<: *alpine_3_18_amd64_image
+system:gcc:alpine3.20:amd64:
+ <<: *alpine_3_20_amd64_image
<<: *system_test_job
needs:
- - job: gcc:alpine3.18:amd64
+ - job: gcc:alpine3.20:amd64
artifacts: true
-unit:gcc:alpine3.18:amd64:
- <<: *alpine_3_18_amd64_image
+unit:gcc:alpine3.20:amd64:
+ <<: *alpine_3_20_amd64_image
<<: *unit_test_job
needs:
- - job: gcc:alpine3.18:amd64
+ - job: gcc:alpine3.20:amd64
artifacts: true
# Jobs for regular GCC builds on Oracle Linux 8 (amd64)
@@ -735,12 +806,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
@@ -748,7 +819,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
@@ -760,12 +831,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
@@ -773,7 +844,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
@@ -823,6 +894,30 @@ unit:gcc:bookworm:amd64:
- job: gcc:bookworm:amd64
artifacts: true
+# Jobs for RBT zone- & cache-enabled GCC builds on Debian 12 "bookworm" (amd64)
+
+gcc:bookworm:rbt:amd64:
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON}"
+ EXTRA_CONFIGURE: "--with-libidn2 --with-zonedb=rbt --with-cachedb=rbt"
+ <<: *debian_bookworm_amd64_image
+ <<: *build_job
+
+system:gcc:bookworm:rbt:amd64:
+ <<: *debian_bookworm_amd64_image
+ <<: *system_test_job
+ needs:
+ - job: unit:gcc:bookworm:rbt:amd64
+ artifacts: true
+
+unit:gcc:bookworm:rbt:amd64:
+ <<: *debian_bookworm_amd64_image
+ <<: *unit_test_job
+ needs:
+ - job: gcc:bookworm:rbt:amd64
+ artifacts: true
+
# Build job for cross-compiled GCC builds on 64-bit Debian 12 "bookworm"
# (amd64) with 32-bit BIND 9.
@@ -877,7 +972,7 @@ gcc:ossl3:sid:amd64:
<<: *build_job
system:gcc:ossl3:sid:amd64:
- # Set up environment variables to run pkcs11-provider system tests
+ # Set up environment variables to run pkcs11-provider based system tests
variables:
OPENSSL_CONF: "/var/tmp/etc/openssl-provider.cnf"
SOFTHSM2_CONF: "/var/tmp/softhsm2/softhsm2.conf"
@@ -909,6 +1004,7 @@ gcc:sid:amd64:
system:gcc:sid:amd64:
<<: *debian_sid_amd64_image
<<: *system_test_job
+ <<: *system_test_make_check_job
needs:
- job: gcc:sid:amd64
artifacts: true
@@ -942,7 +1038,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:
@@ -952,7 +1048,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)
@@ -972,7 +1068,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
@@ -986,7 +1082,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:
@@ -1073,7 +1169,31 @@ unit:gcc:jammy:amd64:
- job: gcc:jammy:amd64
artifacts: true
-# Jobs for ASAN builds on Fedora 38 (amd64)
+# Jobs for regular GCC builds on Ubuntu 24.04 Noble Numbat (amd64)
+
+gcc:noble:amd64:
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON}"
+ EXTRA_CONFIGURE: "--with-libidn2"
+ <<: *ubuntu_noble_amd64_image
+ <<: *build_job
+
+system:gcc:noble:amd64:
+ <<: *ubuntu_noble_amd64_image
+ <<: *system_test_job
+ needs:
+ - job: gcc:noble:amd64
+ artifacts: true
+
+unit:gcc:noble:amd64:
+ <<: *ubuntu_noble_amd64_image
+ <<: *unit_test_job
+ needs:
+ - job: gcc:noble:amd64
+ artifacts: true
+
+# Jobs for ASAN builds on Fedora 40 (amd64)
gcc:asan:
variables:
@@ -1081,20 +1201,20 @@ gcc:asan:
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined"
LDFLAGS: "-fsanitize=address,undefined"
EXTRA_CONFIGURE: "--with-libidn2 --without-jemalloc"
- <<: *fedora_38_amd64_image
+ <<: *fedora_40_amd64_image
<<: *build_job
system:gcc:asan:
variables:
LSAN_OPTIONS: "suppressions=$CI_PROJECT_DIR/suppr-lsan.txt"
- <<: *fedora_38_amd64_image
+ <<: *fedora_40_amd64_image
<<: *system_test_job
needs:
- job: gcc:asan
artifacts: true
unit:gcc:asan:
- <<: *fedora_38_amd64_image
+ <<: *fedora_40_amd64_image
<<: *unit_test_job
needs:
- job: gcc:asan
@@ -1123,7 +1243,7 @@ unit:clang:asan:
- job: clang:asan
artifacts: true
-# Jobs for TSAN builds on Fedora 38 (amd64)
+# Jobs for TSAN builds on Fedora 40 (amd64)
gcc:tsan:
variables:
@@ -1131,13 +1251,13 @@ gcc:tsan:
CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread"
LDFLAGS: "-fsanitize=thread"
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock --without-jemalloc"
- <<: *tsan_fedora_38_amd64_image
+ <<: *tsan_fedora_40_amd64_image
<<: *build_job
system:gcc:tsan:
variables:
TSAN_OPTIONS: "${TSAN_OPTIONS_FEDORA}"
- <<: *tsan_fedora_38_amd64_image
+ <<: *tsan_fedora_40_amd64_image
<<: *system_test_tsan_job
needs:
- job: gcc:tsan
@@ -1146,7 +1266,7 @@ system:gcc:tsan:
unit:gcc:tsan:
variables:
TSAN_OPTIONS: "${TSAN_OPTIONS_FEDORA}"
- <<: *tsan_fedora_38_amd64_image
+ <<: *tsan_fedora_40_amd64_image
<<: *unit_test_tsan_job
needs:
- job: gcc:tsan
@@ -1260,56 +1380,60 @@ unit:clang:bookworm:amd64:
- job: clang:bookworm:amd64
artifacts: true
-# Jobs for Clang builds on FreeBSD 12 (amd64)
+# Jobs for Clang builds on FreeBSD 13 (amd64)
-clang:freebsd12:amd64:
+clang:freebsd13: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_LIBEDIT} --with-gssapi=/usr/local/bin/krb5-config"
USER: gitlab-runner
- <<: *freebsd_12_amd64_image
+ <<: *freebsd_13_amd64_image
<<: *build_job
-system:clang:freebsd12:amd64:
- <<: *freebsd_12_amd64_image
+system:clang:freebsd13:amd64:
+ <<: *freebsd_13_amd64_image
<<: *system_test_job
variables:
USER: gitlab-runner
needs:
- - job: clang:freebsd12:amd64
+ - job: clang:freebsd13:amd64
artifacts: true
-unit:clang:freebsd12:amd64:
- <<: *freebsd_12_amd64_image
+unit:clang:freebsd13:amd64:
+ <<: *freebsd_13_amd64_image
<<: *unit_test_job
needs:
- - job: clang:freebsd12:amd64
+ - job: clang:freebsd13:amd64
artifacts: true
-# Jobs for Clang builds on FreeBSD 13 (amd64)
+# Jobs for Clang builds on FreeBSD 14 (amd64)
-clang:freebsd13:amd64:
+clang:freebsd14: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_EDITLINE} --with-gssapi=/usr/local/bin/krb5-config"
USER: gitlab-runner
- <<: *freebsd_13_amd64_image
+ <<: *freebsd_14_amd64_image
<<: *build_job
-system:clang:freebsd13:amd64:
- <<: *freebsd_13_amd64_image
+system:clang:freebsd14:amd64:
+ <<: *freebsd_14_amd64_image
<<: *system_test_job
variables:
USER: gitlab-runner
needs:
- - job: clang:freebsd13:amd64
+ - job: clang:freebsd14:amd64
artifacts: true
-unit:clang:freebsd13:amd64:
- <<: *freebsd_13_amd64_image
+unit:clang:freebsd14:amd64:
+ <<: *freebsd_14_amd64_image
<<: *unit_test_job
needs:
- - job: clang:freebsd13:amd64
+ - job: clang:freebsd14:amd64
artifacts: true
# Jobs for Clang builds on OpenBSD (amd64)
@@ -1322,17 +1446,6 @@ clang:openbsd:amd64:
<<: *openbsd_amd64_image
<<: *build_job
-system:clang:openbsd:amd64:
- <<: *openbsd_amd64_image
- <<: *system_test_job
- <<: *api_schedules_triggers_web_triggering_rules
- variables:
- USER: gitlab-runner
- needs:
- - job: clang:openbsd:amd64
- artifacts: true
- allow_failure: true
-
unit:clang:openbsd:amd64:
<<: *openbsd_amd64_image
<<: *unit_test_job
@@ -1342,27 +1455,24 @@ unit:clang:openbsd:amd64:
- job: clang:openbsd:amd64
artifacts: true
-# Job producing a release tarball
+# Job producing a release directory
release:
<<: *base_image
stage: release
script:
- - export BIND_DIRECTORY="$(basename "$(find . -name "bind-*.tar.*" -printf "%f")" ".tar.${TARBALL_EXTENSION}")"
+ - export BIND_DIRECTORY="$(basename bind-*.tar.xz ".tar.xz")"
# Prepare release tarball contents (tarballs + documentation)
- - mkdir -p release/doc/arm
- - pushd release
- - mv "../${BIND_DIRECTORY}.tar.${TARBALL_EXTENSION}" .
- - tar --extract --file="${BIND_DIRECTORY}.tar.${TARBALL_EXTENSION}"
+ - mkdir -p "${BIND_DIRECTORY}-release/doc/arm"
+ - pushd "${BIND_DIRECTORY}-release"
+ - mv "../${BIND_DIRECTORY}.tar.xz" .
+ - tar --extract --file="${BIND_DIRECTORY}.tar.xz"
- mv "${BIND_DIRECTORY}"/{CHANGES*,COPYRIGHT,LICENSE,README.md,srcid} .
- rm -rf "${BIND_DIRECTORY}"
- mv "../doc/arm/_build/html" doc/arm/
- - mv "../doc/arm/_build/latex/Bv9ARM.pdf" doc/arm/
- mv "../doc/arm/_build/epub/Bv9ARM.epub" doc/arm/
- echo '
Redirect' > "RELEASE-NOTES-${BIND_DIRECTORY}.html"
- popd
- # Create release tarball
- - tar --create --file="${CI_COMMIT_TAG}.tar.gz" --gzip release/
needs:
- job: tarball-create
artifacts: true
@@ -1370,10 +1480,52 @@ release:
artifacts: true
only:
- tags
+ artifacts:
+ paths:
+ - "*-release"
+ expire_in: "1 month"
+
+# Job signing the source tarballs in the release directory
+
+sign:
+ stage: release
+ tags:
+ - signer
+ script:
+ - export RELEASE_DIRECTORY="$(echo *-release)"
+ - pushd "${RELEASE_DIRECTORY}"
+ - |
+ echo
+ cat > /tmp/sign-bind9.sh <>> Signing \${FILE}..."
+ gpg2 --local-user "\${SIGNING_KEY_FINGERPRINT}" --armor --digest-algo SHA512 --detach-sign --output "\${FILE}.asc" "\${FILE}"
+ done
+ } 2>&1 | tee "${CI_PROJECT_DIR}/signing.log"
+ EOF
+ chmod +x /tmp/sign-bind9.sh
+ echo -e "\e[31m*** Please sign the releases by following the instructions at:\e[0m"
+ echo -e "\e[31m*** \e[0m"
+ echo -e "\e[31m*** ${SIGNING_HELP_URL}\e[0m"
+ echo -e "\e[31m*** \e[0m"
+ echo -e "\e[31m*** Sleeping until files in ${PWD} are signed... ⌛\e[0m"
+ while [ "$(find . -name "*.asc" -size +0 | sed "s|\.asc$||" | sort)" != "$(find . -name "*.tar.xz" | sort)" ]; do sleep 10; done
+ - popd
+ - tar --create --file="${RELEASE_DIRECTORY}.tar.gz" --gzip "${RELEASE_DIRECTORY}"
artifacts:
paths:
- "*.tar.gz"
+ - signing.log
expire_in: never
+ needs:
+ - job: release
+ artifacts: true
+ only:
+ - tags
+ when: manual
+ allow_failure: false
# Coverity Scan analysis upload
@@ -1430,7 +1582,7 @@ coverity:
# Respdiff tests
-respdiff-short:
+respdiff:
<<: *respdiff_job
<<: *default_triggering_rules
<<: *debian_bookworm_amd64_image
@@ -1439,9 +1591,9 @@ respdiff-short:
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"
+ - 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-short:asan:
+respdiff:asan:
<<: *respdiff_job
<<: *default_triggering_rules
<<: *debian_bookworm_amd64_image
@@ -1452,9 +1604,9 @@ respdiff-short:asan:
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"
+ - 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-short:tsan:
+respdiff:tsan:
<<: *respdiff_job
<<: *default_triggering_rules
<<: *tsan_debian_bookworm_amd64_image
@@ -1466,219 +1618,312 @@ respdiff-short:tsan:
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"
+ - 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"
after_script:
- *find_python
- *parse_tsan
-respdiff-long:
+respdiff-third-party:
<<: *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"
- MAX_DISAGREEMENTS_PERCENTAGE: "0.5"
- 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_job
- <<: *api_schedules_tags_triggers_web_triggering_rules
+ <<: *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"
+ CFLAGS: "${CFLAGS_COMMON} -Og"
MAX_DISAGREEMENTS_PERCENTAGE: "0.5"
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"
+ - bash respdiff.sh -s third_party -q "${PWD}/100k_mixed.txt" -c 1 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}"
-respdiff-long:tsan:
- <<: *respdiff_job
- <<: *api_schedules_tags_triggers_web_triggering_rules
- <<: *tsan_debian_bookworm_amd64_image
+# Performance tests
+
+# Run shotgun:udp right away, but delay other shotgun jobs sligthly in order to
+# allow re-use of the built container image. Otherwise, the jobs would do the
+# same builds in parallel rather than re-use the already built image.
+shotgun:udp:
+ <<: *shotgun_job
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}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named"
- after_script:
- - *find_python
- - *parse_tsan
+ SHOTGUN_SCENARIO: udp
+ SHOTGUN_TRAFFIC_MULTIPLIER: 15
-respdiff-long-third-party:
- <<: *respdiff_job
- <<: *api_schedules_tags_triggers_web_triggering_rules
- <<: *debian_bookworm_amd64_image
+shotgun:tcp:
+ <<: *shotgun_job
variables:
- CC: gcc
- CFLAGS: "${CFLAGS_COMMON} -Og"
- MAX_DISAGREEMENTS_PERCENTAGE: "0.5"
- script:
- - bash respdiff.sh -s third_party -q "${PWD}/100k_mixed.txt" -c 1 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}"
+ SHOTGUN_SCENARIO: tcp
+ SHOTGUN_TRAFFIC_MULTIPLIER: 6
+ when: delayed
+ start_in: 5 minutes
-# "Stress" tests
+shotgun:dot:
+ <<: *shotgun_job
+ variables:
+ SHOTGUN_SCENARIO: dot
+ SHOTGUN_TRAFFIC_MULTIPLIER: 3
+ when: delayed
+ start_in: 5 minutes
-# Parallel build in the "make" step is avoided since multiple jobs can be
-# executed concurrently on the same runner. This may present problems when one
-# job runs a performance-sensitive task of replying to queries while another
-# takes all cores to build BIND.
-.stress: &stress_job
+.stress-test: &stress_test
stage: performance
script:
- *configure
- *setup_interfaces
- - make -k all V=1
+ - make -j${BUILD_PARALLEL_JOBS:-1} -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
artifacts: true
+
+.stress-test-short: &stress_test_short_job
+ <<: *stress_test
+ artifacts:
+ untracked: true
+ when: always
+ only:
+ - merge_requests
+
+stress:short:authoritative:fedora:40:amd64:
+ <<: *fedora_40_amd64_image
+ <<: *linux_amd64
+ <<: *stress_test_short_job
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/bin/flame
+ MODE: authoritative
+ RATE: 10000
+ RUN_TIME: 15
+
+stress:short:recursive:fedora:40:amd64:
+ <<: *fedora_40_amd64_image
+ <<: *linux_amd64
+ <<: *stress_test_short_job
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/bin/flame
+ MODE: recursive
+ RATE: 10000
+ RUN_TIME: 15
+
+stress:short:rpz:fedora:40:amd64:
+ <<: *fedora_40_amd64_image
+ <<: *linux_amd64
+ <<: *stress_test_short_job
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/bin/flame
+ MODE: rpz
+ RATE: 1500
+ RUN_TIME: 15
+
+stress:short:authoritative:fedora:40:arm64:
+ <<: *fedora_40_arm64_image
+ <<: *linux_arm64
+ <<: *stress_test_short_job
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/bin/flame
+ MODE: authoritative
+ RATE: 10000
+ RUN_TIME: 15
+
+stress:short:recursive:fedora:40:arm64:
+ <<: *fedora_40_arm64_image
+ <<: *linux_arm64
+ <<: *stress_test_short_job
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/bin/flame
+ MODE: recursive
+ RATE: 10000
+ RUN_TIME: 15
+
+stress:short:rpz:fedora:40:arm64:
+ <<: *fedora_40_arm64_image
+ <<: *linux_arm64
+ <<: *stress_test_short_job
+ variables:
+ CC: gcc
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/bin/flame
+ MODE: rpz
+ RATE: 1500
+ RUN_TIME: 15
+
+stress:short:authoritative:freebsd13:amd64:
+ <<: *freebsd_stress_amd64
+ <<: *stress_test_short_job
+ variables:
+ CC: clang
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/local/bin/flame
+ MODE: authoritative
+ RATE: 10000
+ RUN_TIME: 15
+
+stress:short:recursive:freebsd13:amd64:
+ <<: *freebsd_stress_amd64
+ <<: *stress_test_short_job
+ variables:
+ CC: clang
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/local/bin/flame
+ MODE: recursive
+ RATE: 10000
+ RUN_TIME: 15
+
+stress:short:rpz:freebsd13:amd64:
+ <<: *freebsd_stress_amd64
+ <<: *stress_test_short_job
+ variables:
+ CC: clang
+ CFLAGS: "${CFLAGS_COMMON} -Og"
+ FLAME: /usr/local/bin/flame
+ MODE: rpz
+ RATE: 1500
+ RUN_TIME: 15
+
+.stress-test-long: &stress_test_long_job
+ <<: *stress_test
artifacts:
untracked: true
expire_in: "1 week"
when: always
timeout: 2h
-stress:authoritative:fedora:38:amd64:
- <<: *fedora_38_amd64_image
- <<: *linux_stress_amd64
- <<: *stress_job
+stress:authoritative:fedora:40:amd64:
+ <<: *fedora_40_amd64_image
+ <<: *linux_amd64
+ <<: *stress_test_long_job
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/bin/flame
MODE: authoritative
RATE: 10000
- RUN_TIME: 1
+ RUN_TIME: 60
only:
variables:
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /authoritative/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i)
-stress:recursive:fedora:38:amd64:
- <<: *fedora_38_amd64_image
- <<: *linux_stress_amd64
- <<: *stress_job
+stress:recursive:fedora:40:amd64:
+ <<: *fedora_40_amd64_image
+ <<: *linux_amd64
+ <<: *stress_test_long_job
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/bin/flame
MODE: recursive
RATE: 10000
- RUN_TIME: 1
+ RUN_TIME: 60
only:
variables:
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /recursive/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i)
-stress:rpz:fedora:38:amd64:
- <<: *fedora_38_amd64_image
- <<: *linux_stress_amd64
- <<: *stress_job
+stress:rpz:fedora:40:amd64:
+ <<: *fedora_40_amd64_image
+ <<: *linux_amd64
+ <<: *stress_test_long_job
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/bin/flame
MODE: rpz
RATE: 1500
- RUN_TIME: 1
+ RUN_TIME: 60
only:
variables:
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /rpz/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i)
-stress:authoritative:fedora:38:arm64:
- <<: *fedora_38_arm64_image
- <<: *linux_stress_arm64
- <<: *stress_job
+stress:authoritative:fedora:40:arm64:
+ <<: *fedora_40_arm64_image
+ <<: *linux_arm64
+ <<: *stress_test_long_job
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/bin/flame
MODE: authoritative
RATE: 10000
- RUN_TIME: 1
+ RUN_TIME: 60
only:
variables:
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /authoritative/i && $BIND_STRESS_TEST_ARCH =~ /arm64/i)
-stress:recursive:fedora:38:arm64:
- <<: *fedora_38_arm64_image
- <<: *linux_stress_arm64
- <<: *stress_job
+stress:recursive:fedora:40:arm64:
+ <<: *fedora_40_arm64_image
+ <<: *linux_arm64
+ <<: *stress_test_long_job
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/bin/flame
MODE: recursive
RATE: 10000
- RUN_TIME: 1
+ RUN_TIME: 60
only:
variables:
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /linux/i && $BIND_STRESS_TEST_MODE =~ /recursive/i && $BIND_STRESS_TEST_ARCH =~ /arm64/i)
-stress:rpz:fedora:38:arm64:
- <<: *fedora_38_arm64_image
- <<: *linux_stress_arm64
- <<: *stress_job
+stress:rpz:fedora:40:arm64:
+ <<: *fedora_40_arm64_image
+ <<: *linux_arm64
+ <<: *stress_test_long_job
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/bin/flame
MODE: rpz
RATE: 1500
- RUN_TIME: 1
+ RUN_TIME: 60
only:
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:
- <<: *freebsd_12_amd64_image
+stress:authoritative:freebsd13:amd64:
<<: *freebsd_stress_amd64
- <<: *stress_job
+ <<: *stress_test_long_job
variables:
CC: clang
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/local/bin/flame
MODE: authoritative
RATE: 10000
- RUN_TIME: 1
+ RUN_TIME: 60
only:
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:
- <<: *freebsd_12_amd64_image
+stress:recursive:freebsd13:amd64:
<<: *freebsd_stress_amd64
- <<: *stress_job
+ <<: *stress_test_long_job
variables:
CC: clang
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/local/bin/flame
MODE: recursive
RATE: 10000
- RUN_TIME: 1
+ RUN_TIME: 60
only:
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:
- <<: *freebsd_12_amd64_image
+stress:rpz:freebsd13:amd64:
<<: *freebsd_stress_amd64
- <<: *stress_job
+ <<: *stress_test_long_job
variables:
CC: clang
CFLAGS: "${CFLAGS_COMMON} -Og"
FLAME: /usr/local/bin/flame
MODE: rpz
RATE: 1500
- RUN_TIME: 1
+ RUN_TIME: 60
only:
variables:
- $CI_COMMIT_TAG || ($BIND_STRESS_TEST_OS =~ /freebsd/i && $BIND_STRESS_TEST_MODE =~ /rpz/i && $BIND_STRESS_TEST_ARCH =~ /amd64/i)
@@ -1751,3 +1996,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:$BIND_TEAM_WRITE_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"
diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md
index f8b82b694b..60bab3f6ce 100644
--- a/.gitlab/issue_templates/Bug.md
+++ b/.gitlab/issue_templates/Bug.md
@@ -2,45 +2,62 @@
If the bug you are reporting is potentially security-related - for example,
if it involves an assertion failure or other crash in `named` that can be
triggered repeatedly - then please make sure that you make the new issue
-confidential!
+confidential by clicking the checkbox at the bottom!
-->
### Summary
-(Summarize the bug encountered concisely.)
+
-### BIND version used
+### BIND version affected
+
### Steps to reproduce
-(How one can reproduce the issue - this is very important.)
+
+
+1.
+2.
+3.
### What is the current *bug* behavior?
-(What actually happens.)
+
### What is the expected *correct* behavior?
-(What you should see instead.)
+
### Relevant configuration files
-(Paste any relevant configuration files - please use code blocks (```)
+
-### Possible fixes
+### Relevant logs
-(If you can, link to the line of code that might be responsible for the
-problem.)
+
-/label ~bug
+/label ~Bug
diff --git a/.gitlab/issue_templates/Default.md b/.gitlab/issue_templates/Default.md
new file mode 100644
index 0000000000..c0079fa2a8
--- /dev/null
+++ b/.gitlab/issue_templates/Default.md
@@ -0,0 +1,8 @@
+Hi and thanks for filing an issue! It will be read with care by human beings.
+
+It would be a tremendous help if you could follow these steps first:
+- [ ] Search the existing issues in GitLab (both open and closed) to see if your report might be a duplicate. We have a large database here and many issues have already been fixed in the latest versions!
+- [ ] Make sure this is **not** a support question. If you have specific trouble configuring or debugging your setup, please use the bind-users mailing list: https://lists.isc.org/mailman/listinfo/bind-users
+- [ ] You have read and understood the "out in the open" support policy: https://blog.powerdns.com/2016/01/18/open-source-support-out-in-the-open/ . Even though it was written by the PowerDNS folks, we follow it as well!
+
+Before continuing, **please select the appropriate issue template in the drop-down menu above, under the heading _Description_**.
diff --git a/.gitlab/issue_templates/Feature_Request.md b/.gitlab/issue_templates/Feature_Request.md
index 9ad28f49ed..72d2cb4931 100644
--- a/.gitlab/issue_templates/Feature_Request.md
+++ b/.gitlab/issue_templates/Feature_Request.md
@@ -8,4 +8,4 @@
### Links / references
-/label ~"feature request"
+/label ~Feature
diff --git a/.gitlab/issue_templates/CVE.md b/.gitlab/issue_templates/Internal_use_only-CVE.md
similarity index 84%
rename from .gitlab/issue_templates/CVE.md
rename to .gitlab/issue_templates/Internal_use_only-CVE.md
index 782c2a4d04..7dcf7fe3a9 100644
--- a/.gitlab/issue_templates/CVE.md
+++ b/.gitlab/issue_templates/Internal_use_only-CVE.md
@@ -16,11 +16,9 @@ confidential!
| Mattermost Channel: | [CVE-YYYY-NNNN][mattermost_url] |
| Support Ticket: | [URL] |
| Release Checklist: | #NNNN |
-| Post-mortem Etherpad: | [postmortem-YYYY-MM][postmortem_url] |
[cvss_score]: https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:X/AC:X/PR:X/UI:X/S:X/C:X/I:X/A:X&version=3.1
[mattermost_url]:
-[postmortem_url]:
:bulb: **Click [here][checklist_explanations] (internal resource) for general information about the security incident handling process.**
@@ -30,14 +28,14 @@ confidential!
- [ ] [:link:][step_deputy] **(IM)** Pick a Deputy Incident Manager
- [ ] [:link:][step_respond] **(IM)** Respond to the bug reporter
- - [ ] [:link:][step_etherpad] **(IM)** Create an Etherpad for post-mortem
- [ ] [:link:][step_public_mrs] **(SwEng)** Ensure there are no public merge requests which inadvertently disclose the issue
- [ ] [:link:][step_assign_cve_id] **(IM)** Assign a CVE identifier
- [ ] [:link:][step_note_cve_info] **(SwEng)** Update this issue with the assigned CVE identifier and the CVSS score
- [ ] [:link:][step_versions_affected] **(SwEng)** Determine the range of product versions affected (including the Subscription Edition)
- [ ] [:link:][step_workarounds] **(SwEng)** Determine whether workarounds for the problem exist
- [ ] [:link:][step_coordinate] **(SwEng)** If necessary, coordinate with other parties
- - [ ] [:link:][step_earliest] **(Support)** Prepare and send out "earliest" notifications
+ - [ ] [:link:][step_earliest_prepare] **(Support)** Prepare "earliest" notification text and hand it off to Marketing
+ - [ ] [:link:][step_earliest_send] **(Marketing)** Update "earliest" notification document in SF portal and send bulk email to earliest customers
- [ ] [:link:][step_advisory_mr] **(Support)** Create a merge request for the Security Advisory and include all readily available information in it
- [ ] [:link:][step_reproducer_mr] **(SwEng)** Prepare a private merge request containing a system test reproducing the problem
- [ ] [:link:][step_notify_support] **(SwEng)** Notify Support when a reproducer is ready
@@ -55,46 +53,42 @@ confidential!
### At T-5
- - [ ] [:link:][step_send_asn] **(Support)** Send ASN to eligible customers
- - [ ] [:link:][step_preannouncement] **(Support)** (BIND 9 only) Send a pre-announcement email to the *bind-announce* mailing list to alert users that the upcoming release will include security fixes
-
-### At T-4
-
- - [ ] [:link:][step_verify_asn] **(Support)** Verify that all ASN-eligible customers have received the notification email
+ - [ ] [:link:][step_asn_documents] **(Marketing)** Update the text on the T-5 (from the Printing Press project) and "earliest" ASN documents in the SF portal
+ - [ ] [:link:][step_asn_links] **(Marketing)** (BIND 9 only) Update the BIND -S information document in SF with download links to the new versions
+ - [ ] [:link:][step_asn_send] **(Marketing)** Bulk email eligible customers to check the SF portal
+ - [ ] [:link:][step_preannouncement] **(Marketing)** (BIND 9 only) Send a pre-announcement email to the *bind-announce* mailing list to alert users that the upcoming release will include security fixes
### At T-1
- - [ ] [:link:][step_check_customers] **(Support)** Verify that any new or reinstated customers have received the notification email
- [ ] [:link:][step_packager_emails] **(First IM)** Send notifications to OS packagers
### On the Day of Public Disclosure
- - [ ] [:link:][step_clearance] **(IM)** Grant Support clearance to proceed with public release
- - [ ] [:link:][step_publish] **(Support)** Publish the releases (as outlined in the release checklist)
+ - [ ] [:link:][step_clearance] **(IM)** Grant QA & Marketing clearance to proceed with public release
+ - [ ] [:link:][step_publish] **(QA/Marketing)** Publish the releases (as outlined in the release checklist)
- [ ] [:link:][step_matrix] **(Support)** (BIND 9 only) Add the new CVEs to the vulnerability matrix in the Knowledge Base
- [ ] [:link:][step_publish_advisory] **(Support)** Bump Document Version for the Security Advisory and publish it in the Knowledge Base
- [ ] [:link:][step_notifications] **(First IM)** Send notification emails to third parties
- [ ] [:link:][step_mitre] **(First IM)** Advise MITRE about the disclosed CVEs
- [ ] [:link:][step_merge_advisory] **(First IM)** Merge the Security Advisory merge request
- [ ] [:link:][step_embargo_end] **(IM)** Inform original reporter (if external) that the security disclosure process is complete
- - [ ] [:link:][step_customers] **(Support)** Inform customers a fix has been released
+ - [ ] [:link:][step_asn_clear] **(Marketing)** Update the SF portal to clear the ASN
+ - [ ] [:link:][step_customers] **(Marketing)** Email ASN recipients that the embargo is lifted
### After Public Disclosure
- - [ ] [:link:][step_postmortem] **(First IM)** Organize post-mortem meeting and make sure it happens
- - [ ] [:link:][step_tickets] **(Support)** Close support tickets
- [ ] [:link:][step_regression] **(QA)** Merge a regression test reproducing the bug into all affected (and still maintained) branches
[step_deputy]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#pick-a-deputy-incident-manager
[step_respond]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#respond-to-the-bug-reporter
-[step_etherpad]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#create-an-etherpad-for-post-mortem
[step_public_mrs]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#ensure-there-are-no-public-merge-requests-which-inadvertently-disclose-the-issue
[step_assign_cve_id]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#assign-a-cve-identifier
[step_note_cve_info]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#update-this-issue-with-the-assigned-cve-identifier-and-the-cvss-score
[step_versions_affected]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#determine-the-range-of-product-versions-affected-including-the-subscription-edition
[step_workarounds]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#determine-whether-workarounds-for-the-problem-exist
[step_coordinate]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#if-necessary-coordinate-with-other-parties
-[step_earliest]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#prepare-and-send-out-earliest-notifications
+[step_earliest_prepare]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#prepare-earliest-notification-text-and-hand-it-off-to-marketing
+[step_earliest_send]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#update-earliest-notification-document-in-sf-portal-and-send-bulk-email-to-earliest-customers
[step_advisory_mr]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#create-a-merge-request-for-the-security-advisory-and-include-all-readily-available-information-in-it
[step_reproducer_mr]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#prepare-a-private-merge-request-containing-a-system-test-reproducing-the-problem
[step_notify_support]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#notify-support-when-a-reproducer-is-ready
@@ -109,12 +103,12 @@ confidential!
[step_merge_fixes]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#merge-the-cve-fixes-in-cve-identifier-order
[step_patches]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#prepare-a-standalone-patch-for-the-last-stable-release-of-each-affected-and-still-maintained-product-branch
[step_asn_releases]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#prepare-asn-releases-as-outlined-in-the-release-checklist
-[step_send_asn]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#send-asn-to-eligible-customers
+[step_asn_documents]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#update-the-text-on-the-t-5-from-the-printing-press-project-and-earliest-asn-documents-in-the-sf-portal
+[step_asn_links]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#bind-9-only-update-the-bind-s-information-document-in-sf-with-download-links-to-the-new-versions
+[step_asn_send]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#bulk-email-eligible-customers-to-check-the-sf-portal
[step_preannouncement]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#bind-9-only-send-a-pre-announcement-email-to-the-bind-announce-mailing-list-to-alert-users-that-the-upcoming-release-will-include-security-fixes
-[step_verify_asn]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#verify-that-all-asn-eligible-customers-have-received-the-notification-email
-[step_check_customers]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#verify-that-any-new-or-reinstated-customers-have-received-the-notification-email
[step_packager_emails]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#send-notifications-to-os-packagers
-[step_clearance]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#grant-support-clearance-to-proceed-with-public-release
+[step_clearance]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#grant-qa-marketing-clearance-to-proceed-with-public-release
[step_publish]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#publish-the-releases-as-outlined-in-the-release-checklist
[step_matrix]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#bind-9-only-add-the-new-cves-to-the-vulnerability-matrix-in-the-knowledge-base
[step_publish_advisory]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#bump-document-version-for-the-security-advisory-and-publish-it-in-the-knowledge-base
@@ -122,7 +116,8 @@ confidential!
[step_mitre]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#advise-mitre-about-the-disclosed-cves
[step_merge_advisory]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#merge-the-security-advisory-merge-request
[step_embargo_end]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#inform-original-reporter-if-external-that-the-security-disclosure-process-is-complete
-[step_customers]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#inform-customers-a-fix-has-been-released
-[step_postmortem]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#organize-post-mortem-meeting-and-make-sure-it-happens
-[step_tickets]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#close-support-tickets
+[step_asn_clear]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#update-the-sf-portal-to-clear-the-asn
+[step_customers]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#email-asn-recipients-that-the-embargo-is-lifted
[step_regression]: https://gitlab.isc.org/isc-private/isc-wiki/-/wikis/Security-Incident-Handling-Checklist-Explanations#merge-a-regression-test-reproducing-the-bug-into-all-affected-and-still-maintained-branches
+
+/confidential
diff --git a/.gitlab/issue_templates/Release.md b/.gitlab/issue_templates/Release.md
deleted file mode 100644
index 82d635e70d..0000000000
--- a/.gitlab/issue_templates/Release.md
+++ /dev/null
@@ -1,100 +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 [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 HTML and PDF versions 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)*** 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.
- - [ ] ***(Support)*** 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)
- - [ ] ***(QA)*** Prepare the `patches/` subdirectory for each security release (if applicable).
- - [ ] ***(QA)*** Notify Support that the releases have been prepared.
- - [ ] ***(Support)*** Send out ASNs (if applicable).
-
-### On the Day of Public Release
-
- - [ ] ***(Support)*** Wait for clearance from Security Officer to proceed with the public release (if applicable).
- - [ ] ***(Support)*** Place tarballs in public location on FTP site.
- - [ ] ***(Support)*** Publish links to downloads on ISC website. [Example](https://gitlab.isc.org/website/theme-staging-site/-/commit/1ac7b30b73cb03228df4cd5651fa4e774ac35625)
- - [ ] ***(Support)*** Add the new releases to the [vulnerability matrix in the Knowledge Base](https://kb.isc.org/docs/aa-00913).
- - [ ] ***(Support)*** Use the [Printing Press project](https://gitlab.isc.org/isc-private/printing-press/-/wikis/home#adding-new-documents) to prepare a release announcement email and send it to the *bind-announce* mailing list.
- - [ ] ***(Support)*** Write email to *bind-users* (if a major release). [Example](https://lists.isc.org/pipermail/bind-users/2022-January/105624.html)
- - [ ] ***(Support)*** Send eligible customers updated links to the Subscription Edition (update the -S edition delivery tickets, even if those links were provided earlier via an ASN ticket).
- - [ ] ***(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)*** Inform Marketing of the release.
- - [ ] ***(Marketing)*** Post a short note to Mastodon.
- - [ ] ***(Marketing)*** Update [Wikipedia entry for BIND](https://en.wikipedia.org/wiki/BIND).
- - [ ] ***(Marketing)*** Write blog article (if a major release).
- - [ ] ***(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.
diff --git a/.gitlab/issue_templates/Security_issue.md b/.gitlab/issue_templates/Security_issue.md
new file mode 100644
index 0000000000..2789c45e24
--- /dev/null
+++ b/.gitlab/issue_templates/Security_issue.md
@@ -0,0 +1,139 @@
+### Summary
+
+
+### BIND versions affected
+
+
+### Preconditions and assumptions
+
+
+### Attacker's abilities
+
+
+
+### Impact
+
+
+
+### Steps to reproduce
+
+
+1.
+2.
+3.
+
+### What is the current *bug* behavior?
+
+
+
+### What is the expected *correct* behavior?
+
+
+
+### Relevant logs
+
+
+### Coordination
+- Does this issue affect multiple implementations?
+
+
+- Have you shared the information with anyone else?
+
+
+- What is your plan to publicize this issue?
+
+
+### Acknowledgements
+
+
+
+
+/label ~Bug ~Security
+/confidential
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000000..3204f5b481
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,26 @@
+Alan Clegg
+Aram Sargsyan
+Artem Boldariev
+Curtis Blackburn
+Curtis Blackburn
+Diego Fronza
+Evan Hunt Evan Hunt
+Håvard Eidnes
+Jeremy C. Reed
+Jeremy C. Reed
+Joey Salazar
+John H. DuBois III
+Mark Andrews
+Mark Andrews
+Mark Andrews
+Matthijs Mekking
+Nicki Křížek
+Ondřej Surý
+Ondřej Surý
+Ondřej Surý
+Petr Menšík
+Petr Menšík
+Robert Edmonds
+Tatuya JINMEI 神明達哉
+Witold Kręcicki
+Witold Kręcicki
diff --git a/.pylintrc b/.pylintrc
index 07d503514d..b5ea55a5e5 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -5,6 +5,7 @@ disable=
C0115, # missing-class-docstring
C0116, # missing-function-docstring
C0209, # consider-using-f-string
+ C0301, # line-too-long, handled better by black
C0415, # import-outside-toplevel
R0801, # duplicate-code
R0903, # too-few-public-methods
diff --git a/.reuse/dep5 b/.reuse/dep5
index ded1db308a..a58145d214 100644
--- a/.reuse/dep5
+++ b/.reuse/dep5
@@ -24,6 +24,7 @@ Files: **/*.after*
**/testdata/*
.github/*
.gitlab/*
+ .mailmap
AUTHORS
CHANGES
COPYRIGHT
@@ -38,15 +39,31 @@ Files: **/*.after*
bin/tests/system/doth/CA/index.txt
bin/tests/system/doth/CA/index.txt.attr
bin/tests/system/doth/CA/serial
- bin/tests/system/notify/ns4/named.port.in
+ bin/tests/system/formerr/badnsec3owner
+ bin/tests/system/formerr/badrecordname
+ bin/tests/system/formerr/dupans
+ bin/tests/system/formerr/dupquestion
+ bin/tests/system/formerr/keyclass
+ bin/tests/system/formerr/malformeddeltype
+ bin/tests/system/formerr/malformedrrsig
bin/tests/system/formerr/nametoolong
bin/tests/system/formerr/noquestions
- bin/tests/system/formerr/twoquestions
+ bin/tests/system/formerr/optwrongname
+ bin/tests/system/formerr/qtypeasanswer
+ bin/tests/system/formerr/questionclass
+ bin/tests/system/formerr/shortquestion
+ bin/tests/system/formerr/shortrecord
+ bin/tests/system/formerr/tsignotlast
+ bin/tests/system/formerr/tsigwrongclass
+ bin/tests/system/formerr/twoquestionnames
+ bin/tests/system/formerr/twoquestiontypes
+ bin/tests/system/formerr/wrongclass
bin/tests/system/forward/CA/CA.cfg
bin/tests/system/forward/CA/README
bin/tests/system/forward/CA/index.txt
bin/tests/system/forward/CA/index.txt.attr
bin/tests/system/forward/CA/serial
+ bin/tests/system/isctest/vars/.ac_vars/*
bin/tests/system/journal/ns1/managed-keys.bind.in
bin/tests/system/journal/ns1/managed-keys.bind.jnl.in
bin/tests/system/journal/ns2/managed-keys.bind.in
@@ -54,6 +71,10 @@ Files: **/*.after*
bin/tests/system/keepalive/expected
bin/tests/system/legacy/ns6/edns512.db.signed
bin/tests/system/legacy/ns7/edns512-notcp.db.signed
+ bin/tests/system/masterfile/knowngood.include
+ bin/tests/system/masterfile/knowngood.ttl1
+ bin/tests/system/masterfile/knowngood.ttl2
+ bin/tests/system/notify/ns4/named.port.in
bin/tests/system/nsupdate/CA/CA.cfg
bin/tests/system/nsupdate/CA/README
bin/tests/system/nsupdate/CA/index.txt
@@ -81,7 +102,10 @@ Files: **/*.after*
bin/tests/system/unknown/large.out
bin/tests/system/xfer/ans5/badkeydata
bin/tests/system/xfer/ans5/badmessageid
+ bin/tests/system/xfer/ans5/ednsformerr
+ bin/tests/system/xfer/ans5/ednsnotimp
bin/tests/system/xfer/ans5/goodaxfr
+ bin/tests/system/xfer/ans5/ixfrnotimp
bin/tests/system/xfer/ans5/partial
bin/tests/system/xfer/ans5/soamismatch
bin/tests/system/xfer/ans5/unknownkey
@@ -157,6 +181,7 @@ Files: **/.clang-format
.clang-format
.clang-format.headers
.dir-locals.el
+ .editorconfig
.git-blame-ignore-revs
.gitattributes
.gitignore
@@ -170,6 +195,7 @@ Files: **/.clang-format
doc/misc/options
doc/misc/rndc.grammar
sonar-project.properties
+ tests/bench/names.csv
Copyright: Internet Systems Consortium, Inc. ("ISC")
License: CC0-1.0
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c108dbeec6..a013c4ea73 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -173,7 +173,7 @@ of documentation in the BIND source tree:
they document, in files ending in `.rst`: for example, the
`named` man page is `bin/named/named.rst`.
* The *BIND 9 Administrator Reference Manual* is in the .rst files in
- `doc/arm/`; the PDF and HTML versions are automatically generated from
+ `doc/arm/`; the HTML version is automatically generated from
the `.rst` files.
* API documentation is in the header file describing the API, in
Doxygen-formatted comments.
diff --git a/LICENSES/LicenseRef-Automake-exception-2.0.txt b/LICENSES/Autoconf-exception-generic.txt
similarity index 100%
rename from LICENSES/LicenseRef-Automake-exception-2.0.txt
rename to LICENSES/Autoconf-exception-generic.txt
diff --git a/Makefile.docs b/Makefile.docs
index 674f51d2fc..a205c5efc7 100644
--- a/Makefile.docs
+++ b/Makefile.docs
@@ -25,11 +25,8 @@ common_SPHINXOPTS = \
-a \
$(SPHINX_V)
-# The "today" variable set below is not directly used in the ARM, but its value
-# is implicitly inserted on the title page of the PDF file produced by Sphinx.
ALLSPHINXOPTS = \
$(common_SPHINXOPTS) \
- -D today="$(RELEASE_DATE)" \
-D rst_epilog="$$(printf "$${RST_EPILOG}")" \
$(SPHINXOPTS) \
$(srcdir)
diff --git a/Makefile.tests b/Makefile.tests
index e1b7e0e046..a0ea914d40 100644
--- a/Makefile.tests
+++ b/Makefile.tests
@@ -21,3 +21,8 @@ AM_CPPFLAGS += \
LDADD += \
$(top_builddir)/tests/libtest/libtest.la \
$(CMOCKA_LIBS)
+
+if HAVE_JEMALLOC
+AM_CFLAGS += $(JEMALLOC_CFLAGS)
+LDADD += $(JEMALLOC_LIBS)
+endif
diff --git a/Makefile.top b/Makefile.top
index d01317dadb..5a2fae22e4 100644
--- a/Makefile.top
+++ b/Makefile.top
@@ -23,12 +23,20 @@ AM_LDFLAGS += \
-Wl,-flat_namespace
endif HOST_MACOS
-LIBISC_CFLAGS = \
+if HAVE_JEMALLOC
+LIBISC_CFLAGS = $(JEMALLOC_CFLAGS)
+LIBISC_LIBS = $(JEMALLOC_LIBS)
+else
+LIBISC_CFLAGS =
+LIBISC_LIBS =
+endif
+
+LIBISC_CFLAGS += \
-I$(top_srcdir)/include \
-I$(top_srcdir)/lib/isc/include \
-I$(top_builddir)/lib/isc/include
-LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBISC_LIBS += $(top_builddir)/lib/isc/libisc.la
if HAVE_DTRACE
LIBISC_DTRACE = $(top_builddir)/lib/isc/probes.lo
endif
@@ -63,3 +71,9 @@ LIBISCCC_CFLAGS = \
LIBISCCC_LIBS = \
$(top_builddir)/lib/isccc/libisccc.la
+
+LIBSAQ_CFLAGS = \
+ -I$(top_srcdir)/lib/saq/include
+
+LIBSAQ_LIBS = \
+ $(top_builddir)/lib/saq/libsaq.la
diff --git a/bin/check/check-tool.c b/bin/check/check-tool.c
index 93cde40550..352d83acbf 100644
--- a/bin/check/check-tool.c
+++ b/bin/check/check-tool.c
@@ -73,7 +73,7 @@
#define ERR_IS_MXCNAME 6
#define ERR_IS_SRVCNAME 7
-static const char *dbtype[] = { "rbt" };
+static const char *dbtype[] = { ZONEDB_DEFAULT };
int debug = 0;
const char *journal = NULL;
@@ -88,6 +88,7 @@ bool dochecksrv = false;
bool docheckns = false;
#endif /* if CHECK_LOCAL */
dns_zoneopt_t zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_CHECKMX |
+ DNS_ZONEOPT_CHECKDUPRR | DNS_ZONEOPT_CHECKSPF |
DNS_ZONEOPT_MANYERRORS | DNS_ZONEOPT_CHECKNAMES |
DNS_ZONEOPT_CHECKINTEGRITY |
#if CHECK_SIBLING
diff --git a/bin/check/named-checkconf.c b/bin/check/named-checkconf.c
index c4c4155b1b..7c442b917d 100644
--- a/bin/check/named-checkconf.c
+++ b/bin/check/named-checkconf.c
@@ -63,7 +63,7 @@ usage(void) {
"usage: %s [-achijlvz] [-p [-x]] [-t directory] "
"[named.conf]\n",
program);
- exit(1);
+ exit(EXIT_SUCCESS);
}
/*% directory callback */
@@ -242,7 +242,9 @@ configure_zone(const char *vclass, const char *view, const cfg_obj_t *zconfig,
* Skip checks when using an alternate data source.
*/
cfg_map_get(zoptions, "database", &dbobj);
- if (dbobj != NULL && strcmp("rbt", cfg_obj_asstring(dbobj)) != 0) {
+ if (dbobj != NULL &&
+ strcmp(ZONEDB_DEFAULT, cfg_obj_asstring(dbobj)) != 0)
+ {
return (ISC_R_SUCCESS);
}
diff --git a/bin/check/named-checkzone.c b/bin/check/named-checkzone.c
index 795624651a..db2e345561 100644
--- a/bin/check/named-checkzone.c
+++ b/bin/check/named-checkzone.c
@@ -79,7 +79,7 @@ usage(void) {
"%s zonename [ (filename|-) ]\n",
prog_name,
progmode == progmode_check ? "[-o filename]" : "-o filename");
- exit(1);
+ exit(EXIT_FAILURE);
}
static void
@@ -147,15 +147,12 @@ main(int argc, char **argv) {
UNREACHABLE();
}
- /* Compilation specific defaults */
+ /* When compiling, disable checks by default */
if (progmode == progmode_compile) {
- zone_options |= (DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_FATALNS |
- DNS_ZONEOPT_CHECKSPF | DNS_ZONEOPT_CHECKDUPRR |
- DNS_ZONEOPT_CHECKNAMES |
- DNS_ZONEOPT_CHECKNAMESFAIL |
- DNS_ZONEOPT_CHECKWILDCARD);
- } else {
- zone_options |= (DNS_ZONEOPT_CHECKDUPRR | DNS_ZONEOPT_CHECKSPF);
+ zone_options = 0;
+ docheckmx = false;
+ docheckns = false;
+ dochecksrv = false;
}
#define ARGCMP(X) (strcmp(isc_commandline_argument, X) == 0)
@@ -209,7 +206,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -i: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -243,7 +240,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -k: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -254,7 +251,7 @@ main(int argc, char **argv) {
if (*endp != '\0') {
fprintf(stderr, "source serial number "
"must be numeric");
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -265,7 +262,7 @@ main(int argc, char **argv) {
if (*endp != '\0') {
fprintf(stderr, "maximum TTL "
"must be numeric");
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -282,7 +279,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -n: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -299,7 +296,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -m: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -324,7 +321,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -r: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -337,7 +334,7 @@ main(int argc, char **argv) {
fprintf(stderr,
"unknown or unsupported style: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -347,13 +344,13 @@ main(int argc, char **argv) {
fprintf(stderr, "isc_dir_chroot: %s: %s\n",
isc_commandline_argument,
isc_result_totext(result));
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
case 'v':
printf("%s\n", PACKAGE_VERSION);
- exit(0);
+ exit(EXIT_SUCCESS);
case 'w':
workdir = isc_commandline_argument;
@@ -367,7 +364,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -C: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -388,7 +385,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -M: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -405,7 +402,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -S: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -417,7 +414,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "invalid argument to -T: %s\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -441,7 +438,7 @@ main(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", prog_name,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -450,7 +447,7 @@ main(int argc, char **argv) {
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "isc_dir_chdir: %s: %s\n", workdir,
isc_result_totext(result));
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -466,7 +463,7 @@ main(int argc, char **argv) {
} else {
fprintf(stderr, "unknown file format: %s\n",
inputformatstr);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -484,12 +481,12 @@ main(int argc, char **argv) {
rawversion > 1U)
{
fprintf(stderr, "unknown raw format version\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "unknown file format: %s\n",
outputformatstr);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
diff --git a/bin/check/named-compilezone.rst b/bin/check/named-compilezone.rst
index 0b4c98d449..8c68d0d6d2 100644
--- a/bin/check/named-compilezone.rst
+++ b/bin/check/named-compilezone.rst
@@ -30,10 +30,16 @@ Description
:program:`named-compilezone` checks the syntax and integrity of a zone file,
and dumps the zone contents to a specified file in a specified format.
-It applies strict check levels by default, since the
-dump output is used as an actual zone file loaded by :iscman:`named`.
-When manually specified otherwise, the check levels must at least be as
-strict as those specified in the :iscman:`named` configuration file.
+
+Unlike :program:`named-checkzone`, zone contents are not strictly checked
+by default. If the output is to be used as an actual zone file to be loaded
+by :iscman:`named`, then the check levels should be manually configured to
+be at least as strict as those specified in the :iscman:`named` configuration
+file.
+
+Running :program:`named-checkzone` on the input prior to compiling will
+ensure that the zone compiles with the default requirements of
+:iscman:`named`.
Options
~~~~~~~
@@ -77,13 +83,13 @@ Options
``check-svcb:fail`` turns on additional checks on ``_dns`` SVCB
records and ``check-svcb:ignore`` disables these checks. The
- default is ``check-svcb:fail``.
+ default is ``check-svcb:ignore``.
.. option:: -i mode
This option performs post-load zone integrity checks. Possible modes are
- ``full`` (the default), ``full-sibling``, ``local``,
- ``local-sibling``, and ``none``.
+ ``full``, ``full-sibling``, ``local``,
+ ``local-sibling``, and ``none`` (the default).
Mode ``full`` checks that MX records refer to A or AAAA records
(both in-zone and out-of-zone hostnames). Mode ``local`` only
@@ -127,7 +133,7 @@ Options
.. option:: -k mode
This option performs ``check-names`` checks with the specified failure mode.
- Possible modes are ``fail`` (the default), ``warn``, and ``ignore``.
+ Possible modes are ``fail``, ``warn``, and ``ignore`` (the default).
.. option:: -l ttl
@@ -144,19 +150,19 @@ Options
.. option:: -m mode
This option specifies whether MX records should be checked to see if they are
- addresses. Possible modes are ``fail``, ``warn`` (the default), and
- ``ignore``.
+ addresses. Possible modes are ``fail``, ``warn``, and
+ ``ignore`` (the default).
.. option:: -M mode
This option checks whether a MX record refers to a CNAME. Possible modes are
- ``fail``, ``warn`` (the default), and ``ignore``.
+ ``fail``, ``warn``, and ``ignore`` (the default).
.. option:: -n mode
This option specifies whether NS records should be checked to see if they are
- addresses. Possible modes are ``fail`` (the default), ``warn``, and
- ``ignore``.
+ addresses. Possible modes are ``fail``, ``warn``, and
+ ``ignore`` (the default).
.. option:: -o filename
@@ -167,7 +173,7 @@ Options
This option checks for records that are treated as different by DNSSEC but are
semantically equal in plain DNS. Possible modes are ``fail``,
- ``warn`` (the default), and ``ignore``.
+ ``warn``, and ``ignore`` (the default).
.. option:: -s style
@@ -180,7 +186,7 @@ Options
.. option:: -S mode
This option checks whether an SRV record refers to a CNAME. Possible modes are
- ``fail``, ``warn`` (the default), and ``ignore``.
+ ``fail``, ``warn``, and ``ignore`` (the default).
.. option:: -t directory
@@ -192,7 +198,7 @@ Options
This option checks whether Sender Policy Framework (SPF) records exist and issues a
warning if an SPF-formatted TXT record is not also present. Possible
- modes are ``warn`` (the default) and ``ignore``.
+ modes are ``warn`` and ``ignore`` (the default).
.. option:: -w directory
@@ -210,7 +216,7 @@ Options
This option specifies whether to check for non-terminal wildcards. Non-terminal
wildcards are almost always the result of a failure to understand the
wildcard matching algorithm (:rfc:`4592`). Possible modes are ``warn``
- (the default) and ``ignore``.
+ and ``ignore`` (the default).
.. option:: zonename
diff --git a/bin/confgen/keygen.c b/bin/confgen/keygen.c
index 4698d1a078..348c05d874 100644
--- a/bin/confgen/keygen.c
+++ b/bin/confgen/keygen.c
@@ -124,7 +124,7 @@ generate_key(isc_mem_t *mctx, dns_secalg_t alg, int keysize,
DO("generate key",
dst_key_generate(dns_rootname, alg, keysize, 0, 0, DNS_KEYPROTO_ANY,
- dns_rdataclass_in, mctx, &key, NULL));
+ dns_rdataclass_in, NULL, mctx, &key, NULL));
isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
diff --git a/bin/confgen/rndc-confgen.c b/bin/confgen/rndc-confgen.c
index 4c2c3cafed..c840e2c284 100644
--- a/bin/confgen/rndc-confgen.c
+++ b/bin/confgen/rndc-confgen.c
@@ -146,7 +146,8 @@ main(int argc, char **argv) {
keyfile = isc_commandline_argument;
break;
case 'h':
- usage(0);
+ usage(EXIT_SUCCESS);
+ break;
case 'k':
case 'y': /* Compatible with rndc -y. */
keyname = isc_commandline_argument;
@@ -192,15 +193,15 @@ main(int argc, char **argv) {
if (isc_commandline_option != '?') {
fprintf(stderr, "%s: invalid argument -%c\n",
program, isc_commandline_option);
- usage(1);
+ usage(EXIT_FAILURE);
} else {
- usage(0);
+ usage(EXIT_SUCCESS);
}
break;
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -209,7 +210,7 @@ main(int argc, char **argv) {
POST(argv);
if (argc > 0) {
- usage(1);
+ usage(EXIT_FAILURE);
}
if (alg == DST_ALG_HMACMD5) {
diff --git a/bin/confgen/tsig-keygen.c b/bin/confgen/tsig-keygen.c
index 620717c626..c421702c8b 100644
--- a/bin/confgen/tsig-keygen.c
+++ b/bin/confgen/tsig-keygen.c
@@ -138,13 +138,13 @@ main(int argc, char **argv) {
keysize = alg_bits(alg);
break;
case 'h':
- usage(0);
+ usage(EXIT_SUCCESS);
case 'k':
case 'y':
if (progmode == progmode_confgen) {
keyname = isc_commandline_argument;
} else {
- usage(1);
+ usage(EXIT_FAILURE);
}
break;
case 'M':
@@ -157,7 +157,7 @@ main(int argc, char **argv) {
if (progmode == progmode_confgen) {
quiet = true;
} else {
- usage(1);
+ usage(EXIT_FAILURE);
}
break;
case 'r':
@@ -167,29 +167,29 @@ main(int argc, char **argv) {
if (progmode == progmode_confgen) {
self_domain = isc_commandline_argument;
} else {
- usage(1);
+ usage(EXIT_FAILURE);
}
break;
case 'z':
if (progmode == progmode_confgen) {
zone = isc_commandline_argument;
} else {
- usage(1);
+ usage(EXIT_FAILURE);
}
break;
case '?':
if (isc_commandline_option != '?') {
fprintf(stderr, "%s: invalid argument -%c\n",
program, isc_commandline_option);
- usage(1);
+ usage(EXIT_FAILURE);
} else {
- usage(0);
+ usage(EXIT_SUCCESS);
}
break;
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -200,11 +200,11 @@ main(int argc, char **argv) {
POST(argv);
if (self_domain != NULL && zone != NULL) {
- usage(1); /* -s and -z cannot coexist */
+ usage(EXIT_FAILURE); /* -s and -z cannot coexist */
}
if (argc > isc_commandline_index) {
- usage(1);
+ usage(EXIT_FAILURE);
}
/* Use canonical algorithm name */
diff --git a/bin/confgen/tsig-keygen.rst b/bin/confgen/tsig-keygen.rst
index 7420bede43..5ecce5d0e1 100644
--- a/bin/confgen/tsig-keygen.rst
+++ b/bin/confgen/tsig-keygen.rst
@@ -27,9 +27,10 @@ Synopsis
Description
~~~~~~~~~~~
-:program:`tsig-keygen` is an utility that generates keys for use in TSIG signing.
-The resulting keys can be used, for example, to secure dynamic DNS updates
-to a zone, or for the :iscman:`rndc` command channel.
+:program:`tsig-keygen` is an utility that generates keys for use with TSIG
+(Transaction Signatures) as defined in :rfc:`2845`. The resulting keys can be used,
+for example, to secure dynamic DNS updates to a zone, or for the :iscman:`rndc`
+command channel.
A domain name can be specified on the command line to be used as the name
of the generated key. If no name is specified, the default is ``tsig-key``.
diff --git a/bin/confgen/util.c b/bin/confgen/util.c
index 23b7f3fd57..5d7ce509e4 100644
--- a/bin/confgen/util.c
+++ b/bin/confgen/util.c
@@ -13,14 +13,16 @@
/*! \file */
-#include "util.h"
#include
#include
#include
#include
+#include
#include
+#include "util.h"
+
extern bool verbose;
extern const char *progname;
@@ -45,6 +47,5 @@ fatal(const char *format, ...) {
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
- isc__tls_setfatalmode();
- exit(1);
+ _exit(EXIT_FAILURE);
}
diff --git a/bin/delv/delv.c b/bin/delv/delv.c
index 0ee545a962..a8e1c65bae 100644
--- a/bin/delv/delv.c
+++ b/bin/delv/delv.c
@@ -247,7 +247,7 @@ usage(void) {
"process)\n"
" +[no]yaml (Present the results as "
"YAML)\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
noreturn static void
@@ -263,8 +263,7 @@ fatal(const char *format, ...) {
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
- isc__tls_setfatalmode();
- exit(1);
+ _exit(EXIT_FAILURE);
}
static void
@@ -1165,7 +1164,7 @@ plus_option(char *option) {
if (state) {
fprintf(stderr, "Invalid option: "
"+dlv is obsolete\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
case 'n': /* dnssec */
@@ -1380,10 +1379,6 @@ plus_option(char *option) {
fprintf(stderr, "Invalid option: +%s\n", option);
usage();
}
-
- if (qmin && !fulltrace) {
- fatal("'+qmin' cannot be used without '+ns'");
- }
return;
}
@@ -1436,7 +1431,7 @@ dash_option(char *option, char *next, bool *open_type_class) {
break;
case 'h':
usage();
- exit(0);
+ exit(EXIT_SUCCESS);
case 'i':
no_sigs = true;
root_validation = false;
@@ -1446,7 +1441,7 @@ dash_option(char *option, char *next, bool *open_type_class) {
break;
case 'v':
printf("delv %s\n", PACKAGE_VERSION);
- exit(0);
+ exit(EXIT_SUCCESS);
default:
UNREACHABLE();
}
@@ -1583,7 +1578,7 @@ dash_option(char *option, char *next, bool *open_type_class) {
typeset = true;
} else {
fprintf(stderr, "Invalid IP address %s\n", value);
- exit(1);
+ exit(EXIT_FAILURE);
}
return (value_from_next);
invalid_option:
@@ -1732,6 +1727,11 @@ parse_args(int argc, char **argv) {
}
}
+ /* check consistency */
+ if (qmin && !fulltrace) {
+ fatal("'+qmin' cannot be used without '+ns'");
+ }
+
/*
* If no qname or qtype specified, search for root/NS
* If no qtype specified, use A
@@ -1961,7 +1961,8 @@ recvresponse(void *arg) {
fatal("request event result: %s", isc_result_totext(result));
}
- dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
+ dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE,
+ &response);
result = dns_request_getresponse(request, response,
DNS_MESSAGEPARSE_PRESERVEORDER);
@@ -2076,7 +2077,8 @@ sendquery(void *arg) {
/* Construct query message */
CHECK(convert_name(&qfn, &query_name, qname));
- dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
+ dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
+ &message);
message->opcode = dns_opcode_query;
message->flags = DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_AD;
if (cdflag) {
@@ -2103,9 +2105,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:
@@ -2144,7 +2145,7 @@ run_server(void *arg) {
ns_server_create(mctx, matchview, &sctx);
- CHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
+ CHECK(dns_dispatchmgr_create(mctx, loopmgr, netmgr, &dispatchmgr));
isc_sockaddr_any(&any);
CHECK(dns_dispatch_createudp(dispatchmgr, &any, &dispatch));
CHECK(ns_interfacemgr_create(mctx, sctx, loopmgr, netmgr, dispatchmgr,
@@ -2152,7 +2153,7 @@ run_server(void *arg) {
CHECK(dns_view_create(mctx, dispatchmgr, dns_rdataclass_in, "_default",
&view));
- CHECK(dns_cache_create(loopmgr, dns_rdataclass_in, "", &cache));
+ CHECK(dns_cache_create(loopmgr, dns_rdataclass_in, "", mctx, &cache));
dns_view_setcache(view, cache, false);
dns_cache_detach(&cache);
dns_view_setdstport(view, destport);
@@ -2167,8 +2168,8 @@ run_server(void *arg) {
dns_view_initsecroots(view);
CHECK(setup_dnsseckeys(NULL, view));
- CHECK(dns_view_createresolver(view, loopmgr, 1, 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);
@@ -2184,9 +2185,10 @@ run_server(void *arg) {
CHECK(isc_nm_listenstreamdns(netmgr, ISC_NM_LISTEN_ONE, &addr,
ns_client_request, ifp, accept_cb, ifp, 10,
- NULL, NULL, &ifp->tcplistensocket));
+ 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;
diff --git a/bin/dig/dig.c b/bin/dig/dig.c
index 54f7f81e33..c98fa88277 100644
--- a/bin/dig/dig.c
+++ b/bin/dig/dig.c
@@ -119,7 +119,7 @@ usage(void) {
print_usage(stderr);
fprintf(stderr, "\nUse \"dig -h\" (or \"dig -h | more\") "
"for complete list of options\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
#endif /* if TARGET_OS_IPHONE */
@@ -252,6 +252,14 @@ help(void) {
"request)\n"
" +padding=### (Set padding block size "
"[0])\n"
+ " "
+ "+[no]proxy[=src_addr[#src_port]-dst_addr[#dst_port]] "
+ "(Add PROXYv2 headers to the queries. If addresses are omitted, "
+ "LOCAL PROXYv2 headers are added)\n"
+ " "
+ "+[no]proxy-plain[=src_addr[#src_port]-dst_addr[#dst_port]] "
+ "(The same as '+[no]proxy', but send PROXYv2 headers ahead of "
+ "any encryption if an encrypted transport is used)\n"
" +qid=### (Specify the query ID to "
"use when sending queries)\n"
" +[no]qr (Print question before "
@@ -298,8 +306,7 @@ help(void) {
" +[no]tls-keyfile=file (Load client TLS "
"private key from file)\n"
" +[no]trace (Trace delegation down "
- "from root "
- "[+dnssec])\n"
+ "from root [implies +dnssec])\n"
" +tries=### (Set number of UDP "
"attempts) [3]\n"
" +[no]ttlid (Control display of ttls "
@@ -365,6 +372,39 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
}
printf(";; SERVER: %s(%s) (%s)\n", fromtext, query->userarg,
proto);
+
+ if (query->lookup->proxy_mode) {
+ printf(";; CLIENT PROXY HEADER");
+
+ if ((dig_lookup_is_tls(query->lookup) ||
+ (query->lookup->https_mode &&
+ !query->lookup->http_plain)) &&
+ query->lookup->proxy_plain)
+ {
+ printf(" (plain)");
+ }
+
+ printf(": ");
+
+ if (!query->lookup->proxy_local) {
+ char src_buf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
+ char dst_buf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
+
+ isc_sockaddr_format(
+ &query->lookup->proxy_src_addr, src_buf,
+ sizeof(src_buf));
+
+ isc_sockaddr_format(
+ &query->lookup->proxy_dst_addr, dst_buf,
+ sizeof(dst_buf));
+ printf("source: %s, destination: %s", src_buf,
+ dst_buf);
+ } else {
+ printf("LOCAL");
+ }
+
+ printf("\n");
+ }
time(&tnow);
(void)localtime_r(&tnow, &tmnow);
@@ -1052,6 +1092,323 @@ printgreeting(int argc, char **argv, dig_lookup_t *lookup) {
goto invalid_option; \
} while (0)
+/*
+ * Parse source and destination addresses in the same format as used by "kdig":
+ *
+ * SRC_ADDR[#SRC_PORT]-DST_ADDR[#DST_PORT]
+ *
+ * This can be described (pretty closely for our purpose) using the
+ * following EBNF grammar:
+ *
+ * S = proxy-addrs. (* start rule *)
+ * proxy-addrs = addr "-" addr EOF.
+ * addr = addr-char { addr-char } ["#" port ].
+ * port = digit { digit }.
+ * addr-char = .
+ * EOF = '\0'.
+ */
+#define MATCH(ch) (st->str[0] == (ch))
+#define MATCH_DIGIT() isdigit((unsigned char)(st->str[0]))
+#define ADVANCE() st->str++
+#define GETP() (st->str)
+
+typedef struct isc_proxy_addrs_parser_state {
+ const char *str;
+
+ const char *last_addr_start;
+ size_t last_addr_len;
+
+ const char *last_port_start;
+ size_t last_port_len;
+
+ const char *src_addr_start;
+ size_t src_addr_len;
+
+ const char *src_port_start;
+ size_t src_port_len;
+
+ const char *dst_addr_start;
+ size_t dst_addr_len;
+
+ const char *dst_port_start;
+ size_t dst_port_len;
+} isc_proxy_addrs_parser_state_t;
+
+static bool
+rule_proxy_addrs(isc_proxy_addrs_parser_state_t *st);
+
+static bool
+rule_addr(isc_proxy_addrs_parser_state_t *st);
+
+static bool
+rule_port(isc_proxy_addrs_parser_state_t *st);
+
+static bool
+rule_addr_char(isc_proxy_addrs_parser_state_t *st);
+
+static void
+proxy_handle_port_string(const char *port_start, const size_t port_len,
+ in_port_t *pport) {
+ char buf[512] = { 0 }; /* max */
+ size_t string_size = 0, max_string_bytes = 0;
+ unsigned int tmp;
+ isc_result_t result;
+
+ string_size = port_len + 1;
+ max_string_bytes = string_size > sizeof(buf) ? sizeof(buf)
+ : string_size;
+
+ (void)strlcpy(buf, port_start, max_string_bytes);
+ result = parse_uint(&tmp, buf, MAXPORT, "port number");
+ if (result != ISC_R_SUCCESS) {
+ fatal("Couldn't parse port number");
+ }
+ *pport = tmp;
+}
+
+static isc_result_t
+proxy_handle_addr_string(const char *addr_start, const size_t addr_len,
+ const in_port_t addr_port, isc_sockaddr_t *addr) {
+ isc_result_t result = ISC_R_FAILURE;
+ char buf[512] = { 0 }; /* max */
+ size_t string_size = 0, max_string_bytes = 0;
+ struct in_addr ipv4 = { 0 };
+ struct in6_addr ipv6 = { 0 };
+ int ret = 0;
+
+ string_size = addr_len + 1;
+ max_string_bytes = string_size > sizeof(buf) ? sizeof(buf)
+ : string_size;
+
+ (void)strlcpy(buf, addr_start, max_string_bytes);
+
+ ret = inet_pton(AF_INET, buf, &ipv4);
+ if (ret == 1) {
+ isc_sockaddr_fromin(addr, &ipv4, addr_port);
+ result = ISC_R_SUCCESS;
+ } else {
+ ret = inet_pton(AF_INET6, buf, &ipv6);
+ if (ret == 1) {
+ isc_sockaddr_fromin6(addr, &ipv6, addr_port);
+ result = ISC_R_SUCCESS;
+ }
+ }
+
+ return (result);
+}
+
+static bool
+parse_proxy_addresses(const char *addrs, isc_sockaddr_t *psrc,
+ isc_sockaddr_t *pdst) {
+ isc_result_t result = ISC_R_FAILURE;
+ isc_sockaddr_t src = { 0 }, dst = { 0 };
+ isc_proxy_addrs_parser_state_t st = { 0 };
+ in_port_t src_port = 0, dst_port = 53; /* Follow kdig footsteps */
+
+ REQUIRE(addrs != NULL && *addrs != '\0');
+ REQUIRE(psrc != NULL);
+ REQUIRE(pdst != NULL);
+
+ st.str = addrs;
+
+ /* start syntax analysis and verification */
+ if (!rule_proxy_addrs(&st)) {
+ warn("PROXY source and destination addresses cannot be parsed");
+ return (false);
+ }
+
+ /* get port numeric values */
+ if (st.src_port_len > 0) {
+ INSIST(st.src_port_start != NULL);
+ proxy_handle_port_string(st.src_port_start, st.src_port_len,
+ &src_port);
+ }
+
+ if (st.dst_port_len > 0) {
+ INSIST(st.dst_port_start != NULL);
+ proxy_handle_port_string(st.dst_port_start, st.dst_port_len,
+ &dst_port);
+ }
+
+ /* get addresses */
+ INSIST(st.src_addr_len > 0);
+ INSIST(st.src_addr_start != NULL);
+ INSIST(st.dst_addr_len > 0);
+ INSIST(st.dst_addr_start != NULL);
+
+ result = proxy_handle_addr_string(st.src_addr_start, st.src_addr_len,
+ src_port, &src);
+ if (result != ISC_R_SUCCESS) {
+ warn("Cannot get PROXY source address: %s",
+ isc_result_totext(result));
+ return (false);
+ }
+
+ result = proxy_handle_addr_string(st.dst_addr_start, st.dst_addr_len,
+ dst_port, &dst);
+ if (result != ISC_R_SUCCESS) {
+ warn("Cannot get PROXY destination address: %s",
+ isc_result_totext(result));
+ return (false);
+ }
+
+ /* addresses should be of the same type */
+ if (isc_sockaddr_pf(&src) != isc_sockaddr_pf(&dst)) {
+ warn("PROXY source and destination addresses must be of the "
+ "same type");
+ return (false);
+ }
+
+ *psrc = src;
+ *pdst = dst;
+
+ return (true);
+}
+
+static bool
+rule_proxy_addrs(isc_proxy_addrs_parser_state_t *st) {
+ if (!rule_addr(st)) {
+ return (false);
+ }
+
+ st->src_addr_start = st->last_addr_start;
+ st->src_addr_len = st->last_addr_len;
+ st->src_port_start = st->last_port_start;
+ st->src_port_len = st->last_port_len;
+
+ if (!MATCH('-')) {
+ return (false);
+ }
+
+ ADVANCE();
+
+ if (!rule_addr(st)) {
+ return (false);
+ }
+
+ st->dst_addr_start = st->last_addr_start;
+ st->dst_addr_len = st->last_addr_len;
+ st->dst_port_start = st->last_port_start;
+ st->dst_port_len = st->last_port_len;
+
+ if (!MATCH('\0')) {
+ return (false);
+ }
+
+ return (true);
+}
+
+static bool
+rule_addr(isc_proxy_addrs_parser_state_t *st) {
+ const char *start = GETP();
+ if (!rule_addr_char(st)) {
+ return (false);
+ }
+
+ while (rule_addr_char(st)) {
+ /* skip */
+ }
+
+ st->last_addr_start = start;
+ st->last_addr_len = GETP() - start;
+
+ if (MATCH('#')) {
+ ADVANCE();
+
+ if (!rule_port(st)) {
+ return (false);
+ }
+ }
+
+ return (true);
+}
+
+static bool
+rule_port(isc_proxy_addrs_parser_state_t *st) {
+ const char *start = GETP();
+ if (!MATCH_DIGIT()) {
+ return (false);
+ }
+
+ ADVANCE();
+
+ while (MATCH_DIGIT()) {
+ ADVANCE();
+ }
+
+ st->last_port_start = start;
+ st->last_port_len = GETP() - start;
+
+ return (true);
+}
+
+static bool
+rule_addr_char(isc_proxy_addrs_parser_state_t *st) {
+ if (MATCH('#') || MATCH('-') || MATCH('\0')) {
+ return (false);
+ }
+
+ ADVANCE();
+
+ return (true);
+}
+
+#undef GETP
+#undef ADVANCE
+#undef MATCH_DIGIT
+#undef MATCH
+
+static bool
+plus_proxy_handle_addresses(const char *value, const bool state,
+ dig_lookup_t *lookup) {
+ lookup->proxy_mode = state;
+ if (!state) {
+ /*
+ * We are not interested in the option value in that
+ * case
+ */
+ return (true);
+ }
+
+ if (value == NULL || *value == '\0') {
+ lookup->proxy_local = true;
+ return (true);
+ }
+
+ if (!parse_proxy_addresses(value, &lookup->proxy_src_addr,
+ &lookup->proxy_dst_addr))
+ {
+ return (false);
+ }
+ return (true);
+}
+
+static bool
+plus_proxy_options(const char *cmd, const char *value, const bool state,
+ dig_lookup_t *lookup) {
+ switch (cmd[5]) {
+ case '-':
+ FULLCHECK("proxy-plain");
+ lookup->proxy_plain = state;
+ if (!plus_proxy_handle_addresses(value, state, lookup)) {
+ goto invalid_option;
+ }
+ break;
+ case '\0':
+ FULLCHECK("proxy");
+ if (!plus_proxy_handle_addresses(value, state, lookup)) {
+ goto invalid_option;
+ }
+ break;
+ default:
+ goto invalid_option;
+ }
+ return (true);
+
+invalid_option:
+ return (false);
+}
+
static bool
plus_tls_options(const char *cmd, const char *value, const bool state,
dig_lookup_t *lookup) {
@@ -1318,6 +1675,8 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
switch (cmd[1]) {
case 'e': /* defname */
FULLCHECK("defname");
+ fprintf(stderr, ";; +[no]defname option is "
+ "deprecated; use +[no]search\n");
if (!lookup->trace) {
usesearch = state;
}
@@ -1438,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':
@@ -1692,12 +2055,11 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
goto invalid_option;
}
break;
- case 'm': /* multiline */
+ case 'm':
switch (cmd[1]) {
case 'a':
FULLCHECK("mapped");
- fprintf(stderr, ";; +mapped option is deprecated");
- break;
+ fatal("+mapped option no longer supported");
case 'u':
FULLCHECK("multiline");
lookup->multiline = state;
@@ -1797,19 +2159,30 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
}
break;
case 'p':
- FULLCHECK("padding");
- if (state && lookup->edns == -1) {
- lookup->edns = DEFAULT_EDNS_VERSION;
- }
- if (value == NULL) {
- goto need_value;
- }
- result = parse_uint(&num, value, 512, "padding");
- if (result != ISC_R_SUCCESS) {
- warn("Couldn't parse padding");
- goto exit_or_usage;
+ switch (cmd[1]) {
+ case 'a':
+ FULLCHECK("padding");
+ if (state && lookup->edns == -1) {
+ lookup->edns = DEFAULT_EDNS_VERSION;
+ }
+ if (value == NULL) {
+ goto need_value;
+ }
+ result = parse_uint(&num, value, 512, "padding");
+ if (result != ISC_R_SUCCESS) {
+ warn("Couldn't parse padding");
+ goto exit_or_usage;
+ }
+ lookup->padding = (uint16_t)num;
+ break;
+ case 'r':
+ if (!plus_proxy_options(cmd, value, state, lookup)) {
+ goto invalid_option;
+ }
+ break;
+ default:
+ goto invalid_option;
}
- lookup->padding = (uint16_t)num;
break;
case 'q':
switch (cmd[1]) {
@@ -1940,8 +2313,7 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
break;
case 'i': /* sigchase */
FULLCHECK("sigchase");
- fprintf(stderr, ";; +sigchase option is deprecated");
- break;
+ fatal("+sigchase option no longer supported");
case 'p': /* split */
FULLCHECK("split");
if (value != NULL && !state) {
@@ -2065,8 +2437,7 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
break;
case 'o':
FULLCHECK("topdown");
- fprintf(stderr, ";; +topdown option is deprecated");
- break;
+ fatal("+topdown option no longer supported");
case 'r':
switch (cmd[2]) {
case 'a': /* trace */
@@ -2107,9 +2478,8 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
break;
case 'u': /* trusted-key */
FULLCHECK("trusted-key");
- fprintf(stderr, ";; +trusted-key option is "
- "deprecated");
- break;
+ fatal("+trusted-key option "
+ "no longer supported");
default:
goto invalid_option;
}
@@ -2146,9 +2516,8 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
switch (cmd[2]) {
case 'e':
FULLCHECK("unexpected");
- fprintf(stderr, ";; +unexpected option "
- "is deprecated");
- break;
+ fatal("+unexpected option "
+ "no longer supported");
case 'k':
FULLCHECK("unknownformat");
lookup->print_unknown_format = state;
@@ -2156,11 +2525,7 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
default:
goto invalid_option;
}
- break;
- default:
- goto invalid_option;
}
-
break;
case 'v':
FULLCHECK("vc");
@@ -2263,17 +2628,15 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
break;
case 'h':
help();
- exit(0);
+ exit(EXIT_SUCCESS);
break;
case 'i':
- /* deprecated */
- break;
+ fatal("-%c removed", option[0]);
case 'm': /* memdebug */
/* memdebug is handled in preparse_args() */
break;
case 'n':
- /* deprecated */
- break;
+ fatal("-%c removed", option[0]);
case 'r':
debug("digrc (late)");
digrc = false;
@@ -2283,7 +2646,7 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
break;
case 'v':
printf("DiG %s\n", PACKAGE_VERSION);
- exit(0);
+ exit(EXIT_SUCCESS);
break;
}
if (strlen(option) > 1U) {
@@ -2458,7 +2821,7 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
ptr = ptr2;
ptr2 = ptr3;
} else {
- hmac = DST_ALG_HMACMD5;
+ hmac_alg = DST_ALG_HMACMD5;
digestbits = 0;
}
/* XXXONDREJ: FIXME */
@@ -2492,7 +2855,7 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
ISC_LIST_APPEND(lookup_list, *lookup, link);
} else {
fprintf(stderr, "Invalid IP address %s\n", value);
- exit(1);
+ exit(EXIT_FAILURE);
}
return (value_from_next);
invalid_option:
diff --git a/bin/dig/dig.rst b/bin/dig/dig.rst
index 32029417f5..83c0ab7acf 100644
--- a/bin/dig/dig.rst
+++ b/bin/dig/dig.rst
@@ -507,6 +507,44 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to
mandatory. Responses to padded queries may also be padded, but only
if the query uses TCP or DNS COOKIE.
+.. option:: +proxy[=src_addr[#src_port]-dst_addr[#dst_port]], +noproxy
+
+ When this option is set, :program:`dig` adds PROXYv2 headers to the
+ queries. When source and destination addresses are specified, the
+ headers contain them and use the ``PROXY`` command. It means for
+ the remote peer that the queries were sent on behalf of another
+ node and that the PROXYv2 header reflects the original connection
+ endpoints. The default source port is ``0`` and destination port is
+ `53`.
+
+ For encrypted DNS transports, to prevent accidental information
+ leakage, encryption is applied to the PROXYv2 headers: the headers
+ are sent right after the handshake process has been completed.
+
+ For plain DNS transports, no encryption is applied to the PROXYv2
+ headers.
+
+ If the addressees are omitted, PROXYv2 headers, that use the
+ ``LOCAL`` command set, are added instead. For the remote peer, that
+ means that the queries were sent on purpose without being relayed,
+ so the real connection endpoint addresses must be used.
+
+.. option:: +proxy-plain[=src_addr[#src_port]-dst_addr[#dst_port], +noproxy-plain
+
+ The same as ``+[no]proxy``, but instructs ``dig`` to send PROXYv2
+ headers ahead of any encryption, before any handshake messages are
+ sent. That makes :program:`dig` behave exactly how it is described
+ in the PROXY protocol specification, but not all software expects
+ such behaviour.
+
+ Please consult the software documentation to find out if you need
+ this option. (for example, ``dnsdist`` expects encrypted PROXYv2
+ headers sent over TLS when encryption is used, while ``HAProxy``
+ and many other software packages expect plain ones).
+
+ For plain DNS transports the option is effectively an alias for the
+ ``+[no]proxy`` described above.
+
.. option:: +qid=value
This option specifies the query ID to use when sending queries.
@@ -576,11 +614,6 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to
This option performs [or does not perform] a search showing intermediate results.
-.. option:: +sigchase, +nosigchase
-
- This feature is now obsolete and has been removed; use :iscman:`delv`
- instead.
-
.. option:: +split=W
This option splits long hex- or base64-formatted fields in resource records into
@@ -650,25 +683,23 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to
server TLS certificate verification. Otherwise, the DNS server name
is used. This option has no effect if :option:`+tls-ca` is not specified.
-.. option:: +topdown, +notopdown
-
- This feature is related to :option:`dig +sigchase`, which is obsolete and
- has been removed. Use :iscman:`delv` instead.
-
.. option:: +trace, +notrace
- This option toggles tracing of the delegation path from the root name servers for
- the name being looked up. Tracing is disabled by default. When
- tracing is enabled, :program:`dig` makes iterative queries to resolve the
- name being looked up. It follows referrals from the root servers,
- showing the answer from each server that was used to resolve the
- lookup.
+ This option toggles tracing of the delegation path from the root name
+ servers for the name being looked up. Tracing is disabled by default.
+ When tracing is enabled, :program:`dig` makes iterative queries to
+ resolve the name being looked up. It follows referrals from the root
+ servers, showing the answer from each server that was used to resolve
+ the lookup.
If ``@server`` is also specified, it affects only the initial query for
the root zone name servers.
- :option:`+dnssec` is also set when :option:`+trace` is set, to better emulate the
- default queries from a name server.
+ :option:`+dnssec` is set when :option:`+trace` is set, to better
+ emulate the default queries from a name server.
+
+ Note that the ``delv +ns`` option can also be used for tracing the
+ resolution of a name from the root (see :iscman:`delv`).
.. option:: +tries=T
@@ -676,11 +707,6 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to
instead of the default, 3. If ``T`` is less than or equal to zero,
the number of tries is silently rounded up to 1.
-.. option:: +trusted-key=####
-
- This option formerly specified trusted keys for use with :option:`dig +sigchase`. This
- feature is now obsolete and has been removed; use :iscman:`delv` instead.
-
.. option:: +ttlid, +nottlid
This option displays [or does not display] the TTL when printing the record.
diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c
index 5e8e8422a5..1e2303a1af 100644
--- a/bin/dig/dighost.c
+++ b/bin/dig/dighost.c
@@ -138,7 +138,7 @@ char keyfile[MXNAME] = "";
char keysecret[MXNAME] = "";
unsigned char cookie_secret[33];
unsigned char cookie[8];
-dst_algorithm_t hmac = DST_ALG_UNKNOWN;
+dst_algorithm_t hmac_alg = DST_ALG_UNKNOWN;
unsigned int digestbits = 0;
isc_buffer_t *namebuf = NULL;
dns_tsigkey_t *tsigkey = NULL;
@@ -359,8 +359,6 @@ get_reverse(char *reverse, size_t len, char *value, bool strict) {
}
}
-void (*dighost_pre_exit_hook)(void) = NULL;
-
#if TARGET_OS_IPHONE
void
warn(const char *format, ...) {
@@ -393,10 +391,7 @@ digexit(void) {
exitcode = 10;
}
if (fatalexit != 0) {
- exitcode = fatalexit;
- }
- if (dighost_pre_exit_hook != NULL) {
- dighost_pre_exit_hook();
+ _exit(fatalexit);
}
exit(exitcode);
}
@@ -411,7 +406,11 @@ fatal(const char *format, ...) {
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
- isc__tls_setfatalmode();
+ if (fatalexit == 0 && exitcode != 0) {
+ fatalexit = exitcode;
+ } else if (fatalexit == 0) {
+ fatalexit = EXIT_FAILURE;
+ }
digexit();
}
@@ -794,6 +793,11 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
looknew->rrcomments = lookold->rrcomments;
looknew->fuzzing = lookold->fuzzing;
looknew->fuzztime = lookold->fuzztime;
+ looknew->proxy_mode = lookold->proxy_mode;
+ looknew->proxy_plain = lookold->proxy_plain;
+ looknew->proxy_local = lookold->proxy_local;
+ looknew->proxy_src_addr = lookold->proxy_src_addr;
+ looknew->proxy_dst_addr = lookold->proxy_dst_addr;
if (lookold->ecs_addr != NULL) {
looknew->ecs_addr = isc_mem_get(mctx,
@@ -874,7 +878,7 @@ setup_text_key(void) {
secretsize = isc_buffer_usedlength(&secretbuf);
- if (hmac == DST_ALG_UNKNOWN) {
+ if (hmac_alg == DST_ALG_UNKNOWN) {
result = DST_R_UNSUPPORTEDALG;
goto failure;
}
@@ -884,7 +888,7 @@ setup_text_key(void) {
goto failure;
}
- result = dns_tsigkey_create(&keyname, hmac, secretstore,
+ result = dns_tsigkey_create(&keyname, hmac_alg, secretstore,
(int)secretsize, mctx, &tsigkey);
failure:
if (result != ISC_R_SUCCESS) {
@@ -1036,35 +1040,35 @@ parse_hmac(const char *algname) {
digestbits = 0;
if (strcasecmp(buf, "hmac-md5") == 0) {
- hmac = DST_ALG_HMACMD5;
+ hmac_alg = DST_ALG_HMACMD5;
} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
- hmac = DST_ALG_HMACMD5;
+ hmac_alg = DST_ALG_HMACMD5;
digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128);
} else if (strcasecmp(buf, "hmac-sha1") == 0) {
- hmac = DST_ALG_HMACSHA1;
+ hmac_alg = DST_ALG_HMACSHA1;
digestbits = 0;
} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
- hmac = DST_ALG_HMACSHA1;
+ hmac_alg = DST_ALG_HMACSHA1;
digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160);
} else if (strcasecmp(buf, "hmac-sha224") == 0) {
- hmac = DST_ALG_HMACSHA224;
+ hmac_alg = DST_ALG_HMACSHA224;
} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
- hmac = DST_ALG_HMACSHA224;
+ hmac_alg = DST_ALG_HMACSHA224;
digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224);
} else if (strcasecmp(buf, "hmac-sha256") == 0) {
- hmac = DST_ALG_HMACSHA256;
+ hmac_alg = DST_ALG_HMACSHA256;
} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
- hmac = DST_ALG_HMACSHA256;
+ hmac_alg = DST_ALG_HMACSHA256;
digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256);
} else if (strcasecmp(buf, "hmac-sha384") == 0) {
- hmac = DST_ALG_HMACSHA384;
+ hmac_alg = DST_ALG_HMACSHA384;
} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
- hmac = DST_ALG_HMACSHA384;
+ hmac_alg = DST_ALG_HMACSHA384;
digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384);
} else if (strcasecmp(buf, "hmac-sha512") == 0) {
- hmac = DST_ALG_HMACSHA512;
+ hmac_alg = DST_ALG_HMACSHA512;
} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
- hmac = DST_ALG_HMACSHA512;
+ hmac_alg = DST_ALG_HMACSHA512;
digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512);
} else {
fprintf(stderr,
@@ -1170,7 +1174,7 @@ setup_file_key(void) {
case DST_ALG_HMACSHA256:
case DST_ALG_HMACSHA384:
case DST_ALG_HMACSHA512:
- hmac = dst_key_alg(dstkey);
+ hmac_alg = dst_key_alg(dstkey);
break;
default:
dst_key_attach(dstkey, &sig0key);
@@ -1179,9 +1183,9 @@ setup_file_key(void) {
}
if (dstkey != NULL) {
- result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmac,
- dstkey, false, false, NULL,
- 0, 0, mctx, &tsigkey);
+ result = dns_tsigkey_createfromkey(
+ dst_key_name(dstkey), hmac_alg, dstkey, false, false,
+ NULL, 0, 0, mctx, &tsigkey);
if (result != ISC_R_SUCCESS) {
printf(";; Couldn't create key %s: %s\n", keynametext,
isc_result_totext(result));
@@ -1383,6 +1387,7 @@ typedef struct dig_ednsoptname {
dig_ednsoptname_t optnames[] = {
{ 1, "LLQ" }, /* draft-sekar-dns-llq */
+ { 2, "UL" }, /* draft-ietf-dnssd-update-lease */
{ 3, "NSID" }, /* RFC 5001 */
{ 5, "DAU" }, /* RFC 6975 */
{ 6, "DHU" }, /* RFC 6975 */
@@ -2192,7 +2197,8 @@ setup_lookup(dig_lookup_t *lookup) {
debug("setup_lookup(%p)", lookup);
- dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &lookup->sendmsg);
+ dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
+ &lookup->sendmsg);
if (lookup->new_search) {
debug("resetting lookup counter.");
@@ -2920,6 +2926,9 @@ start_tcp(dig_query_t *query) {
bool tls_mode = false;
isc_tlsctx_client_session_cache_t *sess_cache = NULL;
int local_timeout;
+ isc_nm_proxy_type_t proxy_type = ISC_NM_PROXY_NONE;
+ isc_nm_proxyheader_info_t proxy_info = { 0 };
+ isc_nm_proxyheader_info_t *ppi = NULL;
REQUIRE(DIG_VALID_QUERY(query));
@@ -3011,6 +3020,22 @@ start_tcp(dig_query_t *query) {
}
}
+ if (query->lookup->proxy_mode) {
+ proxy_type = ISC_NM_PROXY_PLAIN;
+ if ((tls_mode || (query->lookup->https_mode &&
+ !query->lookup->http_plain)) &&
+ !query->lookup->proxy_plain)
+ {
+ proxy_type = ISC_NM_PROXY_ENCRYPTED;
+ }
+ if (!query->lookup->proxy_local) {
+ isc_nm_proxyheader_info_init(
+ &proxy_info, &query->lookup->proxy_src_addr,
+ &query->lookup->proxy_dst_addr, NULL);
+ ppi = &proxy_info;
+ }
+ }
+
REQUIRE(query != NULL);
query_attach(query, &connectquery);
@@ -3023,7 +3048,8 @@ start_tcp(dig_query_t *query) {
}
isc_nm_streamdnsconnect(netmgr, &localaddr, &query->sockaddr,
tcp_connected, connectquery,
- local_timeout, tlsctx, sess_cache);
+ local_timeout, tlsctx, sess_cache,
+ proxy_type, ppi);
#if HAVE_LIBNGHTTP2
} else if (query->lookup->https_mode) {
char uri[4096] = { 0 };
@@ -3043,12 +3069,13 @@ start_tcp(dig_query_t *query) {
isc_nm_httpconnect(netmgr, &localaddr, &query->sockaddr, uri,
!query->lookup->https_get, tcp_connected,
connectquery, tlsctx, sess_cache,
- local_timeout);
+ local_timeout, proxy_type, ppi);
#endif
} else {
isc_nm_streamdnsconnect(netmgr, &localaddr, &query->sockaddr,
tcp_connected, connectquery,
- local_timeout, NULL, NULL);
+ local_timeout, NULL, NULL, proxy_type,
+ ppi);
}
return;
@@ -3204,6 +3231,7 @@ udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
start_udp(next);
check_if_done();
} else {
+ dighost_error("no servers could be reached\n");
clear_current_lookup();
}
@@ -3297,9 +3325,24 @@ start_udp(dig_query_t *query) {
}
query_attach(query, &connectquery);
- isc_nm_udpconnect(netmgr, &localaddr, &query->sockaddr, udp_ready,
- connectquery,
- (timeout ? timeout : UDP_TIMEOUT) * 1000);
+ if (query->lookup->proxy_mode) {
+ isc_nm_proxyheader_info_t proxy_info = { 0 };
+ isc_nm_proxyheader_info_t *ppi = NULL;
+ if (!query->lookup->proxy_local) {
+ isc_nm_proxyheader_info_init(
+ &proxy_info, &query->lookup->proxy_src_addr,
+ &query->lookup->proxy_dst_addr, NULL);
+ ppi = &proxy_info;
+ }
+ isc_nm_proxyudpconnect(netmgr, &localaddr, &query->sockaddr,
+ udp_ready, connectquery,
+ (timeout ? timeout : UDP_TIMEOUT) * 1000,
+ ppi);
+ } else {
+ isc_nm_udpconnect(netmgr, &localaddr, &query->sockaddr,
+ udp_ready, connectquery,
+ (timeout ? timeout : UDP_TIMEOUT) * 1000);
+ }
}
/*%
@@ -3523,6 +3566,12 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
debug("tcp_connected(%p, %s, %p)", handle, isc_result_totext(eresult),
query);
+ if (eresult == ISC_R_SHUTTINGDOWN) {
+ query_detach(&query);
+ cancel_all();
+ return;
+ }
+
lookup_attach(query->lookup, &l);
if (eresult == ISC_R_CANCELED || eresult == ISC_R_TLSBADPEERCERT ||
@@ -3601,6 +3650,7 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
start_tcp(next);
check_if_done();
} else {
+ dighost_error("no servers could be reached\n");
clear_current_lookup();
}
@@ -3907,7 +3957,9 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
{
debug("recv_done: cancel");
isc_nmhandle_detach(&query->readhandle);
- if (!query->canceled) {
+ if (eresult == ISC_R_SHUTTINGDOWN) {
+ cancel_all();
+ } else if (!query->canceled) {
cancel_lookup(l);
}
query_detach(&query);
@@ -4124,7 +4176,7 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
goto keep_query;
}
- dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
+ dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &msg);
if (tsigkey != NULL) {
if (l->querysig == NULL) {
@@ -4302,29 +4354,32 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
(check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
{
+ const char *err = (msg->rcode == dns_rcode_servfail &&
+ !l->servfail_stops)
+ ? "SERVFAIL reply"
+ : "recursion not available";
dig_query_t *next = ISC_LIST_NEXT(query, link);
if (l->current_query == query) {
query_detach(&l->current_query);
}
- if (next != NULL) {
+ if (next != NULL && (!l->ns_search_only || l->trace_root)) {
+ dighost_comments(l,
+ "Got %s from %s, trying next server",
+ err, query->servname);
debug("sending query %p", next);
if (l->tcp_mode) {
start_tcp(next);
} else {
start_udp(next);
}
- dighost_comments(l,
- "Got %s from %s, trying next "
- "server",
- msg->rcode == dns_rcode_servfail
- ? "SERVFAIL reply"
- : "recursion not available",
- query->servname);
if (check_if_queries_done(l, query)) {
goto cancel_lookup;
}
goto detach_query;
+ } else {
+ dighost_comments(l, "Got %s from %s", err,
+ query->servname);
}
}
diff --git a/bin/dig/dighost.h b/bin/dig/dighost.h
index af4379ce4c..99c0c3c864 100644
--- a/bin/dig/dighost.h
+++ b/bin/dig/dighost.h
@@ -187,6 +187,13 @@ struct dig_lookup {
char *tls_key_file;
isc_tlsctx_cache_t *tls_ctx_cache;
};
+ struct {
+ bool proxy_mode;
+ bool proxy_plain;
+ bool proxy_local;
+ isc_sockaddr_t proxy_src_addr;
+ isc_sockaddr_t proxy_dst_addr;
+ };
isc_stdtime_t fuzztime;
};
@@ -259,7 +266,7 @@ extern isc_sockaddr_t localaddr;
extern char keynametext[MXNAME];
extern char keyfile[MXNAME];
extern char keysecret[MXNAME];
-extern dst_algorithm_t hmac;
+extern dst_algorithm_t hmac_alg;
extern unsigned int digestbits;
extern dns_tsigkey_t *tsigkey;
extern bool validated;
diff --git a/bin/dig/host.c b/bin/dig/host.c
index 68906389e4..baacb8d54c 100644
--- a/bin/dig/host.c
+++ b/bin/dig/host.c
@@ -132,7 +132,7 @@ show_usage(void) {
" -W specifies how long to wait for a reply\n"
" -4 use IPv4 query transport only\n"
" -6 use IPv6 query transport only\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
static void
@@ -656,7 +656,7 @@ pre_parse_args(int argc, char **argv) {
break;
case 'V':
printf("host %s\n", PACKAGE_VERSION);
- exit(0);
+ exit(EXIT_SUCCESS);
break;
case 'w':
break;
diff --git a/bin/dig/nslookup.c b/bin/dig/nslookup.c
index dc43f7cdcf..12ba49d311 100644
--- a/bin/dig/nslookup.c
+++ b/bin/dig/nslookup.c
@@ -849,7 +849,7 @@ usage(void) {
"'host' using default server\n");
fprintf(stderr, " nslookup [-opt ...] host server # just look up "
"'host' using 'server'\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
static void
@@ -862,7 +862,7 @@ parse_args(int argc, char **argv) {
if (argv[0][0] == '-') {
if (strncasecmp(argv[0], "-ver", 4) == 0) {
printf("nslookup %s\n", PACKAGE_VERSION);
- exit(0);
+ exit(EXIT_SUCCESS);
} else if (argv[0][1] != 0) {
setoption(&argv[0][1]);
} else {
diff --git a/bin/dnssec/.gitignore b/bin/dnssec/.gitignore
index 9d50f6cc8c..c7917cdbbe 100644
--- a/bin/dnssec/.gitignore
+++ b/bin/dnssec/.gitignore
@@ -2,6 +2,7 @@ dnssec-cds
dnssec-dsfromkey
dnssec-keyfromlabel
dnssec-keygen
+dnssec-ksr
dnssec-makekeyset
dnssec-revoke
dnssec-settime
diff --git a/bin/dnssec/Makefile.am b/bin/dnssec/Makefile.am
index 3f7aed488e..26726da8d3 100644
--- a/bin/dnssec/Makefile.am
+++ b/bin/dnssec/Makefile.am
@@ -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,22 +35,18 @@ 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)
dnssec_dsfromkey_CPPFLAGS = \
@@ -57,5 +56,4 @@ dnssec_dsfromkey_CPPFLAGS = \
dnssec_dsfromkey_LDADD = \
$(LDADD) \
- $(LIBISCCFG_LIBS) \
$(OPENSSL_LIBS)
diff --git a/bin/dnssec/dnssec-cds.c b/bin/dnssec/dnssec-cds.c
index 2e2d8999f1..ebd619aaa3 100644
--- a/bin/dnssec/dnssec-cds.c
+++ b/bin/dnssec/dnssec-cds.c
@@ -247,8 +247,8 @@ static void
load_db(const char *filename, dns_db_t **dbp, dns_dbnode_t **nodep) {
isc_result_t result;
- result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0,
- NULL, dbp);
+ result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
+ rdclass, 0, NULL, dbp);
check_result(result, "dns_db_create()");
result = dns_db_load(*dbp, filename, dns_masterformat_text,
@@ -979,8 +979,8 @@ update_diff(const char *cmd, uint32_t ttl, dns_rdataset_t *addset,
dns_rdataset_t diffset;
uint32_t save;
- result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0,
- NULL, &update_db);
+ result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
+ rdclass, 0, NULL, &update_db);
check_result(result, "dns_db_create()");
result = dns_db_newversion(update_db, &update_version);
@@ -1056,7 +1056,7 @@ usage(void) {
" -T TTL of DS records\n"
" -V print version\n"
" -v \n");
- exit(1);
+ exit(EXIT_FAILURE);
}
static void
@@ -1354,5 +1354,6 @@ main(int argc, char *argv[]) {
cleanup:
print_mem_stats = true;
cleanup();
- exit(0);
+
+ return (0);
}
diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c
index e60eff783c..cdb8147eed 100644
--- a/bin/dnssec/dnssec-dsfromkey.c
+++ b/bin/dnssec/dnssec-dsfromkey.c
@@ -60,6 +60,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) {
@@ -106,8 +107,8 @@ loadset(const char *filename, dns_rdataset_t *rdataset) {
dns_name_format(name, setname, sizeof(setname));
- result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0,
- NULL, &db);
+ result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
+ rdclass, 0, NULL, &db);
if (result != ISC_R_SUCCESS) {
fatal("can't create database");
}
@@ -285,8 +286,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");
@@ -353,13 +354,14 @@ 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- file\n"
" -T: TTL of output records (omitted by default)\n"
" -v level: verbosity\n"
" -V: print version information\n");
fprintf(stderr, "Output: DS or CDS RRs\n");
- exit(-1);
+ exit(EXIT_FAILURE);
}
int
@@ -389,7 +391,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':
@@ -441,6 +443,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;
@@ -461,7 +466,7 @@ main(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
#if OPENSSL_VERSION_NUMBER >= 0x30200000L && OPENSSL_API_LEVEL >= 30200
diff --git a/bin/dnssec/dnssec-importkey.c b/bin/dnssec/dnssec-importkey.c
index df01289e19..c93a0158eb 100644
--- a/bin/dnssec/dnssec-importkey.c
+++ b/bin/dnssec/dnssec-importkey.c
@@ -103,8 +103,8 @@ loadset(const char *filename, dns_rdataset_t *rdataset) {
dns_name_format(name, setname, sizeof(setname));
- result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0,
- NULL, &db);
+ result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
+ rdclass, 0, NULL, &db);
if (result != ISC_R_SUCCESS) {
fatal("can't create database");
}
@@ -289,7 +289,7 @@ usage(void) {
fprintf(stderr, " -D sync date/[+-]offset/none: set/unset "
"CDS and CDNSKEY deletion date\n");
- exit(-1);
+ exit(EXIT_FAILURE);
}
int
@@ -395,7 +395,7 @@ main(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c
index 80022095b1..e574ccc70a 100644
--- a/bin/dnssec/dnssec-keyfromlabel.c
+++ b/bin/dnssec/dnssec-keyfromlabel.c
@@ -102,7 +102,7 @@ usage(void) {
fprintf(stderr, " K++.key, "
"K++.private\n");
- exit(-1);
+ exit(EXIT_FAILURE);
}
int
@@ -331,7 +331,7 @@ main(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -403,6 +403,7 @@ main(int argc, char **argv) {
case DST_ALG_SPHINCSSHA256128S:
case DST_ALG_XMSS:
case DST_ALG_XMSSMT:
+ case DST_ALG_MERKLE_TREE:
break;
default:
fatal("%s is incompatible with NSEC3; "
@@ -611,7 +612,7 @@ main(int argc, char **argv) {
fatal("failed to get key %s/%s: %s", namestr, algstr,
isc_result_totext(ret));
UNREACHABLE();
- exit(-1);
+ exit(EXIT_FAILURE);
}
/*
diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c
index d352739984..328d2e6f19 100644
--- a/bin/dnssec/dnssec-keygen.c
+++ b/bin/dnssec/dnssec-keygen.c
@@ -57,10 +57,6 @@
#include
#include
-#include
-#include
-#include
-#include
#if OPENSSL_VERSION_NUMBER >= 0x30200000L && OPENSSL_API_LEVEL >= 30200
#include
#include
@@ -69,9 +65,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";
/*
@@ -94,6 +87,7 @@ struct keygen_ctx {
const char *policy;
const char *configfile;
const char *directory;
+ dns_keystore_t *keystore;
char *algname;
char *nametype;
char *type;
@@ -104,8 +98,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;
@@ -191,7 +186,7 @@ usage(void) {
fprintf(stderr, " -d (0 => max, default)\n");
fprintf(stderr, " -E :\n");
fprintf(stderr, " name of an OpenSSL engine to use\n");
- fprintf(stderr, " -f : KSK | REVOKE\n");
+ fprintf(stderr, " -f : ZSK | KSK | REVOKE\n");
fprintf(stderr, " -F: FIPS mode\n");
fprintf(stderr, " -L : default key TTL\n");
fprintf(stderr, " -p : (default: 3 [dnssec])\n");
@@ -234,7 +229,7 @@ usage(void) {
fprintf(stderr, " K++.key, "
"K++.private\n");
- exit(-1);
+ exit(EXIT_FAILURE);
}
static void
@@ -261,52 +256,6 @@ progress(int p) {
(void)fflush(stderr);
}
-static void
-kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name,
- dns_kasp_t **kaspp) {
- const cfg_listelt_t *element;
- const cfg_obj_t *kasps = NULL;
- dns_kasp_t *kasp = NULL, *kasp_next;
- isc_result_t result = ISC_R_NOTFOUND;
- dns_kasplist_t kasplist;
-
- ISC_LIST_INIT(kasplist);
-
- (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,
- &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);
- }
-}
static void
keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
char filename[255];
@@ -324,7 +273,9 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
dst_key_t *prevkey = NULL;
UNUSED(argc);
+
dns_secalg_format(ctx->alg, algstr, sizeof(algstr));
+
if (ctx->predecessor == NULL) {
if (ctx->prepub == -1) {
ctx->prepub = 0;
@@ -355,6 +306,7 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
break;
}
}
+
if (ctx->use_nsec3) {
switch (ctx->alg) {
case DST_ALG_RSASHA1:
@@ -372,6 +324,7 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
case DST_ALG_SPHINCSSHA256128S:
case DST_ALG_XMSS:
case DST_ALG_XMSSMT:
+ case DST_ALG_MERKLE_TREE:
break;
default:
fatal("algorithm %s is incompatible with NSEC3"
@@ -427,6 +380,7 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
case DST_ALG_SPHINCSSHA256128S:
case DST_ALG_XMSS:
case DST_ALG_XMSSMT:
+ case DST_ALG_MERKLE_TREE:
break;
default:
fatal("key size not specified (-b option)");
@@ -626,6 +580,9 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
fatal("XMSSMT failed to get bits based on param");
}
break;
+ case DST_ALG_MERKLE_TREE:
+ ctx->size = 256;
+ break;
}
if (ctx->nametype == NULL) {
@@ -656,8 +613,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) {
@@ -701,26 +662,41 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
do {
conflict = false;
+
if (!ctx->quiet && show_progress) {
fprintf(stderr, "Generating key pair.");
+ }
+
+ if (ctx->keystore != NULL && ctx->policy != NULL) {
+ ret = dns_keystore_keygen(
+ ctx->keystore, name, ctx->policy, ctx->rdclass,
+ mctx, ctx->alg, ctx->size, flags, &key);
+ } else if (!ctx->quiet && show_progress) {
ret = dst_key_generate(name, ctx->alg, ctx->size, param,
flags, ctx->protocol,
- ctx->rdclass, mctx, &key,
+ ctx->rdclass, NULL, mctx, &key,
&progress);
- putc('\n', stderr);
- fflush(stderr);
} else {
ret = dst_key_generate(name, ctx->alg, ctx->size, param,
flags, ctx->protocol,
- ctx->rdclass, mctx, &key, NULL);
+ ctx->rdclass, NULL, mctx, &key,
+ NULL);
+ }
+
+ if (!ctx->quiet && show_progress) {
+ putc('\n', stderr);
+ fflush(stderr);
}
+
if (ret != ISC_R_SUCCESS) {
char namestr[DNS_NAME_FORMATSIZE];
dns_name_format(name, namestr, sizeof(namestr));
fatal("failed to generate key %s/%s: %s\n", namestr,
algstr, isc_result_totext(ret));
}
+
dst_key_setbits(key, ctx->dbits);
+
/*
* Set key timing metadata (unless using -C)
*
@@ -765,7 +741,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 "
@@ -822,6 +798,7 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
*/
dst_key_setprivateformat(key, 1, 2);
}
+
/* Set the default key TTL */
if (ctx->setttl) {
dst_key_setttl(key, ctx->ttl);
@@ -903,6 +880,18 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
}
}
+static void
+check_keystore_options(keygen_ctx_t *ctx) {
+ ctx->directory = dns_keystore_directory(ctx->keystore, NULL);
+ if (ctx->directory != NULL) {
+ isc_result_t ret = try_dir(ctx->directory);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("cannot open directory %s: %s", ctx->directory,
+ isc_result_totext(ret));
+ }
+ }
+}
+
int
main(int argc, char **argv) {
char *algname = NULL, *freeit = NULL;
@@ -995,9 +984,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);
@@ -1178,7 +1169,7 @@ main(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -1301,8 +1292,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");
@@ -1317,7 +1308,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;
@@ -1342,7 +1332,8 @@ main(int argc, char **argv) {
ctx.policy, ctx.configfile);
}
- kasp_from_conf(config, mctx, ctx.policy, &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);
@@ -1356,22 +1347,26 @@ 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);
-
+ ctx.keystore = dns_kasp_key_keystore(kaspkey);
+ 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);
diff --git a/bin/dnssec/dnssec-keygen.rst b/bin/dnssec/dnssec-keygen.rst
index 121ced4e02..2e12fe60cd 100644
--- a/bin/dnssec/dnssec-keygen.rst
+++ b/bin/dnssec/dnssec-keygen.rst
@@ -27,9 +27,7 @@ Description
~~~~~~~~~~~
:program:`dnssec-keygen` generates keys for DNSSEC (Secure DNS), as defined in
-:rfc:`2535` and :rfc:`4034`. It can also generate keys for use with TSIG
-(Transaction Signatures) as defined in :rfc:`2845`, or TKEY (Transaction
-Key) as defined in :rfc:`2930`.
+:rfc:`2535` and :rfc:`4034`.
The ``name`` of the key is specified on the command line. For DNSSEC
keys, this must match the name of the zone for which the key is being
@@ -107,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
diff --git a/bin/dnssec/dnssec-ksr.c b/bin/dnssec/dnssec-ksr.c
new file mode 100644
index 0000000000..493c483d6e
--- /dev/null
+++ b/bin/dnssec/dnssec-ksr.c
@@ -0,0 +1,1327 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "dnssectool.h"
+
+const char *program = "dnssec-ksr";
+
+/*
+ * Infrastructure
+ */
+static isc_log_t *lctx = NULL;
+static isc_mem_t *mctx = NULL;
+const char *engine = NULL;
+/*
+ * The domain we are working on
+ */
+static const char *namestr = NULL;
+static dns_fixedname_t fname;
+static dns_name_t *name = NULL;
+/*
+ * KSR context
+ */
+struct ksr_ctx {
+ const char *policy;
+ const char *configfile;
+ const char *file;
+ const char *keydir;
+ dns_keystore_t *keystore;
+ isc_stdtime_t now;
+ isc_stdtime_t start;
+ isc_stdtime_t end;
+ bool setstart;
+ bool setend;
+ /* keygen */
+ dns_ttl_t ttl;
+ dns_secalg_t alg;
+ int size;
+ time_t lifetime;
+ time_t propagation;
+ time_t publishsafety;
+ time_t retiresafety;
+ time_t sigrefresh;
+ time_t sigvalidity;
+ time_t signdelay;
+ time_t ttlsig;
+};
+typedef struct ksr_ctx ksr_ctx_t;
+
+/*
+ * These are set here for backwards compatibility.
+ * They are raised to 2048 in FIPS mode.
+ */
+static int min_rsa = 1024;
+static int min_dh = 128;
+
+#define KSR_LINESIZE 1500 /* should be long enough for any DNSKEY record */
+#define DATETIME_INDEX 25
+
+#define MAXWIRE (64 * 1024)
+
+#define STR(t) ((t).value.as_textregion.base)
+
+#define READLINE(lex, opt, token)
+
+#define NEXTTOKEN(lex, opt, token) \
+ { \
+ ret = isc_lex_gettoken(lex, opt, token); \
+ if (ret != ISC_R_SUCCESS) \
+ goto cleanup; \
+ }
+
+#define BADTOKEN() \
+ { \
+ ret = ISC_R_UNEXPECTEDTOKEN; \
+ goto cleanup; \
+ }
+
+#define CHECK(r) \
+ ret = (r); \
+ if (ret != ISC_R_SUCCESS) { \
+ goto fail; \
+ }
+
+isc_bufferlist_t cleanup_list = ISC_LIST_INITIALIZER;
+
+static void
+usage(int ret) {
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, " %s options [options] \n", program);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Version: %s\n", PACKAGE_VERSION);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -E : name of an OpenSSL engine to use\n");
+ fprintf(stderr, " -e : end date\n");
+ fprintf(stderr, " -F: FIPS mode\n");
+ fprintf(stderr, " -f: KSR file to sign\n");
+ fprintf(stderr, " -i : start date\n");
+ fprintf(stderr, " -K : key directory\n");
+ fprintf(stderr, " -k : name of a DNSSEC policy\n");
+ fprintf(stderr, " -l : file with dnssec-policy config\n");
+ fprintf(stderr, " -h: print usage and exit\n");
+ fprintf(stderr, " -V: print version information\n");
+ fprintf(stderr, " -v : set verbosity level\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Commands:\n");
+ fprintf(stderr, " keygen: pregenerate ZSKs\n");
+ fprintf(stderr, " request: create a Key Signing Request (KSR)\n");
+ fprintf(stderr, " sign: sign a KSR, creating a Signed Key "
+ "Response (SKR)\n");
+ exit(ret);
+}
+
+static void
+checkparams(ksr_ctx_t *ksr, const char *command) {
+ if (ksr->configfile == NULL) {
+ fatal("%s requires a configuration file", command);
+ }
+ if (ksr->policy == NULL) {
+ fatal("%s requires a dnssec-policy", command);
+ }
+ if (!ksr->setend) {
+ fatal("%s requires an end date", command);
+ }
+ if (!ksr->setstart) {
+ ksr->start = ksr->now;
+ }
+ if (ksr->keydir == NULL) {
+ ksr->keydir = ".";
+ }
+}
+
+static void
+getkasp(ksr_ctx_t *ksr, dns_kasp_t **kasp) {
+ cfg_parser_t *parser = NULL;
+ cfg_obj_t *config = NULL;
+
+ RUNTIME_CHECK(cfg_parser_create(mctx, lctx, &parser) == ISC_R_SUCCESS);
+ if (cfg_parse_file(parser, ksr->configfile, &cfg_type_namedconf,
+ &config) != ISC_R_SUCCESS)
+ {
+ fatal("unable to load dnssec-policy '%s' from '%s'",
+ ksr->policy, ksr->configfile);
+ }
+ kasp_from_conf(config, mctx, lctx, ksr->policy, ksr->keydir, engine,
+ kasp);
+ if (*kasp == NULL) {
+ fatal("failed to load dnssec-policy '%s'", ksr->policy);
+ }
+ if (ISC_LIST_EMPTY(dns_kasp_keys(*kasp))) {
+ fatal("dnssec-policy '%s' has no keys configured", ksr->policy);
+ }
+ cfg_obj_destroy(parser, &config);
+ cfg_parser_destroy(&parser);
+}
+
+static int
+keytag_cmp(const void *k1, const void *k2) {
+ dns_dnsseckey_t **key1 = (dns_dnsseckey_t **)k1;
+ dns_dnsseckey_t **key2 = (dns_dnsseckey_t **)k2;
+ if (dst_key_id((*key1)->key) < dst_key_id((*key2)->key)) {
+ return (-1);
+ } else if (dst_key_id((*key1)->key) > dst_key_id((*key2)->key)) {
+ return (1);
+ }
+ return (0);
+}
+
+static void
+get_dnskeys(ksr_ctx_t *ksr, dns_dnsseckeylist_t *keys) {
+ dns_dnsseckeylist_t keys_read;
+ dns_dnsseckey_t **keys_sorted;
+ int i = 0, n = 0;
+ isc_result_t ret;
+
+ ISC_LIST_INIT(*keys);
+ ISC_LIST_INIT(keys_read);
+ ret = dns_dnssec_findmatchingkeys(name, NULL, ksr->keydir, NULL,
+ ksr->now, mctx, &keys_read);
+ if (ret != ISC_R_SUCCESS && ret != ISC_R_NOTFOUND) {
+ fatal("failed to load existing keys from %s: %s", ksr->keydir,
+ isc_result_totext(ret));
+ }
+ /* Sort on keytag. */
+ for (dns_dnsseckey_t *dk = ISC_LIST_HEAD(keys_read); dk != NULL;
+ dk = ISC_LIST_NEXT(dk, link))
+ {
+ n++;
+ }
+ keys_sorted = isc_mem_cget(mctx, n, sizeof(dns_dnsseckey_t *));
+ for (dns_dnsseckey_t *dk = ISC_LIST_HEAD(keys_read); dk != NULL;
+ dk = ISC_LIST_NEXT(dk, link), i++)
+ {
+ keys_sorted[i] = dk;
+ }
+ qsort(keys_sorted, n, sizeof(dns_dnsseckey_t *), keytag_cmp);
+ while (!ISC_LIST_EMPTY(keys_read)) {
+ dns_dnsseckey_t *key = ISC_LIST_HEAD(keys_read);
+ ISC_LIST_UNLINK(keys_read, key, link);
+ }
+ /* Save sorted list in 'keys' */
+ for (i = 0; i < n; i++) {
+ ISC_LIST_APPEND(*keys, keys_sorted[i], link);
+ }
+ INSIST(ISC_LIST_EMPTY(keys_read));
+ isc_mem_cput(mctx, keys_sorted, n, sizeof(dns_dnsseckey_t *));
+}
+
+static void
+setcontext(ksr_ctx_t *ksr, dns_kasp_t *kasp) {
+ ksr->propagation = dns_kasp_zonepropagationdelay(kasp);
+ ksr->publishsafety = dns_kasp_publishsafety(kasp);
+ ksr->retiresafety = dns_kasp_retiresafety(kasp);
+ ksr->sigvalidity = dns_kasp_sigvalidity_dnskey(kasp);
+ ksr->sigrefresh = dns_kasp_sigrefresh(kasp);
+ ksr->signdelay = dns_kasp_signdelay(kasp);
+ ksr->ttl = dns_kasp_dnskeyttl(kasp);
+ ksr->ttlsig = dns_kasp_zonemaxttl(kasp, true);
+}
+
+static void
+cleanup(dns_dnsseckeylist_t *keys, dns_kasp_t *kasp) {
+ while (!ISC_LIST_EMPTY(*keys)) {
+ dns_dnsseckey_t *key = ISC_LIST_HEAD(*keys);
+ ISC_LIST_UNLINK(*keys, key, link);
+ dst_key_free(&key->key);
+ dns_dnsseckey_destroy(mctx, &key);
+ }
+ dns_kasp_detach(&kasp);
+
+ isc_buffer_t *cbuf = ISC_LIST_HEAD(cleanup_list);
+ while (cbuf != NULL) {
+ isc_buffer_t *nbuf = ISC_LIST_NEXT(cbuf, link);
+ ISC_LIST_UNLINK(cleanup_list, cbuf, link);
+ isc_buffer_free(&cbuf);
+ cbuf = nbuf;
+ }
+}
+
+static void
+progress(int p) {
+ char c = '*';
+ switch (p) {
+ case 0:
+ c = '.';
+ break;
+ case 1:
+ c = '+';
+ break;
+ case 2:
+ c = '*';
+ break;
+ case 3:
+ c = ' ';
+ break;
+ default:
+ break;
+ }
+ (void)putc(c, stderr);
+ (void)fflush(stderr);
+}
+
+static void
+freerrset(dns_rdataset_t *rdataset) {
+ dns_rdatalist_t *rdlist;
+ dns_rdata_t *rdata;
+
+ if (!dns_rdataset_isassociated(rdataset)) {
+ return;
+ }
+
+ dns_rdatalist_fromrdataset(rdataset, &rdlist);
+
+ for (rdata = ISC_LIST_HEAD(rdlist->rdata); rdata != NULL;
+ rdata = ISC_LIST_HEAD(rdlist->rdata))
+ {
+ ISC_LIST_UNLINK(rdlist->rdata, rdata, link);
+ isc_mem_put(mctx, rdata, sizeof(*rdata));
+ }
+ isc_mem_put(mctx, rdlist, sizeof(*rdlist));
+ dns_rdataset_disassociate(rdataset);
+}
+
+static void
+create_zsk(ksr_ctx_t *ksr, dns_kasp_key_t *kaspkey, dns_dnsseckeylist_t *keys,
+ isc_stdtime_t inception, isc_stdtime_t active,
+ isc_stdtime_t *expiration) {
+ bool conflict = false;
+ bool freekey = false;
+ bool show_progress = true;
+ char algstr[DNS_SECALG_FORMATSIZE];
+ char filename[PATH_MAX + 1];
+ char timestr[26]; /* Minimal buf as per ctime_r() spec. */
+ dst_key_t *key = NULL;
+ int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
+ isc_buffer_t buf;
+ isc_result_t ret;
+ isc_stdtime_t prepub;
+
+ isc_stdtime_tostring(inception, timestr, sizeof(timestr));
+
+ /* Check algorithm and size. */
+ dns_secalg_format(ksr->alg, algstr, sizeof(algstr));
+ if (!dst_algorithm_supported(ksr->alg)) {
+ fatal("unsupported algorithm: %s", algstr);
+ }
+ INSIST(ksr->size >= 0);
+ switch (ksr->alg) {
+ case DST_ALG_RSASHA1:
+ case DST_ALG_NSEC3RSASHA1:
+ if (isc_fips_mode()) {
+ /* verify-only in FIPS mode */
+ fatal("unsupported algorithm: %s", algstr);
+ }
+ FALLTHROUGH;
+ case DST_ALG_RSASHA256:
+ case DST_ALG_RSASHA512:
+ if (ksr->size != 0 &&
+ (ksr->size < min_rsa || ksr->size > MAX_RSA))
+ {
+ fatal("RSA key size %d out of range", ksr->size);
+ }
+ break;
+ case DST_ALG_ECDSA256:
+ ksr->size = 256;
+ break;
+ case DST_ALG_ECDSA384:
+ ksr->size = 384;
+ break;
+ case DST_ALG_ED25519:
+ ksr->size = 256;
+ break;
+ case DST_ALG_ED448:
+ ksr->size = 456;
+ break;
+ default:
+ show_progress = false;
+ break;
+ }
+
+ isc_buffer_init(&buf, filename, sizeof(filename) - 1);
+
+ /* Check existing keys. */
+ for (dns_dnsseckey_t *dk = ISC_LIST_HEAD(*keys); dk != NULL;
+ dk = ISC_LIST_NEXT(dk, link))
+ {
+ isc_stdtime_t act = 0, inact = 0;
+
+ if (!dns_kasp_key_match(kaspkey, dk)) {
+ continue;
+ }
+ (void)dst_key_gettime(dk->key, DST_TIME_ACTIVATE, &act);
+ (void)dst_key_gettime(dk->key, DST_TIME_INACTIVE, &inact);
+ /*
+ * If this key's activation time is set after the inception
+ * time, it is not eligble for the current bundle.
+ */
+ if (act > inception) {
+ continue;
+ }
+ /*
+ * If this key's inactive time is set before the inception
+ * time, it is not eligble for the current bundle.
+ */
+ if (inact > 0 && inception >= inact) {
+ continue;
+ }
+
+ /* Found matching existing key. */
+ if (verbose > 0 && show_progress) {
+ fprintf(stderr,
+ "Selecting key pair for bundle %s: ", timestr);
+ fflush(stderr);
+ }
+ key = dk->key;
+ *expiration = inact;
+ goto output;
+ }
+
+ /* No existing keys match. */
+ do {
+ conflict = false;
+
+ if (verbose > 0 && show_progress) {
+ fprintf(stderr,
+ "Generating key pair for bundle %s: ", timestr);
+ }
+ if (ksr->keystore != NULL && ksr->policy != NULL) {
+ ret = dns_keystore_keygen(
+ ksr->keystore, name, ksr->policy,
+ dns_rdataclass_in, mctx, ksr->alg, ksr->size,
+ DNS_KEYOWNER_ZONE, &key);
+ } else if (show_progress) {
+ ret = dst_key_generate(
+ name, ksr->alg, ksr->size, 0, DNS_KEYOWNER_ZONE,
+ DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, NULL,
+ mctx, &key, &progress);
+ fflush(stderr);
+ } else {
+ ret = dst_key_generate(
+ name, ksr->alg, ksr->size, 0, DNS_KEYOWNER_ZONE,
+ DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, NULL,
+ mctx, &key, NULL);
+ }
+
+ if (ret != ISC_R_SUCCESS) {
+ fatal("failed to generate key %s/%s: %s\n", namestr,
+ algstr, isc_result_totext(ret));
+ }
+
+ /* Do not overwrite an existing key. */
+ if (key_collision(key, name, ksr->keydir, mctx, NULL)) {
+ conflict = true;
+ if (verbose > 0) {
+ isc_buffer_clear(&buf);
+ ret = dst_key_buildfilename(key, 0, ksr->keydir,
+ &buf);
+ if (ret == ISC_R_SUCCESS) {
+ fprintf(stderr,
+ "%s: %s already exists, or "
+ "might collide with another "
+ "key upon revokation. "
+ "Generating a new key\n",
+ program, filename);
+ }
+ }
+ dst_key_free(&key);
+ }
+ } while (conflict);
+
+ freekey = true;
+
+ /* Set key timing metadata. */
+ prepub = ksr->ttl + ksr->publishsafety + ksr->propagation;
+ dst_key_setttl(key, ksr->ttl);
+ dst_key_setnum(key, DST_NUM_LIFETIME, ksr->lifetime);
+ dst_key_setbool(key, DST_BOOL_KSK, false);
+ dst_key_setbool(key, DST_BOOL_ZSK, true);
+ dst_key_settime(key, DST_TIME_CREATED, ksr->now);
+ dst_key_settime(key, DST_TIME_PUBLISH, (active - prepub));
+ dst_key_settime(key, DST_TIME_ACTIVATE, active);
+ if (ksr->lifetime > 0) {
+ isc_stdtime_t inactive = (active + ksr->lifetime);
+ isc_stdtime_t remove = ksr->ttlsig + ksr->propagation +
+ ksr->retiresafety + ksr->signdelay;
+ dst_key_settime(key, DST_TIME_INACTIVE, inactive);
+ dst_key_settime(key, DST_TIME_DELETE, (inactive + remove));
+ *expiration = inactive;
+ } else {
+ *expiration = 0;
+ }
+
+ ret = dst_key_tofile(key, options, ksr->keydir);
+ if (ret != ISC_R_SUCCESS) {
+ char keystr[DST_KEY_FORMATSIZE];
+ dst_key_format(key, keystr, sizeof(keystr));
+ fatal("failed to write key %s: %s\n", keystr,
+ isc_result_totext(ret));
+ }
+
+output:
+ isc_buffer_clear(&buf);
+ ret = dst_key_buildfilename(key, 0, NULL, &buf);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("dst_key_buildfilename returned: %s\n",
+ isc_result_totext(ret));
+ }
+ printf("%s\n", filename);
+ fflush(stdout);
+ if (freekey) {
+ dst_key_free(&key);
+ }
+}
+
+static void
+print_rdata(dns_rdataset_t *rrset) {
+ isc_buffer_t target;
+ isc_region_t r;
+ isc_result_t ret;
+ char buf[4096];
+
+ isc_buffer_init(&target, buf, sizeof(buf));
+ ret = dns_rdataset_totext(rrset, name, false, false, &target);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("failed to print rdata");
+ }
+ isc_buffer_usedregion(&target, &r);
+ fprintf(stdout, "%.*s", (int)r.length, (char *)r.base);
+}
+
+static isc_stdtime_t
+print_dnskeys(dns_kasp_key_t *kaspkey, dns_ttl_t ttl, dns_dnsseckeylist_t *keys,
+ isc_stdtime_t inception, isc_stdtime_t next_inception) {
+ char algstr[DNS_SECALG_FORMATSIZE];
+ char timestr[26]; /* Minimal buf as per ctime_r() spec. */
+ dns_rdatalist_t *rdatalist = NULL;
+ dns_rdataset_t rdataset = DNS_RDATASET_INIT;
+ isc_result_t ret = ISC_R_SUCCESS;
+ isc_stdtime_t next_bundle = next_inception;
+
+ isc_stdtime_tostring(inception, timestr, sizeof(timestr));
+ dns_secalg_format(dns_kasp_key_algorithm(kaspkey), algstr,
+ sizeof(algstr));
+
+ /* Fetch matching key pair. */
+ rdatalist = isc_mem_get(mctx, sizeof(*rdatalist));
+ dns_rdatalist_init(rdatalist);
+ rdatalist->rdclass = dns_rdataclass_in;
+ rdatalist->type = dns_rdatatype_dnskey;
+ rdatalist->ttl = ttl;
+ for (dns_dnsseckey_t *dk = ISC_LIST_HEAD(*keys); dk != NULL;
+ dk = ISC_LIST_NEXT(dk, link))
+ {
+ isc_stdtime_t pub = 0, del = 0;
+
+ (void)dst_key_gettime(dk->key, DST_TIME_PUBLISH, &pub);
+ (void)dst_key_gettime(dk->key, DST_TIME_DELETE, &del);
+
+ /* Determine next bundle. */
+ if (pub > 0 && pub > inception && pub < next_bundle) {
+ next_bundle = pub;
+ }
+ if (del > 0 && del > inception && del < next_bundle) {
+ next_bundle = del;
+ }
+ /* Find matching key. */
+ if (!dns_kasp_key_match(kaspkey, dk)) {
+ continue;
+ }
+ if (pub > inception) {
+ continue;
+ }
+ if (del != 0 && inception >= del) {
+ continue;
+ }
+ /* Found matching key pair, add DNSKEY record to RRset. */
+ isc_buffer_t buf;
+ isc_buffer_t *newbuf = NULL;
+ dns_rdata_t *rdata = NULL;
+ isc_region_t r;
+ unsigned char rdatabuf[DST_KEY_MAXSIZE];
+
+ rdata = isc_mem_get(mctx, sizeof(*rdata));
+ dns_rdata_init(rdata);
+ isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf));
+ CHECK(dst_key_todns(dk->key, &buf));
+ isc_buffer_usedregion(&buf, &r);
+ isc_buffer_allocate(mctx, &newbuf, r.length);
+ isc_buffer_putmem(newbuf, r.base, r.length);
+ isc_buffer_usedregion(newbuf, &r);
+ dns_rdata_fromregion(rdata, dns_rdataclass_in,
+ dns_rdatatype_dnskey, &r);
+ ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+ ISC_LIST_APPEND(cleanup_list, newbuf, link);
+ isc_buffer_clear(newbuf);
+ }
+ /* Error if no key pair found. */
+ if (ISC_LIST_EMPTY(rdatalist->rdata)) {
+ fatal("no %s/%s zsk key pair found for bundle %s", namestr,
+ algstr, timestr);
+ }
+
+ /* All good, print DNSKEY RRset. */
+ dns_rdatalist_tordataset(rdatalist, &rdataset);
+ print_rdata(&rdataset);
+
+fail:
+ /* Cleanup */
+ freerrset(&rdataset);
+
+ if (ret != ISC_R_SUCCESS) {
+ fatal("failed to print %s/%s zsk key pair found for bundle %s",
+ namestr, algstr, timestr);
+ }
+
+ return (next_bundle);
+}
+
+static void
+sign_rrset(ksr_ctx_t *ksr, isc_stdtime_t inception, isc_stdtime_t expiration,
+ dns_rdataset_t *rrset, dns_dnsseckeylist_t *keys) {
+ dns_rdatalist_t *rrsiglist = NULL;
+ dns_rdataset_t rrsigset = DNS_RDATASET_INIT;
+ isc_result_t ret;
+
+ UNUSED(ksr);
+
+ /* Bundle header */
+ if (rrset->type == dns_rdatatype_dnskey) {
+ char timestr[26]; /* Minimal buf as per ctime_r() spec. */
+ char utc[sizeof("YYYYMMDDHHSSMM")];
+ isc_buffer_t timebuf;
+ isc_buffer_t b;
+ isc_region_t r;
+ isc_buffer_init(&timebuf, timestr, sizeof(timestr));
+ isc_stdtime_tostring(inception, timestr, sizeof(timestr));
+ isc_buffer_init(&b, utc, sizeof(utc));
+ ret = dns_time32_totext(inception, &b);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("failed to convert bundle time32 to text: %s",
+ isc_result_totext(ret));
+ }
+ isc_buffer_usedregion(&b, &r);
+ fprintf(stdout, ";; SignedKeyResponse 1.0 %.*s (%s)\n",
+ (int)r.length, r.base, timestr);
+ }
+
+ /* RRset */
+ print_rdata(rrset);
+
+ /* Signatures */
+ rrsiglist = isc_mem_get(mctx, sizeof(*rrsiglist));
+ dns_rdatalist_init(rrsiglist);
+ rrsiglist->rdclass = dns_rdataclass_in;
+ rrsiglist->type = dns_rdatatype_rrsig;
+ rrsiglist->ttl = rrset->ttl;
+ for (dns_dnsseckey_t *dk = ISC_LIST_HEAD(*keys); dk != NULL;
+ dk = ISC_LIST_NEXT(dk, link))
+ {
+ isc_buffer_t buf;
+ isc_buffer_t *newbuf = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_t *rrsig = NULL;
+ isc_region_t rs;
+ unsigned char rdatabuf[SIG_FORMATSIZE];
+ isc_stdtime_t clockskew = inception - 3600;
+
+ rrsig = isc_mem_get(mctx, sizeof(*rrsig));
+ dns_rdata_init(rrsig);
+ isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf));
+ ret = dns_dnssec_sign(name, rrset, dk->key, &clockskew,
+ &expiration, mctx, &buf, &rdata);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("failed to sign KSR");
+ }
+ isc_buffer_usedregion(&buf, &rs);
+ isc_buffer_allocate(mctx, &newbuf, rs.length);
+ isc_buffer_putmem(newbuf, rs.base, rs.length);
+ isc_buffer_usedregion(newbuf, &rs);
+ dns_rdata_fromregion(rrsig, dns_rdataclass_in,
+ dns_rdatatype_rrsig, &rs);
+ ISC_LIST_APPEND(rrsiglist->rdata, rrsig, link);
+ ISC_LIST_APPEND(cleanup_list, newbuf, link);
+ isc_buffer_clear(newbuf);
+ }
+ dns_rdatalist_tordataset(rrsiglist, &rrsigset);
+ print_rdata(&rrsigset);
+ freerrset(&rrsigset);
+}
+
+/*
+ * Create the DNSKEY, CDS, and CDNSKEY records beloing to the KSKs
+ * listed in 'keys'.
+ */
+static void
+create_ksk(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_dnsseckeylist_t *keys,
+ dns_rdataset_t *dnskeyset, dns_rdataset_t *cdnskeyset,
+ dns_rdataset_t *cdsset) {
+ dns_rdatalist_t *dnskeylist = isc_mem_get(mctx, sizeof(*dnskeylist));
+ dns_rdatalist_t *cdnskeylist = isc_mem_get(mctx, sizeof(*cdnskeylist));
+ dns_rdatalist_t *cdslist = isc_mem_get(mctx, sizeof(*cdslist));
+ isc_result_t ret = ISC_R_SUCCESS;
+ dns_kasp_digestlist_t digests = dns_kasp_digests(kasp);
+
+ dns_rdatalist_init(dnskeylist);
+ dnskeylist->rdclass = dns_rdataclass_in;
+ dnskeylist->type = dns_rdatatype_dnskey;
+ dnskeylist->ttl = ksr->ttl;
+
+ dns_rdatalist_init(cdnskeylist);
+ cdnskeylist->rdclass = dns_rdataclass_in;
+ cdnskeylist->type = dns_rdatatype_cdnskey;
+ cdnskeylist->ttl = ksr->ttl;
+
+ dns_rdatalist_init(cdslist);
+ cdslist->rdclass = dns_rdataclass_in;
+ cdslist->type = dns_rdatatype_cds;
+ cdslist->ttl = ksr->ttl;
+
+ for (dns_dnsseckey_t *dk = ISC_LIST_HEAD(*keys); dk != NULL;
+ dk = ISC_LIST_NEXT(dk, link))
+ {
+ isc_buffer_t buf;
+ isc_buffer_t *newbuf;
+ dns_rdata_t *rdata;
+ isc_region_t r;
+ isc_region_t rcds;
+ unsigned char kskbuf[DST_KEY_MAXSIZE];
+ unsigned char cdnskeybuf[DST_KEY_MAXSIZE];
+ unsigned char cdsbuf[DNS_DS_BUFFERSIZE];
+
+ /* KSK */
+ newbuf = NULL;
+ rdata = isc_mem_get(mctx, sizeof(*rdata));
+ dns_rdata_init(rdata);
+
+ isc_buffer_init(&buf, kskbuf, sizeof(kskbuf));
+ CHECK(dst_key_todns(dk->key, &buf));
+ isc_buffer_usedregion(&buf, &r);
+ isc_buffer_allocate(mctx, &newbuf, r.length);
+ isc_buffer_putmem(newbuf, r.base, r.length);
+ isc_buffer_usedregion(newbuf, &r);
+ dns_rdata_fromregion(rdata, dns_rdataclass_in,
+ dns_rdatatype_dnskey, &r);
+ ISC_LIST_APPEND(dnskeylist->rdata, rdata, link);
+ ISC_LIST_APPEND(cleanup_list, newbuf, link);
+ isc_buffer_clear(newbuf);
+
+ /* CDNSKEY */
+ newbuf = NULL;
+ rdata = isc_mem_get(mctx, sizeof(*rdata));
+ dns_rdata_init(rdata);
+
+ isc_buffer_init(&buf, cdnskeybuf, sizeof(cdnskeybuf));
+ CHECK(dst_key_todns(dk->key, &buf));
+ isc_buffer_usedregion(&buf, &r);
+ isc_buffer_allocate(mctx, &newbuf, r.length);
+ isc_buffer_putmem(newbuf, r.base, r.length);
+ isc_buffer_usedregion(newbuf, &r);
+ dns_rdata_fromregion(rdata, dns_rdataclass_in,
+ dns_rdatatype_cdnskey, &r);
+ if (dns_kasp_cdnskey(kasp)) {
+ ISC_LIST_APPEND(cdnskeylist->rdata, rdata, link);
+ }
+ ISC_LIST_APPEND(cleanup_list, newbuf, link);
+ isc_buffer_clear(newbuf);
+
+ /* CDS */
+ for (dns_kasp_digest_t *alg = ISC_LIST_HEAD(digests);
+ alg != NULL; alg = ISC_LIST_NEXT(alg, link))
+ {
+ isc_buffer_t *newbuf2 = NULL;
+ dns_rdata_t *rdata2 = NULL;
+ dns_rdata_t cds = DNS_RDATA_INIT;
+
+ rdata2 = isc_mem_get(mctx, sizeof(*rdata2));
+ dns_rdata_init(rdata2);
+
+ CHECK(dns_ds_buildrdata(name, rdata, alg->digest,
+ cdsbuf, &cds));
+ cds.type = dns_rdatatype_cds;
+ dns_rdata_toregion(&cds, &rcds);
+ isc_buffer_allocate(mctx, &newbuf2, rcds.length);
+ isc_buffer_putmem(newbuf2, rcds.base, rcds.length);
+ isc_buffer_usedregion(newbuf2, &rcds);
+ dns_rdata_fromregion(rdata2, dns_rdataclass_in,
+ dns_rdatatype_cds, &rcds);
+ ISC_LIST_APPEND(cdslist->rdata, rdata2, link);
+ ISC_LIST_APPEND(cleanup_list, newbuf2, link);
+ isc_buffer_clear(newbuf2);
+ }
+
+ if (!dns_kasp_cdnskey(kasp)) {
+ isc_mem_put(mctx, rdata, sizeof(*rdata));
+ }
+ }
+ /* All good */
+ dns_rdatalist_tordataset(dnskeylist, dnskeyset);
+ dns_rdatalist_tordataset(cdnskeylist, cdnskeyset);
+ dns_rdatalist_tordataset(cdslist, cdsset);
+ return;
+
+fail:
+ fatal("failed to create KSK/CDS/CDNSKEY");
+}
+
+static void
+sign_bundle(ksr_ctx_t *ksr, isc_stdtime_t inception,
+ isc_stdtime_t next_inception, dns_rdatalist_t *rdatalist,
+ dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
+ dns_dnsseckeylist_t *keys) {
+ dns_rdataset_t rrset = DNS_RDATASET_INIT;
+ isc_stdtime_t expiration;
+
+ dns_rdataset_init(&rrset);
+ dns_rdatalist_tordataset(rdatalist, &rrset);
+ expiration = inception + ksr->sigvalidity;
+ while (inception <= next_inception) {
+ sign_rrset(ksr, inception, expiration, &rrset, keys);
+ if (dns_rdataset_count(cdnskey) > 0) {
+ sign_rrset(ksr, inception, expiration, cdnskey, keys);
+ }
+ if (dns_rdataset_count(cds) > 0) {
+ sign_rrset(ksr, inception, expiration, cds, keys);
+ }
+ inception = expiration - ksr->sigrefresh;
+ expiration = inception + ksr->sigvalidity;
+ }
+ freerrset(&rrset);
+}
+
+static isc_result_t
+parse_dnskey(isc_lex_t *lex, char *owner, isc_buffer_t *buf, dns_ttl_t *ttl) {
+ dns_fixedname_t dfname;
+ dns_name_t *dname = NULL;
+ dns_rdataclass_t rdclass = dns_rdataclass_in;
+ isc_buffer_t b;
+ isc_result_t ret;
+ isc_token_t token;
+ unsigned int opt = ISC_LEXOPT_EOL;
+
+ isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+
+ /* Read the domain name */
+ if (!strcmp(owner, "@")) {
+ BADTOKEN();
+ }
+
+ dname = dns_fixedname_initname(&dfname);
+ isc_buffer_init(&b, owner, strlen(owner));
+ isc_buffer_add(&b, strlen(owner));
+ ret = dns_name_fromtext(dname, &b, dns_rootname, 0, NULL);
+ if (ret != ISC_R_SUCCESS) {
+ return (ret);
+ }
+ if (dns_name_compare(dname, name) != 0) {
+ return (DNS_R_BADOWNERNAME);
+ }
+ isc_buffer_clear(&b);
+
+ /* Read the next word: either TTL, class, or type */
+ NEXTTOKEN(lex, opt, &token);
+ if (token.type != isc_tokentype_string) {
+ BADTOKEN();
+ }
+
+ /* If it's a TTL, read the next one */
+ ret = dns_ttl_fromtext(&token.value.as_textregion, ttl);
+ if (ret == ISC_R_SUCCESS) {
+ NEXTTOKEN(lex, opt, &token);
+ }
+ if (token.type != isc_tokentype_string) {
+ BADTOKEN();
+ }
+
+ /* If it's a class, read the next one */
+ ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
+ if (ret == ISC_R_SUCCESS) {
+ NEXTTOKEN(lex, opt, &token);
+ }
+ if (token.type != isc_tokentype_string) {
+ BADTOKEN();
+ }
+
+ /* Must be the type */
+ if (strcasecmp(STR(token), "DNSKEY") != 0) {
+ BADTOKEN();
+ }
+
+ ret = dns_rdata_fromtext(NULL, rdclass, dns_rdatatype_dnskey, lex, name,
+ 0, mctx, buf, NULL);
+
+cleanup:
+ isc_lex_setcomments(lex, 0);
+ return (ret);
+}
+
+static void
+keygen(ksr_ctx_t *ksr) {
+ dns_kasp_t *kasp = NULL;
+ dns_dnsseckeylist_t keys;
+ bool noop = true;
+
+ /* Check parameters */
+ checkparams(ksr, "keygen");
+ /* Get the policy */
+ getkasp(ksr, &kasp);
+ /* Get existing keys */
+ get_dnskeys(ksr, &keys);
+ /* Set context */
+ setcontext(ksr, kasp);
+ /* Key generation */
+ for (dns_kasp_key_t *kk = ISC_LIST_HEAD(dns_kasp_keys(kasp));
+ kk != NULL; kk = ISC_LIST_NEXT(kk, link))
+ {
+ if (dns_kasp_key_ksk(kk)) {
+ /* only ZSKs allowed */
+ continue;
+ }
+ ksr->alg = dns_kasp_key_algorithm(kk);
+ ksr->lifetime = dns_kasp_key_lifetime(kk);
+ ksr->keystore = dns_kasp_key_keystore(kk);
+ ksr->size = dns_kasp_key_size(kk);
+ noop = false;
+
+ for (isc_stdtime_t inception = ksr->start, act = ksr->start;
+ inception < ksr->end; inception += ksr->lifetime)
+ {
+ create_zsk(ksr, kk, &keys, inception, act, &act);
+ if (ksr->lifetime == 0) {
+ /* unlimited lifetime, but not infinite loop */
+ break;
+ }
+ }
+ }
+ if (noop) {
+ fatal("policy '%s' has no zsks", ksr->policy);
+ }
+ /* Cleanup */
+ cleanup(&keys, kasp);
+}
+
+static void
+request(ksr_ctx_t *ksr) {
+ char timestr[26]; /* Minimal buf as per ctime_r() spec. */
+ dns_dnsseckeylist_t keys;
+ dns_kasp_t *kasp = NULL;
+ isc_stdtime_t next = 0;
+ isc_stdtime_t inception = 0;
+
+ /* Check parameters */
+ checkparams(ksr, "request");
+ /* Get the policy */
+ getkasp(ksr, &kasp);
+ /* Get keys */
+ get_dnskeys(ksr, &keys);
+ /* Set context */
+ setcontext(ksr, kasp);
+ /* Create request */
+ inception = ksr->start;
+ while (inception <= ksr->end) {
+ char utc[sizeof("YYYYMMDDHHSSMM")];
+ isc_buffer_t b;
+ isc_region_t r;
+ isc_result_t ret;
+
+ isc_stdtime_tostring(inception, timestr, sizeof(timestr));
+ isc_buffer_init(&b, utc, sizeof(utc));
+ ret = dns_time32_totext(inception, &b);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("failed to convert bundle time32 to text: %s",
+ isc_result_totext(ret));
+ }
+ isc_buffer_usedregion(&b, &r);
+ fprintf(stdout, ";; KeySigningRequest 1.0 %.*s (%s)\n",
+ (int)r.length, r.base, timestr);
+
+ next = ksr->end + 1;
+ for (dns_kasp_key_t *kk = ISC_LIST_HEAD(dns_kasp_keys(kasp));
+ kk != NULL; kk = ISC_LIST_NEXT(kk, link))
+ {
+ /*
+ * Output the DNSKEY records for the current bundle
+ * that starts at 'inception. The 'next' variable is
+ * updated to the start time of the
+ * next bundle, determined by the earliest publication
+ * or withdrawal of a key that is after the current
+ * inception.
+ */
+ if (dns_kasp_key_ksk(kk)) {
+ /* We only want ZSKs in the request. */
+ continue;
+ }
+
+ next = print_dnskeys(kk, ksr->ttl, &keys, inception,
+ next);
+ }
+ inception = next;
+ }
+
+ isc_stdtime_tostring(ksr->now, timestr, sizeof(timestr));
+ fprintf(stdout, ";; KeySigningRequest 1.0 generated at %s by %s\n",
+ timestr, PACKAGE_VERSION);
+
+ /* Cleanup */
+ cleanup(&keys, kasp);
+}
+
+static void
+sign(ksr_ctx_t *ksr) {
+ char timestr[26]; /* Minimal buf as per ctime_r() spec. */
+ bool have_bundle = false;
+ dns_dnsseckeylist_t keys;
+ dns_kasp_t *kasp = NULL;
+ dns_rdatalist_t *rdatalist = NULL;
+ dns_rdataset_t ksk = DNS_RDATASET_INIT;
+ dns_rdataset_t cdnskey = DNS_RDATASET_INIT;
+ dns_rdataset_t cds = DNS_RDATASET_INIT;
+ isc_result_t ret;
+ isc_stdtime_t inception;
+ isc_lex_t *lex = NULL;
+ isc_lexspecials_t specials;
+ isc_token_t token;
+ unsigned int opt = ISC_LEXOPT_EOL;
+
+ /* Check parameters */
+ checkparams(ksr, "sign");
+ if (ksr->file == NULL) {
+ fatal("'sign' requires a KSR file");
+ }
+ /* Get the policy */
+ getkasp(ksr, &kasp);
+ /* Get keys */
+ get_dnskeys(ksr, &keys);
+ /* Set context */
+ setcontext(ksr, kasp);
+ /* Sign request */
+ inception = ksr->start;
+ isc_lex_create(mctx, KSR_LINESIZE, &lex);
+ memset(specials, 0, sizeof(specials));
+ specials['('] = 1;
+ specials[')'] = 1;
+ specials['"'] = 1;
+ isc_lex_setspecials(lex, specials);
+ ret = isc_lex_openfile(lex, ksr->file);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("unable to open KSR file %s: %s", ksr->file,
+ isc_result_totext(ret));
+ }
+
+ /* KSK, CDS and CDNSKEY */
+ create_ksk(ksr, kasp, &keys, &ksk, &cdnskey, &cds);
+
+ for (ret = isc_lex_gettoken(lex, opt, &token); ret == ISC_R_SUCCESS;
+ ret = isc_lex_gettoken(lex, opt, &token))
+ {
+ if (token.type != isc_tokentype_string) {
+ fatal("bad KSR file %s(%lu): syntax error", ksr->file,
+ isc_lex_getsourceline(lex));
+ }
+
+ if (strcmp(STR(token), ";;") == 0) {
+ char bundle[KSR_LINESIZE];
+ isc_stdtime_t next_inception;
+
+ CHECK(isc_lex_gettoken(lex, opt, &token));
+ if (token.type != isc_tokentype_string ||
+ strcmp(STR(token), "KeySigningRequest") != 0)
+ {
+ fatal("bad KSR file %s(%lu): expected "
+ "'KeySigningRequest'",
+ ksr->file, isc_lex_getsourceline(lex));
+ }
+
+ CHECK(isc_lex_gettoken(lex, opt, &token));
+ if (token.type != isc_tokentype_string) {
+ fatal("bad KSR file %s(%lu): expected string",
+ ksr->file, isc_lex_getsourceline(lex));
+ }
+
+ if (strcmp(STR(token), "1.0") != 0) {
+ fatal("bad KSR file %s(%lu): expected version",
+ ksr->file, isc_lex_getsourceline(lex));
+ }
+
+ CHECK(isc_lex_gettoken(lex, opt, &token));
+ if (token.type != isc_tokentype_string) {
+ fatal("bad KSR file %s(%lu): expected datetime",
+ ksr->file, isc_lex_getsourceline(lex));
+ }
+ if (strcmp(STR(token), "generated") == 0) {
+ /* Final bundle */
+ goto readline;
+ }
+
+ /* Date and time of bundle */
+ sscanf(STR(token), "%s", bundle);
+ next_inception = strtotime(bundle, ksr->now, ksr->now,
+ NULL);
+
+ if (have_bundle) {
+ /* Sign previous bundle */
+ sign_bundle(ksr, inception, next_inception,
+ rdatalist, &cds, &cdnskey, &keys);
+ fprintf(stdout, "\n");
+ }
+
+ /* Start next bundle */
+ rdatalist = isc_mem_get(mctx, sizeof(*rdatalist));
+ dns_rdatalist_init(rdatalist);
+ rdatalist->rdclass = dns_rdataclass_in;
+ rdatalist->type = dns_rdatatype_dnskey;
+ rdatalist->ttl = ksr->ttl;
+ for (isc_result_t r = dns_rdatalist_first(&ksk);
+ r == ISC_R_SUCCESS; r = dns_rdatalist_next(&ksk))
+ {
+ dns_rdata_t *clone =
+ isc_mem_get(mctx, sizeof(*clone));
+ dns_rdata_init(clone);
+ dns_rdatalist_current(&ksk, clone);
+ ISC_LIST_APPEND(rdatalist->rdata, clone, link);
+ }
+ inception = next_inception;
+ have_bundle = true;
+
+ readline:
+ /* Read remainder of header line */
+ do {
+ ret = isc_lex_gettoken(lex, opt, &token);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("bad KSR file %s(%lu): bad "
+ "header (%s)",
+ ksr->file,
+ isc_lex_getsourceline(lex),
+ isc_result_totext(ret));
+ }
+ } while (token.type != isc_tokentype_eol);
+ } else {
+ /* Parse DNSKEY */
+ dns_ttl_t ttl = ksr->ttl;
+ isc_buffer_t buf;
+ isc_buffer_t *newbuf = NULL;
+ dns_rdata_t *rdata = NULL;
+ isc_region_t r;
+ u_char rdatabuf[DST_KEY_MAXSIZE];
+
+ INSIST(rdatalist != NULL);
+
+ rdata = isc_mem_get(mctx, sizeof(*rdata));
+ dns_rdata_init(rdata);
+ isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf));
+ ret = parse_dnskey(lex, STR(token), &buf, &ttl);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("bad KSR file %s(%lu): bad DNSKEY (%s)",
+ ksr->file, isc_lex_getsourceline(lex),
+ isc_result_totext(ret));
+ }
+ isc_buffer_usedregion(&buf, &r);
+ isc_buffer_allocate(mctx, &newbuf, r.length);
+ isc_buffer_putmem(newbuf, r.base, r.length);
+ isc_buffer_usedregion(newbuf, &r);
+ dns_rdata_fromregion(rdata, dns_rdataclass_in,
+ dns_rdatatype_dnskey, &r);
+ if (rdatalist != NULL && ttl < rdatalist->ttl) {
+ rdatalist->ttl = ttl;
+ }
+
+ ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+ ISC_LIST_APPEND(cleanup_list, newbuf, link);
+ isc_buffer_clear(newbuf);
+ }
+ }
+
+ if (ret != ISC_R_EOF) {
+ fatal("bad KSR file %s(%lu): trailing garbage data", ksr->file,
+ isc_lex_getsourceline(lex));
+ }
+
+ /* Final bundle */
+ if (have_bundle && rdatalist != NULL) {
+ sign_bundle(ksr, inception, ksr->end, rdatalist, &cds, &cdnskey,
+ &keys);
+ } else {
+ fatal("bad KSR file %s(%lu): no bundles", ksr->file,
+ isc_lex_getsourceline(lex));
+ }
+
+ /* Bundle footer */
+ isc_stdtime_tostring(ksr->now, timestr, sizeof(timestr));
+ fprintf(stdout, ";; SignedKeyResponse 1.0 generated at %s by %s\n",
+ timestr, PACKAGE_VERSION);
+
+fail:
+ /* Clean up */
+ freerrset(&ksk);
+ freerrset(&cdnskey);
+ freerrset(&cds);
+
+ isc_lex_destroy(&lex);
+ cleanup(&keys, kasp);
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_result_t ret;
+ isc_buffer_t buf;
+ int ch;
+ char *endp;
+ bool set_fips_mode = false;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
+ OSSL_PROVIDER *fips = NULL, *base = NULL;
+#endif
+ ksr_ctx_t ksr = {
+ .now = isc_stdtime_now(),
+ };
+
+ isc_mem_create(&mctx);
+
+ isc_commandline_errprint = false;
+
+#define OPTIONS "E:e:Ff:hi:K:k:l:v:V"
+ while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) {
+ switch (ch) {
+ case 'E':
+ engine = isc_commandline_argument;
+ break;
+ case 'e':
+ ksr.end = strtotime(isc_commandline_argument, ksr.now,
+ ksr.now, &ksr.setend);
+ break;
+ case 'F':
+ set_fips_mode = true;
+ break;
+ case 'f':
+ ksr.file = isc_commandline_argument;
+ break;
+ case 'h':
+ usage(0);
+ break;
+ case 'i':
+ ksr.start = strtotime(isc_commandline_argument, ksr.now,
+ ksr.now, &ksr.setstart);
+ break;
+ case 'K':
+ ksr.keydir = isc_commandline_argument;
+ ret = try_dir(ksr.keydir);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("cannot open directory %s: %s",
+ ksr.keydir, isc_result_totext(ret));
+ }
+ break;
+ case 'k':
+ ksr.policy = isc_commandline_argument;
+ break;
+ case 'l':
+ ksr.configfile = isc_commandline_argument;
+ break;
+ case 'V':
+ version(program);
+ break;
+ case 'v':
+ verbose = strtoul(isc_commandline_argument, &endp, 0);
+ if (*endp != '\0') {
+ fatal("-v must be followed by a number");
+ }
+ break;
+ default:
+ usage(1);
+ break;
+ }
+ }
+ argv += isc_commandline_index;
+ argc -= isc_commandline_index;
+
+ if (argc != 2) {
+ fatal("must provide a command and zone name");
+ }
+
+ ret = dst_lib_init(mctx, engine);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("could not initialize dst: %s", isc_result_totext(ret));
+ }
+
+ /*
+ * After dst_lib_init which will set FIPS mode if requested
+ * at build time. The minumums are both raised to 2048.
+ */
+ if (isc_fips_mode()) {
+ min_rsa = min_dh = 2048;
+ }
+
+ setup_logging(mctx, &lctx);
+
+ if (set_fips_mode) {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
+ fips = OSSL_PROVIDER_load(NULL, "fips");
+ if (fips == NULL) {
+ fatal("Failed to load FIPS provider");
+ }
+ base = OSSL_PROVIDER_load(NULL, "base");
+ if (base == NULL) {
+ OSSL_PROVIDER_unload(fips);
+ fatal("Failed to load base provider");
+ }
+#endif
+ if (!isc_fips_mode()) {
+ if (isc_fips_set_mode(1) != ISC_R_SUCCESS) {
+ fatal("setting FIPS mode failed");
+ }
+ }
+ }
+
+ /* zone */
+ namestr = argv[1];
+ name = dns_fixedname_initname(&fname);
+ isc_buffer_init(&buf, argv[1], strlen(argv[1]));
+ isc_buffer_add(&buf, strlen(argv[1]));
+ ret = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
+ if (ret != ISC_R_SUCCESS) {
+ fatal("invalid zone name %s: %s", argv[1],
+ isc_result_totext(ret));
+ }
+
+ /* command */
+ if (strcmp(argv[0], "keygen") == 0) {
+ keygen(&ksr);
+ } else if (strcmp(argv[0], "request") == 0) {
+ request(&ksr);
+ } else if (strcmp(argv[0], "sign") == 0) {
+ sign(&ksr);
+ } else {
+ fatal("unknown command '%s'", argv[0]);
+ }
+
+ exit(0);
+}
diff --git a/bin/dnssec/dnssec-ksr.rst b/bin/dnssec/dnssec-ksr.rst
new file mode 100644
index 0000000000..1ed7275aca
--- /dev/null
+++ b/bin/dnssec/dnssec-ksr.rst
@@ -0,0 +1,162 @@
+.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+..
+.. SPDX-License-Identifier: MPL-2.0
+..
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, you 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.
+ This will generate a file with a number of key bundles, where each bundle
+ contains the currently published ZSKs (according to the timing metadata).
+
+.. option:: sign
+
+ Sign a Key Signing Request (KSR), given a DNSSEC policy and an interval,
+ creating a Signed Key Response (SKR). This will add the corresponding DNSKEY,
+ CDS, and CDNSKEY records for the KSK that is being used for signing.
+
+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) `,
+:iscman:`dnssec-signzone(8) `,
+BIND 9 Administrator Reference Manual.
diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c
index ada83fd96a..cf7f2b74de 100644
--- a/bin/dnssec/dnssec-revoke.c
+++ b/bin/dnssec/dnssec-revoke.c
@@ -58,7 +58,7 @@ usage(void) {
fprintf(stderr, " K++.key, "
"K++.private\n");
- exit(-1);
+ exit(EXIT_FAILURE);
}
int
@@ -130,7 +130,7 @@ main(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c
index fcd8c0cb53..f19d0781b5 100644
--- a/bin/dnssec/dnssec-settime.c
+++ b/bin/dnssec/dnssec-settime.c
@@ -101,7 +101,7 @@ usage(void) {
fprintf(stderr, " K++.key, "
"K++.private\n");
- exit(-1);
+ exit(EXIT_FAILURE);
}
static void
@@ -536,7 +536,7 @@ main(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c
index e158e8ce77..094d905ba3 100644
--- a/bin/dnssec/dnssec-signzone.c
+++ b/bin/dnssec/dnssec-signzone.c
@@ -183,6 +183,8 @@ static bool set_maxttl = false;
static dns_ttl_t maxttl = 0;
static bool no_max_check = false;
static const char *sync_records = "cdnskey,cds:sha-256";
+static bool defer_signing = false;
+
#define INCSTAT(counter) \
if (printstats) { \
@@ -275,13 +277,13 @@ lock_and_dumpnode(dns_name_t *name, dns_dbnode_t *node) {
UNLOCK(&namelock);
}
-/*%
+/*
* Sign the given RRset with given key, and add the signature record to the
* given tuple.
*/
static void
signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key,
- dns_ttl_t ttl, dns_diff_t *add, const char *logmsg) {
+ dns_ttl_t ttl, dns_diff_t *add, const char *logmsg, bool check_now) {
isc_result_t result;
isc_stdtime_t jendtime, expiry;
char keystr[DST_KEY_FORMATSIZE];
@@ -298,7 +300,6 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key,
} else {
expiry = endtime;
}
-
jendtime = (jitter != 0) ? expiry - isc_random_uniform(jitter) : expiry;
isc_buffer_init(&b, array, sizeof(array));
result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime,
@@ -309,7 +310,9 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key,
}
INCSTAT(nsigned);
- if (tryverify) {
+ // With deferred signing we need to wait until the signature is finalized
+ // before we can test it if verifies.
+ if (tryverify && check_now) {
result = dns_dnssec_verify(name, rdataset, key, true, 0, mctx,
&trdata, NULL);
if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
@@ -490,7 +493,7 @@ setverifies(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
*/
static void
signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
- dns_rdataset_t *set) {
+ dns_rdataset_t *set, bool check_now) {
dns_rdataset_t sigset;
dns_rdata_t sigrdata = DNS_RDATA_INIT;
dns_rdata_rrsig_t rrsig;
@@ -543,7 +546,6 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
} else {
result = dns_rdataset_first(&sigset);
}
-
while (result == ISC_R_SUCCESS) {
bool expired, future;
bool keep = false, resign = false;
@@ -660,9 +662,8 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
if (resign) {
INSIST(!keep);
-
signwithkey(name, set, key->key, ttl, add,
- "resigning with dnskey");
+ "resigning with dnskey", check_now);
nowsignedby[key->index] = true;
}
@@ -717,8 +718,10 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
if (isksk(key) || !have_ksk ||
(iszsk(key) && !keyset_kskonly))
{
- signwithkey(name, set, key->key, ttl, add,
- "signing with dnskey");
+ if (!defer_signing || !iszsk(key) || (set->type == dns_rdatatype_dnskey && !dst_key_is_deferred_signing(key->key))) {
+ signwithkey(name, set, key->key, ttl, add,
+ "signing with dnskey", check_now);
+ }
}
} else if (iszsk(key)) {
/*
@@ -778,8 +781,10 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
* skip signing with this key.
*/
if (!have_pre_sig) {
- signwithkey(name, set, key->key, ttl, add,
- "signing with dnskey");
+ if (set->type != dns_rdatatype_rrsig) {
+ signwithkey(name, set, key->key, ttl, add,
+ "signing with dnskey", check_now);
+ }
}
}
}
@@ -1000,8 +1005,8 @@ opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
}
isc_buffer_putuint8(&b, 0);
- result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
- rdclass, 0, NULL, dbp);
+ result = dns_db_create(mctx, ZONEDB_DEFAULT, dns_rootname,
+ dns_dbtype_zone, rdclass, 0, NULL, dbp);
check_result(result, "dns_db_create()");
result = dns_db_load(*dbp, filename, inputformat, DNS_MASTER_HINT);
@@ -1169,7 +1174,7 @@ has_dname(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node) {
* Signs all records at a name.
*/
static void
-signname(dns_dbnode_t *node, dns_name_t *name) {
+signname(dns_dbnode_t *node, bool apex, dns_name_t *name) {
isc_result_t result;
dns_rdataset_t rdataset;
dns_rdatasetiter_t *rdsiter;
@@ -1200,7 +1205,8 @@ signname(dns_dbnode_t *node, dns_name_t *name) {
dns_rdatasetiter_current(rdsiter, &rdataset);
/* If this is a RRSIG set, skip it. */
- if (rdataset.type == dns_rdatatype_rrsig) {
+ if (rdataset.type == dns_rdatatype_rrsig ||
+ (defer_signing && rdataset.type == dns_rdatatype_dnskey)) {
goto skip;
}
@@ -1220,9 +1226,13 @@ signname(dns_dbnode_t *node, dns_name_t *name) {
dns_name_format(name, namebuf, sizeof(namebuf));
fatal("'%s': found DS RRset without NS RRset\n",
namebuf);
+ } else if (rdataset.type == dns_rdatatype_dnskey && !apex) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ fatal("'%s': Non-apex DNSKEY RRset\n", namebuf);
}
- signset(&del, &add, node, name, &rdataset);
+ signset(&del, &add, node, name, &rdataset, !defer_signing);
skip:
dns_rdataset_disassociate(&rdataset);
@@ -1539,8 +1549,10 @@ signapex(void) {
check_result(result, "dns_dbiterator_seek()");
result = dns_dbiterator_current(gdbiter, &node, name);
check_dns_dbiterator_current(result);
- signname(node, name);
- dumpnode(name, node);
+ signname(node, true, name);
+ if (!defer_signing) {
+ dumpnode(name, node);
+ }
dns_db_detachnode(gdb, &node);
result = dns_dbiterator_first(gdbiter);
if (result == ISC_R_NOMORE) {
@@ -1643,7 +1655,9 @@ assignwork(void *arg) {
}
if (!found) {
- dumpnode(name, node);
+ if (!defer_signing) {
+ dumpnode(name, node);
+ }
dns_db_detachnode(gdb, &node);
}
@@ -1668,15 +1682,17 @@ assignwork(void *arg) {
UNLOCK(&namelock);
- signname(node, dns_fixedname_name(&fname));
+ signname(node, false, dns_fixedname_name(&fname));
/*%
* Write a node to the output file, and restart the worker task.
*/
- lock_and_dumpnode(dns_fixedname_name(&fname), node);
+ if (!defer_signing) {
+ lock_and_dumpnode(dns_fixedname_name(&fname), node);
+ }
dns_db_detachnode(gdb, &node);
- isc_async_current(loopmgr, assignwork, NULL);
+ isc_async_current(assignwork, NULL);
}
/*%
@@ -2574,8 +2590,8 @@ loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
isc_result_totext(result));
}
- result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0,
- NULL, db);
+ result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
+ rdclass, 0, NULL, db);
check_result(result, "dns_db_create()");
result = dns_db_load(*db, file, inputformat, 0);
@@ -2641,7 +2657,7 @@ loadzonekeys(bool preserve_keys, bool load_public) {
/* Load keys corresponding to the existing DNSKEY RRset. */
result = dns_dnssec_keylistfromrdataset(
- gorigin, directory, mctx, &rdataset, &keysigs, &soasigs,
+ gorigin, NULL, directory, mctx, &rdataset, &keysigs, &soasigs,
preserve_keys, load_public, &keylist);
if (result != ISC_R_SUCCESS) {
fatal("failed to load the zone keys: %s",
@@ -2832,8 +2848,8 @@ build_final_keylist(void) {
/*
* Find keys that match this zone in the key repository.
*/
- result = dns_dnssec_findmatchingkeys(gorigin, directory, now, mctx,
- &matchkeys);
+ result = dns_dnssec_findmatchingkeys(gorigin, NULL, directory, NULL,
+ now, mctx, &matchkeys);
if (result == ISC_R_NOTFOUND) {
result = ISC_R_SUCCESS;
}
@@ -3164,8 +3180,8 @@ writeset(const char *prefix, dns_rdatatype_t type) {
dns_diff_append(&diff, &tuple);
}
- result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
- gclass, 0, NULL, &db);
+ result = dns_db_create(mctx, ZONEDB_DEFAULT, dns_rootname,
+ dns_dbtype_zone, gclass, 0, NULL, &db);
check_result(result, "dns_db_create");
result = dns_db_newversion(db, &dbversion);
@@ -3302,7 +3318,7 @@ usage(void) {
fprintf(stderr, "(default: all zone keys that have private keys)\n");
fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n");
- exit(0);
+ exit(EXIT_FAILURE);
}
static void
@@ -3346,6 +3362,378 @@ print_stats(isc_time_t *timer_start, isc_time_t *timer_finish,
(unsigned int)(time_ms / 1000), (unsigned int)(time_ms % 1000));
}
+static void
+finalize_node_rrsigs(dns_dbnode_t *node, dns_name_t *name, dns_diff_t *add, dns_diff_t *del, dns_dnsseckey_t *key, uint16_t old_keytag) {
+ isc_result_t result;
+ dns_rdatasetiter_t *rdsiter = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdataset_init(&rdataset);
+ result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter);
+ check_result(result, "dns_db_allrdatasets()");
+
+ result = dns_rdatasetiter_first(rdsiter);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+
+ /* Iterate over only rrsigs and update them to include the authpath. */
+ if (rdataset.type != dns_rdatatype_rrsig) {
+ goto skip;
+ }
+ isc_result_t rrsigresult;
+ for (rrsigresult = dns_rdataset_first(&rdataset);
+ rrsigresult == ISC_R_SUCCESS;
+ rrsigresult = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rrsig_rdata = DNS_RDATA_INIT;
+ dns_rdata_rrsig_t rrsig;
+ dns_rdataset_current(&rdataset, &rrsig_rdata);
+ if (rrsig_rdata.type == dns_rdatatype_rrsig) {
+ rrsigresult = dns_rdata_tostruct(&rrsig_rdata, &rrsig, NULL);
+ if (rrsigresult == ISC_R_SUCCESS) {
+ if (rrsig.keyid == old_keytag) {
+ char data[4096];
+ isc_buffer_t databuf;
+ dns_difftuple_t *addtuple = NULL;
+ dns_difftuple_t *deltuple = NULL;
+ dns_rdata_t new_rrsig_rdata = DNS_RDATA_INIT;
+ isc_buffer_init(&databuf, data, sizeof(data));
+ check_result(dst_key_signature_finalize(key->key, &databuf, &rrsig_rdata, &new_rrsig_rdata), "signature finalize");
+ if (tryverify) {
+ dns_rdataset_t target_rdataset;
+ dns_rdataset_init(&target_rdataset);
+ rrsigresult = dns_db_findrdataset(gdb, node, gversion, rrsig.covered,
+ 0, 0, &target_rdataset, NULL);
+ check_result(rrsigresult, "find RRSIG's covered rdataset");
+
+ rrsigresult = dns_dnssec_verify(name, &target_rdataset, key->key, true, 0, mctx,
+ &new_rrsig_rdata, NULL);
+ if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
+ vbprintf(3, "\tsignature verified\n");
+ INCSTAT(nverified);
+ } else {
+ vbprintf(3, "\tsignature failed to verify\n");
+ INCSTAT(nverifyfailed);
+ }
+ dns_rdataset_disassociate(&target_rdataset);
+ }
+ result = dns_difftuple_create(mctx,
+ DNS_DIFFOP_ADDRESIGN, name,
+ rdataset.ttl, &new_rrsig_rdata, &addtuple);
+ check_result(result, "dns_difftuple_create");
+ result = dns_difftuple_create(mctx,
+ DNS_DIFFOP_DELRESIGN, name,
+ rdataset.ttl, &rrsig_rdata, &deltuple);
+ check_result(result, "dns_difftuple_create");
+ dns_diff_append(add, &addtuple);
+ dns_diff_append(del, &deltuple);
+ }
+ dns_rdata_freestruct(&rrsig);
+ }
+ }
+ }
+ skip:
+ dns_rdataset_disassociate(&rdataset);
+ result = dns_rdatasetiter_next(rdsiter);
+ }
+ dns_rdatasetiter_destroy(&rdsiter);
+}
+
+static void
+finalize_rrsigs(dns_diff_t *add, dns_diff_t *del, dns_dnsseckey_t *key, uint16_t old_keytag) {
+ dns_dbnode_t *node = NULL;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ isc_result_t result;
+ dns_dbiterator_t *dbiter = NULL;
+ result = dns_db_createiterator(gdb, 0, &dbiter);
+ check_result(result, "dns_db_createiterator()");
+ name = dns_fixedname_initname(&fixed);
+ result = dns_dbiterator_seek(dbiter, gorigin);
+ check_result(result, "dns_dbiterator_seek()");
+ result = dns_dbiterator_current(dbiter, &node, name);
+ check_dns_dbiterator_current(result);
+ finalize_node_rrsigs(node, name, add, del, key, old_keytag);
+ dns_db_detachnode(gdb, &node);
+ result = dns_dbiterator_first(dbiter);
+ dns_fixedname_t fname;
+
+ result = ISC_R_SUCCESS;
+ while (result == ISC_R_SUCCESS) {
+ name = dns_fixedname_initname(&fname);
+ result = dns_dbiterator_current(dbiter, &node, name);
+ check_dns_dbiterator_current(result);
+ if (dns_name_equal(name, gorigin)) {
+ goto next;
+ }
+ finalize_node_rrsigs(node, name, add, del, key, old_keytag);
+ next:
+ result = dns_dbiterator_next(dbiter);
+ dns_db_detachnode(gdb, &node);
+ if (result == ISC_R_NOMORE) {
+ break;
+ } else if (result != ISC_R_SUCCESS) {
+ fatal("failure iterating database: %s",
+ isc_result_totext(result));
+ }
+ }
+ dns_dbiterator_destroy(&dbiter);
+}
+
+static void
+defered_finalize_signing(dns_dbnode_t *node, dns_name_t *name) {
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ dns_rdatasetiter_t *rdsiter;
+ dns_diff_t del, add;
+ char namestr[DNS_NAME_FORMATSIZE];
+
+ dns_rdataset_init(&rdataset);
+ dns_name_format(name, namestr, sizeof(namestr));
+
+ /*
+ * Now iterate through the rdatasets.
+ */
+ dns_diff_init(mctx, &del);
+ dns_diff_init(mctx, &add);
+ rdsiter = NULL;
+ result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter);
+ check_result(result, "dns_db_allrdatasets()");
+ result = dns_rdatasetiter_first(rdsiter);
+
+ while (result == ISC_R_SUCCESS) {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+
+ /* Now that the all other signatures are signed, finalize defer signing
+ * key and sign DNSKEY set. */
+ if (rdataset.type != dns_rdatatype_dnskey) {
+ goto finalize_skip;
+ }
+
+ // Finalize all keys located in this set
+ isc_result_t keyresult;
+ for (keyresult = dns_rdataset_first(&rdataset);
+ keyresult == ISC_R_SUCCESS;
+ keyresult = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t key_rdata = DNS_RDATA_INIT;
+ dns_rdata_dnskey_t dnskey;
+ dns_rdataset_current(&rdataset, &key_rdata);
+ if (key_rdata.type == dns_rdatatype_dnskey) {
+ isc_region_t key_r;
+ key_r.base = key_rdata.data;
+ key_r.length = key_rdata.length;
+ uint16_t keytag = dst_region_computeid(&key_r);
+ keyresult = dns_rdata_tostruct(&key_rdata, &dnskey, NULL);
+ if (keyresult == ISC_R_SUCCESS) {
+ if (dst_algorithm_is_deferred_signing(dnskey.algorithm)) {
+ dns_dnsseckey_t *key = NULL;
+ for (key = ISC_LIST_HEAD(keylist); key != NULL;
+ key = ISC_LIST_NEXT(key, link))
+ {
+ if (dst_key_id(key->key) == keytag &&
+ dst_key_alg(key->key) == dnskey.algorithm)
+ {
+ dns_difftuple_t *addtuple = NULL;
+ dns_difftuple_t *deltuple = NULL;
+ unsigned char data[4096];
+ isc_buffer_t buffer;
+ isc_region_t r;
+
+ isc_buffer_init(&buffer, data, sizeof(data));
+ check_result(dst_key_finalize(key->key), "dst_key_finalize");
+ dns_rdata_t new_dnskey_rdata = DNS_RDATA_INIT;
+ dns_rdata_t old_dnskey_rdata = DNS_RDATA_INIT;
+
+ dns_rdata_clone(&key_rdata, &old_dnskey_rdata);
+ result = dst_key_todns(key->key, &buffer);
+ check_result(result, "dst_key_todns");
+ isc_buffer_usedregion(&buffer, &r);
+ dns_rdata_fromregion(&new_dnskey_rdata, key_rdata.rdclass, dns_rdatatype_dnskey, &r);
+
+ result = dns_difftuple_create(mctx,
+ DNS_DIFFOP_ADDRESIGN, name,
+ rdataset.ttl, &new_dnskey_rdata, &addtuple);
+ check_result(result, "dns_difftuple_create");
+ result = dns_difftuple_create(mctx,
+ DNS_DIFFOP_DELRESIGN, name,
+ rdataset.ttl, &old_dnskey_rdata, &deltuple);
+ check_result(result, "dns_difftuple_create");
+ dns_diff_append(&add, &addtuple);
+ dns_diff_append(&del, &deltuple);
+ break;
+ }
+ }
+ if (key != NULL) {
+ finalize_rrsigs(&add, &del, key, keytag);
+ }
+ }
+ dns_rdata_freestruct(&dnskey);
+ }
+ }
+ }
+
+ finalize_skip:
+ dns_rdataset_disassociate(&rdataset);
+ result = dns_rdatasetiter_next(rdsiter);
+ }
+ if (result != ISC_R_NOMORE) {
+ fatal("rdataset iteration for name '%s' failed: %s", namestr,
+ isc_result_totext(result));
+ }
+
+ dns_rdatasetiter_destroy(&rdsiter);
+ result = dns_diff_applysilently(&del, gdb, gversion);
+ if (result != ISC_R_SUCCESS) {
+ fatal("failed to delete SIGs at node '%s': %s", namestr,
+ isc_result_totext(result));
+ }
+
+ result = dns_diff_applysilently(&add, gdb, gversion);
+ if (result != ISC_R_SUCCESS) {
+ fatal("failed to add SIGs at node '%s': %s", namestr,
+ isc_result_totext(result));
+ }
+
+ dns_diff_clear(&del);
+ dns_diff_clear(&add);
+ result = dns_db_allrdatasets(gdb, node, gversion, 0, 0, &rdsiter);
+ check_result(result, "dns_db_allrdatasets()");
+ result = dns_rdatasetiter_first(rdsiter);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+
+ /* Now that the all other signatures are signed, finalize defer signing
+ * key and sign DNSKEY set. */
+ if (rdataset.type != dns_rdatatype_dnskey) {
+ goto sign_skip;
+ }
+
+
+ signset(&del, &add, node, name, &rdataset, true);
+
+ sign_skip:
+ dns_rdataset_disassociate(&rdataset);
+ result = dns_rdatasetiter_next(rdsiter);
+ }
+
+ dns_rdatasetiter_destroy(&rdsiter);
+ result = dns_diff_applysilently(&del, gdb, gversion);
+ if (result != ISC_R_SUCCESS) {
+ fatal("failed to delete SIGs at node '%s': %s", namestr,
+ isc_result_totext(result));
+ }
+
+ result = dns_diff_applysilently(&add, gdb, gversion);
+ if (result != ISC_R_SUCCESS) {
+ fatal("failed to add SIGs at node '%s': %s", namestr,
+ isc_result_totext(result));
+ }
+ dns_diff_clear(&del);
+ dns_diff_clear(&add);
+}
+
+static void
+defered_finalize(void) {
+ dns_dbnode_t *node = NULL;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ isc_result_t result;
+ name = dns_fixedname_initname(&fixed);
+ result = dns_dbiterator_seek(gdbiter, gorigin);
+ check_result(result, "dns_dbiterator_seek()");
+ result = dns_dbiterator_current(gdbiter, &node, name);
+ check_dns_dbiterator_current(result);
+ defered_finalize_signing(node, name);
+ dumpnode(name, node);
+ dns_db_detachnode(gdb, &node);
+ result = dns_dbiterator_first(gdbiter);
+ dns_fixedname_t fname;
+ dns_rdataset_t nsec;
+ bool found;
+ static dns_name_t *zonecut = NULL; /* Protected by namelock. */
+ static dns_fixedname_t fzonecut; /* Protected by namelock. */
+
+ result = ISC_R_SUCCESS;
+ while (result == ISC_R_SUCCESS) {
+ name = dns_fixedname_initname(&fname);
+ found = false;
+ while (!found) {
+ result = dns_dbiterator_current(gdbiter, &node, name);
+ check_dns_dbiterator_current(result);
+ if (dns_name_equal(name, gorigin)) {
+ dns_db_detachnode(gdb, &node);
+ goto next;
+ }
+ /*
+ * Sort the zone data from the glue and out-of-zone data.
+ * For NSEC zones nodes with zone data have NSEC records.
+ * For NSEC3 zones the NSEC3 nodes are zone data but
+ * outside of the zone name space. For the rest we need
+ * to track the bottom of zone cuts.
+ * Nodes which don't need to be signed are dumped here.
+ */
+ dns_rdataset_init(&nsec);
+ result = dns_db_findrdataset(gdb, node, gversion, nsec_datatype,
+ 0, 0, &nsec, NULL);
+ if (dns_rdataset_isassociated(&nsec)) {
+ dns_rdataset_disassociate(&nsec);
+ }
+ if (result == ISC_R_SUCCESS) {
+ found = true;
+ } else if (nsec_datatype == dns_rdatatype_nsec3) {
+ if (dns_name_issubdomain(name, gorigin) &&
+ (zonecut == NULL ||
+ !dns_name_issubdomain(name, zonecut)))
+ {
+ if (is_delegation(gdb, gversion, gorigin, name,
+ node, NULL))
+ {
+ zonecut = savezonecut(&fzonecut, name);
+ if (!OPTOUT(nsec3flags) ||
+ secure(name, node))
+ {
+ found = true;
+ }
+ } else if (has_dname(gdb, gversion, node)) {
+ zonecut = savezonecut(&fzonecut, name);
+ found = true;
+ } else {
+ found = true;
+ }
+ }
+ }
+
+ if (!found) {
+ dumpnode(name, node);
+ dns_db_detachnode(gdb, &node);
+ }
+
+ next:
+ result = dns_dbiterator_next(gdbiter);
+ if (result == ISC_R_NOMORE) {
+ break;
+ } else if (result != ISC_R_SUCCESS) {
+ fatal("failure iterating database: %s",
+ isc_result_totext(result));
+ }
+ }
+ if (!dns_name_equal(name, gorigin)) {
+ defered_finalize_signing(node, dns_fixedname_name(&fname));
+ /*%
+ * Write a node to the output file, and restart the worker task.
+ */
+ dumpnode(dns_fixedname_name(&fname), node);
+ }
+ dns_db_detachnode(gdb, &node);
+
+ if (result == ISC_R_NOMORE) {
+ break;
+ } else if (result != ISC_R_SUCCESS) {
+ fatal("failure iterating database: %s",
+ isc_result_totext(result));
+ }
+ }
+
+}
+
int
main(int argc, char *argv[]) {
int ch;
@@ -3497,7 +3885,7 @@ main(int argc, char *argv[]) {
set_iter = true;
/* too-many is NOT DOCUMENTED */
if (strcmp(isc_commandline_argument, "too-many") == 0) {
- nsec3iter = 151;
+ nsec3iter = 51;
no_max_check = true;
break;
}
@@ -3553,7 +3941,7 @@ main(int argc, char *argv[]) {
if (*endp != '\0') {
fprintf(stderr, "source serial number "
"must be numeric");
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -3568,7 +3956,7 @@ main(int argc, char *argv[]) {
if (*endp != '\0') {
fprintf(stderr, "maximum TTL "
"must be numeric");
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -3692,7 +4080,7 @@ main(int argc, char *argv[]) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -3840,7 +4228,7 @@ main(int argc, char *argv[]) {
rawversion > 1U)
{
fprintf(stderr, "unknown raw format version\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
} else {
fatal("unknown file format: %s", outputformatstr);
@@ -3950,6 +4338,9 @@ main(int argc, char *argv[]) {
key = ISC_LIST_NEXT(key, link))
{
key->index = keycount++;
+ if (dst_key_is_deferred_signing(key->key)) {
+ defer_signing = true;
+ }
}
if (keycount == 0) {
@@ -4085,6 +4476,10 @@ main(int argc, char *argv[]) {
fatal("process aborted by user");
}
}
+ if (defer_signing) {
+ // Finalize and dump everything
+ defered_finalize();
+ }
postsign();
sign_finish = isc_time_now();
diff --git a/bin/dnssec/dnssec-signzone.rst b/bin/dnssec/dnssec-signzone.rst
index e6fb455c3d..5c2f1d6b45 100644
--- a/bin/dnssec/dnssec-signzone.rst
+++ b/bin/dnssec/dnssec-signzone.rst
@@ -273,7 +273,7 @@ Options
with cached copies of the old DNSKEY RRset. The :option:`-Q` option forces
:program:`dnssec-signzone` to remove signatures from keys that are no longer
active. This enables ZSK rollover using the procedure described in
- :rfc:`4641#4.2.1.1` ("Pre-Publish Key Rollover").
+ :rfc:`6781#4.1.1.1` ("Pre-Publish Key Rollover").
.. option:: -q
@@ -290,7 +290,7 @@ Options
This option is similar to :option:`-Q`, except it forces
:program:`dnssec-signzone` to remove signatures from keys that are no longer
published. This enables ZSK rollover using the procedure described in
- :rfc:`4641#4.2.1.2` ("Double Signature Zone Signing Key
+ :rfc:`6781#4.1.1.2` ("Double Signature Zone Signing Key
Rollover").
.. option:: -S
@@ -374,6 +374,7 @@ Options
.. note::
``-3 -`` is the recommended configuration. Adding salt provides no practical benefits.
+ See :rfc:`9276`.
.. option:: -H iterations
@@ -382,6 +383,7 @@ Options
.. warning::
Values greater than 0 cause interoperability issues and also increase the risk of CPU-exhausting DoS attacks.
+ See :rfc:`9276`.
.. option:: -A
@@ -390,6 +392,7 @@ Options
.. warning::
Do not use this option unless all its implications are fully understood. This option is intended only for extremely large zones (comparable to ``com.``) with sparse secure delegations.
+ See :rfc:`9276`.
.. option:: -AA
@@ -443,4 +446,4 @@ See Also
~~~~~~~~
:iscman:`dnssec-keygen(8) `, BIND 9 Administrator Reference Manual, :rfc:`4033`,
-:rfc:`4641`.
+:rfc:`6781`.
diff --git a/bin/dnssec/dnssec-verify.c b/bin/dnssec/dnssec-verify.c
index e6b8972b02..c4ce4eadf7 100644
--- a/bin/dnssec/dnssec-verify.c
+++ b/bin/dnssec/dnssec-verify.c
@@ -109,8 +109,8 @@ loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
isc_result_totext(result));
}
- result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0,
- NULL, db);
+ result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
+ rdclass, 0, NULL, db);
check_result(result, "dns_db_create()");
result = dns_db_load(*db, file, inputformat, 0);
@@ -162,7 +162,7 @@ usage(void) {
fprintf(stderr, "\t-x:\tDNSKEY record signed with KSKs only, "
"not ZSKs\n");
fprintf(stderr, "\t-z:\tAll records signed with KSKs\n");
- exit(0);
+ exit(EXIT_SUCCESS);
}
int
@@ -271,7 +271,7 @@ main(int argc, char *argv[]) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c
index 85e2955185..e34c972c67 100644
--- a/bin/dnssec/dnssectool.c
+++ b/bin/dnssec/dnssectool.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
@@ -83,8 +84,7 @@ fatal(const char *format, ...) {
if (fatalcallback != NULL) {
(*fatalcallback)();
}
- isc__tls_setfatalmode();
- exit(1);
+ _exit(EXIT_FAILURE);
}
void
@@ -114,7 +114,7 @@ vbprintf(int level, const char *fmt, ...) {
void
version(const char *name) {
printf("%s %s\n", name, PACKAGE_VERSION);
- exit(0);
+ exit(EXIT_SUCCESS);
}
void
@@ -498,7 +498,8 @@ key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir,
alg = dst_key_alg(dstkey);
ISC_LIST_INIT(matchkeys);
- result = dns_dnssec_findmatchingkeys(name, dir, now, mctx, &matchkeys);
+ result = dns_dnssec_findmatchingkeys(name, NULL, dir, NULL, now, mctx,
+ &matchkeys);
if (result == ISC_R_NOTFOUND) {
return (false);
}
@@ -600,3 +601,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);
+ }
+}
diff --git a/bin/dnssec/dnssectool.h b/bin/dnssec/dnssectool.h
index 5bc69cd14d..c9a1a5f757 100644
--- a/bin/dnssec/dnssectool.h
+++ b/bin/dnssec/dnssectool.h
@@ -20,10 +20,18 @@
#include
#include
+#include
#include
#include
+#include
+#include
+#include
+
+#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);
diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl
index 91f59440d2..ac15b7c934 100644
--- a/bin/named/bind9.xsl
+++ b/bin/named/bind9.xsl
@@ -303,6 +303,7 @@
Status,
Server,
Zones,
+ Incoming Zone Transfers,
Network,
Memory and
Traffic Size
@@ -907,6 +908,63 @@
+
+
+ Incoming Zone Transfers for View
+
+
+
+ | Zone Name |
+ Zone Type |
+ Local Serial |
+ Remote Serial |
+ IXFR |
+ First Refresh |
+ State |
+ Additional Refresh Queued |
+ Local Address |
+ Remote Address |
+ SOA Transport |
+ Transport |
+ TSIG Key Name |
+ Duration (s) |
+ Messages Received |
+ Records Received |
+ Bytes Received |
+
+
+
+
+
+
+ even
+ odd
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
Memory Usage Summary
diff --git a/bin/named/builtin.c b/bin/named/builtin.c
index 1f46f0ad4f..9c446e7c2f 100644
--- a/bin/named/builtin.c
+++ b/bin/named/builtin.c
@@ -529,13 +529,17 @@ authors_lookup(bdbnode_t *node) {
isc_result_t result;
const char **p = NULL;
static const char *authors[] = {
- "Mark Andrews", "Curtis Blackburn", "James Brister",
- "Ben Cottrell", "John H. DuBois III", "Francis Dupont",
- "Michael Graff", "Andreas Gustafsson", "Bob Halley",
- "Evan Hunt", "JINMEI Tatuya", "Witold Krecicki",
- "David Lawrence", "Scott Mann", "Danny Mayer",
- "Damien Neil", "Matt Nelson", "Jeremy C. Reed",
- "Michael Sawyer", "Brian Wellington", NULL
+ "Mark Andrews", "Curtis Blackburn",
+ "James Brister", "Ben Cottrell",
+ "John H. DuBois III", "Francis Dupont",
+ "Michael Graff", "Andreas Gustafsson",
+ "Bob Halley", "Evan Hunt",
+ "JINMEI Tatuya", "Witold Krecicki",
+ "David Lawrence", "Scott Mann",
+ "Danny Mayer", "Aydin Mercan",
+ "Damien Neil", "Matt Nelson",
+ "Jeremy C. Reed", "Michael Sawyer",
+ "Brian Wellington", NULL
};
/*
diff --git a/bin/named/config.c b/bin/named/config.c
index ed43f33f92..94d7610a55 100644
--- a/bin/named/config.c
+++ b/bin/named/config.c
@@ -67,7 +67,6 @@ options {\n\
interface-interval 60;\n\
listen-on {any;};\n\
listen-on-v6 {any;};\n\
-# lock-file \"" NAMED_LOCALSTATEDIR "/run/named/named.lock\";\n\
match-mapped-addresses no;\n\
max-ixfr-ratio 100%;\n\
max-rsa-exponent-size 0; /* no limit */\n\
@@ -133,6 +132,8 @@ options {\n\
/* view */\n\
allow-new-zones no;\n\
allow-notify {none;};\n\
+ allow-proxy {none;};\n\
+ allow-proxy-on {any;};\n\
allow-query-cache { localnets; localhost; };\n\
allow-query-cache-on { any; };\n\
allow-recursion { localnets; localhost; };\n\
@@ -188,8 +189,6 @@ options {\n\
request-expire true;\n\
request-ixfr true;\n\
require-server-cookie no;\n\
- resolver-nonbackoff-tries 3;\n\
- resolver-retry-interval 800; /* in milliseconds */\n\
root-key-sentinel yes;\n\
servfail-ttl 1;\n\
# sortlist \n\
@@ -201,13 +200,14 @@ options {\n\
synth-from-dnssec yes;\n\
# topology \n\
transfer-format many-answers;\n\
+ resolver-use-dns64 false;\n\
v6-bias 50;\n\
zero-no-soa-ttl-cache no;\n\
\n\
/* zone */\n\
allow-query {any;};\n\
allow-query-on {any;};\n\
- allow-transfer {any;};\n\
+ allow-transfer {none;};\n\
# also-notify \n\
check-integrity yes;\n\
check-mx-cname warn;\n\
@@ -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\
@@ -327,14 +328,14 @@ dnssec-policy \"insecure\" {\n\
"# END TRUST ANCHORS\n\
\n\
primaries " DEFAULT_IANA_ROOT_ZONE_PRIMARIES " {\n\
- 2001:500:200::b; # b.root-servers.net\n\
+ 2801:1b8:10::b; # b.root-servers.net\n\
2001:500:2::c; # c.root-servers.net\n\
2001:500:2f::f; # f.root-servers.net\n\
2001:500:12::d0d; # g.root-servers.net\n\
2001:7fd::1; # k.root-servers.net\n\
2620:0:2830:202::132; # xfr.cjr.dns.icann.org\n\
2620:0:2d0:202::132; # xfr.lax.dns.icann.org\n\
- 199.9.14.201; # b.root-servers.net\n\
+ 170.247.170.2; # b.root-servers.net\n\
192.33.4.12; # c.root-servers.net\n\
192.5.5.241; # f.root-servers.net\n\
192.112.36.4; # g.root-servers.net\n\
diff --git a/bin/named/control.c b/bin/named/control.c
index 7f07db1240..a3e009799e 100644
--- a/bin/named/control.c
+++ b/bin/named/control.c
@@ -177,6 +177,7 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly,
/* Do not flush master files */
named_server_flushonshutdown(named_g_server, false);
named_os_shutdownmsg(cmdline, *text);
+ isc_loopmgr_shutdown(named_g_loopmgr);
result = ISC_R_SHUTTINGDOWN;
} else if (command_compare(command, NAMED_COMMAND_STOP)) {
/*
@@ -194,6 +195,7 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly,
#endif /* ifdef HAVE_LIBSCF */
named_server_flushonshutdown(named_g_server, true);
named_os_shutdownmsg(cmdline, *text);
+ isc_loopmgr_shutdown(named_g_loopmgr);
result = ISC_R_SHUTTINGDOWN;
} else if (command_compare(command, NAMED_COMMAND_ADDZONE) ||
command_compare(command, NAMED_COMMAND_MODZONE))
diff --git a/bin/named/controlconf.c b/bin/named/controlconf.c
index 57783d19af..e276497f9e 100644
--- a/bin/named/controlconf.c
+++ b/bin/named/controlconf.c
@@ -49,7 +49,7 @@
#include
#include
-#undef NAMED_CONTROLCONF_TRACE
+/* Add -DNAMED_CONTROLCONF_TRACE=1 to CFLAGS for detailed reference tracing */
typedef struct controlkey controlkey_t;
typedef ISC_LIST(controlkey_t) controlkeylist_t;
@@ -91,10 +91,9 @@ struct controllistener {
isc_sockaddr_t address;
isc_nmsocket_t *sock;
dns_acl_t *acl;
- bool exiting;
+ bool shuttingdown;
isc_refcount_t references;
controlkeylist_t keys;
- isc_mutex_t connections_lock;
controlconnectionlist_t connections;
isc_socktype_t type;
uint32_t perm;
@@ -120,6 +119,8 @@ static void
conn_cleanup(controlconnection_t *conn);
static void
conn_free(controlconnection_t *conn);
+static void
+conn_shutdown(controlconnection_t *conn);
#if NAMED_CONTROLCONF_TRACE
#define controllistener_ref(ptr) \
@@ -148,6 +149,14 @@ ISC_REFCOUNT_DECL(controlconnection);
#define CLOCKSKEW 300
+#define CHECK(x) \
+ { \
+ result = (x); \
+ if (result != ISC_R_SUCCESS) { \
+ goto cleanup; \
+ } \
+ }
+
static void
free_controlkey(controlkey_t *key, isc_mem_t *mctx) {
if (key->keyname != NULL) {
@@ -170,11 +179,8 @@ free_controlkeylist(controlkeylist_t *keylist, isc_mem_t *mctx) {
static void
free_listener(controllistener_t *listener) {
- INSIST(listener->exiting);
- INSIST(ISC_LIST_EMPTY(listener->connections));
-
- isc_refcount_destroy(&listener->references);
-
+ REQUIRE(listener->shuttingdown);
+ REQUIRE(ISC_LIST_EMPTY(listener->connections));
REQUIRE(listener->sock == NULL);
free_controlkeylist(&listener->keys, listener->mctx);
@@ -182,7 +188,6 @@ free_listener(controllistener_t *listener) {
if (listener->acl != NULL) {
dns_acl_detach(&listener->acl);
}
- isc_mutex_destroy(&listener->connections_lock);
isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
}
@@ -197,33 +202,33 @@ ISC_REFCOUNT_IMPL(controlconnection, conn_free);
static void
shutdown_listener(controllistener_t *listener) {
- if (!listener->exiting) {
- char socktext[ISC_SOCKADDR_FORMATSIZE];
+ controlconnection_t *conn = NULL;
+ controlconnection_t *next = NULL;
- for (controlconnection_t *conn =
- ISC_LIST_HEAD(listener->connections);
- conn != NULL; conn = ISC_LIST_HEAD(listener->connections))
- {
- control_recvmessage(conn->ccmsg.handle,
- ISC_R_SHUTTINGDOWN, conn);
- }
-
- ISC_LIST_UNLINK(listener->controls->listeners, listener, link);
+ /* Don't shutdown the same listener twice */
+ if (listener->shuttingdown) {
+ return;
+ }
+ listener->shuttingdown = true;
- isc_sockaddr_format(&listener->address, socktext,
- sizeof(socktext));
- isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
- "stopping command channel on %s", socktext);
-#if 0
- /* XXX: no unix domain socket support */
- if (listener->type == isc_socktype_unix) {
- isc_socket_cleanunix(&listener->address, true);
- }
-#endif
- listener->exiting = true;
+ for (conn = ISC_LIST_HEAD(listener->connections); conn != NULL;
+ conn = next)
+ {
+ /*
+ * 'conn' is likely to be freed by the conn_shutdown() call.
+ */
+ next = ISC_LIST_NEXT(conn, link);
+ conn_shutdown(conn);
}
+ ISC_LIST_UNLINK(listener->controls->listeners, listener, link);
+
+ char socktext[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_format(&listener->address, socktext, sizeof(socktext));
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
+ "stopping command channel on %s", socktext);
+
isc_nm_stoplistening(listener->sock);
isc_nmsocket_close(&listener->sock);
controllistener_detach(&listener);
@@ -237,11 +242,6 @@ address_ok(isc_sockaddr_t *sockaddr, controllistener_t *listener) {
isc_result_t result;
int match;
- /* ACL doesn't apply to unix domain sockets */
- if (listener->type != isc_socktype_tcp) {
- return (true);
- }
-
isc_netaddr_fromsockaddr(&netaddr, sockaddr);
result = dns_acl_match(&netaddr, NULL, listener->acl, env, &match,
@@ -252,33 +252,36 @@ address_ok(isc_sockaddr_t *sockaddr, controllistener_t *listener) {
static void
control_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
controlconnection_t *conn = (controlconnection_t *)arg;
- controllistener_t *listener = conn->listener;
- isc_sockaddr_t peeraddr = isc_nmhandle_peeraddr(handle);
- if (conn->result == ISC_R_SHUTTINGDOWN) {
- isc_loopmgr_shutdown(named_g_loopmgr);
- goto cleanup_sendhandle;
+ if (conn->shuttingdown) {
+ /* The connection is shuttingdown */
+ result = ISC_R_SHUTTINGDOWN;
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ /* Everything is peachy, continue reading from the socket */
+ isccc_ccmsg_readmessage(&conn->ccmsg, control_recvmessage,
+ conn);
+ /* Detach the sending reference */
+ controlconnection_detach(&conn);
+ return;
}
- if (listener->controls->shuttingdown || result == ISC_R_SHUTTINGDOWN) {
- goto cleanup_sendhandle;
- } else if (result != ISC_R_SUCCESS) {
+ if (result != ISC_R_SHUTTINGDOWN) {
char socktext[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t peeraddr = isc_nmhandle_peeraddr(handle);
isc_sockaddr_format(&peeraddr, socktext, sizeof(socktext));
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_CONTROL, ISC_LOG_WARNING,
"error sending command response to %s: %s",
socktext, isc_result_totext(result));
- goto cleanup_sendhandle;
}
- isccc_ccmsg_readmessage(&conn->ccmsg, control_recvmessage, conn);
+ /* Shutdown the reading */
+ conn_shutdown(conn);
-cleanup_sendhandle:
- if (result != ISC_R_SUCCESS) {
- control_recvmessage(handle, result, conn);
- }
+ /* Detach the sending reference */
controlconnection_detach(&conn);
}
@@ -385,6 +388,7 @@ control_respond(controlconnection_t *conn) {
r.base = conn->buffer->base;
r.length = conn->buffer->used;
+ /* Attach the sending reference */
controlconnection_ref(conn);
isccc_ccmsg_sendmessage(&conn->ccmsg, &r, control_senddone, conn);
@@ -395,13 +399,33 @@ control_respond(controlconnection_t *conn) {
static void
control_command(void *arg) {
controlconnection_t *conn = (controlconnection_t *)arg;
- controllistener_t *listener = conn->listener;
- if (!listener->controls->shuttingdown) {
+ /* Don't run the command if we already started the shutdown */
+ if (!conn->shuttingdown) {
conn->result = named_control_docommand(
- conn->request, listener->readonly, &conn->text);
+ conn->request, conn->listener->readonly, &conn->text);
control_respond(conn);
}
+
+ /* Detach the control command reference */
+ controlconnection_detach(&conn);
+}
+
+static void
+conn_shutdown(controlconnection_t *conn) {
+ /* Don't shutdown the same controlconnection twice */
+ if (conn->shuttingdown) {
+ return;
+ }
+ conn->shuttingdown = true;
+
+ /*
+ * Close the TCP connection to make sure that no read callback will be
+ * called for it ever again.
+ */
+ isccc_ccmsg_disconnect(&conn->ccmsg);
+
+ /* Detach the reading reference */
controlconnection_detach(&conn);
}
@@ -415,21 +439,7 @@ control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
isccc_time_t exp;
uint32_t nonce;
- if (conn->shuttingdown) {
- return;
- }
-
- /* Is the server shutting down? */
- if (listener->controls->shuttingdown) {
- result = ISC_R_SHUTTINGDOWN;
- }
-
if (result != ISC_R_SUCCESS) {
- if (result == ISC_R_SHUTTINGDOWN) {
- listener->controls->shuttingdown = true;
- } else if (result != ISC_R_EOF) {
- log_invalid(&conn->ccmsg, result);
- }
goto cleanup;
}
@@ -455,13 +465,13 @@ control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
}
if (key == NULL) {
- log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
+ result = ISCCC_R_BADAUTH;
goto cleanup;
}
/* We shouldn't be getting a reply. */
if (isccc_cc_isreply(conn->request)) {
- log_invalid(&conn->ccmsg, ISC_R_FAILURE);
+ result = ISC_R_FAILURE;
goto cleanup;
}
@@ -472,7 +482,7 @@ control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
*/
conn->ctrl = isccc_alist_lookup(conn->request, "_ctrl");
if (!isccc_alist_alistp(conn->ctrl)) {
- log_invalid(&conn->ccmsg, ISC_R_FAILURE);
+ result = ISC_R_FAILURE;
goto cleanup;
}
@@ -480,11 +490,11 @@ control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
if ((sent + CLOCKSKEW) < conn->now ||
(sent - CLOCKSKEW) > conn->now)
{
- log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW);
+ result = ISCCC_R_CLOCKSKEW;
goto cleanup;
}
} else {
- log_invalid(&conn->ccmsg, ISC_R_FAILURE);
+ result = ISC_R_FAILURE;
goto cleanup;
}
@@ -494,7 +504,7 @@ control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
if (isccc_cc_lookupuint32(conn->ctrl, "_exp", &exp) == ISC_R_SUCCESS &&
conn->now > exp)
{
- log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED);
+ result = ISCCC_R_EXPIRED;
goto cleanup;
}
@@ -510,7 +520,6 @@ control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
if (result == ISC_R_EXISTS) {
result = ISCCC_R_DUPLICATE;
}
- log_invalid(&conn->ccmsg, result);
goto cleanup;
}
@@ -519,7 +528,7 @@ control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
ISC_R_SUCCESS ||
conn->nonce != nonce))
{
- log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH);
+ result = ISCCC_R_BADAUTH;
goto cleanup;
}
@@ -537,40 +546,48 @@ control_recvmessage(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
return;
}
- /*
- * Trigger the command.
- */
+ /* Attach the command reference */
controlconnection_ref(conn);
+
+ /* Trigger the command asynchronously. */
isc_async_run(named_g_mainloop, control_command, conn);
return;
cleanup:
- conn->shuttingdown = true;
- controlconnection_detach(&conn);
+ switch (result) {
+ case ISC_R_SHUTTINGDOWN:
+ case ISC_R_EOF:
+ break;
+ default:
+ log_invalid(&conn->ccmsg, result);
+ }
+
+ conn_shutdown(conn);
}
static void
conn_free(controlconnection_t *conn) {
+ /* Make sure that the connection was shutdown first */
+ REQUIRE(conn->shuttingdown);
+
controllistener_t *listener = conn->listener;
+ isccc_ccmsg_invalidate(&conn->ccmsg);
+
conn_cleanup(conn);
if (conn->buffer != NULL) {
isc_buffer_free(&conn->buffer);
}
- LOCK(&listener->connections_lock);
ISC_LIST_UNLINK(listener->connections, conn, link);
- UNLOCK(&listener->connections_lock);
#ifdef ENABLE_AFL
if (named_g_fuzz_type == isc_fuzz_rndc) {
named_fuzz_notify();
}
#endif /* ifdef ENABLE_AFL */
- isccc_ccmsg_invalidate(&conn->ccmsg);
-
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_CONTROL, ISC_LOG_DEBUG(3),
"freeing control connection");
@@ -582,15 +599,26 @@ conn_free(controlconnection_t *conn) {
static void
newconnection(controllistener_t *listener, isc_nmhandle_t *handle) {
+ /* Don't create new connection if we are shutting down */
+ if (listener->shuttingdown) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_CONTROL, ISC_LOG_DEBUG(3),
+ "rejected new control connection: %s",
+ isc_result_totext(ISC_R_SHUTTINGDOWN));
+ return;
+ }
+
controlconnection_t *conn = isc_mem_get(listener->mctx, sizeof(*conn));
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_CONTROL, ISC_LOG_DEBUG(3),
"allocate new control connection");
- *conn = (controlconnection_t){ .alg = DST_ALG_UNKNOWN };
-
- isc_refcount_init(&conn->references, 1);
- controllistener_attach(listener, &conn->listener);
+ *conn = (controlconnection_t){
+ .alg = DST_ALG_UNKNOWN,
+ .references = ISC_REFCOUNT_INITIALIZER(1),
+ .listener = controllistener_ref(listener),
+ .link = ISC_LINK_INITIALIZER,
+ };
/* isccc_ccmsg_init() attaches to the handle */
isccc_ccmsg_init(listener->mctx, handle, &conn->ccmsg);
@@ -598,10 +626,9 @@ newconnection(controllistener_t *listener, isc_nmhandle_t *handle) {
/* Set a 32 KiB upper limit on incoming message. */
isccc_ccmsg_setmaxsize(&conn->ccmsg, 32768);
- LOCK(&listener->connections_lock);
- ISC_LIST_INITANDAPPEND(listener->connections, conn, link);
- UNLOCK(&listener->connections_lock);
+ ISC_LIST_APPEND(listener->connections, conn, link);
+ /* The reading reference has been initialized in the initializer */
isccc_ccmsg_readmessage(&conn->ccmsg, control_recvmessage, conn);
}
@@ -641,8 +668,7 @@ controls_shutdown(named_controls_t *controls) {
listener = next)
{
/*
- * This is asynchronous. As listeners shut down, they will
- * call their callbacks.
+ * As listeners shut down, they will call their callbacks.
*/
next = ISC_LIST_NEXT(listener, link);
shutdown_listener(listener);
@@ -651,8 +677,20 @@ controls_shutdown(named_controls_t *controls) {
void
named_controls_shutdown(named_controls_t *controls) {
- controls_shutdown(controls);
+ /*
+ * Don't ever shutdown the controls twice.
+ *
+ * NOTE: This functions is called when the server is shutting down, but
+ * controls_shutdown() can and will be called multiple times - on each
+ * reconfiguration, the listeners will be torn down and recreated again,
+ * see named_controls_configure() for details.
+ */
+ if (controls->shuttingdown) {
+ return;
+ }
controls->shuttingdown = true;
+
+ controls_shutdown(controls);
}
static isc_result_t
@@ -781,14 +819,6 @@ register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist,
}
}
-#define CHECK(x) \
- do { \
- result = (x); \
- if (result != ISC_R_SUCCESS) { \
- goto cleanup; \
- } \
- } while (0)
-
static isc_result_t
get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) {
isc_result_t result;
@@ -1031,33 +1061,6 @@ update_listener(named_controls_t *cp, controllistener_t **listenerp,
socktext, isc_result_totext(result));
}
-#if 0
- /* XXX: no unix socket support yet */
- if (result == ISC_R_SUCCESS && type == isc_socktype_unix) {
- uint32_t perm, owner, group;
- perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
- owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner"));
- group = cfg_obj_asuint32(cfg_tuple_get(control, "group"));
- result = ISC_R_SUCCESS;
- if (listener->perm != perm || listener->owner != owner ||
- listener->group != group)
- {
- result = isc_socket_permunix(&listener->address, perm,
- owner, group);
- }
- if (result == ISC_R_SUCCESS) {
- listener->perm = perm;
- listener->owner = owner;
- listener->group = group;
- } else if (control != NULL) {
- cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING,
- "couldn't update ownership/permission for "
- "command channel %s",
- socktext);
- }
- }
-#endif
-
*listenerp = listener;
}
@@ -1075,12 +1078,17 @@ add_listener(named_controls_t *cp, controllistener_t **listenerp,
isc_result_t result = ISC_R_SUCCESS;
int pf;
+ /* Don't create new listener if we are shutting down */
+ if (cp->shuttingdown) {
+ result = ISC_R_SHUTTINGDOWN;
+ goto shuttingdown;
+ }
+
listener = isc_mem_get(mctx, sizeof(*listener));
*listener = (controllistener_t){ .controls = cp,
.address = *addr,
.type = type };
isc_mem_attach(mctx, &listener->mctx);
- isc_mutex_init(&listener->connections_lock);
ISC_LINK_INIT(listener, link);
ISC_LIST_INIT(listener->keys);
ISC_LIST_INIT(listener->connections);
@@ -1129,35 +1137,14 @@ add_listener(named_controls_t *cp, controllistener_t **listenerp,
pf = isc_sockaddr_pf(&listener->address);
if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
- (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) ||
(pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
{
CHECK(ISC_R_FAMILYNOSUPPORT);
}
-#if 0
- /* XXX: no unix socket support yet */
- if (type == isc_socktype_unix) {
- isc_socket_cleanunix(&listener->address, false);
- }
-#endif
-
CHECK(isc_nm_listentcp(named_g_netmgr, ISC_NM_LISTEN_ONE,
&listener->address, control_newconn, listener, 5,
NULL, &listener->sock));
-#if 0
- /* XXX: no unix socket support yet */
- if (type == isc_socktype_unix) {
- listener->perm =
- cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
- listener->owner =
- cfg_obj_asuint32(cfg_tuple_get(control, "owner"));
- listener->group =
- cfg_obj_asuint32(cfg_tuple_get(control, "group"));
- result = isc_socket_permunix(&listener->address, listener->perm,
- listener->owner, listener->group);
- }
-#endif
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_CONTROL, ISC_LOG_NOTICE,
@@ -1167,9 +1154,10 @@ add_listener(named_controls_t *cp, controllistener_t **listenerp,
cleanup:
isc_refcount_decrement(&listener->references);
- listener->exiting = true;
+ listener->shuttingdown = true;
free_listener(listener);
+shuttingdown:
if (control != NULL) {
cfg_obj_log(control, named_g_lctx, ISC_LOG_WARNING,
"couldn't add command channel %s: %s", socktext,
@@ -1214,8 +1202,19 @@ named_controls_configure(named_controls_t *cp, const cfg_obj_t *config,
{
const cfg_obj_t *controls = NULL;
const cfg_obj_t *inetcontrols = NULL;
+ const cfg_obj_t *unixcontrols = NULL;
controls = cfg_listelt_value(element);
+
+ (void)cfg_map_get(controls, "unix", &unixcontrols);
+ if (unixcontrols != NULL) {
+ cfg_obj_log(controls, named_g_lctx,
+ ISC_LOG_ERROR,
+ "UNIX domain sockets are not "
+ "supported");
+ return (ISC_R_FAILURE);
+ }
+
(void)cfg_map_get(controls, "inet", &inetcontrols);
if (inetcontrols == NULL) {
continue;
@@ -1231,8 +1230,8 @@ named_controls_configure(named_controls_t *cp, const cfg_obj_t *config,
/*
* The parser handles BIND 8 configuration file
- * syntax, so it allows unix phrases as well
- * inet phrases with no keys{} clause.
+ * syntax, so it allows inet phrases with no
+ * keys{} clause.
*/
control = cfg_listelt_value(element2);
@@ -1280,91 +1279,6 @@ named_controls_configure(named_controls_t *cp, const cfg_obj_t *config,
}
}
}
- for (element = cfg_list_first(controlslist); element != NULL;
- element = cfg_list_next(element))
- {
- const cfg_obj_t *controls = NULL;
- const cfg_obj_t *unixcontrols = NULL;
-
- controls = cfg_listelt_value(element);
- (void)cfg_map_get(controls, "unix", &unixcontrols);
- if (unixcontrols == NULL) {
- continue;
- }
-
- cfg_obj_log(controls, named_g_lctx, ISC_LOG_ERROR,
- "UNIX domain sockets not yet supported");
- return (ISC_R_FAILURE);
-
-#if 0
- /* XXX: no unix domain socket support in netmgr */
- for (element2 = cfg_list_first(unixcontrols);
- element2 != NULL;
- element2 = cfg_list_next(element2))
- {
- const cfg_obj_t *control = NULL;
- const cfg_obj_t *path = NULL;
- isc_sockaddr_t addr;
- isc_result_t result;
-
- /*
- * The parser handles BIND 8 configuration file
- * syntax, so it allows unix phrases as well
- * inet phrases with no keys{} clause.
- */
- control = cfg_listelt_value(element2);
-
- path = cfg_tuple_get(control, "path");
- result = isc_sockaddr_frompath(
- &addr, cfg_obj_asstring(path));
- if (result != ISC_R_SUCCESS) {
- isc_log_write(
- named_g_lctx,
- NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_CONTROL,
- ISC_LOG_DEBUG(9),
- "control channel '%s': %s",
- cfg_obj_asstring(path),
- isc_result_totext(result));
- continue;
- }
-
- isc_log_write(named_g_lctx,
- NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_CONTROL,
- ISC_LOG_DEBUG(9),
- "processing control channel '%s'",
- cfg_obj_asstring(path));
-
- update_listener(cp, &listener, control, config,
- &addr, aclconfctx,
- cfg_obj_asstring(path),
- isc_socktype_unix);
-
- if (listener != NULL) {
- /*
- * Remove the listener from the old
- * list, so it won't be shut down.
- */
- ISC_LIST_UNLINK(cp->listeners, listener,
- link);
- } else {
- /*
- * This is a new listener.
- */
- add_listener(cp, &listener, control,
- config, &addr, aclconfctx,
- cfg_obj_asstring(path),
- isc_socktype_unix);
- }
-
- if (listener != NULL) {
- ISC_LIST_APPEND(new_listeners, listener,
- link);
- }
- }
-#endif
- }
} else {
int i;
@@ -1461,6 +1375,7 @@ named_controls_destroy(named_controls_t **ctrlsp) {
named_controls_t *controls = *ctrlsp;
*ctrlsp = NULL;
+ REQUIRE(controls->shuttingdown);
REQUIRE(ISC_LIST_EMPTY(controls->listeners));
LOCK(&controls->symtab_lock);
diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h
index 03e35f2cd4..0fc26f212d 100644
--- a/bin/named/include/named/globals.h
+++ b/bin/named/include/named/globals.h
@@ -50,7 +50,6 @@
EXTERN isc_mem_t *named_g_mctx INIT(NULL);
EXTERN unsigned int named_g_cpus INIT(0);
-EXTERN unsigned int named_g_udpdisp INIT(0);
EXTERN isc_loop_t *named_g_mainloop INIT(NULL);
EXTERN isc_loopmgr_t *named_g_loopmgr INIT(NULL);
EXTERN bool named_g_loopmgr_running INIT(false);
@@ -119,11 +118,6 @@ EXTERN const char *named_g_logfile INIT(NULL);
EXTERN const char *named_g_defaultsessionkeyfile INIT(NAMED_LOCALSTATEDIR
"/run/named/"
"session.key");
-EXTERN const char *named_g_defaultlockfile INIT(NAMED_LOCALSTATEDIR "/run/"
- "named/"
- "named."
- "lock");
-EXTERN bool named_g_forcelock INIT(false);
#if NAMED_RUN_PID_DIR
EXTERN const char *named_g_defaultpidfile INIT(NAMED_LOCALSTATEDIR "/run/named/"
diff --git a/bin/named/include/named/os.h b/bin/named/include/named/os.h
index 0f7c1c5385..6066fc391d 100644
--- a/bin/named/include/named/os.h
+++ b/bin/named/include/named/os.h
@@ -56,9 +56,6 @@ named_os_openfile(const char *filename, mode_t mode, bool switch_user);
void
named_os_writepidfile(const char *filename, bool first_time);
-bool
-named_os_issingleton(const char *filename);
-
void
named_os_shutdown(void);
diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h
index 509101f277..52a13d5658 100644
--- a/bin/named/include/named/server.h
+++ b/bin/named/include/named/server.h
@@ -65,6 +65,7 @@ struct named_server {
dns_zonemgr_t *zonemgr;
dns_viewlist_t viewlist;
dns_kasplist_t kasplist;
+ dns_keystorelist_t keystorelist;
ns_interfacemgr_t *interfacemgr;
dns_db_t *in_roothints;
@@ -103,8 +104,6 @@ struct named_server {
dns_dtenv_t *dtenv; /*%< Dnstap environment */
- char *lockfile;
-
isc_tlsctx_cache_t *tlsctx_server_cache;
isc_tlsctx_cache_t *tlsctx_client_cache;
diff --git a/bin/named/include/named/zoneconf.h b/bin/named/include/named/zoneconf.h
index dbecd4a79e..1eb059b25a 100644
--- a/bin/named/include/named/zoneconf.h
+++ b/bin/named/include/named/zoneconf.h
@@ -28,8 +28,8 @@ ISC_LANG_BEGINDECLS
isc_result_t
named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
- dns_kasplist_t *kasplist, dns_zone_t *zone,
- dns_zone_t *raw);
+ dns_kasplist_t *kasplist, dns_keystorelist_t *keystores,
+ dns_zone_t *zone, dns_zone_t *raw);
/*%<
* Configure or reconfigure a zone according to the named.conf
* data.
diff --git a/bin/named/main.c b/bin/named/main.c
index 7877da2414..7e028e7e83 100644
--- a/bin/named/main.c
+++ b/bin/named/main.c
@@ -196,7 +196,7 @@ named_main_earlyfatal(const char *format, ...) {
}
va_end(args);
- exit(1);
+ _exit(EXIT_FAILURE);
}
noreturn static void
@@ -235,7 +235,7 @@ assertion_failed(const char *file, int line, isc_assertiontype_t type,
if (named_g_coreok) {
abort();
}
- exit(1);
+ _exit(EXIT_FAILURE);
}
noreturn static void
@@ -275,7 +275,7 @@ library_fatal_error(const char *file, int line, const char *func,
if (named_g_coreok) {
abort();
}
- exit(1);
+ _exit(EXIT_FAILURE);
}
static void
@@ -314,7 +314,7 @@ usage(void) {
"[-p port] [-s]\n"
" [-S sockets] [-t chrootdir] [-u "
"username] [-U listeners]\n"
- " [-X lockfile] [-m "
+ " [-m "
"{usage|trace|record|size|mctx}]\n"
" [-M fill|nofill]\n"
"usage: named [-v|-V|-C]\n");
@@ -668,7 +668,6 @@ printversion(bool verbose) {
printf(" rndc configuration: %s\n", rndcconf);
printf(" nsupdate session key: %s\n", named_g_defaultsessionkeyfile);
printf(" named PID file: %s\n", named_g_defaultpidfile);
- printf(" named lock file: %s\n", named_g_defaultlockfile);
#if defined(HAVE_GEOIP2)
#define RTC(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
RTC(cfg_parser_create(mctx, named_g_lctx, &parser));
@@ -890,7 +889,7 @@ parse_command_line(int argc, char *argv[]) {
printf("# Built-in default values. "
"This is NOT the run-time configuration!\n");
printf("%s", named_config_getdefault());
- exit(0);
+ exit(EXIT_SUCCESS);
case 'd':
named_g_debuglevel = parse_int(isc_commandline_argument,
"debug "
@@ -946,30 +945,24 @@ parse_command_line(int argc, char *argv[]) {
parse_T_opt(isc_commandline_argument);
break;
case 'U':
- named_g_udpdisp = parse_int(isc_commandline_argument,
- "number of UDP listeners "
- "per interface");
+ /* Obsolete. No longer in use. Ignore. */
+ named_main_earlywarning("option '-U' has been removed");
break;
case 'u':
named_g_username = isc_commandline_argument;
break;
case 'v':
printversion(false);
- exit(0);
+ exit(EXIT_SUCCESS);
case 'V':
printversion(true);
- exit(0);
+ exit(EXIT_SUCCESS);
case 'x':
/* Obsolete. No longer in use. Ignore. */
break;
case 'X':
- named_g_forcelock = true;
- if (strcasecmp(isc_commandline_argument, "none") != 0) {
- named_g_defaultlockfile =
- isc_commandline_argument;
- } else {
- named_g_defaultlockfile = NULL;
- }
+ /* Obsolete. No longer in use. Abort. */
+ named_main_earlyfatal("option '-X' has been removed");
break;
case 'F':
#if OPENSSL_VERSION_NUMBER >= 0x30200000L && OPENSSL_API_LEVEL >= 30200
@@ -998,7 +991,7 @@ parse_command_line(int argc, char *argv[]) {
case '?':
usage();
if (isc_commandline_option == '?') {
- exit(0);
+ exit(EXIT_SUCCESS);
}
p = strchr(NAMED_MAIN_ARGS, isc_commandline_option);
if (p == NULL || *++p != ':') {
@@ -1041,16 +1034,6 @@ create_managers(void) {
ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
named_g_cpus_detected, named_g_cpus_detected == 1 ? "" : "s",
named_g_cpus, named_g_cpus == 1 ? "" : "s");
- if (named_g_udpdisp == 0) {
- named_g_udpdisp = named_g_cpus_detected;
- }
- if (named_g_udpdisp > named_g_cpus) {
- named_g_udpdisp = named_g_cpus;
- }
- isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
- "using %u UDP listener%s per interface", named_g_udpdisp,
- named_g_udpdisp == 1 ? "" : "s");
isc_managers_create(&named_g_mctx, named_g_cpus, &named_g_loopmgr,
&named_g_netmgr);
diff --git a/bin/named/named.rst b/bin/named/named.rst
index 698ffcdfd1..ee893faba7 100644
--- a/bin/named/named.rst
+++ b/bin/named/named.rst
@@ -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**] [**-X** lock-file]
+: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
@@ -198,10 +191,7 @@ Options
.. option:: -X lock-file
- This option acquires a lock on the specified file at runtime; this helps to
- prevent duplicate :program:`named` instances from running simultaneously.
- Use of this option overrides the ``lock-file`` option in
- :iscman:`named.conf`. If set to ``none``, the lock file check is disabled.
+ This option has been removed and using it will cause a fatal error.
Signals
~~~~~~~
diff --git a/bin/named/os.c b/bin/named/os.c
index 858ccbff3f..9efc114479 100644
--- a/bin/named/os.c
+++ b/bin/named/os.c
@@ -51,9 +51,7 @@
#endif /* ifdef HAVE_LIBSCF */
static char *pidfile = NULL;
-static char *lockfile = NULL;
static int devnullfd = -1;
-static int singletonfd = -1;
#ifndef ISC_FACILITY
#define ISC_FACILITY LOG_DAEMON
@@ -430,10 +428,10 @@ named_os_daemonize(void) {
char buf;
n = read(dfd[0], &buf, 1);
if (n == 1) {
- _exit(0);
+ _exit(EXIT_SUCCESS);
}
} while (n == -1 && errno == EINTR);
- _exit(1);
+ _exit(EXIT_FAILURE);
}
(void)close(dfd[0]);
@@ -705,24 +703,6 @@ cleanup_pidfile(void) {
pidfile = NULL;
}
-static void
-cleanup_lockfile(void) {
- if (singletonfd != -1) {
- close(singletonfd);
- singletonfd = -1;
- }
-
- if (lockfile != NULL) {
- int n = unlink(lockfile);
- if (n == -1 && errno != ENOENT) {
- named_main_earlywarning("unlink '%s': failed",
- lockfile);
- }
- free(lockfile);
- lockfile = NULL;
- }
-}
-
/*
* Ensure that a directory exists.
* NOTE: This function overwrites the '/' characters in 'filename' with
@@ -906,69 +886,10 @@ named_os_writepidfile(const char *filename, bool first_time) {
(void)fclose(fh);
}
-bool
-named_os_issingleton(const char *filename) {
- char strbuf[ISC_STRERRORSIZE];
- struct flock lock;
-
- if (singletonfd != -1) {
- return (true);
- }
-
- if (strcasecmp(filename, "none") == 0) {
- return (true);
- }
-
- /*
- * Make the containing directory if it doesn't exist.
- */
- lockfile = strdup(filename);
- if (lockfile == NULL) {
- strerror_r(errno, strbuf, sizeof(strbuf));
- named_main_earlyfatal("couldn't allocate memory for '%s': %s",
- filename, strbuf);
- } else {
- int ret = mkdirpath(lockfile, named_main_earlywarning);
- if (ret == -1) {
- named_main_earlywarning("couldn't create '%s'",
- filename);
- cleanup_lockfile();
- return (false);
- }
- }
-
- /*
- * named_os_openfile() uses safeopen() which removes any existing
- * files. We can't use that here.
- */
- singletonfd = open(filename, O_WRONLY | O_CREAT,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if (singletonfd == -1) {
- cleanup_lockfile();
- return (false);
- }
-
- memset(&lock, 0, sizeof(lock));
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 1;
-
- /* Non-blocking (does not wait for lock) */
- if (fcntl(singletonfd, F_SETLK, &lock) == -1) {
- close(singletonfd);
- singletonfd = -1;
- return (false);
- }
-
- return (true);
-}
-
void
named_os_shutdown(void) {
closelog();
cleanup_pidfile();
- cleanup_lockfile();
}
void
diff --git a/bin/named/server.c b/bin/named/server.c
index 38cdfc8353..c7e2138ba8 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -32,7 +32,6 @@
#include
#endif
-#include
#include
#include
#include
@@ -59,6 +58,7 @@
#include
#include
#include
+#include
#include
#include
@@ -79,6 +79,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -399,6 +400,9 @@ const char *empty_zones[] = {
/* RFC 8375 */
"HOME.ARPA",
+ /* RFC 9462 */
+ "RESOLVER.ARPA",
+
NULL
};
@@ -413,7 +417,8 @@ static isc_result_t
listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
const ns_listen_tls_params_t *tls_params,
isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
- isc_mem_t *mctx, ns_listenelt_t **target);
+ isc_mem_t *mctx, isc_nm_proxy_type_t proxy,
+ ns_listenelt_t **target);
#endif
static isc_result_t
@@ -440,8 +445,8 @@ static isc_result_t
configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
const cfg_obj_t *vconfig, dns_view_t *view,
dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
- cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
- bool modify);
+ dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
+ bool added, bool old_rpz_ok, bool modify);
static void
configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
@@ -1314,8 +1319,8 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
isc_sockaddr_format(&sa, buf, sizeof(buf));
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
- "could not get query source dispatcher (%s)",
- buf);
+ "could not get query source dispatcher (%s): %s",
+ buf, isc_result_totext(result));
return (result);
}
@@ -2484,7 +2489,7 @@ configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
}
#endif /* ifndef USE_DNSRPS */
- result = dns_rpz_new_zones(view->mctx, named_g_loopmgr, rps_cstr,
+ result = dns_rpz_new_zones(view, named_g_loopmgr, rps_cstr,
rps_cstr_size, &view->rpzs);
if (result != ISC_R_SUCCESS) {
return (result);
@@ -2621,10 +2626,10 @@ configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
}
if (*old_rpz_okp) {
- dns_rpz_shutdown_rpzs(view->rpzs);
- dns_rpz_detach_rpzs(&view->rpzs);
- dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
- dns_rpz_detach_rpzs(&pview->rpzs);
+ dns_rpz_zones_shutdown(view->rpzs);
+ dns_rpz_zones_detach(&view->rpzs);
+ dns_rpz_zones_attach(pview->rpzs, &view->rpzs);
+ dns_rpz_zones_detach(&pview->rpzs);
} else if (old != NULL && pview != NULL) {
++pview->rpzs->rpz_ver;
view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
@@ -2655,6 +2660,10 @@ catz_addmodzone_cb(void *arg) {
ns_cfgctx_t *cfg = NULL;
dns_zone_t *zone = NULL;
+ if (isc_loop_shuttingdown(isc_loop_get(named_g_loopmgr, isc_tid()))) {
+ goto cleanup;
+ }
+
cfg = (ns_cfgctx_t *)cz->view->new_zone_config;
if (cfg == NULL) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
@@ -2790,12 +2799,12 @@ catz_addmodzone_cb(void *arg) {
zoneobj = cfg_listelt_value(cfg_list_first(zlist));
/* Mark view unfrozen so that zone can be added */
-
isc_loopmgr_pause(named_g_loopmgr);
dns_view_thaw(cz->view);
result = configure_zone(cfg->config, zoneobj, cfg->vconfig, cz->view,
&cz->cbd->server->viewlist,
- &cz->cbd->server->kasplist, cfg->actx, true,
+ &cz->cbd->server->kasplist,
+ &cz->cbd->server->keystorelist, cfg->actx, true,
false, cz->mod);
dns_view_freeze(cz->view);
isc_loopmgr_resume(named_g_loopmgr);
@@ -2851,7 +2860,7 @@ catz_addmodzone_cb(void *arg) {
}
dns_catz_entry_detach(cz->origin, &cz->entry);
dns_catz_zone_detach(&cz->origin);
- dns_view_detach(&cz->view);
+ dns_view_weakdetach(&cz->view);
isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
}
@@ -2864,6 +2873,10 @@ catz_delzone_cb(void *arg) {
char cname[DNS_NAME_FORMATSIZE];
const char *file = NULL;
+ if (isc_loop_shuttingdown(isc_loop_get(named_g_loopmgr, isc_tid()))) {
+ goto cleanup;
+ }
+
isc_loopmgr_pause(named_g_loopmgr);
dns_name_format(dns_catz_entry_getname(cz->entry), cname,
@@ -2876,7 +2889,7 @@ catz_delzone_cb(void *arg) {
"catz: catz_delzone_cb: "
"zone '%s' not found",
cname);
- goto cleanup;
+ goto resume;
}
if (!dns_zone_getadded(zone)) {
@@ -2885,7 +2898,7 @@ catz_delzone_cb(void *arg) {
"catz: catz_delzone_cb: "
"zone '%s' is not a dynamically added zone",
cname);
- goto cleanup;
+ goto resume;
}
if (dns_zone_get_parentcatz(zone) != cz->origin) {
@@ -2894,7 +2907,7 @@ catz_delzone_cb(void *arg) {
"catz: catz_delzone_cb: zone "
"'%s' exists in multiple catalog zones",
cname);
- goto cleanup;
+ goto resume;
}
/* Stop answering for this zone */
@@ -2903,7 +2916,9 @@ catz_delzone_cb(void *arg) {
dns_zone_unload(zone);
}
- CHECK(dns_view_delzone(cz->view, zone));
+ if (dns_view_delzone(cz->view, zone) != ISC_R_SUCCESS) {
+ goto resume;
+ }
file = dns_zone_getfile(zone);
if (file != NULL) {
isc_file_remove(file);
@@ -2918,14 +2933,15 @@ catz_delzone_cb(void *arg) {
"catz: catz_delzone_cb: "
"zone '%s' deleted",
cname);
-cleanup:
+resume:
isc_loopmgr_resume(named_g_loopmgr);
+cleanup:
if (zone != NULL) {
dns_zone_detach(&zone);
}
dns_catz_entry_detach(cz->origin, &cz->entry);
dns_catz_zone_detach(&cz->origin);
- dns_view_detach(&cz->view);
+ dns_view_weakdetach(&cz->view);
isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
}
@@ -2957,7 +2973,7 @@ catz_run(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
dns_catz_entry_attach(entry, &cz->entry);
dns_catz_zone_attach(origin, &cz->origin);
- dns_view_attach(view, &cz->view);
+ dns_view_weakattach(view, &cz->view);
isc_async_run(named_g_mainloop, action, cz);
@@ -3379,7 +3395,7 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
const cfg_obj_t *obj;
const cfg_obj_t *zconfig;
const cfg_obj_t *zoptions;
- const char *rbt_dbtype[4] = { "rbt" };
+ const char *default_dbtype[4] = { ZONEDB_DEFAULT };
const char *sep = ": view ";
const char *str;
const char *viewname = view->name;
@@ -3392,7 +3408,7 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
dns_name_t *ns;
dns_name_t *zname;
dns_zone_t *zone = NULL;
- int rbt_dbtypec = 1;
+ int default_dbtypec = 1;
isc_result_t result;
dns_namereln_t namereln;
int order;
@@ -3434,7 +3450,7 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
}
}
if (db == NULL) {
- CHECK(dns_db_create(view->mctx, "rbt", name,
+ CHECK(dns_db_create(view->mctx, ZONEDB_DEFAULT, name,
dns_dbtype_zone, view->rdclass, 0,
NULL, &db));
CHECK(dns_db_newversion(db, &version));
@@ -3454,15 +3470,15 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
}
/*
- * Is the existing zone the ok to use?
+ * Is the existing zone ok to use?
*/
if (pzone != NULL) {
unsigned int typec;
- const char **dbargv;
+ const char **dbargv = NULL;
if (db != NULL) {
- typec = rbt_dbtypec;
- dbargv = rbt_dbtype;
+ typec = default_dbtypec;
+ dbargv = default_dbtype;
} else {
typec = empty_dbtypec;
dbargv = empty_dbtype;
@@ -3882,10 +3898,7 @@ create_mapped_acl(void) {
isc_netaddr_fromin6(&addr, &in6);
- result = dns_acl_create(named_g_mctx, 1, &acl);
- if (result != ISC_R_SUCCESS) {
- return (result);
- }
+ dns_acl_create(named_g_mctx, 1, &acl);
result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
if (result == ISC_R_SUCCESS) {
@@ -3981,8 +3994,9 @@ static const char *const response_synonyms[] = { "response", NULL };
static isc_result_t
configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
cfg_obj_t *vconfig, named_cachelist_t *cachelist,
- dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys,
- isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) {
+ dns_kasplist_t *kasplist, dns_keystorelist_t *keystores,
+ const cfg_obj_t *bindkeys, isc_mem_t *mctx,
+ cfg_aclconfctx_t *actx, bool need_hints) {
const cfg_obj_t *maps[4];
const cfg_obj_t *cfgmaps[3];
const cfg_obj_t *optionmaps[3];
@@ -4037,10 +4051,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
named_cache_t *nsc;
bool zero_no_soattl;
dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
- unsigned int query_timeout, ndisp;
+ unsigned int query_timeout;
bool old_rpz_ok = false;
dns_dyndbctx_t *dctx = NULL;
- unsigned int resolver_param;
dns_ntatable_t *ntatable = NULL;
const char *qminmode = NULL;
dns_adb_t *adb = NULL;
@@ -4128,7 +4141,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
{
const cfg_obj_t *zconfig = cfg_listelt_value(element);
CHECK(configure_zone(config, zconfig, vconfig, view, viewlist,
- kasplist, actx, false, old_rpz_ok, false));
+ kasplist, keystores, actx, false,
+ old_rpz_ok, false));
zone_element_latest = element;
}
@@ -4322,6 +4336,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
INSIST(result == ISC_R_SUCCESS);
zero_no_soattl = cfg_obj_asboolean(obj);
+ obj = NULL;
+ result = named_config_get(maps, "resolver-use-dns64", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ view->usedns64 = cfg_obj_asboolean(obj);
+
obj = NULL;
result = named_config_get(maps, "dns64", &obj);
if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
@@ -4541,6 +4560,19 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
view->staleanswerclienttimeout = (uint32_t)-1;
} else {
view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
+
+ /*
+ * BIND 9 no longer supports non-zero values of
+ * stale-answer-client-timeout.
+ */
+ if (view->staleanswerclienttimeout != 0) {
+ view->staleanswerclienttimeout = 0;
+ isc_log_write(
+ named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
+ "BIND 9 no longer supports non-zero values of "
+ "stale-answer-client-timeout, adjusted to 0");
+ }
}
obj = NULL;
@@ -4643,7 +4675,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
* is simply a named cache that is not shared.
*/
CHECK(dns_cache_create(named_g_loopmgr, view->rdclass,
- cachename, &cache));
+ cachename, mctx, &cache));
}
nsc = isc_mem_get(mctx, sizeof(*nsc));
nsc->cache = NULL;
@@ -4684,10 +4716,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
goto cleanup;
}
- ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
- CHECK(dns_view_createresolver(
- view, named_g_loopmgr, ndisp, 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);
@@ -4806,27 +4837,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
query_timeout = cfg_obj_asuint32(obj);
dns_resolver_settimeout(view->resolver, query_timeout);
- /*
- * Adjust stale-answer-client-timeout upper bound
- * to be resolver-query-timeout - 1s.
- * This assignment is safe as dns_resolver_settimeout()
- * ensures that resolver->querytimeout value will be in the
- * [MINIMUM_QUERY_TIMEOUT, MAXIMUM_QUERY_TIMEOUT] range and
- * MINIMUM_QUERY_TIMEOUT is > 1000 (in ms).
- */
- if (view->staleanswerclienttimeout != (uint32_t)-1 &&
- view->staleanswerclienttimeout >
- (dns_resolver_gettimeout(view->resolver) - 1000))
- {
- view->staleanswerclienttimeout =
- dns_resolver_gettimeout(view->resolver) - 1000;
- isc_log_write(
- named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
- "stale-answer-client-timeout adjusted to %" PRIu32,
- view->staleanswerclienttimeout);
- }
-
/* Specify whether to use 0-TTL for negative response for SOA query */
dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
@@ -4892,23 +4902,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
}
view->maxbits = maxbits;
- /*
- * Set resolver retry parameters.
- */
- obj = NULL;
- CHECK(named_config_get(maps, "resolver-retry-interval", &obj));
- resolver_param = cfg_obj_asuint32(obj);
- if (resolver_param > 0) {
- dns_resolver_setretryinterval(view->resolver, resolver_param);
- }
-
- obj = NULL;
- CHECK(named_config_get(maps, "resolver-nonbackoff-tries", &obj));
- resolver_param = cfg_obj_asuint32(obj);
- if (resolver_param > 0) {
- dns_resolver_setnonbackofftries(view->resolver, resolver_param);
- }
-
/*
* Set supported DNSSEC algorithms.
*/
@@ -5209,6 +5202,13 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
NULL, actx, named_g_mctx, &view->cacheonacl));
+ CHECK(configure_view_acl(vconfig, config, named_g_config, "allow-proxy",
+ NULL, actx, named_g_mctx, &view->proxyacl));
+
+ CHECK(configure_view_acl(vconfig, config, named_g_config,
+ "allow-proxy-on", NULL, actx, named_g_mctx,
+ &view->proxyonacl));
+
if (strcmp(view->name, "_bind") != 0 &&
view->rdclass != dns_rdataclass_chaos)
{
@@ -5470,6 +5470,21 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
INSIST(result == ISC_R_SUCCESS);
dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
+ obj = NULL;
+ result = named_config_get(maps, "max-validations-per-fetch", &obj);
+ if (result == ISC_R_SUCCESS) {
+ dns_resolver_setmaxvalidations(view->resolver,
+ cfg_obj_asuint32(obj));
+ }
+
+ obj = NULL;
+ result = named_config_get(maps, "max-validation-failures-per-fetch",
+ &obj);
+ if (result == ISC_R_SUCCESS) {
+ dns_resolver_setmaxvalidationfails(view->resolver,
+ cfg_obj_asuint32(obj));
+ }
+
obj = NULL;
result = named_config_get(maps, "fetches-per-zone", &obj);
INSIST(result == ISC_R_SUCCESS);
@@ -6444,8 +6459,8 @@ static isc_result_t
configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
const cfg_obj_t *vconfig, dns_view_t *view,
dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
- cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
- bool modify) {
+ dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
+ bool added, bool old_rpz_ok, bool modify) {
dns_view_t *pview = NULL; /* Production view */
dns_zone_t *zone = NULL; /* New or reused zone */
dns_zone_t *raw = NULL; /* New or reused raw zone */
@@ -6639,7 +6654,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
dns_zone_setstats(zone, named_g_server->zonestats);
}
CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
- kasplist, zone, NULL));
+ kasplist, keystores, zone, NULL));
dns_zone_attach(zone, &view->redirect);
goto cleanup;
}
@@ -6815,7 +6830,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
* Configure the zone.
*/
CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
- zone, raw));
+ keystores, zone, raw));
/*
* Add the zone to its view in the new view list.
@@ -7056,7 +7071,7 @@ tat_done(void *arg) {
dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
ns_tat_t *tat = NULL;
- INSIST(resp != NULL && resp->type == FETCHDONE);
+ INSIST(resp != NULL);
tat = resp->arg;
@@ -7449,7 +7464,7 @@ generate_session_key(const char *filename, const char *keynamestr,
/* generate key */
result = dst_key_generate(keyname, alg, bits, 1, 0, DNS_KEYPROTO_ANY,
- dns_rdataclass_in, mctx, &key, NULL);
+ dns_rdataclass_in, NULL, mctx, &key, NULL);
if (result != ISC_R_SUCCESS) {
return (result);
}
@@ -7815,7 +7830,8 @@ configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
const cfg_obj_t *zconfig = cfg_listelt_value(element);
CHECK(configure_zone(config, zconfig, vconfig, view,
&named_g_server->viewlist,
- &named_g_server->kasplist, actx, true,
+ &named_g_server->kasplist,
+ &named_g_server->keystorelist, actx, true,
false, false));
}
@@ -8000,7 +8016,8 @@ configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
cfg_aclconfctx_t *actx) {
return (configure_zone(
config, zconfig, vconfig, view, &named_g_server->viewlist,
- &named_g_server->kasplist, actx, true, false, false));
+ &named_g_server->kasplist, &named_g_server->keystorelist, actx,
+ true, false, false));
}
/*%
@@ -8132,89 +8149,6 @@ get_newzone_config(dns_view_t *view, const char *zonename,
#endif /* HAVE_LMDB */
-static isc_result_t
-check_lockfile(named_server_t *server, const cfg_obj_t *config,
- bool first_time) {
- isc_result_t result;
- const char *filename = NULL;
- const cfg_obj_t *maps[3];
- const cfg_obj_t *options;
- const cfg_obj_t *obj;
- int i;
-
- i = 0;
- options = NULL;
- result = cfg_map_get(config, "options", &options);
- if (result == ISC_R_SUCCESS) {
- maps[i++] = options;
- }
- maps[i++] = named_g_defaults;
- maps[i] = NULL;
-
- obj = NULL;
- (void)named_config_get(maps, "lock-file", &obj);
-
- if (!first_time) {
- if (obj != NULL && !cfg_obj_isstring(obj) &&
- server->lockfile != NULL &&
- strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
- {
- isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
- "changing 'lock-file' "
- "has no effect until the "
- "server is restarted");
- }
-
- return (ISC_R_SUCCESS);
- }
-
- if (obj != NULL) {
- if (cfg_obj_isvoid(obj)) {
- isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
- "skipping lock-file check ");
- return (ISC_R_SUCCESS);
- } else if (named_g_forcelock) {
- isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
- "'lock-file' has no effect "
- "because the server was run with -X");
- server->lockfile = isc_mem_strdup(
- server->mctx, named_g_defaultlockfile);
- } else {
- filename = cfg_obj_asstring(obj);
- server->lockfile = isc_mem_strdup(server->mctx,
- filename);
- }
-
- if (server->lockfile == NULL) {
- return (ISC_R_NOMEMORY);
- }
- }
-
- if (named_g_forcelock && named_g_defaultlockfile != NULL) {
- INSIST(server->lockfile == NULL);
- server->lockfile = isc_mem_strdup(server->mctx,
- named_g_defaultlockfile);
- }
-
- if (server->lockfile == NULL) {
- return (ISC_R_SUCCESS);
- }
-
- if (named_os_issingleton(server->lockfile)) {
- return (ISC_R_SUCCESS);
- }
-
- isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
- "could not lock %s; another named "
- "process may be running",
- server->lockfile);
- return (ISC_R_FAILURE);
-}
-
static isc_result_t
load_configuration(const char *filename, named_server_t *server,
bool first_time) {
@@ -8227,10 +8161,14 @@ load_configuration(const char *filename, named_server_t *server,
const cfg_obj_t *options;
const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
const cfg_obj_t *kasps;
+ const cfg_obj_t *keystores;
dns_kasp_t *kasp = NULL;
dns_kasp_t *kasp_next = NULL;
dns_kasp_t *default_kasp = NULL;
dns_kasplist_t tmpkasplist, kasplist;
+ dns_keystore_t *keystore = NULL;
+ dns_keystore_t *keystore_next = NULL;
+ dns_keystorelist_t tmpkeystorelist, keystorelist;
const cfg_obj_t *views;
dns_view_t *view_next = NULL;
@@ -8266,9 +8204,10 @@ 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);
ISC_LIST_INIT(viewlist);
ISC_LIST_INIT(builtin_viewlist);
ISC_LIST_INIT(cachelist);
@@ -8430,14 +8369,6 @@ load_configuration(const char *filename, named_server_t *server,
setstring(server, &server->bindkeysfile, NULL);
}
- /*
- * Check the process lockfile.
- */
- result = check_lockfile(server, config, first_time);
- if (result != ISC_R_SUCCESS) {
- goto cleanup_bindkeys_parser;
- }
-
#if defined(HAVE_GEOIP2)
/*
* Release any previously opened GeoIP2 databases.
@@ -8993,6 +8924,33 @@ load_configuration(const char *filename, named_server_t *server,
*/
(void)configure_session_key(maps, server, named_g_mctx, first_time);
+ /*
+ * Create the built-in key store ("key-directory").
+ */
+ result = cfg_keystore_fromconfig(NULL, named_g_mctx, named_g_lctx,
+ named_g_engine, &keystorelist, NULL);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup_keystorelist;
+ }
+
+ /*
+ * Create the DNSSEC key stores.
+ */
+ keystores = NULL;
+ (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);
+ keystore = NULL;
+ result = cfg_keystore_fromconfig(kconfig, named_g_mctx,
+ named_g_lctx, named_g_engine,
+ &keystorelist, NULL);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup_keystorelist;
+ }
+ }
+
/*
* Create the built-in kasp policies ("default", "insecure").
*/
@@ -9006,7 +8964,7 @@ load_configuration(const char *filename, named_server_t *server,
kasp = NULL;
result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
named_g_mctx, named_g_lctx,
- &kasplist, &kasp);
+ &keystorelist, &kasplist, &kasp);
if (result != ISC_R_SUCCESS) {
goto cleanup_kasplist;
}
@@ -9035,7 +8993,7 @@ load_configuration(const char *filename, named_server_t *server,
kasp = NULL;
result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
named_g_mctx, named_g_lctx,
- &kasplist, &kasp);
+ &keystorelist, &kasplist, &kasp);
if (result != ISC_R_SUCCESS) {
goto cleanup_kasplist;
}
@@ -9043,8 +9001,15 @@ load_configuration(const char *filename, named_server_t *server,
dns_kasp_freeze(kasp);
dns_kasp_detach(&kasp);
}
-
dns_kasp_detach(&default_kasp);
+
+ /*
+ * Save keystore list and kasp list.
+ */
+ tmpkeystorelist = server->keystorelist;
+ server->keystorelist = keystorelist;
+ keystorelist = tmpkeystorelist;
+
tmpkasplist = server->kasplist;
server->kasplist = kasplist;
kasplist = tmpkasplist;
@@ -9148,7 +9113,8 @@ load_configuration(const char *filename, named_server_t *server,
}
result = configure_view(view, &viewlist, config, vconfig,
- &cachelist, &server->kasplist, bindkeys,
+ &cachelist, &server->kasplist,
+ &server->keystorelist, bindkeys,
named_g_mctx, named_g_aclconfctx, true);
if (result != ISC_R_SUCCESS) {
dns_view_detach(&view);
@@ -9169,7 +9135,8 @@ load_configuration(const char *filename, named_server_t *server,
goto cleanup_cachelist;
}
result = configure_view(view, &viewlist, config, NULL,
- &cachelist, &server->kasplist, bindkeys,
+ &cachelist, &server->kasplist,
+ &server->keystorelist, bindkeys,
named_g_mctx, named_g_aclconfctx, true);
if (result != ISC_R_SUCCESS) {
dns_view_detach(&view);
@@ -9196,10 +9163,10 @@ load_configuration(const char *filename, named_server_t *server,
goto cleanup_cachelist;
}
- result = configure_view(view, &viewlist, config, vconfig,
- &cachelist, &server->kasplist, bindkeys,
- named_g_mctx, named_g_aclconfctx,
- false);
+ result = configure_view(
+ view, &viewlist, config, vconfig, &cachelist,
+ &server->kasplist, &server->keystorelist, bindkeys,
+ named_g_mctx, named_g_aclconfctx, false);
if (result != ISC_R_SUCCESS) {
dns_view_detach(&view);
goto cleanup_cachelist;
@@ -9518,8 +9485,6 @@ load_configuration(const char *filename, named_server_t *server,
INSIST(result == ISC_R_SUCCESS);
if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
server->sctx->cookiealg = ns_cookiealg_siphash24;
- } else if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) {
- server->sctx->cookiealg = ns_cookiealg_aes;
} else {
UNREACHABLE();
}
@@ -9586,21 +9551,6 @@ load_configuration(const char *filename, named_server_t *server,
goto cleanup_altsecrets;
}
break;
- case ns_cookiealg_aes:
- expectedlength = ISC_AES128_KEYLENGTH;
- if (usedlength != expectedlength) {
- result = ISC_R_RANGE;
- isc_log_write(
- named_g_lctx,
- NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER,
- ISC_LOG_ERROR,
- "AES cookie-secret must be 128 "
- "bits: %s",
- isc_result_totext(result));
- goto cleanup_altsecrets;
- }
- break;
}
}
} else {
@@ -9713,6 +9663,15 @@ load_configuration(const char *filename, named_server_t *server,
dns_kasp_detach(&kasp);
}
+cleanup_keystorelist:
+ for (keystore = ISC_LIST_HEAD(keystorelist); keystore != NULL;
+ keystore = keystore_next)
+ {
+ keystore_next = ISC_LIST_NEXT(keystore, link);
+ ISC_LIST_UNLINK(keystorelist, keystore, link);
+ dns_keystore_detach(&keystore);
+ }
+
cleanup_v6portset:
isc_portset_destroy(named_g_mctx, &v6portset);
@@ -9901,11 +9860,10 @@ 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_netmgr,
- &named_g_dispatchmgr),
+ CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_loopmgr,
+ named_g_netmgr, &named_g_dispatchmgr),
"creating dispatch manager");
dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
@@ -9977,6 +9935,7 @@ shutdown_server(void *arg) {
named_server_t *server = (named_server_t *)arg;
dns_view_t *view = NULL, *view_next = NULL;
dns_kasp_t *kasp = NULL, *kasp_next = NULL;
+ dns_keystore_t *keystore = NULL, *keystore_next = NULL;
bool flush = server->flushonshutdown;
named_cache_t *nsc = NULL;
@@ -10023,6 +9982,14 @@ shutdown_server(void *arg) {
dns_kasp_detach(&kasp);
}
+ for (keystore = ISC_LIST_HEAD(server->keystorelist); keystore != NULL;
+ keystore = keystore_next)
+ {
+ keystore_next = ISC_LIST_NEXT(keystore, link);
+ ISC_LIST_UNLINK(server->keystorelist, keystore, link);
+ dns_keystore_detach(&keystore);
+ }
+
for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
view = view_next)
{
@@ -10129,6 +10096,7 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
/* Initialize server data structures. */
ISC_LIST_INIT(server->kasplist);
+ ISC_LIST_INIT(server->keystorelist);
ISC_LIST_INIT(server->viewlist);
/* Must be first. */
@@ -10229,9 +10197,6 @@ named_server_destroy(named_server_t **serverp) {
if (server->hostname != NULL) {
isc_mem_free(server->mctx, server->hostname);
}
- if (server->lockfile != NULL) {
- isc_mem_free(server->mctx, server->lockfile);
- }
if (server->zonemgr != NULL) {
dns_zonemgr_detach(&server->zonemgr);
@@ -10240,6 +10205,7 @@ named_server_destroy(named_server_t **serverp) {
dst_lib_destroy();
INSIST(ISC_LIST_EMPTY(server->kasplist));
+ INSIST(ISC_LIST_EMPTY(server->keystorelist));
INSIST(ISC_LIST_EMPTY(server->viewlist));
INSIST(ISC_LIST_EMPTY(server->cachelist));
@@ -10268,8 +10234,7 @@ fatal(const char *msg, isc_result_t result) {
NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
"exiting (due to fatal error)");
named_os_shutdown();
- isc__tls_setfatalmode();
- exit(1);
+ _exit(EXIT_FAILURE);
}
static isc_result_t
@@ -10297,8 +10262,15 @@ reload(named_server_t *server) {
atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
#if HAVE_LIBSYSTEMD
- sd_notify(0, "RELOADING=1\n"
- "STATUS=reload command received\n");
+ char buf[512];
+ int n = snprintf(buf, sizeof(buf),
+ "RELOADING=1\n"
+ "MONOTONIC_USEC=%" PRIu64 "\n"
+ "STATUS=reload command received\n",
+ (uint64_t)isc_time_monotonic() / NS_PER_US);
+ if (n > 0 && (size_t)n < sizeof(buf)) {
+ sd_notify(0, buf);
+ }
#endif /* HAVE_LIBSYSTEMD */
CHECK(loadconfig(server));
@@ -10678,8 +10650,15 @@ named_server_reconfigcommand(named_server_t *server) {
isc_result_t result;
atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
#if HAVE_LIBSYSTEMD
- sd_notify(0, "RELOADING=1\n"
- "STATUS=reconfig command received\n");
+ char buf[512];
+ int n = snprintf(buf, sizeof(buf),
+ "RELOADING=1\n"
+ "MONOTONIC_USEC=%" PRIu64 "\n"
+ "STATUS=reconfig command received\n",
+ (uint64_t)isc_time_monotonic() / NS_PER_US);
+ if (n > 0 && (size_t)n < sizeof(buf)) {
+ sd_notify(0, buf);
+ }
#endif /* HAVE_LIBSYSTEMD */
CHECK(loadconfig(server));
@@ -10898,9 +10877,10 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
const cfg_obj_t *tlsobj = NULL, *httpobj = NULL;
const cfg_obj_t *portobj = NULL;
const cfg_obj_t *http_server = NULL;
+ const cfg_obj_t *proxyobj = NULL;
in_port_t port = 0;
const char *key = NULL, *cert = NULL, *ca_file = NULL,
- *dhparam_file = NULL, *ciphers = NULL;
+ *dhparam_file = NULL, *ciphers = NULL, *cipher_suites = NULL;
bool tls_prefer_server_ciphers = false,
tls_prefer_server_ciphers_set = false;
bool tls_session_tickets = false, tls_session_tickets_set = false;
@@ -10909,6 +10889,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
uint32_t tls_protos = 0;
ns_listen_tls_params_t tls_params = { 0 };
const char *tlsname = NULL;
+ isc_nm_proxy_type_t proxy = ISC_NM_PROXY_NONE;
REQUIRE(target != NULL && *target == NULL);
@@ -10929,6 +10910,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
const cfg_obj_t *tlsmap = NULL;
const cfg_obj_t *tls_proto_list = NULL;
const cfg_obj_t *ciphers_obj = NULL;
+ const cfg_obj_t *cipher_suites_obj = NULL;
const cfg_obj_t *prefer_server_ciphers_obj = NULL;
const cfg_obj_t *session_tickets_obj = NULL;
@@ -10989,6 +10971,13 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
ciphers = cfg_obj_asstring(ciphers_obj);
}
+ if (cfg_map_get(tlsmap, "cipher-suites",
+ &cipher_suites_obj) == ISC_R_SUCCESS)
+ {
+ cipher_suites =
+ cfg_obj_asstring(cipher_suites_obj);
+ }
+
if (cfg_map_get(tlsmap, "prefer-server-ciphers",
&prefer_server_ciphers_obj) ==
ISC_R_SUCCESS)
@@ -11016,6 +11005,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
.protocols = tls_protos,
.dhparam_file = dhparam_file,
.ciphers = ciphers,
+ .cipher_suites = cipher_suites,
.prefer_server_ciphers = tls_prefer_server_ciphers,
.prefer_server_ciphers_set = tls_prefer_server_ciphers_set,
.session_tickets = tls_session_tickets,
@@ -11092,16 +11082,31 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
port = (in_port_t)cfg_obj_asuint32(portobj);
}
+ proxyobj = cfg_tuple_get(ltup, "proxy");
+ if (proxyobj != NULL && cfg_obj_isstring(proxyobj)) {
+ const char *proxyval = cfg_obj_asstring(proxyobj);
+
+ if (strcasecmp(proxyval, "encrypted") == 0) {
+ INSIST(do_tls == true);
+ proxy = ISC_NM_PROXY_ENCRYPTED;
+ } else if (strcasecmp(proxyval, "plain") == 0) {
+ proxy = ISC_NM_PROXY_PLAIN;
+ } else {
+ UNREACHABLE();
+ }
+ }
+
#ifdef HAVE_LIBNGHTTP2
if (http) {
CHECK(listenelt_http(http_server, family, do_tls, &tls_params,
- tlsctx_cache, port, mctx, &delt));
+ tlsctx_cache, port, mctx, proxy, &delt));
}
#endif /* HAVE_LIBNGHTTP2 */
if (!http) {
CHECK(ns_listenelt_create(mctx, port, NULL, family, do_tls,
- &tls_params, tlsctx_cache, &delt));
+ &tls_params, tlsctx_cache, proxy,
+ &delt));
}
result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), config,
@@ -11122,7 +11127,8 @@ static isc_result_t
listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
const ns_listen_tls_params_t *tls_params,
isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
- isc_mem_t *mctx, ns_listenelt_t **target) {
+ isc_mem_t *mctx, isc_nm_proxy_type_t proxy,
+ ns_listenelt_t **target) {
isc_result_t result = ISC_R_SUCCESS;
ns_listenelt_t *delt = NULL;
char **endpoints = NULL;
@@ -11187,9 +11193,9 @@ listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
INSIST(i == len);
- result = ns_listenelt_create_http(mctx, port, NULL, family, tls,
- tls_params, tlsctx_cache, endpoints,
- len, max_clients, max_streams, &delt);
+ result = ns_listenelt_create_http(
+ mctx, port, NULL, family, tls, tls_params, tlsctx_cache, proxy,
+ endpoints, len, max_clients, max_streams, &delt);
if (result != ISC_R_SUCCESS) {
goto error;
}
@@ -12087,8 +12093,8 @@ named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
isc_result_t
named_server_status(named_server_t *server, isc_buffer_t **text) {
isc_result_t result;
- unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
- unsigned int automatic;
+ unsigned int zonecount, xferrunning, xferdeferred, xferfirstrefresh;
+ unsigned int soaqueries, automatic;
const char *ob = "", *cb = "", *alt = "";
char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
@@ -12111,6 +12117,8 @@ named_server_status(named_server_t *server, isc_buffer_t **text) {
DNS_ZONESTATE_XFERRUNNING);
xferdeferred = dns_zonemgr_getcount(server->zonemgr,
DNS_ZONESTATE_XFERDEFERRED);
+ xferfirstrefresh = dns_zonemgr_getcount(server->zonemgr,
+ DNS_ZONESTATE_XFERFIRSTREFRESH);
soaqueries = dns_zonemgr_getcount(server->zonemgr,
DNS_ZONESTATE_SOAQUERY);
automatic = dns_zonemgr_getcount(server->zonemgr,
@@ -12154,10 +12162,6 @@ named_server_status(named_server_t *server, isc_buffer_t **text) {
snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
CHECK(putstr(text, line));
- snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
- named_g_udpdisp);
- CHECK(putstr(text, line));
-
snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
zonecount, automatic);
CHECK(putstr(text, line));
@@ -12171,6 +12175,10 @@ named_server_status(named_server_t *server, isc_buffer_t **text) {
snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
CHECK(putstr(text, line));
+ snprintf(line, sizeof(line), "xfers first refresh: %u\n",
+ xferfirstrefresh);
+ CHECK(putstr(text, line));
+
snprintf(line, sizeof(line), "soa queries in progress: %u\n",
soaqueries);
CHECK(putstr(text, line));
@@ -12187,6 +12195,12 @@ named_server_status(named_server_t *server, isc_buffer_t **text) {
isc_quota_getmax(&server->sctx->recursionquota));
CHECK(putstr(text, line));
+ snprintf(line, sizeof(line), "recursive high-water: %u\n",
+ (unsigned int)ns_stats_get_counter(
+ server->sctx->nsstats,
+ ns_statscounter_recurshighwater));
+ CHECK(putstr(text, line));
+
snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
isc_quota_getused(&server->sctx->tcpquota),
isc_quota_getmax(&server->sctx->tcpquota));
@@ -13445,8 +13459,9 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
/* Mark view unfrozen and configure zone */
dns_view_thaw(view);
result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
- &server->viewlist, &server->kasplist, cfg->actx,
- true, false, false);
+ &server->viewlist, &server->kasplist,
+ &server->keystorelist, cfg->actx, true, false,
+ false);
dns_view_freeze(view);
isc_loopmgr_resume(named_g_loopmgr);
@@ -13630,8 +13645,9 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
/* Reconfigure the zone */
dns_view_thaw(view);
result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
- &server->viewlist, &server->kasplist, cfg->actx,
- true, false, true);
+ &server->viewlist, &server->kasplist,
+ &server->keystorelist, cfg->actx, true, false,
+ true);
dns_view_freeze(view);
isc_loopmgr_resume(named_g_loopmgr);
@@ -14656,7 +14672,6 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
char output[65355];
isc_stdtime_t now, when;
isc_time_t timenow, timewhen;
- const char *dir;
dns_db_t *db = NULL;
dns_dbversion_t *version = NULL;
@@ -14791,7 +14806,6 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
}
/* Get DNSSEC keys. */
- dir = dns_zone_getkeydirectory(zone);
CHECK(dns_zone_getdb(zone, &db));
dns_db_currentversion(db, &version);
LOCK(&kasp->lock);
@@ -14823,11 +14837,11 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
LOCK(&kasp->lock);
if (use_keyid) {
- result = dns_keymgr_checkds_id(kasp, &keys, dir, now,
- when, dspublish, keyid,
+ result = dns_keymgr_checkds_id(kasp, &keys, now, when,
+ dspublish, keyid,
(unsigned int)algorithm);
} else {
- result = dns_keymgr_checkds(kasp, &keys, dir, now, when,
+ result = dns_keymgr_checkds(kasp, &keys, now, when,
dspublish);
}
UNLOCK(&kasp->lock);
@@ -14878,7 +14892,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
isc_result_t ret;
LOCK(&kasp->lock);
- result = dns_keymgr_rollover(kasp, &keys, dir, now, when, keyid,
+ result = dns_keymgr_rollover(kasp, &keys, now, when, keyid,
(unsigned int)algorithm);
UNLOCK(&kasp->lock);
@@ -15096,29 +15110,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);
}
}
@@ -15347,6 +15358,8 @@ named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
* If -dump was specified, list NTA's and return
*/
if (dump) {
+ size_t last = 0;
+
for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
view = ISC_LIST_NEXT(view, link))
{
@@ -15358,6 +15371,12 @@ named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
continue;
}
+ if (last != isc_buffer_usedlength(*text)) {
+ CHECK(putstr(text, "\n"));
+ }
+
+ last = isc_buffer_usedlength(*text);
+
CHECK(dns_ntatable_totext(ntatable, view->name, text));
}
CHECK(putnull(text));
diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c
index 349bec0eef..b9b85e0594 100644
--- a/bin/named/statschannel.c
+++ b/bin/named/statschannel.c
@@ -33,7 +33,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#include
@@ -325,6 +327,8 @@ init_desc(void) {
SET_NSSTATDESC(updatebadprereq,
"updates rejected due to prerequisite failure",
"UpdateBadPrereq");
+ SET_NSSTATDESC(recurshighwater, "Recursive clients high-water",
+ "RecursHighwater");
SET_NSSTATDESC(recursclients, "recursing clients", "RecursClients");
SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64");
SET_NSSTATDESC(ratedropped, "responses dropped for rate limits",
@@ -553,8 +557,6 @@ init_desc(void) {
SET_SOCKSTATDESC(udp6open, "UDP/IPv6 sockets opened", "UDP6Open");
SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open");
SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open");
- SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen");
- SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen");
SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures",
"UDP4OpenFail");
SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures",
@@ -563,18 +565,10 @@ init_desc(void) {
"TCP4OpenFail");
SET_SOCKSTATDESC(tcp6openfail, "TCP/IPv6 socket open failures",
"TCP6OpenFail");
- SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures",
- "UnixOpenFail");
- SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures",
- "RawOpenFail");
SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close");
SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close");
SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close");
SET_SOCKSTATDESC(tcp6close, "TCP/IPv6 sockets closed", "TCP6Close");
- SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose");
- SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed",
- "FDWatchClose");
- SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose");
SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures",
"UDP4BindFail");
SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures",
@@ -583,10 +577,6 @@ init_desc(void) {
"TCP4BindFail");
SET_SOCKSTATDESC(tcp6bindfail, "TCP/IPv6 socket bind failures",
"TCP6BindFail");
- SET_SOCKSTATDESC(unixbindfail, "Unix domain socket bind failures",
- "UnixBindFail");
- SET_SOCKSTATDESC(fdwatchbindfail, "FDwatch socket bind failures",
- "FdwatchBindFail");
SET_SOCKSTATDESC(udp4connectfail, "UDP/IPv4 socket connect failures",
"UDP4ConnFail");
SET_SOCKSTATDESC(udp6connectfail, "UDP/IPv6 socket connect failures",
@@ -595,10 +585,6 @@ init_desc(void) {
"TCP4ConnFail");
SET_SOCKSTATDESC(tcp6connectfail, "TCP/IPv6 socket connect failures",
"TCP6ConnFail");
- SET_SOCKSTATDESC(unixconnectfail, "Unix domain socket connect failures",
- "UnixConnFail");
- SET_SOCKSTATDESC(fdwatchconnectfail, "FDwatch socket connect failures",
- "FDwatchConnFail");
SET_SOCKSTATDESC(udp4connect, "UDP/IPv4 connections established",
"UDP4Conn");
SET_SOCKSTATDESC(udp6connect, "UDP/IPv6 connections established",
@@ -607,48 +593,30 @@ init_desc(void) {
"TCP4Conn");
SET_SOCKSTATDESC(tcp6connect, "TCP/IPv6 connections established",
"TCP6Conn");
- SET_SOCKSTATDESC(unixconnect, "Unix domain connections established",
- "UnixConn");
- SET_SOCKSTATDESC(fdwatchconnect,
- "FDwatch domain connections established",
- "FDwatchConn");
SET_SOCKSTATDESC(tcp4acceptfail, "TCP/IPv4 connection accept failures",
"TCP4AcceptFail");
SET_SOCKSTATDESC(tcp6acceptfail, "TCP/IPv6 connection accept failures",
"TCP6AcceptFail");
- SET_SOCKSTATDESC(unixacceptfail,
- "Unix domain connection accept failures",
- "UnixAcceptFail");
SET_SOCKSTATDESC(tcp4accept, "TCP/IPv4 connections accepted",
"TCP4Accept");
SET_SOCKSTATDESC(tcp6accept, "TCP/IPv6 connections accepted",
"TCP6Accept");
- SET_SOCKSTATDESC(unixaccept, "Unix domain connections accepted",
- "UnixAccept");
SET_SOCKSTATDESC(udp4sendfail, "UDP/IPv4 send errors", "UDP4SendErr");
SET_SOCKSTATDESC(udp6sendfail, "UDP/IPv6 send errors", "UDP6SendErr");
SET_SOCKSTATDESC(tcp4sendfail, "TCP/IPv4 send errors", "TCP4SendErr");
SET_SOCKSTATDESC(tcp6sendfail, "TCP/IPv6 send errors", "TCP6SendErr");
- SET_SOCKSTATDESC(unixsendfail, "Unix domain send errors",
- "UnixSendErr");
- SET_SOCKSTATDESC(fdwatchsendfail, "FDwatch send errors",
- "FDwatchSendErr");
SET_SOCKSTATDESC(udp4recvfail, "UDP/IPv4 recv errors", "UDP4RecvErr");
SET_SOCKSTATDESC(udp6recvfail, "UDP/IPv6 recv errors", "UDP6RecvErr");
SET_SOCKSTATDESC(tcp4recvfail, "TCP/IPv4 recv errors", "TCP4RecvErr");
SET_SOCKSTATDESC(tcp6recvfail, "TCP/IPv6 recv errors", "TCP6RecvErr");
- SET_SOCKSTATDESC(unixrecvfail, "Unix domain recv errors",
- "UnixRecvErr");
- SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
- "FDwatchRecvErr");
- SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr");
SET_SOCKSTATDESC(udp4active, "UDP/IPv4 sockets active", "UDP4Active");
SET_SOCKSTATDESC(udp6active, "UDP/IPv6 sockets active", "UDP6Active");
SET_SOCKSTATDESC(tcp4active, "TCP/IPv4 sockets active", "TCP4Active");
SET_SOCKSTATDESC(tcp6active, "TCP/IPv6 sockets active", "TCP6Active");
- SET_SOCKSTATDESC(unixactive, "Unix domain sockets active",
- "UnixActive");
- SET_SOCKSTATDESC(rawactive, "Raw sockets active", "RawActive");
+ SET_SOCKSTATDESC(tcp4clients, "TCP/IPv4 clients currently connected",
+ "TCP4Clients");
+ SET_SOCKSTATDESC(tcp6clients, "TCP/IPv6 clients currently connected",
+ "TCP6Clients");
INSIST(i == isc_sockstatscounter_max);
/* Initialize DNSSEC statistics */
@@ -1304,6 +1272,7 @@ dnssecsignstat_dump(uint32_t kval, uint64_t val, void *arg) {
#define STATS_XML_STATUS 0x00 /* display only common statistics */
#define STATS_XML_SERVER 0x01
#define STATS_XML_ZONES 0x02
+#define STATS_XML_XFRINS 0x04
#define STATS_XML_NET 0x08
#define STATS_XML_MEM 0x10
#define STATS_XML_TRAFFIC 0x20
@@ -1489,6 +1458,280 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
return (ISC_R_FAILURE);
}
+static isc_result_t
+xfrin_xmlrender(dns_zone_t *zone, void *arg) {
+ char buf[1024 + 32]; /* sufficiently large for zone name and class */
+ dns_rdataclass_t rdclass;
+ const char *ztype;
+ uint32_t serial;
+ isc_sockaddr_t addr;
+ const isc_sockaddr_t *addrp = NULL;
+ char addr_buf[ISC_SOCKADDR_FORMATSIZE];
+ dns_transport_type_t transport_type;
+ xmlTextWriterPtr writer = arg;
+ dns_zonestat_level_t statlevel;
+ int xmlrc;
+ dns_xfrin_t *xfr = NULL;
+ bool is_firstrefresh, is_running, is_deferred, is_presoa, is_pending;
+ bool needs_refresh;
+ bool is_first_data_received, is_ixfr;
+ unsigned int nmsg = 0;
+ unsigned int nrecs = 0;
+ uint64_t nbytes = 0;
+
+ statlevel = dns_zone_getstatlevel(zone);
+ if (statlevel == dns_zonestat_none) {
+ return (ISC_R_SUCCESS);
+ }
+
+ if (dns_zone_getxfr(zone, &xfr, &is_firstrefresh, &is_running,
+ &is_deferred, &is_presoa, &is_pending,
+ &needs_refresh) != ISC_R_SUCCESS)
+ {
+ /*
+ * Failed to get information about the zone's incoming transfer
+ * (if any), but we still want to continue generating the
+ * remaining parts of the output.
+ */
+ return (ISC_R_SUCCESS);
+ }
+
+ if (!is_running && !is_deferred && !is_presoa && !is_pending &&
+ !needs_refresh)
+ {
+ if (xfr != NULL) {
+ dns_xfrin_detach(&xfr);
+ }
+ /* No ongoing/queued transfer. */
+ return (ISC_R_SUCCESS);
+ }
+
+ if (is_running && xfr == NULL) {
+ /* The transfer is finished, and it's shutting down. */
+ return (ISC_R_SUCCESS);
+ }
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "xfrin"));
+
+ dns_zone_nameonly(zone, buf, sizeof(buf));
+ TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
+ ISC_XMLCHAR buf));
+
+ rdclass = dns_zone_getclass(zone);
+ dns_rdataclass_format(rdclass, buf, sizeof(buf));
+ TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "class",
+ ISC_XMLCHAR buf));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"));
+ ztype = user_zonetype(zone);
+ if (ztype != NULL) {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR ztype));
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"));
+ if (dns_zone_getserial(zone, &serial) == ISC_R_SUCCESS) {
+ TRY0(xmlTextWriterWriteFormatString(writer, "%u", serial));
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "remoteserial"));
+ if (is_running) {
+ serial = dns_xfrin_getendserial(xfr);
+ if (serial != 0) {
+ TRY0(xmlTextWriterWriteFormatString(writer, "%u",
+ serial));
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "firstrefresh"));
+ TRY0(xmlTextWriterWriteString(
+ writer, ISC_XMLCHAR(is_firstrefresh ? "Yes" : "No")));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "state"));
+ if (is_running) {
+ const char *xfr_state = NULL;
+
+ dns_xfrin_getstate(xfr, &xfr_state, &is_first_data_received,
+ &is_ixfr);
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR xfr_state));
+ } else if (is_deferred) {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "Deferred"));
+ } else if (is_presoa) {
+ TRY0(xmlTextWriterWriteString(writer,
+ ISC_XMLCHAR "Refresh SOA"));
+ } else if (is_pending) {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "Pending"));
+ } else if (needs_refresh) {
+ TRY0(xmlTextWriterWriteString(writer,
+ ISC_XMLCHAR "Needs Refresh"));
+ } else {
+ UNREACHABLE();
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "refreshqueued"));
+ TRY0(xmlTextWriterWriteString(
+ writer,
+ ISC_XMLCHAR(is_running && needs_refresh ? "Yes" : "No")));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "localaddr"));
+ if (is_running) {
+ addrp = dns_xfrin_getsourceaddr(xfr);
+ isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf));
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf));
+ } else if (is_presoa) {
+ addr = dns_zone_getsourceaddr(zone);
+ isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf));
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf));
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "remoteaddr"));
+ if (is_running) {
+ addrp = dns_xfrin_getprimaryaddr(xfr);
+ isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf));
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf));
+ } else if (is_presoa) {
+ addr = dns_zone_getprimaryaddr(zone);
+ isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf));
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf));
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "soatransport"));
+ if (is_running || is_presoa) {
+ if (is_running) {
+ transport_type = dns_xfrin_getsoatransporttype(xfr);
+ } else {
+ transport_type = dns_zone_getrequesttransporttype(zone);
+ }
+ if (transport_type == DNS_TRANSPORT_UDP) {
+ TRY0(xmlTextWriterWriteString(writer,
+ ISC_XMLCHAR "UDP"));
+ } else if (transport_type == DNS_TRANSPORT_TCP) {
+ TRY0(xmlTextWriterWriteString(writer,
+ ISC_XMLCHAR "TCP"));
+ } else if (transport_type == DNS_TRANSPORT_TLS) {
+ TRY0(xmlTextWriterWriteString(writer,
+ ISC_XMLCHAR "TLS"));
+ } else if (transport_type == DNS_TRANSPORT_NONE) {
+ TRY0(xmlTextWriterWriteString(writer,
+ ISC_XMLCHAR "None"));
+ } else {
+ /* We don't expect any other SOA transport type. */
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "transport"));
+ if (is_running) {
+ transport_type = dns_xfrin_gettransporttype(xfr);
+ if (transport_type == DNS_TRANSPORT_TCP) {
+ TRY0(xmlTextWriterWriteString(writer,
+ ISC_XMLCHAR "TCP"));
+ } else if (transport_type == DNS_TRANSPORT_TLS) {
+ TRY0(xmlTextWriterWriteString(writer,
+ ISC_XMLCHAR "TLS"));
+ } else {
+ /* We don't expect any other transport type. */
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-"));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tsigkeyname"));
+ if (is_running) {
+ const dns_name_t *tsigkeyname = dns_xfrin_gettsigkeyname(xfr);
+ char tsigkeyname_buf[DNS_NAME_FORMATSIZE];
+
+ if (tsigkeyname != NULL) {
+ dns_name_format(tsigkeyname, tsigkeyname_buf,
+ sizeof(tsigkeyname_buf));
+ TRY0(xmlTextWriterWriteString(
+ writer, ISC_XMLCHAR tsigkeyname_buf));
+ }
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "duration"));
+ if (is_running || is_deferred || is_presoa || is_pending) {
+ isc_time_t start = is_running ? dns_xfrin_getstarttime(xfr)
+ : dns_zone_getxfrintime(zone);
+ isc_time_t now = isc_time_now();
+ isc_time_t diff;
+ uint32_t sec;
+
+ isc_time_subtract(&now, &start, &diff);
+ sec = isc_time_seconds(&diff);
+ TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu32, sec));
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "0"));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ if (is_running) {
+ dns_xfrin_getstats(xfr, &nmsg, &nrecs, &nbytes);
+ }
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "nmsg"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%u", nmsg));
+ TRY0(xmlTextWriterEndElement(writer));
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "nrecs"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%u", nrecs));
+ TRY0(xmlTextWriterEndElement(writer));
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "nbytes"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64, nbytes));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ixfr"));
+ if (is_running && is_first_data_received) {
+ TRY0(xmlTextWriterWriteString(
+ writer, ISC_XMLCHAR(is_ixfr ? "Yes" : "No")));
+ } else {
+ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR ""));
+ }
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterEndElement(writer)); /* xfrin */
+
+ if (xfr != NULL) {
+ dns_xfrin_detach(&xfr);
+ }
+
+ return (ISC_R_SUCCESS);
+
+cleanup:
+ if (xfr != NULL) {
+ dns_xfrin_detach(&xfr);
+ }
+
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "Failed at xfrin_xmlrender()");
+
+ return (ISC_R_FAILURE);
+}
+
static isc_result_t
generatexml(named_server_t *server, uint32_t flags, int *buflen,
xmlChar **buf) {
@@ -1767,8 +2010,8 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
*/
view = ISC_LIST_HEAD(server->viewlist);
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views"));
- while (view != NULL &&
- ((flags & (STATS_XML_SERVER | STATS_XML_ZONES)) != 0))
+ while (view != NULL && ((flags & (STATS_XML_SERVER | STATS_XML_ZONES |
+ STATS_XML_XFRINS)) != 0))
{
isc_stats_t *istats = NULL;
dns_stats_t *dstats = NULL;
@@ -1786,6 +2029,14 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterEndElement(writer)); /* /zones */
}
+ if ((flags & STATS_XML_XFRINS) != 0) {
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "xfrins"));
+ CHECK(dns_zt_apply(view->zonetable, true, NULL,
+ xfrin_xmlrender, writer));
+ TRY0(xmlTextWriterEndElement(writer)); /* /xfrins */
+ }
+
if ((flags & STATS_XML_SERVER) == 0) {
TRY0(xmlTextWriterEndElement(writer)); /* /view */
view = ISC_LIST_NEXT(view, link);
@@ -1974,6 +2225,17 @@ render_xml_zones(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
freecb, freecb_args));
}
+static isc_result_t
+render_xml_xfrins(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
+ void *arg, unsigned int *retcode, const char **retmsg,
+ const char **mimetype, isc_buffer_t *b,
+ isc_httpdfree_t **freecb, void **freecb_args) {
+ UNUSED(httpd);
+ UNUSED(urlinfo);
+ return (render_xml(STATS_XML_XFRINS, arg, retcode, retmsg, mimetype, b,
+ freecb, freecb_args));
+}
+
static isc_result_t
render_xml_net(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
@@ -2016,6 +2278,7 @@ render_xml_traffic(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
#define STATS_JSON_STATUS 0x00 /* display only common statistics */
#define STATS_JSON_SERVER 0x01
#define STATS_JSON_ZONES 0x02
+#define STATS_JSON_XFRINS 0x04
#define STATS_JSON_NET 0x08
#define STATS_JSON_MEM 0x10
#define STATS_JSON_TRAFFIC 0x20
@@ -2266,6 +2529,260 @@ zone_jsonrender(dns_zone_t *zone, void *arg) {
return (result);
}
+static isc_result_t
+xfrin_jsonrender(dns_zone_t *zone, void *arg) {
+ isc_result_t result;
+ char buf[1024 + 32]; /* sufficiently large for zone name and class */
+ char classbuf[64]; /* sufficiently large for class */
+ char *zone_name_only = NULL;
+ char *class_only = NULL;
+ dns_rdataclass_t rdclass;
+ uint32_t serial;
+ json_object *xfrinarray = (json_object *)arg;
+ json_object *xfrinobj = NULL;
+ isc_sockaddr_t addr;
+ const isc_sockaddr_t *addrp = NULL;
+ char addr_buf[ISC_SOCKADDR_FORMATSIZE];
+ dns_transport_type_t transport_type;
+ dns_zonestat_level_t statlevel;
+ dns_xfrin_t *xfr = NULL;
+ bool is_firstrefresh, is_running, is_deferred, is_presoa, is_pending;
+ bool needs_refresh;
+ bool is_first_data_received, is_ixfr;
+ unsigned int nmsg = 0;
+ unsigned int nrecs = 0;
+ uint64_t nbytes = 0;
+
+ statlevel = dns_zone_getstatlevel(zone);
+ if (statlevel == dns_zonestat_none) {
+ return (ISC_R_SUCCESS);
+ }
+
+ dns_zone_nameonly(zone, buf, sizeof(buf));
+ zone_name_only = buf;
+
+ rdclass = dns_zone_getclass(zone);
+ dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf));
+ class_only = classbuf;
+
+ if (dns_zone_getserial(zone, &serial) != ISC_R_SUCCESS) {
+ xfrinobj = addzone(zone_name_only, class_only,
+ user_zonetype(zone), 0, false);
+ } else {
+ xfrinobj = addzone(zone_name_only, class_only,
+ user_zonetype(zone), serial, true);
+ }
+
+ if (xfrinobj == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ result = dns_zone_getxfr(zone, &xfr, &is_firstrefresh, &is_running,
+ &is_deferred, &is_presoa, &is_pending,
+ &needs_refresh);
+ if (result != ISC_R_SUCCESS) {
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+
+ if (!is_running && !is_deferred && !is_presoa && !is_pending &&
+ !needs_refresh)
+ {
+ /* No ongoing/queued transfer. */
+ goto cleanup;
+ }
+
+ if (is_running && xfr == NULL) {
+ /* The transfer is finished, and it's shutting down. */
+ goto cleanup;
+ }
+
+ if (is_running) {
+ serial = dns_xfrin_getendserial(xfr);
+ if (serial != 0) {
+ json_object_object_add(xfrinobj, "remoteserial",
+ json_object_new_int64(serial));
+ }
+ }
+
+ json_object_object_add(
+ xfrinobj, "firstrefresh",
+ json_object_new_string(is_firstrefresh ? "Yes" : "No"));
+
+ if (is_running) {
+ const char *xfr_state = NULL;
+
+ dns_xfrin_getstate(xfr, &xfr_state, &is_first_data_received,
+ &is_ixfr);
+ json_object_object_add(xfrinobj, "state",
+ json_object_new_string(xfr_state));
+ } else if (is_deferred) {
+ json_object_object_add(xfrinobj, "state",
+ json_object_new_string("Deferred"));
+ } else if (is_presoa) {
+ json_object_object_add(xfrinobj, "state",
+ json_object_new_string("Refresh SOA"));
+ } else if (is_pending) {
+ json_object_object_add(xfrinobj, "state",
+ json_object_new_string("Pending"));
+ } else if (needs_refresh) {
+ json_object_object_add(xfrinobj, "state",
+ json_object_new_string("Needs Refresh"));
+ } else {
+ UNREACHABLE();
+ }
+
+ json_object_object_add(
+ xfrinobj, "refreshqueued",
+ json_object_new_string(is_running && needs_refresh ? "Yes"
+ : "No"));
+
+ if (is_running) {
+ addrp = dns_xfrin_getsourceaddr(xfr);
+ isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf));
+ json_object_object_add(xfrinobj, "localaddr",
+ json_object_new_string(addr_buf));
+ } else if (is_presoa) {
+ addr = dns_zone_getsourceaddr(zone);
+ isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf));
+ json_object_object_add(xfrinobj, "localaddr",
+ json_object_new_string(addr_buf));
+ } else {
+ json_object_object_add(xfrinobj, "localaddr",
+ json_object_new_string("-"));
+ }
+
+ if (is_running) {
+ addrp = dns_xfrin_getprimaryaddr(xfr);
+ isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf));
+ json_object_object_add(xfrinobj, "remoteaddr",
+ json_object_new_string(addr_buf));
+ } else if (is_presoa) {
+ addr = dns_zone_getprimaryaddr(zone);
+ isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf));
+ json_object_object_add(xfrinobj, "remoteaddr",
+ json_object_new_string(addr_buf));
+ } else {
+ json_object_object_add(xfrinobj, "remoteaddr",
+ json_object_new_string("-"));
+ }
+
+ if (is_running || is_presoa) {
+ if (is_running) {
+ transport_type = dns_xfrin_getsoatransporttype(xfr);
+ } else {
+ transport_type = dns_zone_getrequesttransporttype(zone);
+ }
+
+ if (transport_type == DNS_TRANSPORT_UDP) {
+ json_object_object_add(xfrinobj, "soatransport",
+ json_object_new_string("UDP"));
+ } else if (transport_type == DNS_TRANSPORT_TCP) {
+ json_object_object_add(xfrinobj, "soatransport",
+ json_object_new_string("TCP"));
+ } else if (transport_type == DNS_TRANSPORT_TLS) {
+ json_object_object_add(xfrinobj, "soatransport",
+ json_object_new_string("TLS"));
+ } else if (transport_type == DNS_TRANSPORT_NONE) {
+ json_object_object_add(xfrinobj, "soatransport",
+ json_object_new_string("None"));
+ } else {
+ /* We don't expect any other SOA transport type. */
+ json_object_object_add(xfrinobj, "soatransport",
+ json_object_new_string("-"));
+ }
+ } else {
+ json_object_object_add(xfrinobj, "soatransport",
+ json_object_new_string("-"));
+ }
+
+ if (is_running) {
+ transport_type = dns_xfrin_gettransporttype(xfr);
+ if (transport_type == DNS_TRANSPORT_TCP) {
+ json_object_object_add(xfrinobj, "transport",
+ json_object_new_string("TCP"));
+ } else if (transport_type == DNS_TRANSPORT_TLS) {
+ json_object_object_add(xfrinobj, "transport",
+ json_object_new_string("TLS"));
+ } else {
+ /* We don't expect any other transport type. */
+ json_object_object_add(xfrinobj, "transport",
+ json_object_new_string("-"));
+ }
+ } else {
+ json_object_object_add(xfrinobj, "transport",
+ json_object_new_string("-"));
+ }
+
+ if (is_running) {
+ const dns_name_t *tsigkeyname = dns_xfrin_gettsigkeyname(xfr);
+ char tsigkeyname_buf[DNS_NAME_FORMATSIZE];
+
+ if (tsigkeyname != NULL) {
+ dns_name_format(tsigkeyname, tsigkeyname_buf,
+ sizeof(tsigkeyname_buf));
+ json_object_object_add(
+ xfrinobj, "tsigkeyname",
+ json_object_new_string(tsigkeyname_buf));
+ } else {
+ json_object_object_add(xfrinobj, "tsigkeyname", NULL);
+ }
+ } else {
+ json_object_object_add(xfrinobj, "tsigkeyname", NULL);
+ }
+
+ if (is_running || is_deferred || is_presoa || is_pending) {
+ isc_time_t start = is_running ? dns_xfrin_getstarttime(xfr)
+ : dns_zone_getxfrintime(zone);
+ isc_time_t now = isc_time_now();
+ isc_time_t diff;
+ uint32_t sec;
+
+ isc_time_subtract(&now, &start, &diff);
+ sec = isc_time_seconds(&diff);
+ json_object_object_add(xfrinobj, "duration",
+ json_object_new_int64((int64_t)sec));
+ } else {
+ json_object_object_add(xfrinobj, "duration",
+ json_object_new_int64(0));
+ }
+
+ if (is_running) {
+ dns_xfrin_getstats(xfr, &nmsg, &nrecs, &nbytes);
+ }
+ json_object_object_add(xfrinobj, "nmsg",
+ json_object_new_int64((int64_t)nmsg));
+ json_object_object_add(xfrinobj, "nrecs",
+ json_object_new_int64((int64_t)nrecs));
+ json_object_object_add(
+ xfrinobj, "nbytes",
+ json_object_new_int64(nbytes > INT64_MAX ? INT64_MAX
+ : (int64_t)nbytes));
+
+ if (is_running && is_first_data_received) {
+ json_object_object_add(
+ xfrinobj, "ixfr",
+ json_object_new_string(is_ixfr ? "Yes" : "No"));
+ } else {
+ json_object_object_add(xfrinobj, "ixfr",
+ json_object_new_string(""));
+ }
+
+ json_object_array_add(xfrinarray, xfrinobj);
+ xfrinobj = NULL;
+ result = ISC_R_SUCCESS;
+
+cleanup:
+ if (xfr != NULL) {
+ dns_xfrin_detach(&xfr);
+ }
+ if (xfrinobj != NULL) {
+ json_object_put(xfrinobj);
+ }
+ return (result);
+}
+
static isc_result_t
generatejson(named_server_t *server, size_t *msglen, const char **msg,
json_object **rootp, uint32_t flags) {
@@ -2484,7 +3001,9 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
#endif /* ifdef HAVE_DNSTAP */
}
- if ((flags & (STATS_JSON_ZONES | STATS_JSON_SERVER)) != 0) {
+ if ((flags &
+ (STATS_JSON_SERVER | STATS_JSON_ZONES | STATS_JSON_XFRINS)) != 0)
+ {
viewlist = json_object_new_object();
CHECKMEM(viewlist);
@@ -2492,7 +3011,7 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
view = ISC_LIST_HEAD(server->viewlist);
while (view != NULL) {
- json_object *za, *v = json_object_new_object();
+ json_object *za, *xa, *v = json_object_new_object();
dns_adb_t *adb = NULL;
CHECKMEM(v);
@@ -2512,6 +3031,20 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
json_object_put(za);
}
+ xa = json_object_new_array();
+ CHECKMEM(xa);
+
+ if ((flags & STATS_JSON_XFRINS) != 0) {
+ CHECK(dns_zt_apply(view->zonetable, true, NULL,
+ xfrin_jsonrender, xa));
+ }
+
+ if (json_object_array_length(xa) != 0) {
+ json_object_object_add(v, "xfrins", xa);
+ } else {
+ json_object_put(xa);
+ }
+
if ((flags & STATS_JSON_SERVER) != 0) {
json_object *res = NULL;
dns_stats_t *dstats = NULL;
@@ -2895,6 +3428,17 @@ render_json_zones(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
freecb, freecb_args));
}
+static isc_result_t
+render_json_xfrins(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
+ void *arg, unsigned int *retcode, const char **retmsg,
+ const char **mimetype, isc_buffer_t *b,
+ isc_httpdfree_t **freecb, void **freecb_args) {
+ UNUSED(httpd);
+ UNUSED(urlinfo);
+ return (render_json(STATS_JSON_XFRINS, arg, retcode, retmsg, mimetype,
+ b, freecb, freecb_args));
+}
+
static isc_result_t
render_json_mem(const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo,
void *arg, unsigned int *retcode, const char **retmsg,
@@ -3100,6 +3644,9 @@ add_listener(named_server_t *server, named_statschannel_t **listenerp,
isc_httpdmgr_addurl(listener->httpdmgr,
"/xml/v" STATS_XML_VERSION_MAJOR "/zones", false,
render_xml_zones, server);
+ isc_httpdmgr_addurl(listener->httpdmgr,
+ "/xml/v" STATS_XML_VERSION_MAJOR "/xfrins", false,
+ render_xml_xfrins, server);
isc_httpdmgr_addurl(listener->httpdmgr,
"/xml/v" STATS_XML_VERSION_MAJOR "/net", false,
render_xml_net, server);
@@ -3125,6 +3672,9 @@ add_listener(named_server_t *server, named_statschannel_t **listenerp,
isc_httpdmgr_addurl(listener->httpdmgr,
"/json/v" STATS_JSON_VERSION_MAJOR "/zones", false,
render_json_zones, server);
+ isc_httpdmgr_addurl(listener->httpdmgr,
+ "/json/v" STATS_JSON_VERSION_MAJOR "/xfrins", false,
+ render_json_xfrins, server);
isc_httpdmgr_addurl(listener->httpdmgr,
"/json/v" STATS_JSON_VERSION_MAJOR "/net", false,
render_json_net, server);
diff --git a/bin/named/transportconf.c b/bin/named/transportconf.c
index f24aab11dd..d1736d0726 100644
--- a/bin/named/transportconf.c
+++ b/bin/named/transportconf.c
@@ -120,11 +120,13 @@ add_doh_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
dns_transport_set_tls_versions);
parse_transport_option(doh, transport, "ciphers",
dns_transport_set_ciphers);
+ parse_transport_option(doh, transport, "cipher-suites",
+ dns_transport_set_cipher_suites);
parse_transport_bool_option(
doh, transport, "prefer-server-ciphers",
- dns_transport_set_prefer_server_ciphers)
- parse_transport_option(doh, transport, "ca-file",
- dns_transport_set_cafile);
+ dns_transport_set_prefer_server_ciphers);
+ parse_transport_option(doh, transport, "ca-file",
+ dns_transport_set_cafile);
parse_transport_option(doh, transport, "remote-hostname",
dns_transport_set_remote_hostname);
}
@@ -172,11 +174,13 @@ add_tls_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
dns_transport_set_tls_versions);
parse_transport_option(tls, transport, "ciphers",
dns_transport_set_ciphers);
+ parse_transport_option(tls, transport, "cipher-suites",
+ dns_transport_set_cipher_suites);
parse_transport_bool_option(
tls, transport, "prefer-server-ciphers",
- dns_transport_set_prefer_server_ciphers)
- parse_transport_option(tls, transport, "ca-file",
- dns_transport_set_cafile);
+ dns_transport_set_prefer_server_ciphers);
+ parse_transport_option(tls, transport, "ca-file",
+ dns_transport_set_cafile);
parse_transport_option(tls, transport, "remote-hostname",
dns_transport_set_remote_hostname);
}
diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c
index fa34b4c7d4..c45051b42a 100644
--- a/bin/named/zoneconf.c
+++ b/bin/named/zoneconf.c
@@ -866,8 +866,8 @@ process_notifytype(dns_notifytype_t ntype, dns_zonetype_t ztype,
isc_result_t
named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
- dns_kasplist_t *kasplist, dns_zone_t *zone,
- dns_zone_t *raw) {
+ dns_kasplist_t *kasplist, dns_keystorelist_t *keystorelist,
+ dns_zone_t *zone, dns_zone_t *raw) {
isc_result_t result;
const char *zname;
dns_rdataclass_t zclass;
@@ -885,7 +885,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
uint32_t count;
unsigned int dbargc;
char **dbargv;
- static char default_dbtype[] = "rbt";
+ static char default_dbtype[] = ZONEDB_DEFAULT;
static char dlz_dbtype[] = "dlz";
char *cpval = default_dbtype;
isc_mem_t *mctx = dns_zone_getmctx(zone);
@@ -1576,6 +1576,8 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
filename = cfg_obj_asstring(obj);
CHECK(dns_zone_setkeydirectory(zone, filename));
}
+ /* Also save a reference to the keystore list. */
+ dns_zone_setkeystores(zone, keystorelist);
obj = NULL;
result = named_config_get(maps, "sig-signing-signatures", &obj);
@@ -2014,13 +2016,7 @@ named_zone_inlinesigning(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
}
maps[i] = NULL;
- /* "inline-signing" is a zone-only clause, so look in maps[0] only. */
- res = cfg_map_get(maps[0], "inline-signing", &signing);
- if (res == ISC_R_SUCCESS && cfg_obj_isboolean(signing)) {
- return (cfg_obj_asboolean(signing));
- }
-
- /* If inline-signing is not set, check the value in dnssec-policy. */
+ /* Check the value in dnssec-policy. */
policy = NULL;
res = named_config_get(maps, "dnssec-policy", &policy);
/* If no dnssec-policy found, then zone is not using inline-signing. */
@@ -2039,5 +2035,15 @@ named_zone_inlinesigning(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
inline_signing = dns_kasp_inlinesigning(kasp);
dns_kasp_detach(&kasp);
+ /*
+ * The zone option 'inline-signing' may override the value in
+ * dnssec-policy. This is a zone-only option, so look in maps[0]
+ * only.
+ */
+ res = cfg_map_get(maps[0], "inline-signing", &signing);
+ if (res == ISC_R_SUCCESS && cfg_obj_isboolean(signing)) {
+ return (cfg_obj_asboolean(signing));
+ }
+
return (inline_signing);
}
diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c
index 3e673f493d..3048df8345 100644
--- a/bin/nsupdate/nsupdate.c
+++ b/bin/nsupdate/nsupdate.c
@@ -102,6 +102,8 @@
#define DNSDEFAULTPORT 53
+#define DEFAULT_EDNS_BUFSIZE 1232
+
/* Number of addresses to request from isc_getaddresses() */
#define MAX_SERVERADDRS 4
@@ -175,6 +177,8 @@ static isc_mutex_t answer_lock;
static dns_message_t *answer = NULL;
static uint32_t default_ttl = 0;
static bool default_ttl_set = false;
+static uint32_t lease = 0, keylease = 0;
+static bool lease_set = false, keylease_set = false;
static bool checknames = true;
static bool checksvcb = true;
static const char *resolvconf = RESOLV_CONF;
@@ -275,8 +279,7 @@ fatal(const char *format, ...) {
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
- isc__tls_setfatalmode();
- exit(1);
+ _exit(EXIT_FAILURE);
}
static void
@@ -364,7 +367,8 @@ reset_system(void) {
if (updatemsg != NULL) {
dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
} else {
- dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER, &updatemsg);
+ dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
+ &updatemsg);
}
updatemsg->opcode = dns_opcode_update;
if (usegsstsig) {
@@ -378,13 +382,13 @@ reset_system(void) {
}
static bool
-parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac,
+parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac_alg,
uint16_t *digestbitsp) {
uint16_t digestbits = 0;
isc_result_t result;
char buf[20];
- REQUIRE(hmac != NULL);
+ REQUIRE(hmac_alg != NULL);
REQUIRE(hmacstr != NULL);
if (len >= sizeof(buf)) {
@@ -396,9 +400,9 @@ parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac,
strlcpy(buf, hmacstr, ISC_MIN(len + 1, sizeof(buf)));
if (strcasecmp(buf, "hmac-md5") == 0) {
- *hmac = DST_ALG_HMACMD5;
+ *hmac_alg = DST_ALG_HMACMD5;
} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
- *hmac = DST_ALG_HMACMD5;
+ *hmac_alg = DST_ALG_HMACMD5;
result = isc_parse_uint16(&digestbits, &buf[9], 10);
if (result != ISC_R_SUCCESS || digestbits > 128) {
error("digest-bits out of range [0..128]");
@@ -406,9 +410,9 @@ parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac,
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha1") == 0) {
- *hmac = DST_ALG_HMACSHA1;
+ *hmac_alg = DST_ALG_HMACSHA1;
} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
- *hmac = DST_ALG_HMACSHA1;
+ *hmac_alg = DST_ALG_HMACSHA1;
result = isc_parse_uint16(&digestbits, &buf[10], 10);
if (result != ISC_R_SUCCESS || digestbits > 160) {
error("digest-bits out of range [0..160]");
@@ -416,9 +420,9 @@ parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac,
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha224") == 0) {
- *hmac = DST_ALG_HMACSHA224;
+ *hmac_alg = DST_ALG_HMACSHA224;
} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
- *hmac = DST_ALG_HMACSHA224;
+ *hmac_alg = DST_ALG_HMACSHA224;
result = isc_parse_uint16(&digestbits, &buf[12], 10);
if (result != ISC_R_SUCCESS || digestbits > 224) {
error("digest-bits out of range [0..224]");
@@ -426,9 +430,9 @@ parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac,
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha256") == 0) {
- *hmac = DST_ALG_HMACSHA256;
+ *hmac_alg = DST_ALG_HMACSHA256;
} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
- *hmac = DST_ALG_HMACSHA256;
+ *hmac_alg = DST_ALG_HMACSHA256;
result = isc_parse_uint16(&digestbits, &buf[12], 10);
if (result != ISC_R_SUCCESS || digestbits > 256) {
error("digest-bits out of range [0..256]");
@@ -436,9 +440,9 @@ parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac,
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha384") == 0) {
- *hmac = DST_ALG_HMACSHA384;
+ *hmac_alg = DST_ALG_HMACSHA384;
} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
- *hmac = DST_ALG_HMACSHA384;
+ *hmac_alg = DST_ALG_HMACSHA384;
result = isc_parse_uint16(&digestbits, &buf[12], 10);
if (result != ISC_R_SUCCESS || digestbits > 384) {
error("digest-bits out of range [0..384]");
@@ -446,9 +450,9 @@ parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac,
}
*digestbitsp = (digestbits + 7) & ~0x7U;
} else if (strcasecmp(buf, "hmac-sha512") == 0) {
- *hmac = DST_ALG_HMACSHA512;
+ *hmac_alg = DST_ALG_HMACSHA512;
} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
- *hmac = DST_ALG_HMACSHA512;
+ *hmac_alg = DST_ALG_HMACSHA512;
result = isc_parse_uint16(&digestbits, &buf[12], 10);
if (result != ISC_R_SUCCESS || digestbits > 512) {
error("digest-bits out of range [0..512]");
@@ -488,7 +492,7 @@ setup_keystr(void) {
dns_fixedname_t fkeyname;
dns_name_t *mykeyname = NULL;
char *name = NULL;
- dst_algorithm_t hmac;
+ dst_algorithm_t hmac_alg;
uint16_t digestbits = 0;
mykeyname = dns_fixedname_initname(&fkeyname);
@@ -507,11 +511,11 @@ setup_keystr(void) {
}
name = secretstr;
secretstr = n + 1;
- if (!parse_hmac(keystr, s - keystr, &hmac, &digestbits)) {
- exit(1);
+ if (!parse_hmac(keystr, s - keystr, &hmac_alg, &digestbits)) {
+ exit(EXIT_FAILURE);
}
} else {
- hmac = DST_ALG_HMACMD5;
+ hmac_alg = DST_ALG_HMACMD5;
name = keystr;
n = s;
}
@@ -538,8 +542,8 @@ setup_keystr(void) {
secretlen = isc_buffer_usedlength(&secretbuf);
debug("keycreate");
- result = dns_tsigkey_create(mykeyname, hmac, secret, secretlen, gmctx,
- &tsigkey);
+ result = dns_tsigkey_create(mykeyname, hmac_alg, secret, secretlen,
+ gmctx, &tsigkey);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "could not create key from %s: %s\n", keystr,
isc_result_totext(result));
@@ -622,7 +626,7 @@ static void
setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
dst_key_t *dstkey = NULL;
isc_result_t result;
- dst_algorithm_t hmac = DST_ALG_UNKNOWN;
+ dst_algorithm_t hmac_alg = DST_ALG_UNKNOWN;
debug("Creating key...");
@@ -658,7 +662,7 @@ setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
case DST_ALG_HMACSHA256:
case DST_ALG_HMACSHA384:
case DST_ALG_HMACSHA512:
- hmac = dst_key_alg(dstkey);
+ hmac_alg = dst_key_alg(dstkey);
break;
default:
dst_key_attach(dstkey, &sig0key);
@@ -666,9 +670,9 @@ setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
return;
}
- result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmac, dstkey,
- false, false, NULL, 0, 0, mctx,
- &tsigkey);
+ result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmac_alg,
+ dstkey, false, false, NULL, 0, 0,
+ mctx, &tsigkey);
dst_key_free(&dstkey);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "could not create key from %s: %s\n", keyfile,
@@ -798,7 +802,7 @@ create_name(const char *str, char *namedata, size_t len, dns_name_t *name) {
}
static void
-setup_system(void) {
+setup_system(void *arg ISC_ATTR_UNUSED) {
isc_result_t result;
isc_sockaddr_t bind_any, bind_any6;
isc_sockaddrlist_t *nslist;
@@ -919,7 +923,7 @@ setup_system(void) {
irs_resconf_destroy(&resconf);
- result = dns_dispatchmgr_create(gmctx, netmgr, &dispatchmgr);
+ result = dns_dispatchmgr_create(gmctx, loopmgr, netmgr, &dispatchmgr);
check_result(result, "dns_dispatchmgr_create");
result = dst_lib_init(gmctx, NULL);
@@ -1049,7 +1053,7 @@ pre_parse_args(int argc, char **argv) {
"[-A tlscafile] [-H tlshostname] "
"[-O] ] [-v] [-V] [-P] [-T] [-4 | -6] "
"[filename]\n");
- exit(1);
+ exit(EXIT_FAILURE);
case 'P':
for (t = 0xff00; t <= 0xfffe; t++) {
@@ -1087,7 +1091,7 @@ pre_parse_args(int argc, char **argv) {
}
}
if (doexit) {
- exit(0);
+ exit(EXIT_SUCCESS);
}
isc_commandline_reset = true;
isc_commandline_index = 1;
@@ -1162,7 +1166,7 @@ parse_args(int argc, char **argv) {
"bad library debug value "
"'%s'\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
logdebuglevel = i;
break;
@@ -1193,7 +1197,7 @@ parse_args(int argc, char **argv) {
"bad port number "
"'%s'\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
case 'S':
@@ -1205,7 +1209,7 @@ parse_args(int argc, char **argv) {
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "bad timeout '%s'\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (timeout == 0) {
timeout = UINT_MAX;
@@ -1217,7 +1221,7 @@ parse_args(int argc, char **argv) {
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "bad udp timeout '%s'\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
case 'r':
@@ -1226,7 +1230,7 @@ parse_args(int argc, char **argv) {
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "bad udp retries '%s'\n",
isc_commandline_argument);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -1237,19 +1241,19 @@ parse_args(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option: %c\n", argv[0],
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
if (keyfile != NULL && keystr != NULL) {
fprintf(stderr, "%s: cannot specify both -k and -y\n", argv[0]);
- exit(1);
+ exit(EXIT_FAILURE);
}
#if HAVE_GSSAPI
if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
argv[0]);
- exit(1);
+ exit(EXIT_FAILURE);
}
#else /* HAVE_GSSAPI */
if (usegsstsig) {
@@ -1257,7 +1261,7 @@ parse_args(int argc, char **argv) {
"%s: cannot specify -g or -o, "
"program not linked with GSS API Library\n",
argv[0]);
- exit(1);
+ exit(EXIT_FAILURE);
}
#endif /* HAVE_GSSAPI */
@@ -1270,14 +1274,14 @@ parse_args(int argc, char **argv) {
"%s: cannot specify the -K option without"
"the -E option, and vice versa.\n",
argv[0]);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (tls_ca_file != NULL && tls_always_verify_remote == false) {
fprintf(stderr,
"%s: cannot specify the -A option in "
"conjuction with the -O option.\n",
argv[0]);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -1291,7 +1295,7 @@ parse_args(int argc, char **argv) {
fprintf(stderr, "could not open '%s': %s\n",
argv[isc_commandline_index],
isc_result_totext(result));
- exit(1);
+ exit(EXIT_FAILURE);
}
}
if (!force_interactive) {
@@ -1517,6 +1521,90 @@ evaluate_prereq(char *cmdline) {
return (make_prereq(cmdline, ispositive, isrrset));
}
+static void
+updateopt(void) {
+ isc_result_t result;
+ dns_ednsopt_t ednsopts[1];
+ unsigned char ul[8];
+ unsigned int count = 0;
+
+ if (lease_set) {
+ isc_buffer_t b;
+ INSIST(count < ARRAY_SIZE(ednsopts));
+ ednsopts[count++] = (dns_ednsopt_t){ .code = DNS_OPT_UL,
+ .length = keylease_set ? 8
+ : 4,
+ .value = ul };
+
+ isc_buffer_init(&b, ul, sizeof(ul));
+ isc_buffer_putuint32(&b, lease);
+ isc_buffer_putuint32(&b, keylease);
+ }
+
+ if (count != 0) {
+ dns_rdataset_t *opt = NULL;
+ result = dns_message_buildopt(updatemsg, &opt, 0,
+ DEFAULT_EDNS_BUFSIZE, 0, ednsopts,
+ count);
+ check_result(result, "dns_message_buildopt");
+ result = dns_message_setopt(updatemsg, opt);
+ check_result(result, "dns_message_setopt");
+ } else {
+ result = dns_message_setopt(updatemsg, NULL);
+ check_result(result, "dns_message_setopt");
+ }
+}
+
+static uint16_t
+evaluate_lease(char *cmdline) {
+ char *word;
+ isc_result_t result;
+ uint32_t value1, value2;
+
+ word = nsu_strsep(&cmdline, " \t\r\n");
+ if (word == NULL || *word == 0) {
+ fprintf(stderr, "could not read ttl\n");
+ return (STATUS_SYNTAX);
+ }
+
+ if (!strcasecmp(word, "none")) {
+ lease = 0;
+ lease_set = false;
+ keylease = 0;
+ keylease_set = false;
+ updateopt();
+ return (STATUS_MORE);
+ }
+
+ result = isc_parse_uint32(&value1, word, 10);
+ if (result != ISC_R_SUCCESS) {
+ return (STATUS_SYNTAX);
+ }
+
+ word = nsu_strsep(&cmdline, " \t\r\n");
+ if (word == NULL || *word == 0) {
+ lease = value1;
+ lease_set = true;
+ keylease = 0;
+ keylease_set = false;
+ updateopt();
+ return (STATUS_MORE);
+ }
+
+ result = isc_parse_uint32(&value2, word, 10);
+ if (result != ISC_R_SUCCESS) {
+ return (STATUS_SYNTAX);
+ }
+
+ lease = value1;
+ lease_set = true;
+ keylease = value2;
+ keylease_set = true;
+ updateopt();
+
+ return (STATUS_MORE);
+}
+
static uint16_t
evaluate_server(char *cmdline) {
char *word, *server;
@@ -1633,7 +1721,7 @@ evaluate_key(char *cmdline) {
int secretlen;
unsigned char *secret = NULL;
isc_buffer_t secretbuf;
- dst_algorithm_t hmac = DST_ALG_UNKNOWN;
+ dst_algorithm_t hmac_alg = DST_ALG_UNKNOWN;
uint16_t digestbits = 0;
char *n;
@@ -1647,12 +1735,12 @@ evaluate_key(char *cmdline) {
n = strchr(namestr, ':');
if (n != NULL) {
- if (!parse_hmac(namestr, n - namestr, &hmac, &digestbits)) {
+ if (!parse_hmac(namestr, n - namestr, &hmac_alg, &digestbits)) {
return (STATUS_SYNTAX);
}
namestr = n + 1;
} else {
- hmac = DST_ALG_HMACMD5;
+ hmac_alg = DST_ALG_HMACMD5;
}
isc_buffer_init(&b, namestr, strlen(namestr));
@@ -1684,8 +1772,8 @@ evaluate_key(char *cmdline) {
if (tsigkey != NULL) {
dns_tsigkey_detach(&tsigkey);
}
- result = dns_tsigkey_create(mykeyname, hmac, secret, secretlen, gmctx,
- &tsigkey);
+ result = dns_tsigkey_create(mykeyname, hmac_alg, secret, secretlen,
+ gmctx, &tsigkey);
isc_mem_free(gmctx, secret);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "could not create key from %s %s: %s\n",
@@ -2158,7 +2246,7 @@ show_message(FILE *stream, dns_message_t *msg, const char *description) {
if (bufsz > MAXTEXT) {
fprintf(stderr, "could not allocate large enough "
"buffer to display message\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
if (buf != NULL) {
isc_buffer_free(&buf);
@@ -2221,6 +2309,9 @@ do_next_command(char *cmdline) {
if (strcasecmp(word, "add") == 0) {
return (update_addordelete(cmdline, false));
}
+ if (strcasecmp(word, "lease") == 0) {
+ return (evaluate_lease(cmdline));
+ }
if (strcasecmp(word, "server") == 0) {
return (evaluate_server(cmdline));
}
@@ -2393,7 +2484,7 @@ static void
done_update(void) {
ddebug("done_update()");
- isc_async_current(loopmgr, getinput, NULL);
+ isc_async_current(getinput, NULL);
}
static void
@@ -2470,7 +2561,7 @@ update_completed(void *arg) {
}
LOCK(&answer_lock);
- dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &answer);
+ dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &answer);
result = dns_request_getresponse(request, answer,
DNS_MESSAGEPARSE_PRESERVEORDER);
switch (result) {
@@ -2658,7 +2749,7 @@ recvsoa(void *arg) {
reqinfo = NULL;
ddebug("About to create rcvmsg");
- dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
+ dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
result = dns_request_getresponse(request, rcvmsg,
DNS_MESSAGEPARSE_PRESERVEORDER);
if (result == DNS_R_TSIGERRORSET && servers != NULL) {
@@ -3069,7 +3160,7 @@ start_gssrequest(dns_name_t *primary) {
keyname->attributes.nocompress = true;
rmsg = NULL;
- dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER, &rmsg);
+ dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER, &rmsg);
/* Build first request. */
context = GSS_C_NO_CONTEXT;
@@ -3184,7 +3275,7 @@ recvgss(void *arg) {
isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t));
ddebug("recvgss creating rcvmsg");
- dns_message_create(gmctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
+ dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
result = dns_request_getresponse(request, rcvmsg,
DNS_MESSAGEPARSE_PRESERVEORDER);
@@ -3295,7 +3386,8 @@ start_update(void) {
return;
}
- dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER, &soaquery);
+ dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
+ &soaquery);
if (default_servers) {
soaquery->flags |= DNS_MESSAGEFLAG_RD;
@@ -3475,8 +3567,7 @@ main(int argc, char **argv) {
timeoutms = timeout * 1000;
isc_nm_settimeouts(netmgr, timeoutms, timeoutms, timeoutms, timeoutms);
- setup_system();
-
+ isc_loopmgr_setup(loopmgr, setup_system, NULL);
isc_loopmgr_setup(loopmgr, getinput, NULL);
isc_loopmgr_teardown(loopmgr, shutdown_program, NULL);
isc_loopmgr_run(loopmgr);
@@ -3485,7 +3576,7 @@ main(int argc, char **argv) {
if (seenerror) {
return (2);
- } else {
- return (0);
}
+
+ return (0);
}
diff --git a/bin/nsupdate/nsupdate.rst b/bin/nsupdate/nsupdate.rst
index 88263904ed..b98d70bbff 100644
--- a/bin/nsupdate/nsupdate.rst
+++ b/bin/nsupdate/nsupdate.rst
@@ -323,6 +323,11 @@ The command formats and their meanings are as follows:
By default check-svcb processing is on. If check-svcb processing
fails, the record is not added to the UPDATE message.
+``lease time [keytime]``
+ Set the EDNS Update Lease (UL) option to value to ``time`` and
+ optionally also set the key lease time to ``keytime`` in seconds.
+ If ``time`` is ``none`` the lease times are cleared.
+
``prereq nxdomain domain-name``
This command requires that no resource record of any type exist with the name
``domain-name``.
diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c
index 6e8261c784..1d35ded62b 100644
--- a/bin/rndc/rndc.c
+++ b/bin/rndc/rndc.c
@@ -260,18 +260,11 @@ get_addresses(const char *host, in_port_t port) {
REQUIRE(host != NULL);
- if (*host == '/') {
- result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
- host);
- if (result == ISC_R_SUCCESS) {
- nserveraddrs++;
- }
- } else {
- count = SERVERADDRS - nserveraddrs;
- result = isc_getaddresses(
- host, port, &serveraddrs[nserveraddrs], count, &found);
- nserveraddrs += found;
- }
+ count = SERVERADDRS - nserveraddrs;
+ result = isc_getaddresses(host, port, &serveraddrs[nserveraddrs], count,
+ &found);
+ nserveraddrs += found;
+
if (result != ISC_R_SUCCESS) {
fatal("couldn't get address for '%s': %s", host,
isc_result_totext(result));
@@ -312,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));
@@ -355,7 +347,7 @@ rndc_recvdone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
isccc_sexpr_free(&response);
- isccc_ccmsg_invalidate(ccmsg);
+ isccc_ccmsg_disconnect(ccmsg);
isc_loopmgr_shutdown(loopmgr);
}
@@ -388,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));
@@ -518,11 +509,6 @@ rndc_startconnect(isc_sockaddr_t *addr) {
case AF_INET6:
local = &local6;
break;
- case AF_UNIX:
- /*
- * TODO: support UNIX domain sockets in netgmr.
- */
- fatal("UNIX domain sockets not currently supported");
default:
UNREACHABLE();
}
@@ -944,7 +930,7 @@ main(int argc, char **argv) {
default:
fprintf(stderr, "%s: unhandled option -%c\n", program,
isc_commandline_option);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -1015,6 +1001,8 @@ main(int argc, char **argv) {
isc_loopmgr_run(loopmgr);
+ isccc_ccmsg_invalidate(&rndc_ccmsg);
+
isc_log_destroy(&log);
isc_log_setcontext(NULL);
diff --git a/bin/rndc/rndc.conf b/bin/rndc/rndc.conf
deleted file mode 100644
index 78ee858515..0000000000
--- a/bin/rndc/rndc.conf
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*
- * Sample rndc configuration file.
- */
-
-options {
- default-server localhost;
- default-key "key";
-};
-
-server localhost {
- key "key";
-};
-
-key "cc64b3d1db63fc88d7cb5d2f9f57d258" {
- algorithm hmac-sha256;
- secret "34f88008d07deabbe65bd01f1d233d47";
-};
-
-server "test1" {
- key "cc64b3d1db63fc88d7cb5d2f9f57d258";
- port 5353;
- addresses { 10.53.0.1; };
-};
-
-key "key" {
- algorithm hmac-sha256;
- secret "c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K";
-};
diff --git a/bin/rndc/rndc.rst b/bin/rndc/rndc.rst
index db43974a4b..da9f0710e4 100644
--- a/bin/rndc/rndc.rst
+++ b/bin/rndc/rndc.rst
@@ -440,6 +440,7 @@ Currently supported commands are:
.. option:: zone [class [view]]
If a zone is specified, this command reloads only the given zone.
+ If no zone is specified, the reloading happens asynchronously.
.. program:: rndc
@@ -604,7 +605,8 @@ Currently supported commands are:
refused. If the zone has changed and the ``ixfr-from-differences``
option is in use, the journal file is updated to reflect
changes in the zone. Otherwise, if the zone has changed, any existing
- journal file is removed.
+ journal file is removed. If no zone is specified, the reloading happens
+ asynchronously.
See also :option:`rndc freeze`.
diff --git a/bin/rndc/util.c b/bin/rndc/util.c
index 23b7f3fd57..e0529aa772 100644
--- a/bin/rndc/util.c
+++ b/bin/rndc/util.c
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
@@ -45,6 +46,5 @@ fatal(const char *format, ...) {
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
- isc__tls_setfatalmode();
- exit(1);
+ _exit(EXIT_FAILURE);
}
diff --git a/bin/tests/.gitignore b/bin/tests/.gitignore
index 26185a7889..9a60c2ca80 100644
--- a/bin/tests/.gitignore
+++ b/bin/tests/.gitignore
@@ -3,7 +3,6 @@ nxtify
sdig
*_test
gsstest
-conf.sh
dlopen
keycreate
keydelete
diff --git a/bin/tests/startperf/setup.sh b/bin/tests/startperf/setup.sh
index 66821386d7..775667c4f1 100644
--- a/bin/tests/startperf/setup.sh
+++ b/bin/tests/startperf/setup.sh
@@ -11,20 +11,20 @@
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
-usage () {
- echo "Usage: $0 [-s] []"
- echo " -s: use the same zone file all zones"
- exit 1
+usage() {
+ echo "Usage: $0 [-s] []"
+ echo " -s: use the same zone file all zones"
+ exit 1
}
if [ "$#" -lt 1 -o "$#" -gt 3 ]; then
- usage
+ usage
fi
single_file=""
if [ $1 = "-s" ]; then
- single_file=yes
- shift
+ single_file=yes
+ shift
fi
nzones=$1
@@ -35,9 +35,9 @@ nrecords=5
. ../system/conf.sh
-cat << EOF
+cat < zones/$zonename.db
- echo "zone $zonename { type primary; file \"zones/$zonename.db\"; };"
- fi
+ if [ $single_file ]; then
+ echo "zone $zonename { type primary; file \"smallzone.db\"; };"
+ else
+ [ -d zones ] || mkdir zones
+ $PERL mkzonefile.pl $zonename $nrecords >zones/$zonename.db
+ echo "zone $zonename { type primary; file \"zones/$zonename.db\"; };"
+ fi
done
diff --git a/bin/tests/system/.gitignore b/bin/tests/system/.gitignore
index e2daf1cef5..3c2db219b0 100644
--- a/bin/tests/system/.gitignore
+++ b/bin/tests/system/.gitignore
@@ -13,12 +13,14 @@ named.run
/random.data
/*.log
/*.trs
+/*.xml
/resolve
-/legacy.run.sh
/run.log
/start.sh
/stop.sh
/ifconfig.sh
+/isctest/vars/.ac_vars/*
+!/isctest/vars/.ac_vars/*.in
# Ignore file names with underscore in their name except python or shell files.
# This is done to ignore the temporary directories and symlinks created by the
@@ -26,3 +28,4 @@ named.run
/*_*
!/*_*.py
!/*_*.sh
+!/_common
diff --git a/bin/tests/system/Makefile.am b/bin/tests/system/Makefile.am
index 44282372de..842bb5db8b 100644
--- a/bin/tests/system/Makefile.am
+++ b/bin/tests/system/Makefile.am
@@ -24,6 +24,8 @@ LDADD += \
$(LIBDNS_LIBS)
if HAVE_PERL
+if HAVE_PYTHON
+if HAVE_PYTEST
noinst_PROGRAMS = \
feature-test \
@@ -68,23 +70,14 @@ rpz_dnsrps_LDADD = \
$(LIBDNS_LIBS) \
$(DLOPEN_LIBS)
-TESTS =
-
-if HAVE_PERLMOD_TIME_HIRES
-TESTS += serve-stale
-endif HAVE_PERLMOD_TIME_HIRES
-
-if HAVE_PERLMOD_NET_DNS
-TESTS += \
- rpzrecurse
-endif HAVE_PERLMOD_NET_DNS
-
-if HAVE_LIBNGHTTP2
-TESTS += \
- doth
-endif
-
-TESTS += \
+# Longer running tests are listed (and executed) first to take the most
+# advantage of parallel execution.
+TESTS = \
+ rpz \
+ rpzrecurse \
+ serve-stale \
+ timeouts \
+ upforwd \
acl \
additional \
addzone \
@@ -96,13 +89,21 @@ TESTS += \
case \
catz \
cds \
+ chain \
checkconf \
+ checkds \
checknames \
checkzone \
+ cookie \
database \
dialup \
+ digdelv \
+ dispatch \
dlzexternal \
dns64 \
+ dnssec \
+ dnstap \
+ doth \
dsdigest \
dyndb \
ecdsa \
@@ -111,18 +112,23 @@ TESTS += \
emptyzones \
enginepkcs11 \
filter-aaaa \
+ fetchlimit \
formerr \
+ forward \
geoip2 \
glue \
idna \
include-multiplecfg \
inline \
integrity \
+ ixfr \
hooks \
host \
journal \
+ kasp \
keepalive \
keyfromlabel \
+ ksr \
legacy \
limits \
logfileconfig \
@@ -131,28 +137,41 @@ TESTS += \
metadata \
mirror \
mkeys \
+ multisigner \
names \
notify \
nsec3 \
nslookup \
+ nsupdate \
+ nzd2nzf \
padding \
pending \
+ proxy \
+ pipelined \
+ qmin \
+ reclimit \
redirect \
+ resolver \
rndc \
rootkeysentinel \
- rpz \
+ rpzextra \
rrchecker \
rrl \
rrsetorder \
rsabigexponent \
runtime \
sfcache \
+ shutdown \
smartsign \
sortlist \
spf \
staticstub \
+ statistics \
+ statschannel \
+ stress \
stub \
synthfromdnssec \
+ tcp \
tools \
transport-acl \
tsig \
@@ -162,62 +181,21 @@ TESTS += \
verify \
views \
wildcard \
+ xfer \
xferquota \
+ zero \
zonechecks
-if HAVE_LMDB
-TESTS += nzd2nzf
-endif # HAVE_LMDB
-
-if HAVE_PERLMOD_NET_DNS
-
-TESTS += \
- fetchlimit \
- ixfr \
- nsupdate \
- resolver \
- statistics \
- stress \
- upforwd \
- zero
-
-if HAVE_DNSTAP
-TESTS += dnstap
-endif
-
-if HAVE_PERLMOD_FILE_FETCH
-TESTS += statschannel
-endif HAVE_PERLMOD_FILE_FETCH
-
-if HAVE_PERLMOD_DIGEST_HMAC
-TESTS += xfer
-endif HAVE_PERLMOD_DIGEST_HMAC
-
-if HAVE_PERLMOD_NET_DNS_NAMESERVER
-TESTS += reclimit
-endif HAVE_PERLMOD_NET_DNS_NAMESERVER
-
-endif HAVE_PERLMOD_NET_DNS
-
-if HAVE_PYTHON
-TESTS += kasp multisigner tcp pipelined
-
-if HAVE_PYTEST
-TESTS += checkds dispatch rpzextra shutdown timeouts
-endif
-
-if HAVE_PYMOD_DNS
-TESTS += qmin cookie
-if HAVE_PERLMOD_NET_DNS
-TESTS += digdelv dnssec forward
-if HAVE_PERLMOD_NET_DNS_NAMESERVER
-TESTS += chain
-endif HAVE_PERLMOD_NET_DNS_NAMESERVER
-endif HAVE_PERLMOD_NET_DNS
-endif HAVE_PYMOD_DNS
-
-endif HAVE_PYTHON
-
+else !HAVE_PYTEST
+check:
+ echo pytest is not available, no tests were ran
+ exit 1
+endif !HAVE_PYTEST
+else !HAVE_PYTHON
+check:
+ echo Python is not available, no tests were ran
+ exit 1
+endif !HAVE_PYTHON
else !HAVE_PERL
check:
echo Perl is not available, no tests were ran
@@ -232,12 +210,9 @@ LOG_DRIVER_V_1 = --verbose yes
LOG_DRIVER = $(srcdir)/custom-test-driver
AM_LOG_DRIVER_FLAGS = $(LOG_DRIVER_V)
-LOG_COMPILER = $(builddir)/legacy.run.sh
-AM_LOG_FLAGS = -r
-
-$(TESTS): legacy.run.sh
+LOG_COMPILER = $(srcdir)/run.sh
test-local: check
clean-local::
- -find $(builddir) -maxdepth 1 -type d -name "*_*" | xargs rm -rf
+ -find -L . -mindepth 1 -maxdepth 1 -type d -name "*_*" -and -not -name "_common" -exec rm -rf {} \;
diff --git a/bin/tests/system/README b/bin/tests/system/README
deleted file mode 100644
index 6c5bae15c1..0000000000
--- a/bin/tests/system/README
+++ /dev/null
@@ -1,778 +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.
-
-Introduction
-===
-This directory holds a simple test environment for running bind9 system tests
-involving multiple name servers.
-
-With the exception of "common" (which holds configuration information common to
-multiple tests), each directory holds a set of scripts and configuration
-files to test different parts of BIND. The directories are named for the
-aspect of BIND they test, for example:
-
- dnssec/ DNSSEC tests
- forward/ Forwarding tests
- glue/ Glue handling tests
-
-etc.
-
-Typically each set of tests sets up 2-5 name servers and then performs one or
-more tests against them. Within the test subdirectory, each name server has a
-separate subdirectory containing its configuration data. These subdirectories
-are named "nsN" or "ansN" (where N is a number between 1 and 8, e.g. ns1, ans2
-etc.)
-
-The tests are completely self-contained and do not require access to the real
-DNS. Generally, one of the test servers (usually ns1) is set up as a root
-nameserver and is listed in the hints file of the others.
-
-
-Preparing to Run the Tests
-===
-To enable all servers to run on the same machine, they bind to separate virtual
-IP addresses on the loopback interface. ns1 runs on 10.53.0.1, ns2 on
-10.53.0.2, etc. Before running any tests, you must set up these addresses by
-running the command
-
- sh ifconfig.sh up
-
-as root. The interfaces can be removed by executing the command:
-
- sh ifconfig.sh down
-
-... also as root.
-
-The servers use unprivileged ports (above 1024) instead of the usual port 53,
-so they can be run without root privileges once the interfaces have been set
-up.
-
-
-Note for MacOS Users
----
-If you wish to make the interfaces survive across reboots, copy
-org.isc.bind.system and org.isc.bind.system.plist to /Library/LaunchDaemons
-then run
-
- launchctl load /Library/LaunchDaemons/org.isc.bind.system.plist
-
-... as root.
-
-
-Running the System Tests with pytest
-===
-
-The pytest system test runner is currently in development, but it is the
-recommended way to run tests. Please report issues to QA.
-
-Running an Individual Test
----
-
-pytest -k
-
-Note that in comparison to the legacy test runner, some additional tests might
-be picked up when specifying just the system test directory name. To check
-which tests will be executed, you can use the `--collect-only` option. You
-might also be able to find a more specific test name to provide to ensure only
-your desired test is executed. See help for `-k` option in `pytest --help` for
-more info.
-
-It is also possible to run a single individual pytest test case. For example,
-you can use the name test_sslyze_dot to execute just the test_sslyze_dot()
-function from doth/tests_sslyze.py. The entire needed setup and teardown will
-be handled by the framework.
-
-Running All the System Tests
----
-
-Issuing plain `pytest` command without any argument will execute all tests
-sequenatially. To execute them in parallel, ensure you have pytest-xdist
-installed and run:
-
-pytest -n
-
-
-Running the System Tests Using the Legacy Runner
-===
-
-!!! WARNING !!!
----
-The legacy way to run system tests is currently being reworked into a pytest
-system test runner described in the previous section. The contents of this
-section might be out of date and no longer applicable. Please try and use the
-pytest runner if possible and report issues and missing features.
-
-Running an Individual Test
----
-The tests can be run individually using the following command:
-
- sh legacy.run.sh [flags] []
-
-e.g.
-
- sh legacy.run.sh [flags] notify
-
-Optional flags are:
-
- -k Keep servers running after the test completes. Each test
- usually starts a number of nameservers, either instances
- of the "named" being tested, or custom servers (written in
- Python or Perl) that feature test-specific behavior. The
- servers are automatically started before the test is run
- and stopped after it ends. This flag leaves them running
- at the end of the test, so that additional queries can be
- sent by hand. To stop the servers afterwards, use the
- command "sh stop.sh ".
-
- -n Noclean - do not remove the output files if the test
- completes successfully. By default, files created by the
- test are deleted if it passes; they are not deleted if the
- test fails.
-
- -p Sets the range of ports used by the test. A block of 100
- ports is available for each test, the number given to the
- "-p" switch being the number of the start of that block
- (e.g. "-p 7900" will mean that the test is able to use
- ports 7900 through 7999). If not specified, the test will
- have ports 5000 to 5099 available to it.
-
-Arguments are:
-
- test-name Mandatory. The name of the test, which is the name of the
- subdirectory in bin/tests/system holding the test files.
-
- test-arguments Optional arguments that are passed to each of the test's
- scripts.
-
-
-Running All The System Tests
----
-To run all the system tests, enter the command:
-
- make [-j numproc] test
-
-The optional "numproc" argument specifies the maximum number of tests that can
-run in parallel. The default is 1, which means that all of the tests run
-sequentially. If greater than 1, up to "numproc" tests will run simultaneously,
-new tests being started as tests finish. Each test will get a unique set of
-ports, so there is no danger of tests interfering with one another. Parallel
-running will reduce the total time taken to run the BIND system tests, but will
-mean that the output from all the tests sent to the screen will be mixed up
-with one another.
-
-In this case, retention of the output files after a test completes successfully
-is specified by setting the environment variable SYSTEMTEST_NO_CLEAN to 1 prior
-to running make, e.g.
-
- SYSTEMTEST_NO_CLEAN=1 make [-j numproc] test
-
-while setting environment variable SYSTEMTEST_FORCE_COLOR to 1 forces system
-test output to be printed in color.
-
-
-Format of Test Output
----
-All output from the system tests is in the form of lines with the following
-structure:
-
- :: [()]
-
-e.g.
-
- I:catz:checking that dom1.example is not served by primary (1)
-
-The meanings of the fields are as follows:
-
-
-This indicates the type of message. This is one of:
-
- S Start of the test
- A Start of test (retained for backwards compatibility)
- T Start of test (retained for backwards compatibility)
- E End of the test
- I Information. A test will typically output many of these messages
- during its run, indicating test progress. Note that such a message may
- be of the form "I:testname:failed", indicating that a sub-test has
- failed.
- R Result. Each test will result in one such message, which is of the
- form:
-
- R::
-
- where is one of:
-
- PASS The test passed
- FAIL The test failed
- SKIPPED The test was not run, usually because some
- prerequisites required to run the test are missing.
-
-
-This is the name of the test from which the message emanated, which is also the
-name of the subdirectory holding the test files.
-
-
-This is text output by the test during its execution.
-
-()
-If present, this will correlate with a file created by the test. The tests
-execute commands and route the output of each command to a file. The name of
-this file depends on the command and the test, but will usually be of the form:
-
- .out.
-
-e.g. nsupdate.out.test28, dig.out.q3. This aids diagnosis of problems by
-allowing the output that caused the problem message to be identified.
-
-
-Re-Running the Tests
----
-If there is a requirement to re-run a test (or the entire test suite), the
-files produced by the tests should be deleted first. Normally, these files are
-deleted if the test succeeds but are retained on error. The legacy.run.sh
-script automatically calls a given test's clean.sh script before invoking its
-setup.sh script.
-
-Deletion of the files produced by the set of tests (e.g. after the execution of
-make) can be carried out using the command:
-
- sh cleanall.sh
-
-or
-
- make testclean
-
-(Note that the Makefile has two other targets for cleaning up files: "clean"
-will delete all the files produced by the tests, as well as the object and
-executable files used by the tests. "distclean" does all the work of "clean"
-as well as deleting configuration files produced by "configure".)
-
-
-Developer Notes
-===
-This section is intended for developers writing new tests.
-
-
-Overview
----
-As noted above, each test is in a separate directory. To interact with the
-test framework, the directories contain the following standard files:
-
-prereq.sh Run at the beginning to determine whether the test can be run at
- all; if not, we see a R:SKIPPED result. This file is optional:
- if not present, the test is assumed to have all its prerequisites
- met.
-
-setup.sh Run after prereq.sh, this sets up the preconditions for the tests.
- Although optional, virtually all tests will require such a file to
- set up the ports they should use for the test.
-
-tests.sh Runs the actual tests. This file is mandatory.
-
-clean.sh Run at the end to clean up temporary files, but only if the test
- was completed successfully and its running was not inhibited by the
- "-n" switch being passed to "legacy.run.sh". Otherwise the
- temporary files are left in place for inspection.
-
-ns These subdirectories contain test name servers that can be queried
- or can interact with each other. The value of N indicates the
- address the server listens on: for example, ns2 listens on
- 10.53.0.2, and ns4 on 10.53.0.4. All test servers use an
- unprivileged port, so they don't need to run as root. These
- servers log at the highest debug level and the log is captured in
- the file "named.run".
-
-ans Like ns[X], but these are simple mock name servers implemented in
- Perl or Python. They are generally programmed to misbehave in ways
- named would not so as to exercise named's ability to interoperate
- with badly behaved name servers.
-
-
-Port Usage
----
-In order for the tests to run in parallel, each test requires a unique set of
-ports. These are specified by the "-p" option passed to "legacy.run.sh", which
-sets environment variables that the scripts listed above can reference.
-
-The convention used in the system tests is that the number passed is the start
-of a range of 100 ports. The test is free to use the ports as required,
-although the first ten ports in the block are named and generally tests use the
-named ports for their intended purpose. The names of the environment variables
-are:
-
- PORT Number to be used for the query port.
- CONTROLPORT Number to be used as the RNDC control port.
- EXTRAPORT1 - EXTRAPORT8 Eight port numbers that can be used as needed.
-
-Two other environment variables are defined:
-
- LOWPORT The lowest port number in the range.
- HIGHPORT The highest port number in the range.
-
-Since port ranges usually start on a boundary of 10, the variables are set such
-that the last digit of the port number corresponds to the number of the
-EXTRAPORTn variable. For example, if the port range were to start at 5200, the
-port assignments would be:
-
- PORT = 5200
- EXTRAPORT1 = 5201
- :
- EXTRAPORT8 = 5208
- CONTROLPORT = 5209
- LOWPORT = 5200
- HIGHPORT = 5299
-
-When running tests in parallel (i.e. giving a value of "numproc" greater than 1
-in the "make" command listed above), it is guaranteed that each
-test will get a set of unique port numbers.
-
-
-Writing a Test
----
-The test framework requires up to four shell scripts (listed above) as well as
-a number of nameserver instances to run. Certain expectations are put on each
-script:
-
-
-General
----
-1. Each of the four scripts will be invoked with the command
-
- (cd ; sh