Compare commits
57
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a28b46d60c | ||
|
|
2524abe0b7 | ||
|
|
59bb3e9b72 | ||
|
|
bb991c356f | ||
|
|
663047ac8b | ||
|
|
386890a161 | ||
|
|
c1723b2535 | ||
|
|
1596d3b498 | ||
|
|
44b49955e1 | ||
|
|
b2028e26da | ||
|
|
eb6a8b47d7 | ||
|
|
31e8b2b13c | ||
|
|
705810d577 | ||
|
|
157eb5cd30 | ||
|
|
551acb44f4 | ||
|
|
2389fcb4dc | ||
|
|
f47e697da3 | ||
|
|
7f43520893 | ||
|
|
a224754d59 | ||
|
|
6801899134 | ||
|
|
49b42e7fcc | ||
|
|
3a24eacbb6 | ||
|
|
8e74974ce1 | ||
|
|
899f9440c0 | ||
|
|
32da119ed8 | ||
|
|
0c350fbcb7 | ||
|
|
503e2dff64 | ||
|
|
d02a58adc0 | ||
|
|
01c4c3301e | ||
|
|
2df610a882 | ||
|
|
d151a10f30 | ||
|
|
5826c85a22 | ||
|
|
715b7a7cec | ||
|
|
c6d5d5c88f | ||
|
|
7af9883b48 | ||
|
|
3377bc4b02 | ||
|
|
3d121ede6c | ||
|
|
3d264dbe81 | ||
|
|
0c898084cd | ||
|
|
84463f33bf | ||
|
|
6ebce9425e | ||
|
|
a9aa295f1f | ||
|
|
8ef01c7b50 | ||
|
|
6325c0993a | ||
|
|
4167eba3c3 | ||
|
|
7c8179c503 | ||
|
|
03727c1462 | ||
|
|
0d06a62dd1 | ||
|
|
4154677f2e | ||
|
|
281531d82b | ||
|
|
ec72d1100d | ||
|
|
5f5721aa11 | ||
|
|
d07c3d6c8c | ||
|
|
ddd0d356e5 | ||
|
|
262f087bcf | ||
|
|
ec9f80cabc | ||
|
|
5fedd21e16 |
+217
-203
@@ -15,11 +15,10 @@ variables:
|
||||
BUILD_PARALLEL_JOBS: 6
|
||||
TEST_PARALLEL_JOBS: 6
|
||||
|
||||
MAKE_COMMAND: make
|
||||
CONFIGURE: ./configure
|
||||
CLANG: clang-9
|
||||
SCAN_BUILD: scan-build-9
|
||||
SYMBOLIZER: /usr/lib/llvm-9/bin/llvm-symbolizer
|
||||
CLANG: clang-10
|
||||
SCAN_BUILD: scan-build-10
|
||||
SYMBOLIZER: /usr/lib/llvm-10/bin/llvm-symbolizer
|
||||
ASAN_SYMBOLIZER_PATH: "$SYMBOLIZER"
|
||||
CLANG_FORMAT: clang-format-10
|
||||
|
||||
@@ -27,6 +26,7 @@ variables:
|
||||
|
||||
# Pass run-time flags to AddressSanitizer to get core dumps on error.
|
||||
ASAN_OPTIONS_COMMON: abort_on_error=1:disable_coredump=0:unmap_shadow_on_exit=1
|
||||
TSAN_OPTIONS_COMMON: "second_deadlock_stack=1 history_size=7 log_exe_name=true log_path=tsan external_symbolizer_path=$SYMBOLIZER"
|
||||
|
||||
TARBALL_COMPRESSOR: xz
|
||||
TARBALL_EXTENSION: xz
|
||||
@@ -98,10 +98,6 @@ stages:
|
||||
image: "$CI_REGISTRY_IMAGE:debian-stretch-amd64"
|
||||
<<: *linux_amd64
|
||||
|
||||
.debian-stretch-i386: &debian_stretch_i386_image
|
||||
image: "$CI_REGISTRY_IMAGE:debian-stretch-i386"
|
||||
<<: *linux_i386
|
||||
|
||||
.debian-buster-amd64: &debian_buster_amd64_image
|
||||
image: "$CI_REGISTRY_IMAGE:debian-buster-amd64"
|
||||
<<: *linux_amd64
|
||||
@@ -136,17 +132,15 @@ stages:
|
||||
image: "$CI_REGISTRY_IMAGE:ubuntu-xenial-amd64"
|
||||
<<: *linux_amd64
|
||||
|
||||
.ubuntu-xenial-i386: &ubuntu_xenial_i386_image
|
||||
image: "$CI_REGISTRY_IMAGE:ubuntu-xenial-i386"
|
||||
<<: *linux_i386
|
||||
|
||||
.ubuntu-bionic-amd64: &ubuntu_bionic_amd64_image
|
||||
image: "$CI_REGISTRY_IMAGE:ubuntu-bionic-amd64"
|
||||
<<: *linux_amd64
|
||||
|
||||
.ubuntu-bionic-i386: &ubuntu_bionic_i386_image
|
||||
image: "$CI_REGISTRY_IMAGE:ubuntu-bionic-i386"
|
||||
<<: *linux_i386
|
||||
# Base image
|
||||
# This is a meta image that is used as a base for non-specific jobs
|
||||
|
||||
.base: &base_image
|
||||
<<: *debian_buster_amd64_image
|
||||
|
||||
### Job Templates
|
||||
|
||||
@@ -168,12 +162,12 @@ stages:
|
||||
|
||||
.precheck: &precheck_job
|
||||
<<: *default_triggering_rules
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
stage: precheck
|
||||
|
||||
.autoconf: &autoconf_job
|
||||
<<: *release_branch_triggering_rules
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
stage: precheck
|
||||
script:
|
||||
- autoreconf -fi
|
||||
@@ -203,11 +197,11 @@ stages:
|
||||
- test -n "${OOT_BUILD_WORKSPACE}" && mkdir "${OOT_BUILD_WORKSPACE}" && cd "${OOT_BUILD_WORKSPACE}"
|
||||
script:
|
||||
- *configure
|
||||
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} -k all V=1
|
||||
- make -j${BUILD_PARALLEL_JOBS:-1} -k all V=1
|
||||
- test -z "${RUN_MAKE_INSTALL}" || make install
|
||||
- test -z "${RUN_MAKE_INSTALL}" || sh util/check-make-install
|
||||
needs:
|
||||
- job: autoreconf:sid:amd64
|
||||
- job: autoreconf
|
||||
artifacts: true
|
||||
artifacts:
|
||||
untracked: true
|
||||
@@ -237,7 +231,7 @@ stages:
|
||||
- 'Set-Item -path "Env:CL" -value "/MP$([Math]::Truncate($BUILD_PARALLEL_JOBS/2))"'
|
||||
- '& msbuild.exe /maxCpuCount:2 /t:Build /p:Configuration=$VSCONF bind9.sln'
|
||||
needs:
|
||||
- job: autoreconf:sid:amd64
|
||||
- job: autoreconf
|
||||
artifacts: false
|
||||
artifacts:
|
||||
untracked: true
|
||||
@@ -254,7 +248,7 @@ stages:
|
||||
export SLOT=$(sh -x bin/tests/prepare-softhsm2.sh)
|
||||
test -n "${SLOT}" && test "${SLOT}" -gt 0
|
||||
|
||||
.system_test: &system_test_job
|
||||
.system_test_common: &system_test_common
|
||||
<<: *default_triggering_rules
|
||||
stage: system
|
||||
before_script:
|
||||
@@ -263,11 +257,27 @@ stages:
|
||||
script:
|
||||
- ( cd bin/tests/system && make -j${TEST_PARALLEL_JOBS:-1} -k test V=1 )
|
||||
- test -s bin/tests/system/systests.output
|
||||
|
||||
.system_test: &system_test_job
|
||||
<<: *system_test_common
|
||||
artifacts:
|
||||
untracked: true
|
||||
expire_in: "1 day"
|
||||
when: on_failure
|
||||
|
||||
.system_test_tsan: &system_test_tsan_job
|
||||
<<: *system_test_common
|
||||
allow_failure: true
|
||||
after_script:
|
||||
- find bin -name 'tsan.*' -exec python3 util/parse_tsan.py {} \;
|
||||
artifacts:
|
||||
expire_in: "1 day"
|
||||
paths:
|
||||
- bin/tests/system/*/tsan.*
|
||||
- bin/tests/system/*/*/tsan.*
|
||||
- tsan/
|
||||
when: on_failure
|
||||
|
||||
.kyua_report: &kyua_report_html |
|
||||
kyua --logfile /dev/null report-html \
|
||||
--force \
|
||||
@@ -299,7 +309,7 @@ stages:
|
||||
- tags
|
||||
- web
|
||||
|
||||
.unit_test: &unit_test_job
|
||||
.unit_test_common: &unit_test_common
|
||||
<<: *default_triggering_rules
|
||||
stage: unit
|
||||
before_script:
|
||||
@@ -308,40 +318,45 @@ stages:
|
||||
- make unit
|
||||
after_script:
|
||||
- *kyua_report_html
|
||||
|
||||
.unit_test: &unit_test_job
|
||||
<<: *unit_test_common
|
||||
artifacts:
|
||||
untracked: true
|
||||
expire_in: "1 day"
|
||||
when: on_failure
|
||||
|
||||
.unit_test_tsan: &unit_test_tsan_job
|
||||
<<: *unit_test_common
|
||||
allow_failure: true
|
||||
after_script:
|
||||
- *kyua_report_html
|
||||
- find lib -name 'tsan.*' -exec python3 util/parse_tsan.py {} \;
|
||||
artifacts:
|
||||
expire_in: "1 day"
|
||||
paths:
|
||||
- lib/*/tests/tsan.*
|
||||
- tsan/
|
||||
- kyua.log
|
||||
- kyua.results
|
||||
- kyua_html/
|
||||
when: on_failure
|
||||
|
||||
.cppcheck_args: &run_cppcheck |
|
||||
cppcheck --enable=warning,performance,portability,information,missingInclude \
|
||||
--include=config.h \
|
||||
--quiet \
|
||||
--std=c11 \
|
||||
--language=c \
|
||||
--project=compile_commands.json \
|
||||
--error-exitcode=2 \
|
||||
-j ${TEST_PARALLEL_JOBS:-1} \
|
||||
--xml \
|
||||
--output-file=cppcheck.results \
|
||||
--relative-paths="$CI_PROJECT_DIR" \
|
||||
--inline-suppr \
|
||||
--suppressions-list=util/suppressions.txt
|
||||
cppcheck --enable=warning,performance,portability,information,missingInclude --include=config.h --std=c11 --language=c --project=compile_commands.json --error-exitcode=2 -j ${TEST_PARALLEL_JOBS:-1} --xml --output-file=cppcheck.results --relative-paths="$CI_PROJECT_DIR" --inline-suppr --suppressions-list=util/suppressions.txt
|
||||
|
||||
.cppcheck_report: &cppcheck_report_html |
|
||||
cppcheck-htmlreport --title="BIND 9 ($CI_COMMIT_SHORT_SHA) Cppcheck Report" \
|
||||
--file=cppcheck.results \
|
||||
--report-dir=cppcheck_html/
|
||||
cppcheck-htmlreport --title="BIND 9 ($CI_COMMIT_SHORT_SHA) Cppcheck Report" --file=cppcheck.results --report-dir=cppcheck_html/
|
||||
|
||||
.cppcheck: &cppcheck_job
|
||||
<<: *default_triggering_rules
|
||||
stage: postcheck
|
||||
before_script:
|
||||
script:
|
||||
- *configure
|
||||
- (make -nwk all || true) | compiledb
|
||||
- export GCC_VERSION=$(gcc --version | sed -n 's/.*\([0-9]\+\)\.[0-9]\+\.[0-9]\+.*/\1/p')
|
||||
- sed -i "/gcc\",/a\"-DCPPCHECK\", \"-D__STDC__\", \"-D__GNUC__=${GCC_VERSION}\"," compile_commands.json
|
||||
script:
|
||||
- *run_cppcheck
|
||||
after_script:
|
||||
- *cppcheck_report_html
|
||||
artifacts:
|
||||
paths:
|
||||
@@ -350,15 +365,18 @@ stages:
|
||||
- cppcheck_html/
|
||||
expire_in: "1 day"
|
||||
when: on_failure
|
||||
needs:
|
||||
- job: autoreconf
|
||||
artifacts: true
|
||||
|
||||
### Job Definitions
|
||||
|
||||
# Jobs in the precheck stage
|
||||
|
||||
autoreconf:sid:amd64:
|
||||
autoreconf:
|
||||
<<: *autoconf_job
|
||||
|
||||
misc:sid:amd64:
|
||||
misc:
|
||||
<<: *precheck_job
|
||||
script:
|
||||
- sh util/check-ans-prereq.sh
|
||||
@@ -386,24 +404,23 @@ misc:sid:amd64:
|
||||
expire_in: "1 day"
|
||||
when: on_failure
|
||||
|
||||
💾:sid:amd64:
|
||||
clang-format:
|
||||
<<: *precheck_job
|
||||
needs: []
|
||||
script:
|
||||
- if [ -r .clang-format ]; then "${CLANG_FORMAT}" -i -style=file $(git ls-files '*.c' '*.h'); fi
|
||||
- if test "$(git status --porcelain | grep -Ev '\?\?' | wc -l)" -gt "0"; then git status --short; exit 1; fi
|
||||
|
||||
🐞:sid:amd64:
|
||||
coccinelle:
|
||||
<<: *precheck_job
|
||||
<<: *debian_buster_amd64_image
|
||||
needs: []
|
||||
script:
|
||||
- util/check-cocci
|
||||
- if test "$(git status --porcelain | grep -Ev '\?\?' | wc -l)" -gt "0"; then git status --short; exit 1; fi
|
||||
|
||||
tarball-create:sid:amd64:
|
||||
tarball-create:
|
||||
stage: precheck
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
script:
|
||||
- source version
|
||||
- export BIND_DIRECTORY="bind-${MAJORVER}.${MINORVER}.${PATCHVER}${RELEASETYPE}${RELEASEVER}"
|
||||
@@ -420,27 +437,27 @@ tarball-create:sid:amd64:
|
||||
|
||||
# Jobs for doc builds on Debian Sid (amd64)
|
||||
|
||||
docs:sid:amd64:
|
||||
docs:
|
||||
<<: *release_branch_triggering_rules
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
stage: docs
|
||||
script:
|
||||
- ./configure || cat config.log
|
||||
- make -C doc/misc docbook
|
||||
- make -C doc/arm Bv9ARM.html
|
||||
needs:
|
||||
- job: autoreconf:sid:amd64
|
||||
- job: autoreconf
|
||||
artifacts: true
|
||||
artifacts:
|
||||
paths:
|
||||
- doc/arm/
|
||||
expire_in: "1 month"
|
||||
|
||||
push:docs:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
push:docs:
|
||||
<<: *base_image
|
||||
stage: push
|
||||
needs:
|
||||
- job: docs:sid:amd64
|
||||
- job: docs
|
||||
artifacts: false
|
||||
script:
|
||||
- curl -X POST -F token=$GITLAB_PAGES_DOCS_TRIGGER_TOKEN -F ref=master $GITLAB_PAGES_DOCS_TRIGGER_URL
|
||||
@@ -600,9 +617,9 @@ unit:gcc:buster:amd64:
|
||||
-o scan-build.reports \
|
||||
make -j${BUILD_PARALLEL_JOBS:-1} all V=1
|
||||
|
||||
scan-build:buster:amd64:
|
||||
scan-build:
|
||||
<<: *default_triggering_rules
|
||||
<<: *debian_buster_amd64_image
|
||||
<<: *base_image
|
||||
stage: postcheck
|
||||
variables:
|
||||
CC: "${CLANG}"
|
||||
@@ -613,7 +630,7 @@ scan-build:buster:amd64:
|
||||
- *configure
|
||||
- *scan_build
|
||||
needs:
|
||||
- job: autoreconf:sid:amd64
|
||||
- job: autoreconf
|
||||
artifacts: true
|
||||
artifacts:
|
||||
paths:
|
||||
@@ -629,7 +646,6 @@ gcc:sid:amd64:
|
||||
CFLAGS: "${CFLAGS_COMMON} -O3"
|
||||
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
|
||||
RUN_MAKE_INSTALL: 1
|
||||
MAKE_COMMAND: bear --use-cc=${CC} --verbose make
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *build_job
|
||||
|
||||
@@ -647,64 +663,61 @@ unit:gcc:sid:amd64:
|
||||
- job: gcc:sid:amd64
|
||||
artifacts: true
|
||||
|
||||
cppcheck:gcc:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
cppcheck:
|
||||
<<: *base_image
|
||||
<<: *cppcheck_job
|
||||
needs:
|
||||
- job: gcc:sid:amd64
|
||||
artifacts: true
|
||||
|
||||
# Job for out-of-tree GCC build on Debian Sid (amd64)
|
||||
|
||||
oot:sid:amd64:
|
||||
gcc:out-of-tree:
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -O3"
|
||||
CFLAGS: "${CFLAGS_COMMON} -Og"
|
||||
CONFIGURE: ../configure
|
||||
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
|
||||
RUN_MAKE_INSTALL: 1
|
||||
OOT_BUILD_WORKSPACE: workspace
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
<<: *build_job
|
||||
|
||||
# Jobs for tarball GCC builds on Debian Sid (amd64)
|
||||
|
||||
tarball:sid:amd64:
|
||||
gcc:tarball:
|
||||
variables:
|
||||
CC: gcc
|
||||
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
|
||||
RUN_MAKE_INSTALL: 1
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
<<: *build_job
|
||||
before_script:
|
||||
- tar --extract --file bind-*.tar.${TARBALL_EXTENSION}
|
||||
- rm -f bind-*.tar.${TARBALL_EXTENSION}
|
||||
- cd bind-*
|
||||
needs:
|
||||
- job: tarball-create:sid:amd64
|
||||
- job: tarball-create
|
||||
artifacts: true
|
||||
only:
|
||||
- tags
|
||||
|
||||
system:tarball:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
system:gcc:tarball:
|
||||
<<: *base_image
|
||||
<<: *system_test_job
|
||||
before_script:
|
||||
- cd bind-*
|
||||
- *setup_interfaces
|
||||
needs:
|
||||
- job: tarball:sid:amd64
|
||||
- job: gcc:tarball
|
||||
artifacts: true
|
||||
only:
|
||||
- tags
|
||||
|
||||
unit:tarball:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
unit:gcc:tarball:
|
||||
<<: *base_image
|
||||
<<: *unit_test_job
|
||||
before_script:
|
||||
- cd bind-*
|
||||
needs:
|
||||
- job: tarball:sid:amd64
|
||||
- job: gcc:tarball
|
||||
artifacts: true
|
||||
only:
|
||||
- tags
|
||||
@@ -714,8 +727,8 @@ unit:tarball:sid:amd64:
|
||||
gcc:sid:arm64:
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -O2"
|
||||
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
|
||||
CFLAGS: "${CFLAGS_COMMON} -Og"
|
||||
EXTRA_CONFIGURE: "--with-libidn2"
|
||||
<<: *debian_sid_arm64_image
|
||||
<<: *build_job
|
||||
|
||||
@@ -739,7 +752,7 @@ gcc:sid:i386:
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON}"
|
||||
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2 --without-python"
|
||||
EXTRA_CONFIGURE: "--with-libidn2 --without-python"
|
||||
<<: *debian_sid_i386_image
|
||||
<<: *build_job
|
||||
|
||||
@@ -853,39 +866,93 @@ unit:gcc:bionic:amd64:
|
||||
- job: gcc:bionic:amd64
|
||||
artifacts: true
|
||||
|
||||
# Jobs for GCC builds with ASAN enabled on Debian Sid (amd64)
|
||||
# Jobs for builds with ASAN enabled
|
||||
|
||||
asan:sid:amd64:
|
||||
gcc:asan:
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0"
|
||||
LDFLAGS: "-fsanitize=address,undefined"
|
||||
EXTRA_CONFIGURE: "--with-libidn2"
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
<<: *build_job
|
||||
|
||||
system:asan:sid:amd64:
|
||||
system:gcc:asan:
|
||||
variables:
|
||||
ASAN_OPTIONS: ${ASAN_OPTIONS_COMMON}
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
<<: *system_test_job
|
||||
needs:
|
||||
- job: asan:sid:amd64
|
||||
- job: gcc:asan
|
||||
artifacts: true
|
||||
|
||||
unit:asan:sid:amd64:
|
||||
unit:gcc:asan:
|
||||
variables:
|
||||
ASAN_OPTIONS: ${ASAN_OPTIONS_COMMON}
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
<<: *unit_test_job
|
||||
needs:
|
||||
- job: asan:sid:amd64
|
||||
- job: gcc:asan
|
||||
artifacts: true
|
||||
|
||||
# Jobs for GCC builds with TSAN enabled on Debian Sid (amd64)
|
||||
clang:asan:
|
||||
variables:
|
||||
CC: ${CLANG}
|
||||
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0"
|
||||
LDFLAGS: "-fsanitize=address,undefined"
|
||||
EXTRA_CONFIGURE: "--with-libidn2"
|
||||
<<: *base_image
|
||||
<<: *build_job
|
||||
|
||||
tsan:buster:amd64:
|
||||
<<: *debian_buster_amd64_image
|
||||
system:clang:asan:
|
||||
variables:
|
||||
ASAN_OPTIONS: ${ASAN_OPTIONS_COMMON}
|
||||
<<: *base_image
|
||||
<<: *system_test_job
|
||||
needs:
|
||||
- job: gcc:asan
|
||||
artifacts: true
|
||||
|
||||
unit:clang:asan:
|
||||
variables:
|
||||
ASAN_OPTIONS: ${ASAN_OPTIONS_COMMON}
|
||||
<<: *base_image
|
||||
<<: *unit_test_job
|
||||
needs:
|
||||
- job: gcc:asan
|
||||
artifacts: true
|
||||
|
||||
# Jobs for builds with TSAN enabled
|
||||
|
||||
gcc:tsan:
|
||||
<<: *base_image
|
||||
<<: *build_job
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread -DISC_MEM_USE_INTERNAL_MALLOC=0"
|
||||
LDFLAGS: "-fsanitize=thread"
|
||||
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock"
|
||||
|
||||
system:gcc:tsan:
|
||||
variables:
|
||||
TSAN_OPTIONS: ${TSAN_OPTIONS_COMMON}
|
||||
<<: *base_image
|
||||
<<: *system_test_tsan_job
|
||||
needs:
|
||||
- job: gcc:tsan
|
||||
artifacts: true
|
||||
|
||||
unit:gcc:tsan:
|
||||
variables:
|
||||
TSAN_OPTIONS: ${TSAN_OPTIONS_COMMON}
|
||||
<<: *base_image
|
||||
<<: *unit_test_tsan_job
|
||||
needs:
|
||||
- job: gcc:tsan
|
||||
artifacts: true
|
||||
|
||||
clang:tsan:
|
||||
<<: *base_image
|
||||
<<: *build_job
|
||||
variables:
|
||||
CC: "${CLANG}"
|
||||
@@ -893,146 +960,93 @@ tsan:buster:amd64:
|
||||
LDFLAGS: "-fsanitize=thread"
|
||||
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock"
|
||||
|
||||
system:tsan:buster:amd64:
|
||||
system:clang:tsan:
|
||||
variables:
|
||||
TSAN_OPTIONS: "second_deadlock_stack=1 history_size=7 log_exe_name=true log_path=tsan external_symbolizer_path=$SYMBOLIZER exitcode=0"
|
||||
before_script:
|
||||
- *setup_interfaces
|
||||
- echo $TSAN_OPTIONS
|
||||
<<: *debian_buster_amd64_image
|
||||
<<: *system_test_job
|
||||
TSAN_OPTIONS: ${TSAN_OPTIONS_COMMON}
|
||||
<<: *base_image
|
||||
<<: *system_test_tsan_job
|
||||
needs:
|
||||
- job: tsan:buster:amd64
|
||||
artifacts: true
|
||||
allow_failure: true
|
||||
after_script:
|
||||
- find bin -name 'tsan.*' -exec python3 util/parse_tsan.py {} \;
|
||||
artifacts:
|
||||
expire_in: "1 day"
|
||||
paths:
|
||||
- bin/tests/system/*/tsan.*
|
||||
- bin/tests/system/*/*/tsan.*
|
||||
- tsan/
|
||||
when: on_failure
|
||||
|
||||
unit:tsan:buster:amd64:
|
||||
variables:
|
||||
TSAN_OPTIONS: "second_deadlock_stack=1 history_size=7 log_exe_name=true log_path=tsan external_symbolizer_path=$SYMBOLIZER"
|
||||
before_script:
|
||||
- echo $TSAN_OPTIONS
|
||||
- lib/isc/tests/result_test
|
||||
<<: *debian_buster_amd64_image
|
||||
<<: *unit_test_job
|
||||
needs:
|
||||
- job: tsan:buster:amd64
|
||||
artifacts: true
|
||||
allow_failure: true
|
||||
after_script:
|
||||
- find lib -name 'tsan.*' -exec python3 util/parse_tsan.py {} \;
|
||||
artifacts:
|
||||
expire_in: "1 day"
|
||||
paths:
|
||||
- lib/*/tests/tsan.*
|
||||
- tsan/
|
||||
- kyua.log
|
||||
- kyua.results
|
||||
- kyua_html/
|
||||
when: on_failure
|
||||
|
||||
rwlock:sid:amd64:
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -Wall -Wextra -O2 -g -DISC_MEM_USE_INTERNAL_MALLOC=0"
|
||||
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock"
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *build_job
|
||||
|
||||
system:rwlock:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *system_test_job
|
||||
needs:
|
||||
- job: rwlock:sid:amd64
|
||||
- job: clang:tsan
|
||||
artifacts: true
|
||||
|
||||
unit:rwlock:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *unit_test_job
|
||||
unit:clang:tsan:
|
||||
variables:
|
||||
TSAN_OPTIONS: ${TSAN_OPTIONS_COMMON}
|
||||
<<: *base_image
|
||||
<<: *unit_test_tsan_job
|
||||
needs:
|
||||
- job: rwlock:sid:amd64
|
||||
- job: clang:tsan
|
||||
artifacts: true
|
||||
|
||||
# Jobs for mutex-based atomics on Debian SID (amd64)
|
||||
mutexatomics:sid:amd64:
|
||||
gcc:mutexatomics:
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -DISC_MEM_USE_INTERNAL_MALLOC=0"
|
||||
EXTRA_CONFIGURE: "--with-libidn2 --enable-mutex-atomics"
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
<<: *build_job
|
||||
|
||||
system:mutexatomics:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
system:gcc:mutexatomics:
|
||||
<<: *base_image
|
||||
<<: *system_test_job
|
||||
needs:
|
||||
- job: mutexatomics:sid:amd64
|
||||
- job: gcc:mutexatomics
|
||||
artifacts: true
|
||||
|
||||
unit:mutexatomics:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
unit:gcc:mutexatomics:
|
||||
<<: *base_image
|
||||
<<: *unit_test_job
|
||||
needs:
|
||||
- job: mutexatomics:sid:amd64
|
||||
- job: gcc:mutexatomics
|
||||
artifacts: true
|
||||
|
||||
# Jobs for Clang builds on Debian Stretch (amd64)
|
||||
# Jobs for Clang builds on Debian Buster (amd64)
|
||||
|
||||
clang:stretch:amd64:
|
||||
clang:buster:amd64:
|
||||
variables:
|
||||
CC: clang
|
||||
CC: ${CLANG}
|
||||
CFLAGS: "${CFLAGS_COMMON} -Wenum-conversion"
|
||||
EXTRA_CONFIGURE: "--with-python=python3"
|
||||
<<: *debian_stretch_amd64_image
|
||||
<<: *debian_buster_amd64_image
|
||||
<<: *build_job
|
||||
|
||||
unit:clang:stretch:amd64:
|
||||
<<: *debian_stretch_amd64_image
|
||||
<<: *unit_test_job
|
||||
system:clang:buster:amd64:
|
||||
<<: *debian_buster_amd64_image
|
||||
<<: *system_test_job
|
||||
needs:
|
||||
- job: clang:stretch:amd64
|
||||
- job: clang:buster:amd64
|
||||
artifacts: true
|
||||
|
||||
# Jobs for Clang builds on Debian Stretch (i386)
|
||||
|
||||
clang:stretch:i386:
|
||||
variables:
|
||||
CC: clang
|
||||
CFLAGS: "${CFLAGS_COMMON} -Wenum-conversion"
|
||||
EXTRA_CONFIGURE: "--with-python=python2"
|
||||
<<: *debian_stretch_i386_image
|
||||
<<: *build_job
|
||||
unit:clang:buster:amd64:
|
||||
<<: *debian_buster_amd64_image
|
||||
<<: *unit_test_job
|
||||
needs:
|
||||
- job: clang:buster:amd64
|
||||
artifacts: true
|
||||
|
||||
# Jobs for PKCS#11-enabled GCC builds on Debian Sid (amd64)
|
||||
|
||||
pkcs11:sid:amd64:
|
||||
gcc:pkcs11:
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON}"
|
||||
EXTRA_CONFIGURE: "--enable-native-pkcs11 --with-pkcs11=/usr/lib/softhsm/libsofthsm2.so"
|
||||
<<: *debian_sid_amd64_image
|
||||
<<: *base_image
|
||||
<<: *build_job
|
||||
|
||||
system:pkcs11:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
system:gcc:pkcs11:
|
||||
<<: *base_image
|
||||
<<: *system_test_job
|
||||
needs:
|
||||
- job: pkcs11:sid:amd64
|
||||
- job: gcc:pkcs11
|
||||
artifacts: true
|
||||
|
||||
unit:pkcs11:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
unit:gcc:pkcs11:
|
||||
<<: *base_image
|
||||
<<: *unit_test_job
|
||||
needs:
|
||||
- job: pkcs11:sid:amd64
|
||||
- job: gcc:pkcs11
|
||||
artifacts: true
|
||||
|
||||
# Jobs for Clang builds on FreeBSD 11.3 (amd64)
|
||||
@@ -1144,8 +1158,8 @@ system:msvc-debug:windows:amd64:
|
||||
|
||||
# Job producing a release tarball
|
||||
|
||||
release:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
release:
|
||||
<<: *base_image
|
||||
stage: release
|
||||
script:
|
||||
# Determine BIND version
|
||||
@@ -1174,7 +1188,7 @@ release:sid:amd64:
|
||||
# Create release tarball
|
||||
- tar --create --file="${CI_COMMIT_TAG}.tar.gz" --gzip release/
|
||||
needs:
|
||||
- job: tarball-create:sid:amd64
|
||||
- job: tarball-create
|
||||
artifacts: true
|
||||
- job: msvc:windows:amd64
|
||||
artifacts: true
|
||||
@@ -1215,19 +1229,19 @@ release:sid:amd64:
|
||||
| tee curl-response.txt
|
||||
grep -q 'Build successfully submitted' curl-response.txt
|
||||
|
||||
build:coverity:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
stage: build
|
||||
coverity:
|
||||
<<: *base_image
|
||||
stage: postcheck
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -O3"
|
||||
CFLAGS: "${CFLAGS_COMMON} -Og"
|
||||
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
|
||||
script:
|
||||
- *coverity_cache_prep
|
||||
- *configure
|
||||
- *coverity_build
|
||||
needs:
|
||||
- job: autoreconf:sid:amd64
|
||||
- job: autoreconf
|
||||
artifacts: true
|
||||
artifacts:
|
||||
paths:
|
||||
@@ -1247,26 +1261,26 @@ build:coverity:sid:amd64:
|
||||
|
||||
# Respdiff test
|
||||
|
||||
respdiff:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
respdiff:
|
||||
<<: *base_image
|
||||
stage: system
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON} -O3"
|
||||
CFLAGS: "${CFLAGS_COMMON} -Og"
|
||||
BIND_BASELINE_VERSION: v9_11_3
|
||||
script:
|
||||
- ./configure --without-make-clean
|
||||
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} V=1
|
||||
- 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
|
||||
- git clone --branch "${BIND_BASELINE_VERSION}" --depth 1 https://gitlab.isc.org/isc-projects/bind9.git refbind
|
||||
- cd refbind/
|
||||
- ./configure --without-make-clean
|
||||
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} V=1
|
||||
- make -j${BUILD_PARALLEL_JOBS:-1} V=1
|
||||
- cd ../bind-qa/bind9/respdiff
|
||||
- bash respdiff.sh -q "${PWD}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}/refbind" "${CI_PROJECT_DIR}"
|
||||
needs:
|
||||
- job: tarball-create:sid:amd64
|
||||
- job: tarball-create
|
||||
artifacts: true
|
||||
only:
|
||||
- tags
|
||||
@@ -1279,11 +1293,11 @@ respdiff:sid:amd64:
|
||||
|
||||
# ABI check
|
||||
|
||||
abi-check:sid:amd64:
|
||||
<<: *debian_sid_amd64_image
|
||||
abi-check:
|
||||
<<: *base_image
|
||||
stage: build
|
||||
needs:
|
||||
- job: autoreconf:sid:amd64
|
||||
- job: autoreconf
|
||||
artifacts: true
|
||||
variables:
|
||||
CC: gcc
|
||||
@@ -1291,11 +1305,11 @@ abi-check:sid:amd64:
|
||||
BIND_BASELINE_VERSION: v9_17_0
|
||||
script:
|
||||
- *configure
|
||||
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} V=1
|
||||
- make -j${BUILD_PARALLEL_JOBS:-1} V=1
|
||||
- git clone --branch "${BIND_BASELINE_VERSION}" --depth 1 https://gitlab.isc.org/isc-projects/bind9.git refbind
|
||||
- cd refbind/
|
||||
- *configure
|
||||
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} V=1
|
||||
- make -j${BUILD_PARALLEL_JOBS:-1} V=1
|
||||
- cd ..
|
||||
- util/api-checker.sh . refbind
|
||||
artifacts:
|
||||
|
||||
@@ -1,3 +1,27 @@
|
||||
5373. [bug] Collecting DNSSEC signing operations introduced by
|
||||
GL #513 (change 5254) allocated counters for every
|
||||
possible key id per zone which results in a lot of
|
||||
wasted memory. Fix by tracking up to four keys
|
||||
per zone, rotate counters when keys are replaced.
|
||||
This fixes the immediate problem of the high
|
||||
memory usage, but should be improved in a future
|
||||
release by growing and shrinking the number of
|
||||
keys to track triggered by key rollover events.
|
||||
[GL #1179]
|
||||
|
||||
5372. [bug] Fix migration from existing DNSSEC key files using
|
||||
auto-dnssec maintain to dnssec-policy. [GL #1706]
|
||||
|
||||
5371. [bug] Improve incremental updates of the RPZ summary
|
||||
database to reduce delays that could occur when
|
||||
a policy zone update included a large number of
|
||||
record deletions. [GL #1447]
|
||||
|
||||
5370. [bug] Deactivation of a netmgr handle associated with a
|
||||
socket could be skipped in some circumstances.
|
||||
Fixed by deactivating the netmgr handle before
|
||||
scheduling the asynchronous close routine. [GL #1700]
|
||||
|
||||
5369. [func] Add the ability to specify whether or not to wait
|
||||
for nameserver domain names to be looked up, with
|
||||
a new RPZ modifying directive 'nsdname-wait-recurse'.
|
||||
|
||||
@@ -754,6 +754,8 @@ ds_from_cds(dns_rdatalist_t *dslist, isc_buffer_t *buf, dns_rdata_t *cds) {
|
||||
dns_rdata_ds_t ds;
|
||||
dns_rdata_t *rdata;
|
||||
|
||||
REQUIRE(buf != NULL);
|
||||
|
||||
rdata = rdata_get();
|
||||
|
||||
result = dns_rdata_tostruct(cds, &ds, NULL);
|
||||
@@ -772,6 +774,8 @@ ds_from_cdnskey(dns_rdatalist_t *dslist, isc_buffer_t *buf,
|
||||
isc_result_t result;
|
||||
unsigned i, n;
|
||||
|
||||
REQUIRE(buf != NULL);
|
||||
|
||||
n = sizeof(dtype) / sizeof(dtype[0]);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (dtype[i] != 0) {
|
||||
|
||||
@@ -1251,6 +1251,7 @@ setup(void) {
|
||||
#endif /* if CONTRIB_DLZ */
|
||||
|
||||
named_server_create(named_g_mctx, &named_g_server);
|
||||
ENSURE(named_g_server != NULL);
|
||||
sctx = named_g_server->sctx;
|
||||
|
||||
/*
|
||||
|
||||
+32
-36
@@ -1814,7 +1814,6 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
|
||||
isc_stats_t *gluecachestats;
|
||||
dns_stats_t *rcvquerystats;
|
||||
dns_stats_t *dnssecsignstats;
|
||||
dns_stats_t *dnssecrefreshstats;
|
||||
uint64_t nsstat_values[ns_statscounter_max];
|
||||
uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
|
||||
|
||||
@@ -1880,6 +1879,7 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
|
||||
|
||||
dnssecsignstats = dns_zone_getdnssecsignstats(zone);
|
||||
if (dnssecsignstats != NULL) {
|
||||
/* counters type="dnssec-sign"*/
|
||||
TRY0(xmlTextWriterStartElement(writer,
|
||||
ISC_XMLCHAR "counters"));
|
||||
TRY0(xmlTextWriterWriteAttribute(
|
||||
@@ -1887,19 +1887,17 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
|
||||
ISC_XMLCHAR "dnssec-sign"));
|
||||
|
||||
dumparg.result = ISC_R_SUCCESS;
|
||||
dns_dnssecsignstats_dump(dnssecsignstats,
|
||||
dnssecsignstat_dump, &dumparg,
|
||||
0);
|
||||
dns_dnssecsignstats_dump(
|
||||
dnssecsignstats, dns_dnssecsignstats_sign,
|
||||
dnssecsignstat_dump, &dumparg, 0);
|
||||
if (dumparg.result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* counters type="dnssec-sign"*/
|
||||
TRY0(xmlTextWriterEndElement(writer));
|
||||
}
|
||||
|
||||
dnssecrefreshstats = dns_zone_getdnssecrefreshstats(zone);
|
||||
if (dnssecrefreshstats != NULL) {
|
||||
/* counters type="dnssec-refresh"*/
|
||||
TRY0(xmlTextWriterStartElement(writer,
|
||||
ISC_XMLCHAR "counters"));
|
||||
TRY0(xmlTextWriterWriteAttribute(
|
||||
@@ -1907,9 +1905,9 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
|
||||
ISC_XMLCHAR "dnssec-refresh"));
|
||||
|
||||
dumparg.result = ISC_R_SUCCESS;
|
||||
dns_dnssecsignstats_dump(dnssecrefreshstats,
|
||||
dnssecsignstat_dump, &dumparg,
|
||||
0);
|
||||
dns_dnssecsignstats_dump(
|
||||
dnssecsignstats, dns_dnssecsignstats_refresh,
|
||||
dnssecsignstat_dump, &dumparg, 0);
|
||||
if (dumparg.result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
@@ -2626,7 +2624,6 @@ zone_jsonrender(dns_zone_t *zone, void *arg) {
|
||||
isc_stats_t *gluecachestats;
|
||||
dns_stats_t *rcvquerystats;
|
||||
dns_stats_t *dnssecsignstats;
|
||||
dns_stats_t *dnssecrefreshstats;
|
||||
uint64_t nsstat_values[ns_statscounter_max];
|
||||
uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
|
||||
|
||||
@@ -2708,50 +2705,49 @@ zone_jsonrender(dns_zone_t *zone, void *arg) {
|
||||
dnssecsignstats = dns_zone_getdnssecsignstats(zone);
|
||||
if (dnssecsignstats != NULL) {
|
||||
stats_dumparg_t dumparg;
|
||||
json_object *counters = json_object_new_object();
|
||||
CHECKMEM(counters);
|
||||
json_object *sign_counters = json_object_new_object();
|
||||
CHECKMEM(sign_counters);
|
||||
|
||||
dumparg.type = isc_statsformat_json;
|
||||
dumparg.arg = counters;
|
||||
dumparg.arg = sign_counters;
|
||||
dumparg.result = ISC_R_SUCCESS;
|
||||
dns_dnssecsignstats_dump(dnssecsignstats,
|
||||
dnssecsignstat_dump, &dumparg,
|
||||
0);
|
||||
dns_dnssecsignstats_dump(
|
||||
dnssecsignstats, dns_dnssecsignstats_sign,
|
||||
dnssecsignstat_dump, &dumparg, 0);
|
||||
if (dumparg.result != ISC_R_SUCCESS) {
|
||||
json_object_put(counters);
|
||||
json_object_put(sign_counters);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (json_object_get_object(counters)->count != 0) {
|
||||
if (json_object_get_object(sign_counters)->count != 0) {
|
||||
json_object_object_add(zoneobj, "dnssec-sign",
|
||||
counters);
|
||||
sign_counters);
|
||||
} else {
|
||||
json_object_put(counters);
|
||||
json_object_put(sign_counters);
|
||||
}
|
||||
}
|
||||
|
||||
dnssecrefreshstats = dns_zone_getdnssecrefreshstats(zone);
|
||||
if (dnssecrefreshstats != NULL) {
|
||||
stats_dumparg_t dumparg;
|
||||
json_object *counters = json_object_new_object();
|
||||
CHECKMEM(counters);
|
||||
json_object *refresh_counters =
|
||||
json_object_new_object();
|
||||
CHECKMEM(refresh_counters);
|
||||
|
||||
dumparg.type = isc_statsformat_json;
|
||||
dumparg.arg = counters;
|
||||
dumparg.arg = refresh_counters;
|
||||
dumparg.result = ISC_R_SUCCESS;
|
||||
dns_dnssecsignstats_dump(dnssecrefreshstats,
|
||||
dnssecsignstat_dump, &dumparg,
|
||||
0);
|
||||
dns_dnssecsignstats_dump(
|
||||
dnssecsignstats, dns_dnssecsignstats_refresh,
|
||||
dnssecsignstat_dump, &dumparg, 0);
|
||||
if (dumparg.result != ISC_R_SUCCESS) {
|
||||
json_object_put(counters);
|
||||
json_object_put(refresh_counters);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (json_object_get_object(counters)->count != 0) {
|
||||
json_object_object_add(
|
||||
zoneobj, "dnssec-refresh", counters);
|
||||
if (json_object_get_object(refresh_counters)->count !=
|
||||
0) {
|
||||
json_object_object_add(zoneobj,
|
||||
"dnssec-refresh",
|
||||
refresh_counters);
|
||||
} else {
|
||||
json_object_put(counters);
|
||||
json_object_put(refresh_counters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -869,7 +869,7 @@ named_os_shutdownmsg(char *command, isc_buffer_t *text) {
|
||||
pid_t pid;
|
||||
|
||||
/* Skip the command name. */
|
||||
if ((ptr = strtok_r(command, " \t", &last)) == NULL) {
|
||||
if (strtok_r(command, " \t", &last) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -890,7 +890,6 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
|
||||
isc_stats_t *zoneqrystats;
|
||||
dns_stats_t *rcvquerystats;
|
||||
dns_stats_t *dnssecsignstats;
|
||||
dns_stats_t *dnssecrefreshstats;
|
||||
dns_zonestat_level_t statlevel = dns_zonestat_none;
|
||||
int seconds;
|
||||
dns_zone_t *mayberaw = (raw != NULL) ? raw : zone;
|
||||
@@ -1187,18 +1186,15 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
|
||||
zoneqrystats = NULL;
|
||||
rcvquerystats = NULL;
|
||||
dnssecsignstats = NULL;
|
||||
dnssecrefreshstats = NULL;
|
||||
if (statlevel == dns_zonestat_full) {
|
||||
RETERR(isc_stats_create(mctx, &zoneqrystats,
|
||||
ns_statscounter_max));
|
||||
RETERR(dns_rdatatypestats_create(mctx, &rcvquerystats));
|
||||
RETERR(dns_dnssecsignstats_create(mctx, &dnssecsignstats));
|
||||
RETERR(dns_dnssecsignstats_create(mctx, &dnssecrefreshstats));
|
||||
}
|
||||
dns_zone_setrequeststats(zone, zoneqrystats);
|
||||
dns_zone_setrcvquerystats(zone, rcvquerystats);
|
||||
dns_zone_setdnssecsignstats(zone, dnssecsignstats);
|
||||
dns_zone_setdnssecrefreshstats(zone, dnssecrefreshstats);
|
||||
|
||||
if (zoneqrystats != NULL) {
|
||||
isc_stats_detach(&zoneqrystats);
|
||||
@@ -1212,10 +1208,6 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
|
||||
dns_stats_detach(&dnssecsignstats);
|
||||
}
|
||||
|
||||
if (dnssecrefreshstats != NULL) {
|
||||
dns_stats_detach(&dnssecrefreshstats);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure master functionality. This applies
|
||||
* to primary masters (type "master") and slaves
|
||||
|
||||
+3
-1
@@ -252,6 +252,8 @@ get_addresses(const char *host, in_port_t port) {
|
||||
isc_result_t result;
|
||||
int found = 0, count;
|
||||
|
||||
REQUIRE(host != NULL);
|
||||
|
||||
if (*host == '/') {
|
||||
result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
|
||||
host);
|
||||
@@ -1036,7 +1038,7 @@ main(int argc, char **argv) {
|
||||
fatal("'%s' is not implemented", command);
|
||||
}
|
||||
|
||||
if (nserveraddrs == 0) {
|
||||
if (nserveraddrs == 0 && servername != NULL) {
|
||||
get_addresses(servername, (in_port_t)remoteport);
|
||||
}
|
||||
|
||||
|
||||
@@ -305,6 +305,7 @@ main(int argc, char *argv[]) {
|
||||
isc_sockaddr_fromin(&sa, &ina, 53);
|
||||
ISC_LIST_APPEND(sal, &sa, link);
|
||||
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname,
|
||||
&sal, dns_fwdpolicy_only) ==
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
@@ -24,6 +24,7 @@ options {
|
||||
listen-on-v6 { none; };
|
||||
allow-transfer { any; };
|
||||
recursion no;
|
||||
key-directory ".";
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
@@ -35,6 +36,35 @@ controls {
|
||||
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
/* These are zones that migrate to dnssec-policy. */
|
||||
zone "migrate.kasp" {
|
||||
type master;
|
||||
file "migrate.kasp.db";
|
||||
auto-dnssec maintain;
|
||||
allow-update { any; };
|
||||
dnssec-dnskey-kskonly yes;
|
||||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
zone "migrate-nomatch-algnum.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch-algnum.kasp.db";
|
||||
auto-dnssec maintain;
|
||||
allow-update { any; };
|
||||
dnssec-dnskey-kskonly yes;
|
||||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
zone "migrate-nomatch-alglen.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch-alglen.kasp.db";
|
||||
auto-dnssec maintain;
|
||||
allow-update { any; };
|
||||
dnssec-dnskey-kskonly yes;
|
||||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
/* These are alorithm rollover test zones. */
|
||||
zone "step1.algorithm-roll.kasp" {
|
||||
type master;
|
||||
file "step1.algorithm-roll.kasp.db";
|
||||
|
||||
@@ -35,6 +35,31 @@ controls {
|
||||
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
/* These are zones that migrate to dnssec-policy. */
|
||||
zone "migrate.kasp" {
|
||||
type master;
|
||||
file "migrate.kasp.db";
|
||||
allow-update { any; };
|
||||
dnssec-policy "migrate";
|
||||
};
|
||||
|
||||
zone "migrate-nomatch-algnum.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch-algnum.kasp.db";
|
||||
allow-update { any; };
|
||||
dnssec-policy "migrate-nomatch-algnum";
|
||||
};
|
||||
|
||||
zone "migrate-nomatch-alglen.kasp" {
|
||||
type master;
|
||||
file "migrate-nomatch-alglen.kasp.db";
|
||||
allow-update { any; };
|
||||
dnssec-policy "migrate-nomatch-alglen";
|
||||
};
|
||||
|
||||
/*
|
||||
* Zones for testing KSK/ZSK algorithm roll.
|
||||
*/
|
||||
zone "step1.algorithm-roll.kasp" {
|
||||
type master;
|
||||
file "step1.algorithm-roll.kasp.db";
|
||||
|
||||
@@ -48,3 +48,56 @@ dnssec-policy "ecdsa256" {
|
||||
parent-propagation-delay pt1h;
|
||||
parent-ds-ttl 7200;
|
||||
};
|
||||
|
||||
dnssec-policy "migrate" {
|
||||
dnskey-ttl 300;
|
||||
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
|
||||
zsk key-directory lifetime P60D algorithm ECDSAP256SHA256;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* This policy tests migration from existing keys with 1024 bits RSASHA1 keys
|
||||
* to ECDSAP256SHA256 keys.
|
||||
*/
|
||||
dnssec-policy "migrate-nomatch-algnum" {
|
||||
dnskey-ttl 300;
|
||||
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm ecdsa256;
|
||||
zsk key-directory lifetime P60D algorithm ecdsa256;
|
||||
};
|
||||
|
||||
// Together 12h
|
||||
zone-propagation-delay 3600;
|
||||
max-zone-ttl 11h;
|
||||
|
||||
// Together 24h
|
||||
parent-registration-delay 21h;
|
||||
parent-propagation-delay pt1h;
|
||||
parent-ds-ttl 7200;
|
||||
};
|
||||
|
||||
/*
|
||||
* This policy tests migration from existing keys with 1024 bits RSASHA1 keys
|
||||
* to 2048 bits RSASHA1 keys.
|
||||
*/
|
||||
dnssec-policy "migrate-nomatch-alglen" {
|
||||
dnskey-ttl 300;
|
||||
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm rsasha1 2048;
|
||||
zsk key-directory lifetime P60D algorithm rsasha1 2048;
|
||||
};
|
||||
|
||||
// Together 12h
|
||||
zone-propagation-delay 3600;
|
||||
max-zone-ttl 11h;
|
||||
|
||||
// Together 24h
|
||||
parent-registration-delay 21h;
|
||||
parent-propagation-delay pt1h;
|
||||
parent-ds-ttl 7200;
|
||||
};
|
||||
|
||||
@@ -39,6 +39,54 @@ R="RUMOURED"
|
||||
O="OMNIPRESENT"
|
||||
U="UNRETENTIVE"
|
||||
|
||||
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy.
|
||||
setup migrate.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a ECDSAP256SHA256 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a ECDSAP256SHA256 -L 300 $zone 2> keygen.out.$zone.2)
|
||||
$SETTIME -P now -P sync now -A now "$KSK" > settime.out.$zone.1 2>&1
|
||||
$SETTIME -P now -A now "$ZSK" > settime.out.$zone.2 2>&1
|
||||
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
|
||||
private_type_record $zone 5 "$KSK" >> "$infile"
|
||||
private_type_record $zone 5 "$ZSK" >> "$infile"
|
||||
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
|
||||
|
||||
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
|
||||
# time the existing keys do not match the policy. The existing keys are
|
||||
# RSASHA1 keys, and will be migrated to a dnssec-policy that dictates
|
||||
# ECDSAP256SHA256 keys.
|
||||
setup migrate-nomatch-algnum.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a RSASHA1 -b 2048 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a RSASHA1 -b 1024 -L 300 $zone 2> keygen.out.$zone.2)
|
||||
Tds="now-24h" # Time according to dnssec-policy that DS will be OMNIPRESENT
|
||||
Tkey="now-3900s" # DNSKEY TTL + propagation delay
|
||||
Tsig="now-12h" # Zone's maximum TTL + propagation delay
|
||||
$SETTIME -P $Tkey -P sync $Tds -A $Tkey "$KSK" > settime.out.$zone.1 2>&1
|
||||
$SETTIME -P $Tsig -A $Tsig "$ZSK" > settime.out.$zone.2 2>&1
|
||||
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
|
||||
private_type_record $zone 5 "$KSK" >> "$infile"
|
||||
private_type_record $zone 5 "$ZSK" >> "$infile"
|
||||
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
|
||||
|
||||
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
|
||||
# time the existing keys do not match the policy. The existing keys are
|
||||
# 1024 bits RSASHA1 keys, and will be migrated to a dnssec-policy that
|
||||
# dictates 2048 bits RSASHA1 keys.
|
||||
setup migrate-nomatch-alglen.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a RSASHA1 -b 1024 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a RSASHA1 -b 1024 -L 300 $zone 2> keygen.out.$zone.2)
|
||||
Tds="now-24h" # Time according to dnssec-policy that DS will be OMNIPRESENT
|
||||
Tkey="now-3900s" # DNSKEY TTL + propagation delay
|
||||
Tsig="now-12h" # Zone's maximum TTL + propagation delay
|
||||
$SETTIME -P $Tkey -P sync $Tds -A $Tkey "$KSK" > settime.out.$zone.1 2>&1
|
||||
$SETTIME -P $Tsig -A $Tsig "$ZSK" > settime.out.$zone.2 2>&1
|
||||
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
|
||||
private_type_record $zone 5 "$KSK" >> "$infile"
|
||||
private_type_record $zone 5 "$ZSK" >> "$infile"
|
||||
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
|
||||
|
||||
#
|
||||
# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK
|
||||
# algorithm rollover.
|
||||
@@ -47,6 +95,7 @@ U="UNRETENTIVE"
|
||||
# Step 1:
|
||||
# Introduce the first key. This will immediately be active.
|
||||
setup step1.algorithm-roll.kasp
|
||||
echo "$zone" >> zones
|
||||
KSK=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
|
||||
TactN="now"
|
||||
|
||||
+414
-69
@@ -55,6 +55,7 @@ VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8="
|
||||
# STATE_DS=18
|
||||
# EXPECT_ZRRSIG=19
|
||||
# EXPECT_KRRSIG=20
|
||||
# LEGACY=21
|
||||
|
||||
key_key() {
|
||||
echo "${1}__${2}"
|
||||
@@ -77,7 +78,7 @@ key_clear() {
|
||||
key_set "$1" "ROLE" 'none'
|
||||
key_set "$1" "KSK" 'no'
|
||||
key_set "$1" "ZSK" 'no'
|
||||
key_set "$1" "LIFETIME" '0'
|
||||
key_set "$1" "LIFETIME" 'none'
|
||||
key_set "$1" "ALG_NUM" '0'
|
||||
key_set "$1" "ALG_STR" 'none'
|
||||
key_set "$1" "ALG_LEN" '0'
|
||||
@@ -93,6 +94,7 @@ key_clear() {
|
||||
key_set "$1" "STATE_DS" 'none'
|
||||
key_set "$1" "EXPECT_ZRRSIG" 'no'
|
||||
key_set "$1" "EXPECT_KRRSIG" 'no'
|
||||
key_set "$1" "LEGACY" 'no'
|
||||
}
|
||||
|
||||
# Start clear.
|
||||
@@ -238,6 +240,7 @@ check_key() {
|
||||
_length=$(key_get "$1" "ALG_LEN")
|
||||
_dnskey_ttl="$DNSKEY_TTL"
|
||||
_lifetime=$(key_get "$1" LIFETIME)
|
||||
_legacy=$(key_get "$1" LEGACY)
|
||||
|
||||
_published=$(key_get "$1" PUBLISHED)
|
||||
_active=$(key_get "$1" ACTIVE)
|
||||
@@ -277,10 +280,13 @@ check_key() {
|
||||
# Check file existence.
|
||||
[ -s "$KEY_FILE" ] || ret=1
|
||||
[ -s "$PRIVATE_FILE" ] || ret=1
|
||||
[ -s "$STATE_FILE" ] || ret=1
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
[ -s "$STATE_FILE" ] || ret=1
|
||||
fi
|
||||
[ "$ret" -eq 0 ] || log_error "${BASE_FILE} files missing"
|
||||
[ "$ret" -eq 0 ] || return
|
||||
|
||||
test $_log -eq 1 && echo_i "check key $BASE_FILE"
|
||||
test $_log -eq 1 && echo_i "check key file $BASE_FILE"
|
||||
|
||||
# Check the public key file.
|
||||
grep "This is a ${_role2} key, keyid ${_key_id}, for ${_zone}." "$KEY_FILE" > /dev/null || log_error "mismatch top comment in $KEY_FILE"
|
||||
@@ -289,106 +295,134 @@ check_key() {
|
||||
grep "Private-key-format: v1.3" "$PRIVATE_FILE" > /dev/null || log_error "mismatch private key format in $PRIVATE_FILE"
|
||||
grep "Algorithm: ${_alg_num} (${_alg_string})" "$PRIVATE_FILE" > /dev/null || log_error "mismatch algorithm in $PRIVATE_FILE"
|
||||
# Now check the key state file.
|
||||
grep "This is the state of key ${_key_id}, for ${_zone}." "$STATE_FILE" > /dev/null || log_error "mismatch top comment in $STATE_FILE"
|
||||
grep "Lifetime: ${_lifetime}" "$STATE_FILE" > /dev/null || log_error "mismatch lifetime in $STATE_FILE"
|
||||
grep "Algorithm: ${_alg_num}" "$STATE_FILE" > /dev/null || log_error "mismatch algorithm in $STATE_FILE"
|
||||
grep "Length: ${_length}" "$STATE_FILE" > /dev/null || log_error "mismatch length in $STATE_FILE"
|
||||
grep "KSK: ${_ksk}" "$STATE_FILE" > /dev/null || log_error "mismatch ksk in $STATE_FILE"
|
||||
grep "ZSK: ${_zsk}" "$STATE_FILE" > /dev/null || log_error "mismatch zsk in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "This is the state of key ${_key_id}, for ${_zone}." "$STATE_FILE" > /dev/null || log_error "mismatch top comment in $STATE_FILE"
|
||||
if [ "$_lifetime" == "none" ]; then
|
||||
grep "Lifetime: " "$STATE_FILE" > /dev/null && log_error "unexpected lifetime in $STATE_FILE"
|
||||
else
|
||||
grep "Lifetime: ${_lifetime}" "$STATE_FILE" > /dev/null || log_error "mismatch lifetime in $STATE_FILE"
|
||||
fi
|
||||
grep "Algorithm: ${_alg_num}" "$STATE_FILE" > /dev/null || log_error "mismatch algorithm in $STATE_FILE"
|
||||
grep "Length: ${_length}" "$STATE_FILE" > /dev/null || log_error "mismatch length in $STATE_FILE"
|
||||
grep "KSK: ${_ksk}" "$STATE_FILE" > /dev/null || log_error "mismatch ksk in $STATE_FILE"
|
||||
grep "ZSK: ${_zsk}" "$STATE_FILE" > /dev/null || log_error "mismatch zsk in $STATE_FILE"
|
||||
|
||||
# Check key states.
|
||||
if [ "$_goal" = "none" ]; then
|
||||
grep "GoalState: " "$STATE_FILE" > /dev/null && log_error "unexpected goal state in $STATE_FILE"
|
||||
else
|
||||
grep "GoalState: ${_goal}" "$STATE_FILE" > /dev/null || log_error "mismatch goal state in $STATE_FILE"
|
||||
fi
|
||||
# Check key states.
|
||||
if [ "$_goal" = "none" ]; then
|
||||
grep "GoalState: " "$STATE_FILE" > /dev/null && log_error "unexpected goal state in $STATE_FILE"
|
||||
else
|
||||
grep "GoalState: ${_goal}" "$STATE_FILE" > /dev/null || log_error "mismatch goal state in $STATE_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_state_dnskey" = "none" ]; then
|
||||
grep "DNSKEYState: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey state in $STATE_FILE"
|
||||
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey change in $STATE_FILE"
|
||||
else
|
||||
grep "DNSKEYState: ${_state_dnskey}" "$STATE_FILE" > /dev/null || log_error "mismatch dnskey state in $STATE_FILE"
|
||||
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null || log_error "mismatch dnskey change in $STATE_FILE"
|
||||
fi
|
||||
if [ "$_state_dnskey" = "none" ]; then
|
||||
grep "DNSKEYState: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey state in $STATE_FILE"
|
||||
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey change in $STATE_FILE"
|
||||
else
|
||||
grep "DNSKEYState: ${_state_dnskey}" "$STATE_FILE" > /dev/null || log_error "mismatch dnskey state in $STATE_FILE"
|
||||
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null || log_error "mismatch dnskey change in $STATE_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_state_zrrsig" = "none" ]; then
|
||||
grep "ZRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig state in $STATE_FILE"
|
||||
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig change in $STATE_FILE"
|
||||
else
|
||||
grep "ZRRSIGState: ${_state_zrrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig state in $STATE_FILE"
|
||||
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig change in $STATE_FILE"
|
||||
fi
|
||||
if [ "$_state_zrrsig" = "none" ]; then
|
||||
grep "ZRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig state in $STATE_FILE"
|
||||
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig change in $STATE_FILE"
|
||||
else
|
||||
grep "ZRRSIGState: ${_state_zrrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig state in $STATE_FILE"
|
||||
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig change in $STATE_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_state_krrsig" = "none" ]; then
|
||||
grep "KRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig state in $STATE_FILE"
|
||||
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig change in $STATE_FILE"
|
||||
else
|
||||
grep "KRRSIGState: ${_state_krrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch krrsig state in $STATE_FILE"
|
||||
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch krrsig change in $STATE_FILE"
|
||||
fi
|
||||
if [ "$_state_krrsig" = "none" ]; then
|
||||
grep "KRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig state in $STATE_FILE"
|
||||
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig change in $STATE_FILE"
|
||||
else
|
||||
grep "KRRSIGState: ${_state_krrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch krrsig state in $STATE_FILE"
|
||||
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch krrsig change in $STATE_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_state_ds" = "none" ]; then
|
||||
grep "DSState: " "$STATE_FILE" > /dev/null && log_error "unexpected ds state in $STATE_FILE"
|
||||
grep "DSChange: " "$STATE_FILE" > /dev/null && log_error "unexpected ds change in $STATE_FILE"
|
||||
else
|
||||
grep "DSState: ${_state_ds}" "$STATE_FILE" > /dev/null || log_error "mismatch ds state in $STATE_FILE"
|
||||
grep "DSChange: " "$STATE_FILE" > /dev/null || log_error "mismatch ds change in $STATE_FILE"
|
||||
if [ "$_state_ds" = "none" ]; then
|
||||
grep "DSState: " "$STATE_FILE" > /dev/null && log_error "unexpected ds state in $STATE_FILE"
|
||||
grep "DSChange: " "$STATE_FILE" > /dev/null && log_error "unexpected ds change in $STATE_FILE"
|
||||
else
|
||||
grep "DSState: ${_state_ds}" "$STATE_FILE" > /dev/null || log_error "mismatch ds state in $STATE_FILE"
|
||||
grep "DSChange: " "$STATE_FILE" > /dev/null || log_error "mismatch ds change in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check timing metadata.
|
||||
if [ "$_published" = "none" ]; then
|
||||
grep "; Publish:" "$KEY_FILE" > /dev/null && log_error "unexpected publish comment in $KEY_FILE"
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
|
||||
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Publish:" "$KEY_FILE" > /dev/null || log_error "mismatch publish comment in $KEY_FILE ($KEY_PUBLISHED)"
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch publish in $PRIVATE_FILE ($KEY_PUBLISHED)"
|
||||
grep "Published:" "$STATE_FILE" > /dev/null || log_error "mismatch publish in $STATE_FILE ($KEY_PUBLISHED)"
|
||||
grep "; Publish:" "$KEY_FILE" > /dev/null || log_error "mismatch publish comment in $KEY_FILE"
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch publish in $PRIVATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Published:" "$STATE_FILE" > /dev/null || log_error "mismatch publish in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_active" = "none" ]; then
|
||||
grep "; Activate:" "$KEY_FILE" > /dev/null && log_error "unexpected active comment in $KEY_FILE"
|
||||
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
|
||||
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Activate:" "$KEY_FILE" > /dev/null || log_error "mismatch active comment in $KEY_FILE"
|
||||
grep "Activate:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch active in $PRIVATE_FILE"
|
||||
grep "Active: " "$STATE_FILE" > /dev/null || log_error "mismatch active in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Active: " "$STATE_FILE" > /dev/null || log_error "mismatch active in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_retired" = "none" ]; then
|
||||
grep "; Inactive:" "$KEY_FILE" > /dev/null && log_error "unexpected retired comment in $KEY_FILE"
|
||||
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Inactive:" "$KEY_FILE" > /dev/null || log_error "mismatch retired comment in $KEY_FILE"
|
||||
grep "Inactive:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch retired in $PRIVATE_FILE"
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null || log_error "mismatch retired in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null || log_error "mismatch retired in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_revoked" = "none" ]; then
|
||||
grep "; Revoke:" "$KEY_FILE" > /dev/null && log_error "unexpected revoked comment in $KEY_FILE"
|
||||
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Revoke:" "$KEY_FILE" > /dev/null || log_error "mismatch revoked comment in $KEY_FILE"
|
||||
grep "Revoke:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch revoked in $PRIVATE_FILE"
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null || log_error "mismatch revoked in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null || log_error "mismatch revoked in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_removed" = "none" ]; then
|
||||
grep "; Delete:" "$KEY_FILE" > /dev/null && log_error "unexpected removed comment in $KEY_FILE"
|
||||
grep "Delete:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected removed in $PRIVATE_FILE"
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
|
||||
fi
|
||||
else
|
||||
grep "; Delete:" "$KEY_FILE" > /dev/null || log_error "mismatch removed comment in $KEY_FILE"
|
||||
grep "Delete:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch removed in $PRIVATE_FILE"
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null || log_error "mismatch removed in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null || log_error "mismatch removed in $STATE_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
grep "; Created:" "$KEY_FILE" > /dev/null || log_error "mismatch created comment in $KEY_FILE"
|
||||
grep "Created:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch created in $PRIVATE_FILE"
|
||||
grep "Generated: " "$STATE_FILE" > /dev/null || log_error "mismatch generated in $STATE_FILE"
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Generated: " "$STATE_FILE" > /dev/null || log_error "mismatch generated in $STATE_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check the key with key id $1 and see if it is unused.
|
||||
@@ -424,20 +458,24 @@ key_unused() {
|
||||
|
||||
# Check timing metadata.
|
||||
grep "; Publish:" "$KEY_FILE" > /dev/null && log_error "unexpected publish comment in $KEY_FILE"
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
|
||||
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
|
||||
grep "; Activate:" "$KEY_FILE" > /dev/null && log_error "unexpected active comment in $KEY_FILE"
|
||||
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
|
||||
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
|
||||
grep "; Inactive:" "$KEY_FILE" > /dev/null && log_error "unexpected retired comment in $KEY_FILE"
|
||||
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
|
||||
grep "; Revoke:" "$KEY_FILE" > /dev/null && log_error "unexpected revoked comment in $KEY_FILE"
|
||||
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
|
||||
grep "; Delete:" "$KEY_FILE" > /dev/null && log_error "unexpected removed comment in $KEY_FILE"
|
||||
|
||||
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
|
||||
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
|
||||
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
|
||||
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
|
||||
grep "Delete:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected removed in $PRIVATE_FILE"
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
|
||||
|
||||
if [ "$_legacy" == "no" ]; then
|
||||
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
|
||||
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
|
||||
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
|
||||
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
|
||||
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Test: dnssec-verify zone $1.
|
||||
@@ -848,7 +886,7 @@ check_keys()
|
||||
for _id in $_ids; do
|
||||
# There are three key files with the same algorithm.
|
||||
# Check them until a match is found.
|
||||
echo_i "check key $_id"
|
||||
echo_i "check key id $_id"
|
||||
|
||||
if [ "no" = "$(key_get KEY1 ID)" ] && [ "$(key_get KEY1 EXPECT)" = "yes" ]; then
|
||||
ret=0
|
||||
@@ -863,19 +901,19 @@ check_keys()
|
||||
if [ "no" = "$(key_get KEY3 ID)" ] && [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
|
||||
ret=0
|
||||
check_key "KEY3" "$_id"
|
||||
test "$ret" -eq 0 && key_set KEY3 ID "$KEY_ID" && continue
|
||||
test "$ret" -eq 0 && key_set KEY3 "ID" "$KEY_ID" && continue
|
||||
fi
|
||||
if [ "no" = "$(key_get KEY4 ID)" ] && [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
|
||||
ret=0
|
||||
check_key "KEY4" "$_id"
|
||||
test "$ret" -eq 0 && key_set KEY4 ID "$KEY_ID" && continue
|
||||
test "$ret" -eq 0 && key_set KEY4 "ID" "$KEY_ID" && continue
|
||||
fi
|
||||
|
||||
# This may be an unused key. Assume algorithm of KEY1.
|
||||
ret=0 && key_unused "$_id" "$(key_get KEY1 ALG_NUM)"
|
||||
test "$ret" -eq 0 && continue
|
||||
|
||||
# If ret is still non-zero, non of the files matched.
|
||||
# If ret is still non-zero, none of the files matched.
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status+1))
|
||||
done
|
||||
@@ -885,15 +923,19 @@ check_keys()
|
||||
|
||||
ret=0
|
||||
if [ "$(key_get KEY1 EXPECT)" = "yes" ]; then
|
||||
echo_i "KEY1 ID $(key_get KEY1 ID)"
|
||||
test "no" = "$(key_get KEY1 ID)" && log_error "No KEY1 found for zone ${ZONE}"
|
||||
fi
|
||||
if [ "$(key_get KEY2 EXPECT)" = "yes" ]; then
|
||||
echo_i "KEY2 ID $(key_get KEY2 ID)"
|
||||
test "no" = "$(key_get KEY2 ID)" && log_error "No KEY2 found for zone ${ZONE}"
|
||||
fi
|
||||
if [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
|
||||
echo_i "KEY3 ID $(key_get KEY3 ID)"
|
||||
test "no" = "$(key_get KEY3 ID)" && log_error "No KEY3 found for zone ${ZONE}"
|
||||
fi
|
||||
if [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
|
||||
echo_i "KEY4 ID $(key_get KEY4 ID)"
|
||||
test "no" = "$(key_get KEY4 ID)" && log_error "No KEY4 found for zone ${ZONE}"
|
||||
fi
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
@@ -2821,7 +2863,166 @@ dnssec_verify
|
||||
# interval.
|
||||
check_next_key_event 3600
|
||||
|
||||
# Reconfig dnssec-policy (triggering algorithm roll).
|
||||
#
|
||||
# Testing good migration.
|
||||
#
|
||||
set_zone "migrate.kasp"
|
||||
set_policy "none" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
init_migration_match() {
|
||||
key_clear "KEY1"
|
||||
key_set "KEY1" "LEGACY" "yes"
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keylifetime "KEY1" "0"
|
||||
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "no"
|
||||
|
||||
key_clear "KEY2"
|
||||
key_set "KEY2" "LEGACY" "yes"
|
||||
set_keyrole "KEY2" "zsk"
|
||||
set_keylifetime "KEY2" "5184000"
|
||||
set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY2" "no"
|
||||
set_zonesigning "KEY2" "yes"
|
||||
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
set_keytime "KEY1" "PUBLISHED" "yes"
|
||||
set_keytime "KEY1" "ACTIVE" "yes"
|
||||
set_keytime "KEY1" "RETIRED" "none"
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY1" "STATE_DS" "rumoured"
|
||||
|
||||
set_keytime "KEY2" "PUBLISHED" "yes"
|
||||
set_keytime "KEY2" "ACTIVE" "yes"
|
||||
set_keytime "KEY2" "RETIRED" "none"
|
||||
set_keystate "KEY2" "GOAL" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
|
||||
}
|
||||
init_migration_match
|
||||
|
||||
# Make sure the zone is signed with legacy keys.
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Remember legacy key tags.
|
||||
_migrate_ksk=$(key_get KEY1 ID)
|
||||
_migrate_zsk=$(key_get KEY2 ID)
|
||||
|
||||
#
|
||||
# Testing migration with unmatched existing keys (different algorithm).
|
||||
#
|
||||
set_zone "migrate-nomatch-algnum.kasp"
|
||||
set_policy "none" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
init_migration_nomatch_algnum() {
|
||||
key_clear "KEY1"
|
||||
key_set "KEY1" "LEGACY" "yes"
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keyalgorithm "KEY1" "5" "RSASHA1" "2048"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "no"
|
||||
|
||||
key_clear "KEY2"
|
||||
key_set "KEY2" "LEGACY" "yes"
|
||||
set_keyrole "KEY2" "zsk"
|
||||
set_keyalgorithm "KEY2" "5" "RSASHA1" "1024"
|
||||
set_keysigning "KEY2" "no"
|
||||
set_zonesigning "KEY2" "yes"
|
||||
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
set_keytime "KEY1" "PUBLISHED" "yes"
|
||||
set_keytime "KEY1" "ACTIVE" "yes"
|
||||
set_keytime "KEY1" "RETIRED" "none"
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DS" "omnipresent"
|
||||
|
||||
set_keytime "KEY2" "PUBLISHED" "yes"
|
||||
set_keytime "KEY2" "ACTIVE" "yes"
|
||||
set_keytime "KEY2" "RETIRED" "none"
|
||||
set_keystate "KEY2" "GOAL" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
|
||||
}
|
||||
init_migration_nomatch_algnum
|
||||
|
||||
# Make sure the zone is signed with legacy keys.
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Remember legacy key tags.
|
||||
_migratenomatch_algnum_ksk=$(key_get KEY1 ID)
|
||||
_migratenomatch_algnum_zsk=$(key_get KEY2 ID)
|
||||
|
||||
#
|
||||
# Testing migration with unmatched existing keys (different length).
|
||||
#
|
||||
set_zone "migrate-nomatch-alglen.kasp"
|
||||
set_policy "none" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
init_migration_nomatch_alglen() {
|
||||
key_clear "KEY1"
|
||||
key_set "KEY1" "LEGACY" "yes"
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keyalgorithm "KEY1" "5" "RSASHA1" "1024"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "no"
|
||||
|
||||
key_clear "KEY2"
|
||||
key_set "KEY2" "LEGACY" "yes"
|
||||
set_keyrole "KEY2" "zsk"
|
||||
set_keyalgorithm "KEY2" "5" "RSASHA1" "1024"
|
||||
set_keysigning "KEY2" "no"
|
||||
set_zonesigning "KEY2" "yes"
|
||||
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
set_keytime "KEY1" "PUBLISHED" "yes"
|
||||
set_keytime "KEY1" "ACTIVE" "yes"
|
||||
set_keytime "KEY1" "RETIRED" "none"
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DS" "omnipresent"
|
||||
|
||||
set_keytime "KEY2" "PUBLISHED" "yes"
|
||||
set_keytime "KEY2" "ACTIVE" "yes"
|
||||
set_keytime "KEY2" "RETIRED" "none"
|
||||
set_keystate "KEY2" "GOAL" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
|
||||
}
|
||||
init_migration_nomatch_alglen
|
||||
|
||||
# Make sure the zone is signed with legacy keys.
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Remember legacy key tags.
|
||||
_migratenomatch_alglen_ksk=$(key_get KEY1 ID)
|
||||
_migratenomatch_alglen_zsk=$(key_get KEY2 ID)
|
||||
|
||||
# Reconfig dnssec-policy (triggering algorithm roll and other dnssec-policy
|
||||
# changes).
|
||||
echo_i "reconfig dnssec-policy to trigger algorithm rollover"
|
||||
copy_setports ns6/named2.conf.in ns6/named.conf
|
||||
rndc_reconfig ns6 10.53.0.6
|
||||
@@ -2854,6 +3055,150 @@ status=$((status+ret))
|
||||
|
||||
next_key_event_threshold=$((next_key_event_threshold+i))
|
||||
|
||||
#
|
||||
# Testing migration.
|
||||
#
|
||||
set_zone "migrate.kasp"
|
||||
set_policy "migrate" "2" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
# Key properties, timings and metadata should be the same as legacy keys above.
|
||||
# However, because the zsk has a lifetime, kasp will set the retired time.
|
||||
init_migration_match
|
||||
|
||||
key_set "KEY1" "LEGACY" "no"
|
||||
|
||||
key_set "KEY2" "LEGACY" "no"
|
||||
set_keytime "KEY2" "RETIRED" "yes"
|
||||
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Check key tags, should be the same.
|
||||
n=$((n+1))
|
||||
echo_i "check that of zone ${ZONE} migration to dnssec-policy uses the same keys ($n)"
|
||||
ret=0
|
||||
[ $_migrate_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
|
||||
[ $_migrate_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
|
||||
status=$((status+ret))
|
||||
|
||||
# Test migration to dnssec-policy, existing keys do not match key algorithm.
|
||||
set_zone "migrate-nomatch-algnum.kasp"
|
||||
set_policy "migrate-nomatch-algnum" "4" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
# The legacy keys need to be retired, but otherwise stay present until the
|
||||
# new keys are omnipresent, and can be used to construct a chain of trust.
|
||||
init_migration_nomatch_algnum
|
||||
|
||||
key_set "KEY1" "LEGACY" "no"
|
||||
set_keytime "KEY1" "RETIRED" "yes"
|
||||
set_keystate "KEY1" "GOAL" "hidden"
|
||||
|
||||
key_set "KEY2" "LEGACY" "no"
|
||||
set_keytime "KEY2" "RETIRED" "yes"
|
||||
set_keystate "KEY2" "GOAL" "hidden"
|
||||
|
||||
set_keyrole "KEY3" "ksk"
|
||||
set_keylifetime "KEY3" "0"
|
||||
set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY3" "yes"
|
||||
set_zonesigning "KEY3" "no"
|
||||
|
||||
set_keyrole "KEY4" "zsk"
|
||||
set_keylifetime "KEY4" "5184000"
|
||||
set_keyalgorithm "KEY4" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY4" "no"
|
||||
set_zonesigning "KEY4" "yes"
|
||||
|
||||
set_keytime "KEY3" "PUBLISHED" "yes"
|
||||
set_keytime "KEY3" "ACTIVE" "yes"
|
||||
set_keytime "KEY3" "RETIRED" "none"
|
||||
set_keystate "KEY3" "GOAL" "omnipresent"
|
||||
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY3" "STATE_DS" "hidden"
|
||||
|
||||
set_keytime "KEY4" "PUBLISHED" "yes"
|
||||
set_keytime "KEY4" "ACTIVE" "yes"
|
||||
set_keytime "KEY4" "RETIRED" "yes"
|
||||
set_keystate "KEY4" "GOAL" "omnipresent"
|
||||
set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY4" "STATE_ZRRSIG" "rumoured"
|
||||
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Check key tags, should be the same.
|
||||
n=$((n+1))
|
||||
echo_i "check that of zone ${ZONE} migration to dnssec-policy keeps existing keys ($n)"
|
||||
ret=0
|
||||
[ $_migratenomatch_algnum_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
|
||||
[ $_migratenomatch_algnum_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
|
||||
status=$((status+ret))
|
||||
|
||||
# Test migration to dnssec-policy, existing keys do not match key length.
|
||||
set_zone "migrate-nomatch-alglen.kasp"
|
||||
set_policy "migrate-nomatch-alglen" "4" "300"
|
||||
set_server "ns6" "10.53.0.6"
|
||||
|
||||
# The legacy keys need to be retired, but otherwise stay present until the
|
||||
# new keys are omnipresent, and can be used to construct a chain of trust.
|
||||
init_migration_nomatch_alglen
|
||||
|
||||
key_set "KEY1" "LEGACY" "no"
|
||||
set_keytime "KEY1" "RETIRED" "yes"
|
||||
set_keystate "KEY1" "GOAL" "hidden"
|
||||
|
||||
key_set "KEY2" "LEGACY" "no"
|
||||
set_keytime "KEY2" "RETIRED" "yes"
|
||||
set_keystate "KEY2" "GOAL" "hidden"
|
||||
|
||||
set_keyrole "KEY3" "ksk"
|
||||
set_keylifetime "KEY3" "0"
|
||||
set_keyalgorithm "KEY3" "5" "RSASHA1" "2048"
|
||||
set_keysigning "KEY3" "yes"
|
||||
set_zonesigning "KEY3" "no"
|
||||
|
||||
set_keyrole "KEY4" "zsk"
|
||||
set_keylifetime "KEY4" "5184000"
|
||||
set_keyalgorithm "KEY4" "5" "RSASHA1" "2048"
|
||||
set_keysigning "KEY4" "no"
|
||||
# This key is considered to be prepublished, so it is not yet signing.
|
||||
set_zonesigning "KEY4" "no"
|
||||
|
||||
set_keytime "KEY3" "PUBLISHED" "yes"
|
||||
set_keytime "KEY3" "ACTIVE" "yes"
|
||||
set_keytime "KEY3" "RETIRED" "none"
|
||||
set_keystate "KEY3" "GOAL" "omnipresent"
|
||||
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY3" "STATE_DS" "hidden"
|
||||
|
||||
set_keytime "KEY4" "PUBLISHED" "yes"
|
||||
set_keytime "KEY4" "ACTIVE" "yes"
|
||||
set_keytime "KEY4" "RETIRED" "yes"
|
||||
set_keystate "KEY4" "GOAL" "omnipresent"
|
||||
set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY4" "STATE_ZRRSIG" "hidden"
|
||||
|
||||
check_keys
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Check key tags, should be the same.
|
||||
n=$((n+1))
|
||||
echo_i "check that of zone ${ZONE} migration to dnssec-policy keeps existing keys ($n)"
|
||||
ret=0
|
||||
[ $_migratenomatch_alglen_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
|
||||
[ $_migratenomatch_alglen_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
|
||||
status=$((status+ret))
|
||||
|
||||
#
|
||||
# Testing KSK/ZSK algorithm rollover.
|
||||
#
|
||||
|
||||
@@ -22,5 +22,6 @@ rm -f xml.*mem json.*mem
|
||||
rm -f compressed.headers regular.headers compressed.out regular.out
|
||||
rm -f ns*/managed-keys.bind*
|
||||
rm -f ns2/Kdnssec* ns2/dnssec.*.id
|
||||
rm -f ns2/dnssec.db.signed* ns2/dsset-dnssec.
|
||||
rm -f ns2/Kmanykeys* ns2/manykeys.*.id
|
||||
rm -f ns2/*.db.signed* ns2/dsset-*. ns2/*.jbk
|
||||
rm -f ns2/core
|
||||
|
||||
@@ -34,6 +34,17 @@ controls {
|
||||
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
dnssec-policy "manykeys" {
|
||||
keys {
|
||||
ksk lifetime unlimited algorithm 5;
|
||||
zsk lifetime unlimited algorithm 5;
|
||||
ksk lifetime unlimited algorithm 13;
|
||||
zsk lifetime unlimited algorithm 13;
|
||||
ksk lifetime unlimited algorithm 14;
|
||||
zsk lifetime unlimited algorithm 14;
|
||||
};
|
||||
};
|
||||
|
||||
zone "example" {
|
||||
type master;
|
||||
file "example.db";
|
||||
@@ -49,3 +60,10 @@ zone "dnssec" {
|
||||
dnssec-dnskey-kskonly yes;
|
||||
update-check-ksk yes;
|
||||
};
|
||||
|
||||
zone "manykeys" {
|
||||
type master;
|
||||
file "manykeys.db.signed";
|
||||
zone-statistics full;
|
||||
dnssec-policy "manykeys";
|
||||
};
|
||||
|
||||
@@ -17,12 +17,27 @@ set -e
|
||||
zone=dnssec.
|
||||
infile=dnssec.db.in
|
||||
zonefile=dnssec.db.signed
|
||||
|
||||
ksk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
|
||||
zsk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
|
||||
# Sign deliberately with a very short expiration date.
|
||||
"$SIGNER" -S -x -O full -e "now"+1s -o "$zone" -f "$zonefile" "$infile" > /dev/null 2>&1
|
||||
|
||||
keyfile_to_key_id "$ksk" > dnssec.ksk.id
|
||||
keyfile_to_key_id "$zsk" > dnssec.zsk.id
|
||||
|
||||
zone=manykeys.
|
||||
infile=manykeys.db.in
|
||||
zonefile=manykeys.db.signed
|
||||
ksk8=$("$KEYGEN" -q -a RSASHA256 -b 2048 -f KSK "$zone")
|
||||
zsk8=$("$KEYGEN" -q -a RSASHA256 -b 2048 "$zone")
|
||||
ksk13=$("$KEYGEN" -q -a ECDSAP256SHA256 -b 256 -f KSK "$zone")
|
||||
zsk13=$("$KEYGEN" -q -a ECDSAP256SHA256 -b 256 "$zone")
|
||||
ksk14=$("$KEYGEN" -q -a ECDSAP384SHA384 -b 384 -f KSK "$zone")
|
||||
zsk14=$("$KEYGEN" -q -a ECDSAP384SHA384 -b 384 "$zone")
|
||||
# Sign deliberately with a very short expiration date.
|
||||
"$SIGNER" -S -x -O full -e "now"+1s -o "$zone" -f "$zonefile" "$infile" > /dev/null 2>&1
|
||||
keyfile_to_key_id "$ksk8" > manykeys.ksk8.id
|
||||
keyfile_to_key_id "$zsk8" > manykeys.zsk8.id
|
||||
keyfile_to_key_id "$ksk13" > manykeys.ksk13.id
|
||||
keyfile_to_key_id "$zsk13" > manykeys.zsk13.id
|
||||
keyfile_to_key_id "$ksk14" > manykeys.ksk14.id
|
||||
keyfile_to_key_id "$zsk14" > manykeys.zsk14.id
|
||||
|
||||
@@ -70,8 +70,8 @@ getzones() {
|
||||
*) return 1 ;;
|
||||
esac
|
||||
file=`$PERL fetch.pl -p ${EXTRAPORT1} $path`
|
||||
cp $file $file.$1.$2
|
||||
$PERL zones-${1}.pl $file 2>/dev/null | sort > zones.out.$2
|
||||
cp $file $file.$1.$3
|
||||
$PERL zones-${1}.pl $file $2 2>/dev/null | sort > zones.out.$3
|
||||
result=$?
|
||||
return $result
|
||||
}
|
||||
@@ -292,11 +292,11 @@ rm -f zones.expect
|
||||
# Fetch and check the dnssec sign statistics.
|
||||
echo_i "fetching zone stats data after zone maintenance at startup ($n)"
|
||||
if [ $PERL_XML ]; then
|
||||
getzones xml x$n || ret=1
|
||||
getzones xml $zone x$n || ret=1
|
||||
cmp zones.out.x$n zones.expect.$n || ret=1
|
||||
fi
|
||||
if [ $PERL_JSON ]; then
|
||||
getzones json j$n || ret=1
|
||||
getzones json $zone j$n || ret=1
|
||||
cmp zones.out.j$n zones.expect.$n || ret=1
|
||||
fi
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
@@ -322,11 +322,11 @@ rm -f zones.expect
|
||||
# Fetch and check the dnssec sign statistics.
|
||||
echo_i "fetching zone stats data after dynamic update ($n)"
|
||||
if [ $PERL_XML ]; then
|
||||
getzones xml x$n || ret=1
|
||||
getzones xml $zone x$n || ret=1
|
||||
cmp zones.out.x$n zones.expect.$n || ret=1
|
||||
fi
|
||||
if [ $PERL_JSON ]; then
|
||||
getzones json j$n || ret=1
|
||||
getzones json $zone j$n || ret=1
|
||||
cmp zones.out.j$n zones.expect.$n || ret=1
|
||||
fi
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
@@ -349,16 +349,39 @@ cat zones.expect | sort > zones.expect.$n
|
||||
rm -f zones.expect
|
||||
# Fetch and check the dnssec sign statistics.
|
||||
if [ $PERL_XML ]; then
|
||||
getzones xml x$n || ret=1
|
||||
getzones xml $zone x$n || ret=1
|
||||
cmp zones.out.x$n zones.expect.$n || ret=1
|
||||
fi
|
||||
if [ $PERL_JSON ]; then
|
||||
getzones json j$n || ret=1
|
||||
getzones json $zone j$n || ret=1
|
||||
cmp zones.out.j$n zones.expect.$n || ret=1
|
||||
fi
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
n=`expr $n + 1`
|
||||
|
||||
# 4. Test a zone with more than four keys.
|
||||
zone="manykeys"
|
||||
ksk8_id=`cat ns2/$zone.ksk8.id`
|
||||
zsk8_id=`cat ns2/$zone.zsk8.id`
|
||||
ksk13_id=`cat ns2/$zone.ksk13.id`
|
||||
zsk13_id=`cat ns2/$zone.zsk13.id`
|
||||
ksk14_id=`cat ns2/$zone.ksk14.id`
|
||||
zsk14_id=`cat ns2/$zone.zsk14.id`
|
||||
|
||||
ret=0
|
||||
echo_i "fetch zone stats data for a zone with many keys ($n)"
|
||||
# Fetch and check the dnssec sign statistics.
|
||||
if [ $PERL_XML ]; then
|
||||
getzones xml $zone x$n || ret=1
|
||||
fi
|
||||
if [ $PERL_JSON ]; then
|
||||
getzones json $zone j$n || ret=1
|
||||
fi
|
||||
# The output is gibberish, but at least make sure it does not crash.
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
n=`expr $n + 1`
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
use JSON;
|
||||
|
||||
my $file = $ARGV[0];
|
||||
my $zone = $ARGV[1];
|
||||
open(INPUT, "<$file");
|
||||
my $text = do{local$/;<INPUT>};
|
||||
close(INPUT);
|
||||
@@ -23,12 +24,12 @@ close(INPUT);
|
||||
my $ref = decode_json($text);
|
||||
|
||||
|
||||
my $dnssecsign = $ref->{views}->{_default}->{zones}[0]->{"dnssec-sign"};
|
||||
my $dnssecsign = $ref->{views}->{_default}->{zones}[$zone]->{"dnssec-sign"};
|
||||
my $type = "dnssec-sign operations ";
|
||||
foreach $key (keys %{$dnssecsign}) {
|
||||
print $type . $key . ": ". $dnssecsign->{$key} ."\n";
|
||||
}
|
||||
my $dnssecrefresh = $ref->{views}->{_default}->{zones}[0]->{"dnssec-refresh"};
|
||||
my $dnssecrefresh = $ref->{views}->{_default}->{zones}[$zone]->{"dnssec-refresh"};
|
||||
my $type = "dnssec-refresh operations ";
|
||||
foreach $key (keys %{$dnssecrefresh}) {
|
||||
print $type . $key . ": ". $dnssecrefresh->{$key} ."\n";
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
use XML::Simple;
|
||||
|
||||
my $file = $ARGV[0];
|
||||
my $zone = $ARGV[1];
|
||||
|
||||
my $ref = XMLin($file);
|
||||
|
||||
my $counters = $ref->{views}->{view}->{_default}->{zones}->{zone}->{dnssec}->{counters};
|
||||
my $counters = $ref->{views}->{view}->{_default}->{zones}->{zone}->{$zone}->{counters};
|
||||
|
||||
foreach $group (@$counters) {
|
||||
|
||||
|
||||
@@ -62,6 +62,10 @@
|
||||
#include <dlz/sdlz_helper.h>
|
||||
#include <named/globals.h>
|
||||
|
||||
#if !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000
|
||||
typedef bool my_bool;
|
||||
#endif /* !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000 */
|
||||
|
||||
static dns_sdlzimplementation_t *dlz_mysql = NULL;
|
||||
|
||||
#define dbc_search_limit 30
|
||||
@@ -759,9 +763,6 @@ mysql_create(const char *dlzname, unsigned int argc, char *argv[],
|
||||
char *endp;
|
||||
int j;
|
||||
unsigned int flags = 0;
|
||||
#if MYSQL_VERSION_ID >= 50000
|
||||
my_bool auto_reconnect = 1;
|
||||
#endif /* if MYSQL_VERSION_ID >= 50000 */
|
||||
|
||||
UNUSED(driverarg);
|
||||
UNUSED(dlzname);
|
||||
@@ -897,21 +898,21 @@ mysql_create(const char *dlzname, unsigned int argc, char *argv[],
|
||||
pass = getParameterValue(argv[1], "pass=");
|
||||
socket = getParameterValue(argv[1], "socket=");
|
||||
|
||||
#if MYSQL_VERSION_ID >= 50000
|
||||
/* enable automatic reconnection. */
|
||||
if (mysql_options((MYSQL *)dbi->dbconn, MYSQL_OPT_RECONNECT,
|
||||
&auto_reconnect) != 0)
|
||||
&(my_bool){ 1 }) != 0)
|
||||
{
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
||||
DNS_LOGMODULE_DLZ, ISC_LOG_WARNING,
|
||||
"mysql driver failed to set "
|
||||
"MYSQL_OPT_RECONNECT option, continuing");
|
||||
"MYSQL_OPT_RECONNECT option, "
|
||||
"continuing");
|
||||
}
|
||||
#endif /* if MYSQL_VERSION_ID >= 50000 */
|
||||
|
||||
for (j = 0; dbc == NULL && j < 4; j++)
|
||||
for (j = 0; dbc == NULL && j < 4; j++) {
|
||||
dbc = mysql_real_connect((MYSQL *)dbi->dbconn, host, user, pass,
|
||||
dbname, port, socket, flags);
|
||||
}
|
||||
|
||||
/* let user know if we couldn't connect. */
|
||||
if (dbc == NULL) {
|
||||
|
||||
@@ -59,6 +59,10 @@
|
||||
#include <dlz_minimal.h>
|
||||
#include <dlz_pthread.h>
|
||||
|
||||
#if !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000
|
||||
typedef bool my_bool;
|
||||
#endif /* !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000 */
|
||||
|
||||
#define dbc_search_limit 30
|
||||
#define ALLNODES 1
|
||||
#define ALLOWXFR 2
|
||||
@@ -812,9 +816,6 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
|
||||
char *endp;
|
||||
int j;
|
||||
const char *helper_name;
|
||||
#if MYSQL_VERSION_ID >= 50000
|
||||
my_bool auto_reconnect = 1;
|
||||
#endif /* if MYSQL_VERSION_ID >= 50000 */
|
||||
#if PTHREADS
|
||||
int dbcount;
|
||||
int i;
|
||||
@@ -1012,17 +1013,15 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
|
||||
|
||||
dbc = NULL;
|
||||
|
||||
#if MYSQL_VERSION_ID >= 50000
|
||||
/* enable automatic reconnection. */
|
||||
if (mysql_options((MYSQL *)dbi->dbconn, MYSQL_OPT_RECONNECT,
|
||||
&auto_reconnect) != 0)
|
||||
&(my_bool){ 1 }) != 0)
|
||||
{
|
||||
mysql->log(ISC_LOG_WARNING, "MySQL module failed to "
|
||||
"set "
|
||||
"MYSQL_OPT_RECONNECT "
|
||||
"option, continuing");
|
||||
}
|
||||
#endif /* if MYSQL_VERSION_ID >= 50000 */
|
||||
|
||||
for (j = 0; dbc == NULL && j < 4; j++) {
|
||||
dbc = mysql_real_connect(
|
||||
|
||||
@@ -61,6 +61,10 @@
|
||||
#include <dlz_minimal.h>
|
||||
#include <dlz_pthread.h>
|
||||
|
||||
#if !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000
|
||||
typedef bool my_bool;
|
||||
#endif /* !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000 */
|
||||
|
||||
/*
|
||||
* The SQL queries that will be used for lookups and updates are defined
|
||||
* here. They will be processed into queries by the build_query()
|
||||
@@ -1020,7 +1024,6 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
|
||||
*/
|
||||
if (mysql_thread_safe()) {
|
||||
for (n = 0; n < MAX_DBI; n++) {
|
||||
my_bool opt = 1;
|
||||
dlz_mutex_init(&state->db[n].mutex, NULL);
|
||||
dlz_mutex_lock(&state->db[n].mutex);
|
||||
state->db[n].id = n;
|
||||
@@ -1029,7 +1032,7 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
|
||||
mysql_options(state->db[n].sock,
|
||||
MYSQL_READ_DEFAULT_GROUP, modname);
|
||||
mysql_options(state->db[n].sock, MYSQL_OPT_RECONNECT,
|
||||
&opt);
|
||||
&(my_bool){ 1 });
|
||||
dlz_mutex_unlock(&state->db[n].mutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -887,9 +887,6 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
|
||||
char *tmp = NULL;
|
||||
char *endp;
|
||||
const char *helper_name;
|
||||
#if SQLITE3_VERSION_ID >= 50000
|
||||
my_bool auto_reconnect = 1;
|
||||
#endif /* if SQLITE3_VERSION_ID >= 50000 */
|
||||
#if PTHREADS
|
||||
int dbcount;
|
||||
int i, ret;
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<!--
|
||||
- Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
-
|
||||
- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
-
|
||||
- See the COPYRIGHT file distributed with this work for additional
|
||||
- information regarding copyright ownership.
|
||||
-->
|
||||
|
||||
<section xml:id="relnotes-9.17.1"><info><title>Notes for BIND 9.17.1</title></info>
|
||||
|
||||
<section xml:id="relnotes-9.17.1-security"><info><title>Security Fixes</title></info>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
None.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="relnotes-9.17.1-known"><info><title>Known Issues</title></info>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
None.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="relnotes-9.17.1-new"><info><title>New Features</title></info>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
None.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="relnotes-9.17.1-changes"><info><title>Feature Changes</title></info>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The DNSSEC sign statistics used lots of memory. The number of keys
|
||||
to track is reduced to four per zone, which should be enough for
|
||||
99% of all signed zones. [GL #1179]
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="relnotes-9.17.1-bugs"><info><title>Bug Fixes</title></info>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When an RPZ policy zone was updated via zone transfer
|
||||
and a large number of records were deleted, <command>named</command>
|
||||
could become nonresponsive for a short period while deleted
|
||||
names were removed from the RPZ summary database. This database
|
||||
cleanup is now done incrementally over a longer period of time,
|
||||
reducing such delays. [GL #1447]
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Migration to dnssec-policy from existing DNSSEC strategy with
|
||||
auto-dnssec maintain did not work due to bad initializing of the
|
||||
key states. Fixed by looking closely at the time metadata to
|
||||
set the key states to the correct values. [GL #1706]
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
@@ -23,6 +23,7 @@
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-platforms.xml"/>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-download.xml"/>
|
||||
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-9.17.1.xml"/>
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-9.17.0.xml"/>
|
||||
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-license.xml"/>
|
||||
|
||||
@@ -491,6 +491,14 @@ LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[];
|
||||
#define DNS_RDATASTATSTYPE_ATTR(type) ((type) >> 16)
|
||||
#define DNS_RDATASTATSTYPE_VALUE(b, a) (((a) << 16) | (b))
|
||||
|
||||
/*%
|
||||
* Types of DNSSEC sign statistics operations.
|
||||
*/
|
||||
typedef enum {
|
||||
dns_dnssecsignstats_sign = 1,
|
||||
dns_dnssecsignstats_refresh = 2
|
||||
} dnssecsignstats_type_t;
|
||||
|
||||
/*%<
|
||||
* Types of dump callbacks.
|
||||
*/
|
||||
@@ -684,9 +692,11 @@ dns_rcodestats_increment(dns_stats_t *stats, dns_opcode_t code);
|
||||
*/
|
||||
|
||||
void
|
||||
dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id);
|
||||
dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id, uint8_t alg,
|
||||
dnssecsignstats_type_t operation);
|
||||
/*%<
|
||||
* Increment the statistics counter for the DNSKEY 'id'.
|
||||
* Increment the statistics counter for the DNSKEY 'id'. The 'operation'
|
||||
* determines what counter is incremented.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'stats' is a valid dns_stats_t created by dns_dnssecsignstats_create().
|
||||
@@ -737,7 +747,7 @@ dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
|
||||
*/
|
||||
|
||||
void
|
||||
dns_dnssecsignstats_dump(dns_stats_t * stats,
|
||||
dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation,
|
||||
dns_dnssecsignstats_dumper_t dump_fn, void *arg,
|
||||
unsigned int options);
|
||||
/*%<
|
||||
|
||||
@@ -1957,9 +1957,6 @@ dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats);
|
||||
|
||||
void
|
||||
dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats);
|
||||
|
||||
void
|
||||
dns_zone_setdnssecrefreshstats(dns_zone_t *zone, dns_stats_t *stats);
|
||||
/*%<
|
||||
* Set additional statistics sets to zone. These are attached to the zone
|
||||
* but are not counted in the zone module; only the caller updates the
|
||||
@@ -1979,9 +1976,6 @@ dns_zone_getrcvquerystats(dns_zone_t *zone);
|
||||
|
||||
dns_stats_t *
|
||||
dns_zone_getdnssecsignstats(dns_zone_t *zone);
|
||||
|
||||
dns_stats_t *
|
||||
dns_zone_getdnssecrefreshstats(dns_zone_t *zone);
|
||||
/*%<
|
||||
* Get the additional statistics for zone, if one is installed.
|
||||
*
|
||||
@@ -1993,17 +1987,6 @@ dns_zone_getdnssecrefreshstats(dns_zone_t *zone);
|
||||
* otherwise NULL.
|
||||
*/
|
||||
|
||||
/*%<
|
||||
* Set additional statistics sets to zone. These are attached to the zone
|
||||
* but are not counted in the zone module; only the caller updates the
|
||||
* counters.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'zone' to be a valid zone.
|
||||
*
|
||||
*\li stats is a valid statistics.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_zone_dialup(dns_zone_t *zone);
|
||||
/*%<
|
||||
|
||||
+117
-48
@@ -43,13 +43,13 @@
|
||||
* Set key state to HIDDEN and change last changed to now,
|
||||
* only if key state has not been set before.
|
||||
*/
|
||||
#define INITIALIZE_STATE(key, state, time) \
|
||||
#define INITIALIZE_STATE(key, state, time, target) \
|
||||
do { \
|
||||
dst_key_state_t s; \
|
||||
if (dst_key_getstate((key), (state), &s) == ISC_R_NOTFOUND) { \
|
||||
isc_stdtime_t t; \
|
||||
dst_key_gettime((key), DST_TIME_CREATED, &t); \
|
||||
dst_key_setstate((key), (state), HIDDEN); \
|
||||
dst_key_setstate((key), (state), target); \
|
||||
dst_key_settime((key), (time), t); \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -105,7 +105,7 @@ static isc_stdtime_t
|
||||
keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
uint32_t lifetime, isc_stdtime_t now) {
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t active, retire, prepub;
|
||||
isc_stdtime_t active, retire, pub, prepub;
|
||||
bool ksk = false;
|
||||
|
||||
REQUIRE(key != NULL);
|
||||
@@ -125,7 +125,8 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
uint32_t klifetime = 0;
|
||||
/*
|
||||
* An active key must have an activate timing metadata.
|
||||
* An active key must have publish and activate timing
|
||||
* metadata.
|
||||
*/
|
||||
ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
@@ -133,6 +134,12 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
dst_key_settime(key->key, DST_TIME_ACTIVATE, now);
|
||||
active = now;
|
||||
}
|
||||
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
/* Super weird, but if it happens, set it to now. */
|
||||
dst_key_settime(key->key, DST_TIME_PUBLISH, now);
|
||||
pub = now;
|
||||
}
|
||||
|
||||
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
@@ -1214,19 +1221,25 @@ transition:
|
||||
}
|
||||
|
||||
/*
|
||||
* See if this key needs to be initialized with a role. A key created and
|
||||
* derived from a dnssec-policy will have the required metadata available,
|
||||
* otherwise these may be missing and need to be initialized.
|
||||
* See if this key needs to be initialized with properties. A key created
|
||||
* and derived from a dnssec-policy will have the required metadata available,
|
||||
* otherwise these may be missing and need to be initialized. The key states
|
||||
* will be initialized according to existing timing metadata.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
keymgr_key_init_role(dns_dnsseckey_t *key) {
|
||||
keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) {
|
||||
bool ksk, zsk;
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t active = 0, pub = 0, syncpub = 0;
|
||||
dst_key_state_t dnskey_state = HIDDEN;
|
||||
dst_key_state_t ds_state = HIDDEN;
|
||||
dst_key_state_t zrrsig_state = HIDDEN;
|
||||
|
||||
REQUIRE(key != NULL);
|
||||
REQUIRE(key->key != NULL);
|
||||
|
||||
/* Initialize role. */
|
||||
ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
ksk = ((dst_key_flags(key->key) & DNS_KEYFLAG_KSK) != 0);
|
||||
@@ -1237,6 +1250,52 @@ keymgr_key_init_role(dns_dnsseckey_t *key) {
|
||||
zsk = ((dst_key_flags(key->key) & DNS_KEYFLAG_KSK) == 0);
|
||||
dst_key_setbool(key->key, DST_BOOL_ZSK, zsk);
|
||||
}
|
||||
|
||||
/* Get time metadata. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
|
||||
if (active <= now && ret == ISC_R_SUCCESS) {
|
||||
dns_ttl_t key_ttl = dst_key_getttl(key->key);
|
||||
key_ttl += dns_kasp_zonepropagationdelay(kasp);
|
||||
if ((active + key_ttl) <= now) {
|
||||
dnskey_state = OMNIPRESENT;
|
||||
} else {
|
||||
dnskey_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
|
||||
if (pub <= now && ret == ISC_R_SUCCESS) {
|
||||
dns_ttl_t zone_ttl = dns_kasp_zonemaxttl(kasp);
|
||||
zone_ttl += dns_kasp_zonepropagationdelay(kasp);
|
||||
if ((pub + zone_ttl) <= now) {
|
||||
zrrsig_state = OMNIPRESENT;
|
||||
} else {
|
||||
zrrsig_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
ret = dst_key_gettime(key->key, DST_TIME_SYNCPUBLISH, &syncpub);
|
||||
if (syncpub <= now && ret == ISC_R_SUCCESS) {
|
||||
dns_ttl_t ds_ttl = dns_kasp_dsttl(kasp);
|
||||
ds_ttl += dns_kasp_parentregistrationdelay(kasp);
|
||||
ds_ttl += dns_kasp_parentpropagationdelay(kasp);
|
||||
if ((syncpub + ds_ttl) <= now) {
|
||||
ds_state = OMNIPRESENT;
|
||||
} else {
|
||||
ds_state = RUMOURED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set key states for all keys that do not have them. */
|
||||
INITIALIZE_STATE(key->key, DST_KEY_DNSKEY, DST_TIME_DNSKEY,
|
||||
dnskey_state);
|
||||
if (ksk) {
|
||||
INITIALIZE_STATE(key->key, DST_KEY_KRRSIG, DST_TIME_KRRSIG,
|
||||
dnskey_state);
|
||||
INITIALIZE_STATE(key->key, DST_KEY_DS, DST_TIME_DS, ds_state);
|
||||
}
|
||||
if (zsk) {
|
||||
INITIALIZE_STATE(key->key, DST_KEY_ZRRSIG, DST_TIME_ZRRSIG,
|
||||
zrrsig_state);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1302,23 +1361,13 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
{
|
||||
bool found_match = false;
|
||||
|
||||
/* Make sure this key knows about roles. */
|
||||
keymgr_key_init_role(dkey);
|
||||
keymgr_key_init(dkey, kasp, now);
|
||||
|
||||
for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
|
||||
kkey = ISC_LIST_NEXT(kkey, link))
|
||||
{
|
||||
if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
|
||||
found_match = true;
|
||||
dst_key_format(dkey->key, keystr,
|
||||
sizeof(keystr));
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC,
|
||||
ISC_LOG_DEBUG(1),
|
||||
"keymgr: DNSKEY %s (%s) matches "
|
||||
"policy %s",
|
||||
keystr, keymgr_keyrole(dkey->key),
|
||||
dns_kasp_getname(kasp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1343,8 +1392,17 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
{
|
||||
if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
|
||||
/* Found a match. */
|
||||
dst_key_format(dkey->key, keystr,
|
||||
sizeof(keystr));
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC,
|
||||
ISC_LOG_DEBUG(1),
|
||||
"keymgr: DNSKEY %s (%s) matches "
|
||||
"policy %s",
|
||||
keystr, keymgr_keyrole(dkey->key),
|
||||
dns_kasp_getname(kasp));
|
||||
|
||||
/* Initialize lifetime. */
|
||||
/* Initialize lifetime if not set. */
|
||||
uint32_t l;
|
||||
if (dst_key_getnum(dkey->key, DST_NUM_LIFETIME,
|
||||
&l) != ISC_R_SUCCESS) {
|
||||
@@ -1353,18 +1411,49 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
lifetime);
|
||||
}
|
||||
|
||||
if (dst_key_goal(dkey->key) == OMNIPRESENT) {
|
||||
if (active_key != NULL) {
|
||||
if (active_key) {
|
||||
/* We already have an active key that
|
||||
* matches the kasp policy.
|
||||
*/
|
||||
if (!dst_key_is_unused(dkey->key) &&
|
||||
(dst_key_goal(dkey->key) ==
|
||||
OMNIPRESENT) &&
|
||||
!keymgr_key_is_successor(
|
||||
dkey->key,
|
||||
active_key->key) &&
|
||||
!keymgr_key_is_successor(
|
||||
active_key->key, dkey->key))
|
||||
{
|
||||
/*
|
||||
* Multiple signing keys match
|
||||
* the kasp key configuration.
|
||||
* Retire excess keys.
|
||||
* Retire excess keys in use.
|
||||
*/
|
||||
keymgr_key_retire(dkey, now);
|
||||
} else {
|
||||
/* Save the matched key. */
|
||||
active_key = dkey;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is possibly an active key created
|
||||
* outside dnssec-policy. Initialize goal,
|
||||
* if not set.
|
||||
*/
|
||||
dst_key_state_t goal;
|
||||
if (dst_key_getstate(dkey->key, DST_KEY_GOAL,
|
||||
&goal) != ISC_R_SUCCESS) {
|
||||
dst_key_setstate(dkey->key,
|
||||
DST_KEY_GOAL,
|
||||
OMNIPRESENT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the matched key only if it is active
|
||||
* or desires to be active.
|
||||
*/
|
||||
if (dst_key_goal(dkey->key) == OMNIPRESENT ||
|
||||
dst_key_is_active(dkey->key, now)) {
|
||||
active_key = dkey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1377,7 +1466,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
isc_log_write(
|
||||
dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
|
||||
"keymgr: DNSKEY %s (%s) matches "
|
||||
"keymgr: DNSKEY %s (%s) is active in "
|
||||
"policy %s",
|
||||
keystr, keymgr_keyrole(active_key->key),
|
||||
dns_kasp_getname(kasp));
|
||||
@@ -1446,6 +1535,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
dst_key_setttl(dst_key, dns_kasp_dnskeyttl(kasp));
|
||||
dst_key_settime(dst_key, DST_TIME_CREATED, now);
|
||||
RETERR(dns_dnsseckey_create(mctx, &dst_key, &newkey));
|
||||
keymgr_key_init(newkey, kasp, now);
|
||||
} else {
|
||||
newkey = candidate;
|
||||
dst_key_setnum(newkey->key, DST_NUM_LIFETIME, lifetime);
|
||||
@@ -1512,27 +1602,6 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
ISC_LIST_APPENDLIST(*keyring, newkeys, link);
|
||||
}
|
||||
|
||||
/* Initialize key states (for keys that don't have them yet). */
|
||||
for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
|
||||
dkey = ISC_LIST_NEXT(dkey, link))
|
||||
{
|
||||
bool ksk = false, zsk = false;
|
||||
|
||||
/* Set key states for all keys that do not have them. */
|
||||
INITIALIZE_STATE(dkey->key, DST_KEY_DNSKEY, DST_TIME_DNSKEY);
|
||||
(void)dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
|
||||
if (ksk) {
|
||||
INITIALIZE_STATE(dkey->key, DST_KEY_KRRSIG,
|
||||
DST_TIME_KRRSIG);
|
||||
INITIALIZE_STATE(dkey->key, DST_KEY_DS, DST_TIME_DS);
|
||||
}
|
||||
(void)dst_key_getbool(dkey->key, DST_BOOL_ZSK, &zsk);
|
||||
if (zsk) {
|
||||
INITIALIZE_STATE(dkey->key, DST_KEY_ZRRSIG,
|
||||
DST_TIME_ZRRSIG);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read to update key states. */
|
||||
keymgr_update(keyring, kasp, now, nexttime);
|
||||
|
||||
|
||||
@@ -518,7 +518,6 @@ static bool
|
||||
openssleddsa_isprivate(const dst_key_t *key) {
|
||||
EVP_PKEY *pkey = key->keydata.pkey;
|
||||
int len;
|
||||
unsigned long err;
|
||||
|
||||
if (pkey == NULL) {
|
||||
return (false);
|
||||
@@ -529,7 +528,7 @@ openssleddsa_isprivate(const dst_key_t *key) {
|
||||
return (true);
|
||||
}
|
||||
/* can check if first error is EC_R_INVALID_PRIVATE_KEY */
|
||||
while ((err = ERR_get_error()) != 0) {
|
||||
while (ERR_get_error() != 0) {
|
||||
/**/
|
||||
}
|
||||
|
||||
|
||||
+129
-66
@@ -1114,7 +1114,8 @@ trim_zbits(dns_rpz_zbits_t zbits, dns_rpz_zbits_t found) {
|
||||
x = zbits & found;
|
||||
x &= (~x + 1);
|
||||
x = (x << 1) - 1;
|
||||
return (zbits &= x);
|
||||
zbits &= x;
|
||||
return (zbits);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1780,32 +1781,85 @@ cleanup:
|
||||
|
||||
static void
|
||||
finish_update(dns_rpz_zone_t *rpz) {
|
||||
isc_result_t result;
|
||||
isc_ht_t *tmpht = NULL;
|
||||
isc_ht_iter_t *iter = NULL;
|
||||
dns_fixedname_t fname;
|
||||
char dname[DNS_NAME_FORMATSIZE];
|
||||
dns_name_t *name;
|
||||
LOCK(&rpz->rpzs->maint_lock);
|
||||
rpz->updaterunning = false;
|
||||
|
||||
/*
|
||||
* Iterate over old ht with existing nodes deleted to delete
|
||||
* deleted nodes from RPZ
|
||||
* If there's an update pending, schedule it.
|
||||
*/
|
||||
result = isc_ht_iter_create(rpz->nodes, &iter);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
char domain[DNS_NAME_FORMATSIZE];
|
||||
if (rpz->updatepending == true) {
|
||||
if (rpz->min_update_interval > 0) {
|
||||
uint64_t defer = rpz->min_update_interval;
|
||||
char dname[DNS_NAME_FORMATSIZE];
|
||||
isc_interval_t interval;
|
||||
|
||||
dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE);
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
||||
"rpz: %s: failed to create HT iterator - %s",
|
||||
domain, isc_result_totext(result));
|
||||
goto cleanup;
|
||||
dns_name_format(&rpz->origin, dname,
|
||||
DNS_NAME_FORMATSIZE);
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
|
||||
"rpz: %s: new zone version came "
|
||||
"too soon, deferring update for "
|
||||
"%" PRIu64 " seconds",
|
||||
dname, defer);
|
||||
isc_interval_set(&interval, (unsigned int)defer, 0);
|
||||
isc_timer_reset(rpz->updatetimer, isc_timertype_once,
|
||||
NULL, &interval, true);
|
||||
} else {
|
||||
isc_event_t *event = NULL;
|
||||
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||
ISC_EVENT_INIT(&rpz->updateevent,
|
||||
sizeof(rpz->updateevent), 0, NULL,
|
||||
DNS_EVENT_RPZUPDATED,
|
||||
dns_rpz_update_taskaction, rpz, rpz,
|
||||
NULL, NULL);
|
||||
event = &rpz->updateevent;
|
||||
isc_task_send(rpz->rpzs->updater, &event);
|
||||
}
|
||||
}
|
||||
UNLOCK(&rpz->rpzs->maint_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_quantum(isc_task_t *task, isc_event_t *event) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
char domain[DNS_NAME_FORMATSIZE];
|
||||
dns_rpz_zone_t *rpz = NULL;
|
||||
isc_ht_iter_t *iter = NULL;
|
||||
dns_fixedname_t fname;
|
||||
dns_name_t *name = NULL;
|
||||
int count = 0;
|
||||
|
||||
UNUSED(task);
|
||||
|
||||
REQUIRE(event != NULL);
|
||||
REQUIRE(event->ev_sender != NULL);
|
||||
|
||||
rpz = (dns_rpz_zone_t *)event->ev_sender;
|
||||
iter = (isc_ht_iter_t *)event->ev_arg;
|
||||
isc_event_free(&event);
|
||||
|
||||
if (iter == NULL) {
|
||||
/*
|
||||
* Iterate over old ht with existing nodes deleted to
|
||||
* delete deleted nodes from RPZ
|
||||
*/
|
||||
result = isc_ht_iter_create(rpz->nodes, &iter);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_name_format(&rpz->origin, domain,
|
||||
DNS_NAME_FORMATSIZE);
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
||||
"rpz: %s: failed to create HT "
|
||||
"iterator - %s",
|
||||
domain, isc_result_totext(result));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
name = dns_fixedname_initname(&fname);
|
||||
|
||||
for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
|
||||
for (result = isc_ht_iter_first(iter);
|
||||
result == ISC_R_SUCCESS && count++ < DNS_RPZ_QUANTUM;
|
||||
result = isc_ht_iter_delcurrent_next(iter))
|
||||
{
|
||||
isc_region_t region;
|
||||
@@ -1819,58 +1873,62 @@ finish_update(dns_rpz_zone_t *rpz) {
|
||||
dns_rpz_delete(rpz->rpzs, rpz->num, name);
|
||||
}
|
||||
|
||||
tmpht = rpz->nodes;
|
||||
rpz->nodes = rpz->newnodes;
|
||||
rpz->newnodes = tmpht;
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
isc_event_t *nevent = NULL;
|
||||
|
||||
LOCK(&rpz->rpzs->maint_lock);
|
||||
rpz->updaterunning = false;
|
||||
/*
|
||||
* If there's an update pending schedule it
|
||||
*/
|
||||
if (rpz->updatepending == true) {
|
||||
if (rpz->min_update_interval > 0) {
|
||||
uint64_t defer = rpz->min_update_interval;
|
||||
isc_interval_t interval;
|
||||
dns_name_format(&rpz->origin, dname,
|
||||
DNS_NAME_FORMATSIZE);
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
|
||||
"rpz: %s: new zone version came "
|
||||
"too soon, deferring update for "
|
||||
"%" PRIu64 " seconds",
|
||||
dname, defer);
|
||||
isc_interval_set(&interval, (unsigned int)defer, 0);
|
||||
isc_timer_reset(rpz->updatetimer, isc_timertype_once,
|
||||
NULL, &interval, true);
|
||||
} else {
|
||||
isc_event_t *event;
|
||||
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||
ISC_EVENT_INIT(&rpz->updateevent,
|
||||
sizeof(rpz->updateevent), 0, NULL,
|
||||
DNS_EVENT_RPZUPDATED,
|
||||
dns_rpz_update_taskaction, rpz, rpz,
|
||||
NULL, NULL);
|
||||
event = &rpz->updateevent;
|
||||
isc_task_send(rpz->rpzs->updater, &event);
|
||||
}
|
||||
/*
|
||||
* We finished a quantum; trigger the next one and return.
|
||||
*/
|
||||
|
||||
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
|
||||
NULL, DNS_EVENT_RPZUPDATED, cleanup_quantum,
|
||||
iter, rpz, NULL, NULL);
|
||||
nevent = &rpz->updateevent;
|
||||
isc_task_send(rpz->rpzs->updater, &nevent);
|
||||
return;
|
||||
} else if (result == ISC_R_NOMORE) {
|
||||
isc_ht_t *tmpht = NULL;
|
||||
|
||||
/*
|
||||
* Done with cleanup of deleted nodes; finalize
|
||||
* the update.
|
||||
*/
|
||||
tmpht = rpz->nodes;
|
||||
rpz->nodes = rpz->newnodes;
|
||||
rpz->newnodes = tmpht;
|
||||
|
||||
finish_update(rpz);
|
||||
dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE);
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
|
||||
"rpz: %s: reload done", domain);
|
||||
}
|
||||
UNLOCK(&rpz->rpzs->maint_lock);
|
||||
|
||||
/*
|
||||
* If we're here, we're finished or something went wrong.
|
||||
*/
|
||||
cleanup:
|
||||
if (iter != NULL) {
|
||||
isc_ht_iter_destroy(&iter);
|
||||
}
|
||||
if (rpz->newnodes != NULL) {
|
||||
isc_ht_destroy(&rpz->newnodes);
|
||||
}
|
||||
dns_db_closeversion(rpz->updb, &rpz->updbversion, false);
|
||||
dns_db_detach(&rpz->updb);
|
||||
rpz_detach(&rpz);
|
||||
}
|
||||
|
||||
static void
|
||||
update_quantum(isc_task_t *task, isc_event_t *event) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_dbnode_t *node = NULL;
|
||||
dns_rpz_zone_t *rpz;
|
||||
dns_rpz_zone_t *rpz = NULL;
|
||||
char domain[DNS_NAME_FORMATSIZE];
|
||||
dns_fixedname_t fixname;
|
||||
dns_name_t *name;
|
||||
dns_name_t *name = NULL;
|
||||
isc_event_t *nevent = NULL;
|
||||
int count = 0;
|
||||
|
||||
UNUSED(task);
|
||||
@@ -1974,13 +2032,13 @@ update_quantum(isc_task_t *task, isc_event_t *event) {
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
isc_event_t *nevent;
|
||||
/*
|
||||
* Pause the iterator so that the DB is not locked
|
||||
* Pause the iterator so that the DB is not locked.
|
||||
*/
|
||||
dns_dbiterator_pause(rpz->updbit);
|
||||
|
||||
/*
|
||||
* We finished a quantum; trigger the next one and return
|
||||
* We finished a quantum; trigger the next one and return.
|
||||
*/
|
||||
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
|
||||
@@ -1991,17 +2049,22 @@ update_quantum(isc_task_t *task, isc_event_t *event) {
|
||||
return;
|
||||
} else if (result == ISC_R_NOMORE) {
|
||||
/*
|
||||
* All done.
|
||||
* Done with the new database; now we just need to
|
||||
* clean up the old.
|
||||
*/
|
||||
finish_update(rpz);
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
|
||||
"rpz: %s: reload done", domain);
|
||||
dns_dbiterator_destroy(&rpz->updbit);
|
||||
|
||||
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
|
||||
NULL, DNS_EVENT_RPZUPDATED, cleanup_quantum,
|
||||
NULL, rpz, NULL, NULL);
|
||||
nevent = &rpz->updateevent;
|
||||
isc_task_send(rpz->rpzs->updater, &nevent);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're here, we've either finished or something went wrong,
|
||||
* so clean up.
|
||||
* If we're here, something went wrong, so clean up.
|
||||
*/
|
||||
if (rpz->updbit != NULL) {
|
||||
dns_dbiterator_destroy(&rpz->updbit);
|
||||
|
||||
+106
-8
@@ -20,6 +20,7 @@
|
||||
#include <isc/stats.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/log.h>
|
||||
#include <dns/opcode.h>
|
||||
#include <dns/rdatatype.h>
|
||||
#include <dns/stats.h>
|
||||
@@ -93,8 +94,19 @@ typedef enum {
|
||||
*/
|
||||
#define RDTYPECOUNTER_MAXVAL 0x0602
|
||||
|
||||
/* dnssec maximum key id */
|
||||
static int dnssec_keyid_max = 65535;
|
||||
/*
|
||||
* DNSSEC sign statistics.
|
||||
*
|
||||
* Per key we maintain 3 counters. The first is actually no counter but
|
||||
* a key id reference. The second is the number of signatures the key created.
|
||||
* The third is the number of signatures refreshed by the key.
|
||||
*/
|
||||
|
||||
/* Maximum number of keys to keep track of for DNSSEC signing statistics. */
|
||||
static int dnssecsign_max_keys = 4;
|
||||
static int dnssecsign_block_size = 3;
|
||||
/* Key id mask */
|
||||
#define DNSSECSIGNSTATS_KEY_ID_MASK 0x0000FFFF
|
||||
|
||||
struct dns_stats {
|
||||
unsigned int magic;
|
||||
@@ -228,8 +240,12 @@ isc_result_t
|
||||
dns_dnssecsignstats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
|
||||
REQUIRE(statsp != NULL && *statsp == NULL);
|
||||
|
||||
return (create_stats(mctx, dns_statstype_dnssec, dnssec_keyid_max,
|
||||
statsp));
|
||||
/*
|
||||
* Create two counters per key, one is the key id, the other two are
|
||||
* the actual counters for creating and refreshing signatures.
|
||||
*/
|
||||
return (create_stats(mctx, dns_statstype_dnssec,
|
||||
dnssecsign_max_keys * 3, statsp));
|
||||
}
|
||||
|
||||
/*%
|
||||
@@ -342,10 +358,64 @@ dns_rcodestats_increment(dns_stats_t *stats, dns_rcode_t code) {
|
||||
}
|
||||
|
||||
void
|
||||
dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id) {
|
||||
dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id, uint8_t alg,
|
||||
dnssecsignstats_type_t operation) {
|
||||
uint32_t kval;
|
||||
|
||||
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_dnssec);
|
||||
|
||||
isc_stats_increment(stats->counters, (isc_statscounter_t)id);
|
||||
/* Shift algorithm in front of key tag, which is 16 bits */
|
||||
kval = (uint32_t)(alg << 16 | id);
|
||||
|
||||
/* Look up correct counter. */
|
||||
for (int i = 0; i < dnssecsign_max_keys; i++) {
|
||||
int idx = i * dnssecsign_block_size;
|
||||
uint32_t counter = isc_stats_get_counter(stats->counters, idx);
|
||||
if (counter == kval) {
|
||||
/* Match */
|
||||
isc_stats_increment(stats->counters, (idx + operation));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* No match found. Store key in unused slot. */
|
||||
for (int i = 0; i < dnssecsign_max_keys; i++) {
|
||||
int idx = i * dnssecsign_block_size;
|
||||
uint32_t counter = isc_stats_get_counter(stats->counters, idx);
|
||||
if (counter == 0) {
|
||||
isc_stats_set(stats->counters, kval, idx);
|
||||
isc_stats_increment(stats->counters, (idx + operation));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* No room, rotate keys. */
|
||||
for (int i = 1; i < dnssecsign_max_keys; i++) {
|
||||
int gidx = i * dnssecsign_block_size; /* Get key (get index,
|
||||
gidx) */
|
||||
uint32_t keyv = isc_stats_get_counter(stats->counters, gidx);
|
||||
uint32_t sign = isc_stats_get_counter(
|
||||
stats->counters, (gidx + dns_dnssecsignstats_sign));
|
||||
uint32_t refr = isc_stats_get_counter(
|
||||
stats->counters, (gidx + dns_dnssecsignstats_refresh));
|
||||
|
||||
int sidx = (i - 1) * dnssecsign_block_size; /* Set key, (set
|
||||
index, sidx) */
|
||||
isc_stats_set(stats->counters, keyv, sidx);
|
||||
isc_stats_set(stats->counters, sign,
|
||||
(sidx + dns_dnssecsignstats_sign));
|
||||
isc_stats_set(stats->counters, refr,
|
||||
(sidx + dns_dnssecsignstats_refresh));
|
||||
}
|
||||
|
||||
/* Reset counters for new key (new index, nidx). */
|
||||
int nidx = (dnssecsign_max_keys - 1) * dnssecsign_block_size;
|
||||
isc_stats_set(stats->counters, kval, nidx);
|
||||
isc_stats_set(stats->counters, 0, (nidx + dns_dnssecsignstats_sign));
|
||||
isc_stats_set(stats->counters, 0, (nidx + dns_dnssecsignstats_refresh));
|
||||
|
||||
/* And increment the counter for the given operation. */
|
||||
isc_stats_increment(stats->counters, (nidx + operation));
|
||||
}
|
||||
|
||||
/*%
|
||||
@@ -452,8 +522,34 @@ dnssec_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
|
||||
dnssecarg->fn((dns_keytag_t)counter, value, dnssecarg->arg);
|
||||
}
|
||||
|
||||
static void
|
||||
dnssec_statsdump(isc_stats_t *stats, dnssecsignstats_type_t operation,
|
||||
isc_stats_dumper_t dump_fn, void *arg, unsigned int options) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dnssecsign_max_keys; i++) {
|
||||
int idx = dnssecsign_block_size * i;
|
||||
uint32_t kval, val;
|
||||
dns_keytag_t id;
|
||||
|
||||
kval = isc_stats_get_counter(stats, idx);
|
||||
if (kval == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
val = isc_stats_get_counter(stats, (idx + operation));
|
||||
if ((options & ISC_STATSDUMP_VERBOSE) == 0 && val == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
id = (dns_keytag_t)kval & DNSSECSIGNSTATS_KEY_ID_MASK;
|
||||
|
||||
dump_fn((isc_statscounter_t)id, val, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dns_dnssecsignstats_dump(dns_stats_t *stats,
|
||||
dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation,
|
||||
dns_dnssecsignstats_dumper_t dump_fn, void *arg0,
|
||||
unsigned int options) {
|
||||
dnssecsigndumparg_t arg;
|
||||
@@ -462,7 +558,9 @@ dns_dnssecsignstats_dump(dns_stats_t *stats,
|
||||
|
||||
arg.fn = dump_fn;
|
||||
arg.arg = arg0;
|
||||
isc_stats_dump(stats->counters, dnssec_dumpcb, &arg, options);
|
||||
|
||||
dnssec_statsdump(stats->counters, operation, dnssec_dumpcb, &arg,
|
||||
options);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+4
-1
@@ -1117,6 +1117,7 @@ add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
|
||||
|
||||
#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
|
||||
#define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
|
||||
#define ID(x) dst_key_id(x)
|
||||
#define ALG(x) dst_key_alg(x)
|
||||
|
||||
/*
|
||||
@@ -1260,7 +1261,9 @@ add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
|
||||
/* Update DNSSEC sign statistics. */
|
||||
if (dnssecsignstats != NULL) {
|
||||
dns_dnssecsignstats_increment(dnssecsignstats,
|
||||
dst_key_id(keys[i]));
|
||||
ID(keys[i]),
|
||||
(uint8_t)ALG(keys[i]),
|
||||
dns_dnssecsignstats_sign);
|
||||
}
|
||||
}
|
||||
if (!added_sig) {
|
||||
|
||||
@@ -1194,7 +1194,6 @@ dns_zone_getchecknames
|
||||
dns_zone_getclass
|
||||
dns_zone_getdb
|
||||
dns_zone_getdbtype
|
||||
dns_zone_getdnssecrefreshstats
|
||||
dns_zone_getdnssecsignstats
|
||||
dns_zone_getexpiretime
|
||||
dns_zone_getfile
|
||||
@@ -1298,7 +1297,6 @@ dns_zone_setclass
|
||||
dns_zone_setdb
|
||||
dns_zone_setdbtype
|
||||
dns_zone_setdialup
|
||||
dns_zone_setdnssecrefreshstats
|
||||
dns_zone_setdnssecsignstats
|
||||
dns_zone_setfile
|
||||
dns_zone_setflag
|
||||
|
||||
+17
-41
@@ -120,6 +120,7 @@
|
||||
*/
|
||||
#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
|
||||
#define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
|
||||
#define ID(x) dst_key_id(x)
|
||||
#define ALG(x) dst_key_alg(x)
|
||||
|
||||
/*
|
||||
@@ -338,7 +339,6 @@ struct dns_zone {
|
||||
isc_stats_t *requeststats;
|
||||
dns_stats_t *rcvquerystats;
|
||||
dns_stats_t *dnssecsignstats;
|
||||
dns_stats_t *dnssecrefreshstats;
|
||||
uint32_t notifydelay;
|
||||
dns_isselffunc_t isself;
|
||||
void *isselfarg;
|
||||
@@ -1091,7 +1091,6 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
|
||||
zone->requeststats = NULL;
|
||||
zone->rcvquerystats = NULL;
|
||||
zone->dnssecsignstats = NULL;
|
||||
zone->dnssecrefreshstats = NULL;
|
||||
zone->notifydelay = 5;
|
||||
zone->isself = NULL;
|
||||
zone->isselfarg = NULL;
|
||||
@@ -1270,9 +1269,6 @@ zone_free(dns_zone_t *zone) {
|
||||
if (zone->dnssecsignstats != NULL) {
|
||||
dns_stats_detach(&zone->dnssecsignstats);
|
||||
}
|
||||
if (zone->dnssecrefreshstats != NULL) {
|
||||
dns_stats_detach(&zone->dnssecrefreshstats);
|
||||
}
|
||||
if (zone->db != NULL) {
|
||||
zone_detachdb(zone);
|
||||
}
|
||||
@@ -6752,7 +6748,6 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_zone_t *zone,
|
||||
dns_dbnode_t *node = NULL;
|
||||
dns_kasp_t *kasp = dns_zone_getkasp(zone);
|
||||
dns_stats_t *dnssecsignstats;
|
||||
dns_stats_t *dnssecrefreshstats;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_rdata_t sig_rdata = DNS_RDATA_INIT;
|
||||
unsigned char data[1024]; /* XXX */
|
||||
@@ -6926,16 +6921,17 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_zone_t *zone,
|
||||
|
||||
/* Update DNSSEC sign statistics. */
|
||||
dnssecsignstats = dns_zone_getdnssecsignstats(zone);
|
||||
dnssecrefreshstats = dns_zone_getdnssecrefreshstats(zone);
|
||||
if (dnssecsignstats != NULL) {
|
||||
/* Generated a new signature. */
|
||||
dns_dnssecsignstats_increment(dnssecsignstats,
|
||||
ID(keys[i]),
|
||||
(uint8_t)ALG(keys[i]),
|
||||
dns_dnssecsignstats_sign);
|
||||
/* This is a refresh. */
|
||||
dns_dnssecsignstats_increment(
|
||||
dns_zone_getdnssecsignstats(zone),
|
||||
dst_key_id(keys[i]));
|
||||
}
|
||||
if (dnssecrefreshstats != NULL) {
|
||||
dns_dnssecsignstats_increment(
|
||||
dns_zone_getdnssecrefreshstats(zone),
|
||||
dst_key_id(keys[i]));
|
||||
dnssecsignstats, ID(keys[i]),
|
||||
(uint8_t)ALG(keys[i]),
|
||||
dns_dnssecsignstats_refresh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7396,7 +7392,6 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
|
||||
dns_rdataset_t rdataset;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_stats_t *dnssecsignstats;
|
||||
dns_stats_t *dnssecrefreshstats;
|
||||
|
||||
isc_buffer_t buffer;
|
||||
unsigned char data[1024];
|
||||
@@ -7515,16 +7510,15 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
|
||||
|
||||
/* Update DNSSEC sign statistics. */
|
||||
dnssecsignstats = dns_zone_getdnssecsignstats(zone);
|
||||
dnssecrefreshstats = dns_zone_getdnssecrefreshstats(zone);
|
||||
if (dnssecsignstats != NULL) {
|
||||
/* Generated a new signature. */
|
||||
dns_dnssecsignstats_increment(dnssecsignstats, ID(key),
|
||||
ALG(key),
|
||||
dns_dnssecsignstats_sign);
|
||||
/* This is a refresh. */
|
||||
dns_dnssecsignstats_increment(
|
||||
dns_zone_getdnssecsignstats(zone),
|
||||
dst_key_id(key));
|
||||
}
|
||||
if (dnssecrefreshstats != NULL) {
|
||||
dns_dnssecsignstats_increment(
|
||||
dns_zone_getdnssecrefreshstats(zone),
|
||||
dst_key_id(key));
|
||||
dnssecsignstats, ID(key), ALG(key),
|
||||
dns_dnssecsignstats_refresh);
|
||||
}
|
||||
|
||||
(*signatures)--;
|
||||
@@ -18458,17 +18452,6 @@ dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats) {
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
void
|
||||
dns_zone_setdnssecrefreshstats(dns_zone_t *zone, dns_stats_t *stats) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
if (stats != NULL && zone->dnssecrefreshstats == NULL) {
|
||||
dns_stats_attach(stats, &zone->dnssecrefreshstats);
|
||||
}
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
dns_stats_t *
|
||||
dns_zone_getdnssecsignstats(dns_zone_t *zone) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
@@ -18476,13 +18459,6 @@ dns_zone_getdnssecsignstats(dns_zone_t *zone) {
|
||||
return (zone->dnssecsignstats);
|
||||
}
|
||||
|
||||
dns_stats_t *
|
||||
dns_zone_getdnssecrefreshstats(dns_zone_t *zone) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
|
||||
return (zone->dnssecrefreshstats);
|
||||
}
|
||||
|
||||
isc_stats_t *
|
||||
dns_zone_getrequeststats(dns_zone_t *zone) {
|
||||
/*
|
||||
|
||||
@@ -177,9 +177,9 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_udp_stoplistening(isc_nmsocket_t *sock);
|
||||
isc_nm_stoplistening(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Stop listening for UDP packets on socket 'sock'.
|
||||
* Stop listening on socket 'sock'.
|
||||
*/
|
||||
|
||||
void
|
||||
@@ -226,6 +226,10 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
* in 'cb'.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_connecttcp(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *remote, isc_nm_cb_t cb);
|
||||
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
|
||||
void *cbarg, size_t extrahandlesize, int backlog,
|
||||
@@ -251,12 +255,6 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
|
||||
* prepended with a two-byte length field, and handles buffering.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_tcp_stoplistening(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Stop listening on TCP socket 'sock'.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
void *cbarg, isc_nm_cb_t accept_cb, void *accept_cbarg,
|
||||
@@ -285,12 +283,6 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
* 'quota' is passed to isc_nm_listentcp() when opening the raw TCP socket.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_tcpdns_stoplistening(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Stop listening on TCPDNS socket 'sock'.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_tcpdns_sequential(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
|
||||
+38
-21
@@ -40,11 +40,23 @@
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
/*% isc_quota_cb - quota callback structure */
|
||||
typedef struct isc_quota_cb isc_quota_cb_t;
|
||||
typedef void (*isc_quota_cb_func_t)(isc_quota_t *quota, void *data);
|
||||
struct isc_quota_cb {
|
||||
isc_quota_cb_func_t cb_func;
|
||||
void * data;
|
||||
ISC_LINK(isc_quota_cb_t) link;
|
||||
};
|
||||
|
||||
/*% isc_quota structure */
|
||||
struct isc_quota {
|
||||
atomic_uint_fast32_t max;
|
||||
atomic_uint_fast32_t used;
|
||||
atomic_uint_fast32_t soft;
|
||||
atomic_uint_fast32_t waiting;
|
||||
isc_mutex_t cblock;
|
||||
ISC_LIST(isc_quota_cb_t) cbs;
|
||||
};
|
||||
|
||||
void
|
||||
@@ -90,41 +102,46 @@ isc_quota_getused(isc_quota_t *quota);
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_quota_reserve(isc_quota_t *quota);
|
||||
isc_quota_attach(isc_quota_t *quota, isc_quota_t **p);
|
||||
/*%<
|
||||
* Attempt to reserve one unit of 'quota'.
|
||||
*
|
||||
* Attempt to reserve one unit of 'quota', and also attaches '*p' to the quota
|
||||
* if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA).
|
||||
*
|
||||
* Returns:
|
||||
* \li #ISC_R_SUCCESS Success
|
||||
* \li #ISC_R_SUCCESS Success
|
||||
* \li #ISC_R_SOFTQUOTA Success soft quota reached
|
||||
* \li #ISC_R_QUOTA Quota is full
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_quota_attach_cb(isc_quota_t *quota, isc_quota_t **p, isc_quota_cb_t *cb);
|
||||
/*%<
|
||||
*
|
||||
* Like isc_quota_attach(), but if there's no quota left then cb->cb_func will
|
||||
* be called when we are attached to quota.
|
||||
* Note: It's the callee responsibility to make sure that we don't end up with
|
||||
* extremely huge number of callbacks waiting - making it easy to create a
|
||||
* resource exhaustion attack. For example in case of TCP listening we simply
|
||||
* don't accept new connections - so the number of callbacks waiting in the
|
||||
* queue is limited by listen() backlog.
|
||||
*
|
||||
* Returns:
|
||||
* \li #ISC_R_SUCCESS Success
|
||||
* \li #ISC_R_SOFTQUOTA Success soft quota reached
|
||||
* \li #ISC_R_QUOTA Quota is full
|
||||
*/
|
||||
|
||||
void
|
||||
isc_quota_release(isc_quota_t *quota);
|
||||
isc_quota_cb_init(isc_quota_cb_t *cb, isc_quota_cb_func_t cb_func, void *data);
|
||||
/*%<
|
||||
* Release one unit of quota.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_quota_attach(isc_quota_t *quota, isc_quota_t **p);
|
||||
/*%<
|
||||
* Like isc_quota_reserve, and also attaches '*p' to the
|
||||
* quota if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA).
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_quota_force(isc_quota_t *quota, isc_quota_t **p);
|
||||
/*%<
|
||||
* Like isc_quota_attach, but will attach '*p' to the quota
|
||||
* even if the hard quota has been exceeded.
|
||||
* Initialize isc_quota_cb_t - setup the list, set the callback and data.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_quota_detach(isc_quota_t **p);
|
||||
/*%<
|
||||
* Like isc_quota_release, and also detaches '*p' from the
|
||||
* quota.
|
||||
* Release one unit of quota, and also detaches '*p' from the quota.
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
@@ -79,11 +79,8 @@ struct isc_rwlock {
|
||||
#endif /* USE_PTHREAD_RWLOCK */
|
||||
|
||||
isc_result_t
|
||||
isc__rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
|
||||
unsigned int write_quota, const char *file,
|
||||
unsigned int line);
|
||||
#define isc_rwlock_init(l, rq, wq) isc__rwlock_init((l), (rq), (wq),\
|
||||
__FILE__, __LINE__)
|
||||
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
|
||||
unsigned int write_quota);
|
||||
|
||||
isc_result_t
|
||||
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
|
||||
|
||||
+90
-55
@@ -112,7 +112,7 @@ struct isc_logconfig {
|
||||
ISC_LIST(isc_logchannellist_t) * channellists;
|
||||
unsigned int channellist_count;
|
||||
unsigned int duplicate_interval;
|
||||
int highest_level;
|
||||
int_fast32_t highest_level;
|
||||
char *tag;
|
||||
bool dynamic;
|
||||
};
|
||||
@@ -142,7 +142,7 @@ struct isc_log {
|
||||
unsigned int category_count;
|
||||
isc_logmodule_t *modules;
|
||||
unsigned int module_count;
|
||||
int debug_level;
|
||||
atomic_int_fast32_t debug_level;
|
||||
isc_rwlock_t lcfg_rwl;
|
||||
/* Locked by isc_log lcfg_rwl */
|
||||
isc_logconfig_t *logconfig;
|
||||
@@ -150,6 +150,8 @@ struct isc_log {
|
||||
/* Locked by isc_log lock. */
|
||||
char buffer[LOG_BUFFER_SIZE];
|
||||
ISC_LIST(isc_logmessage_t) messages;
|
||||
atomic_bool dynamic;
|
||||
atomic_int_fast32_t highest_level;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -174,9 +176,9 @@ static const int syslog_map[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE,
|
||||
* channellist in the log context, it must come first in isc_categories[].
|
||||
*/
|
||||
LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = { { "default",
|
||||
0 }, /* "default"
|
||||
* must come
|
||||
* first. */
|
||||
0 }, /* "default
|
||||
must come
|
||||
first. */
|
||||
{ "general", 0 },
|
||||
{ NULL, 0 } };
|
||||
|
||||
@@ -211,6 +213,9 @@ assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
|
||||
static void
|
||||
sync_channellist(isc_logconfig_t *lcfg);
|
||||
|
||||
static void
|
||||
sync_highest_level(isc_log_t *lctx, isc_logconfig_t *lcfg);
|
||||
|
||||
static isc_result_t
|
||||
greatest_version(isc_logfile_t *file, int versions, int *greatest);
|
||||
|
||||
@@ -256,7 +261,7 @@ isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
|
||||
lctx->category_count = 0;
|
||||
lctx->modules = NULL;
|
||||
lctx->module_count = 0;
|
||||
lctx->debug_level = 0;
|
||||
atomic_init(&lctx->debug_level, 0);
|
||||
|
||||
ISC_LIST_INIT(lctx->messages);
|
||||
|
||||
@@ -280,6 +285,9 @@ isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
|
||||
|
||||
lctx->logconfig = lcfg;
|
||||
|
||||
atomic_init(&lctx->highest_level, lcfg->highest_level);
|
||||
atomic_init(&lctx->dynamic, lcfg->dynamic);
|
||||
|
||||
*lctxp = lctx;
|
||||
if (lcfgp != NULL) {
|
||||
*lcfgp = lcfg;
|
||||
@@ -309,7 +317,7 @@ isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) {
|
||||
|
||||
/*
|
||||
* Create the default channels:
|
||||
* default_syslog, default_stderr, default_debug and null.
|
||||
* default_syslog, default_stderr, default_debug and null.
|
||||
*/
|
||||
destination.facility = LOG_DAEMON;
|
||||
isc_log_createchannel(lcfg, "default_syslog", ISC_LOG_TOSYSLOG, level,
|
||||
@@ -362,6 +370,7 @@ isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) {
|
||||
WRLOCK(&lctx->lcfg_rwl);
|
||||
old_cfg = lctx->logconfig;
|
||||
lctx->logconfig = lcfg;
|
||||
sync_highest_level(lctx, lcfg);
|
||||
WRUNLOCK(&lctx->lcfg_rwl);
|
||||
|
||||
isc_logconfig_destroy(&old_cfg);
|
||||
@@ -380,6 +389,11 @@ isc_log_destroy(isc_log_t **lctxp) {
|
||||
*lctxp = NULL;
|
||||
mctx = lctx->mctx;
|
||||
|
||||
/* Stop the logging as a first thing */
|
||||
atomic_store_release(&lctx->debug_level, 0);
|
||||
atomic_store_release(&lctx->highest_level, 0);
|
||||
atomic_store_release(&lctx->dynamic, false);
|
||||
|
||||
WRLOCK(&lctx->lcfg_rwl);
|
||||
lcfg = lctx->logconfig;
|
||||
lctx->logconfig = NULL;
|
||||
@@ -400,7 +414,6 @@ isc_log_destroy(isc_log_t **lctxp) {
|
||||
}
|
||||
|
||||
lctx->buffer[0] = '\0';
|
||||
lctx->debug_level = 0;
|
||||
lctx->categories = NULL;
|
||||
lctx->category_count = 0;
|
||||
lctx->modules = NULL;
|
||||
@@ -745,6 +758,13 @@ isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the highest logging level, if the current lcfg is in use.
|
||||
*/
|
||||
if (lcfg->lctx->logconfig == lcfg) {
|
||||
sync_highest_level(lctx, lcfg);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -805,7 +825,7 @@ void
|
||||
isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) {
|
||||
REQUIRE(VALID_CONTEXT(lctx));
|
||||
|
||||
lctx->debug_level = level;
|
||||
atomic_store_release(&lctx->debug_level, level);
|
||||
/*
|
||||
* Close ISC_LOG_DEBUGONLY channels if level is zero.
|
||||
*/
|
||||
@@ -837,7 +857,7 @@ unsigned int
|
||||
isc_log_getdebuglevel(isc_log_t *lctx) {
|
||||
REQUIRE(VALID_CONTEXT(lctx));
|
||||
|
||||
return (lctx->debug_level);
|
||||
return (atomic_load_acquire(&lctx->debug_level));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -988,6 +1008,12 @@ sync_channellist(isc_logconfig_t *lcfg) {
|
||||
lcfg->channellist_count = lctx->category_count;
|
||||
}
|
||||
|
||||
static void
|
||||
sync_highest_level(isc_log_t *lctx, isc_logconfig_t *lcfg) {
|
||||
atomic_store(&lctx->highest_level, lcfg->highest_level);
|
||||
atomic_store(&lctx->dynamic, lcfg->dynamic);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
greatest_version(isc_logfile_t *file, int versions, int *greatestp) {
|
||||
char *bname, *digit_end;
|
||||
@@ -1414,7 +1440,6 @@ isc_log_open(isc_logchannel_t *channel) {
|
||||
|
||||
bool
|
||||
isc_log_wouldlog(isc_log_t *lctx, int level) {
|
||||
bool ret = false;
|
||||
/*
|
||||
* Try to avoid locking the mutex for messages which can't
|
||||
* possibly be logged to any channels -- primarily debugging
|
||||
@@ -1429,15 +1454,16 @@ isc_log_wouldlog(isc_log_t *lctx, int level) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
RDLOCK(&lctx->lcfg_rwl);
|
||||
isc_logconfig_t *lcfg = lctx->logconfig;
|
||||
if (lcfg != NULL) {
|
||||
ret = (level <= lcfg->highest_level ||
|
||||
(lcfg->dynamic && level <= lctx->debug_level));
|
||||
if (level <= atomic_load_acquire(&lctx->highest_level)) {
|
||||
return (true);
|
||||
}
|
||||
if (atomic_load_acquire(&lctx->dynamic) &&
|
||||
level <= atomic_load_acquire(&lctx->debug_level))
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
RDUNLOCK(&lctx->lcfg_rwl);
|
||||
|
||||
return (ret);
|
||||
return (false);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1494,13 +1520,13 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]);
|
||||
|
||||
/*
|
||||
* XXXDCL add duplicate filtering? (To not write multiple times to
|
||||
* the same source via various channels).
|
||||
* XXXDCL add duplicate filtering? (To not write multiple times
|
||||
* to the same source via various channels).
|
||||
*/
|
||||
do {
|
||||
/*
|
||||
* If the channel list end was reached and a match was made,
|
||||
* everything is finished.
|
||||
* If the channel list end was reached and a match was
|
||||
* made, everything is finished.
|
||||
*/
|
||||
if (category_channels == NULL && matched) {
|
||||
break;
|
||||
@@ -1510,8 +1536,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
category_channels != ISC_LIST_HEAD(lcfg->channellists[0]))
|
||||
{
|
||||
/*
|
||||
* No category/module pair was explicitly configured.
|
||||
* Try the category named "default".
|
||||
* No category/module pair was explicitly
|
||||
* configured. Try the category named "default".
|
||||
*/
|
||||
category_channels =
|
||||
ISC_LIST_HEAD(lcfg->channellists[0]);
|
||||
@@ -1520,8 +1546,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
if (category_channels == NULL && !matched) {
|
||||
/*
|
||||
* No matching module was explicitly configured
|
||||
* for the category named "default". Use the internal
|
||||
* default channel.
|
||||
* for the category named "default". Use the
|
||||
* internal default channel.
|
||||
*/
|
||||
category_channels = &default_channel;
|
||||
}
|
||||
@@ -1538,13 +1564,14 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
channel = category_channels->channel;
|
||||
category_channels = ISC_LIST_NEXT(category_channels, link);
|
||||
|
||||
if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) &&
|
||||
lctx->debug_level == 0) {
|
||||
int_fast32_t dlevel = atomic_load_acquire(&lctx->debug_level);
|
||||
if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) && dlevel == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (channel->level == ISC_LOG_DYNAMIC) {
|
||||
if (lctx->debug_level < level) {
|
||||
if (dlevel < level) {
|
||||
continue;
|
||||
}
|
||||
} else if (channel->level < level) {
|
||||
@@ -1600,17 +1627,18 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
lcfg->duplicate_interval, 0);
|
||||
|
||||
/*
|
||||
* 'oldest' is the age of the oldest messages
|
||||
* which fall within the duplicate_interval
|
||||
* range.
|
||||
* 'oldest' is the age of the oldest
|
||||
* messages which fall within the
|
||||
* duplicate_interval range.
|
||||
*/
|
||||
TIME_NOW(&oldest);
|
||||
if (isc_time_subtract(&oldest, &interval,
|
||||
&oldest) != ISC_R_SUCCESS)
|
||||
{
|
||||
/*
|
||||
* Can't effectively do the checking
|
||||
* without having a valid time.
|
||||
* Can't effectively do the
|
||||
* checking without having a
|
||||
* valid time.
|
||||
*/
|
||||
message = NULL;
|
||||
} else {
|
||||
@@ -1622,15 +1650,18 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
&oldest) < 0) {
|
||||
/*
|
||||
* This message is older
|
||||
* than the duplicate_interval,
|
||||
* so it should be dropped from
|
||||
* the history.
|
||||
* than the
|
||||
* duplicate_interval,
|
||||
* so it should be
|
||||
* dropped from the
|
||||
* history.
|
||||
*
|
||||
* Setting the interval to be
|
||||
* to be longer will obviously
|
||||
* not cause the expired
|
||||
* message to spring back into
|
||||
* existence.
|
||||
* Setting the interval
|
||||
* to be to be longer
|
||||
* will obviously not
|
||||
* cause the expired
|
||||
* message to spring
|
||||
* back into existence.
|
||||
*/
|
||||
next = ISC_LIST_NEXT(message,
|
||||
link);
|
||||
@@ -1648,15 +1679,17 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
}
|
||||
|
||||
/*
|
||||
* This message is in the duplicate
|
||||
* filtering interval ...
|
||||
* This message is in the
|
||||
* duplicate filtering interval
|
||||
* ...
|
||||
*/
|
||||
if (strcmp(lctx->buffer,
|
||||
message->text) == 0) {
|
||||
/*
|
||||
* ... and it is a duplicate.
|
||||
* Unlock the mutex and
|
||||
* get the hell out of Dodge.
|
||||
* ... and it is a
|
||||
* duplicate. Unlock the
|
||||
* mutex and get the
|
||||
* hell out of Dodge.
|
||||
*/
|
||||
goto unlock;
|
||||
}
|
||||
@@ -1713,11 +1746,12 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
/*
|
||||
* If the file can be rolled, OR
|
||||
* If the file no longer exists, OR
|
||||
* If the file is less than the maximum size,
|
||||
* (such as if it had been renamed and
|
||||
* a new one touched, or it was truncated
|
||||
* in place)
|
||||
* ... then close it to trigger reopening.
|
||||
* If the file is less than the maximum
|
||||
* size, (such as if it had been renamed
|
||||
* and a new one touched, or it was
|
||||
* truncated in place)
|
||||
* ... then close it to trigger
|
||||
* reopening.
|
||||
*/
|
||||
if (FILE_VERSIONS(channel) !=
|
||||
ISC_LOG_ROLLNEVER ||
|
||||
@@ -1743,7 +1777,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
(channel->flags & ISC_LOG_OPENERR) == 0)
|
||||
{
|
||||
syslog(LOG_ERR,
|
||||
"isc_log_open '%s' failed: %s",
|
||||
"isc_log_open '%s' "
|
||||
"failed: %s",
|
||||
FILE_NAME(channel),
|
||||
isc_result_totext(result));
|
||||
channel->flags |= ISC_LOG_OPENERR;
|
||||
@@ -1774,8 +1809,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
|
||||
|
||||
/*
|
||||
* If the file now exceeds its maximum size
|
||||
* threshold, note it so that it will not be logged
|
||||
* to any more.
|
||||
* threshold, note it so that it will not be
|
||||
* logged to any more.
|
||||
*/
|
||||
if (FILE_MAXSIZE(channel) > 0) {
|
||||
INSIST(channel->type == ISC_LOG_TOFILE);
|
||||
|
||||
+60
-30
@@ -22,6 +22,7 @@
|
||||
#include <isc/mem.h>
|
||||
#include <isc/netmgr.h>
|
||||
#include <isc/queue.h>
|
||||
#include <isc/quota.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/region.h>
|
||||
@@ -124,20 +125,22 @@ struct isc_nmiface {
|
||||
typedef enum isc__netievent_type {
|
||||
netievent_udpsend,
|
||||
netievent_udprecv,
|
||||
netievent_udpstop,
|
||||
|
||||
netievent_tcpconnect,
|
||||
netievent_tcpsend,
|
||||
netievent_tcprecv,
|
||||
netievent_tcpstartread,
|
||||
netievent_tcppauseread,
|
||||
netievent_tcpchildlisten,
|
||||
netievent_tcpchildstop,
|
||||
netievent_closecb,
|
||||
netievent_shutdown,
|
||||
netievent_stop,
|
||||
netievent_udpstop,
|
||||
netievent_tcpchildaccept,
|
||||
netievent_tcpaccept,
|
||||
netievent_tcpstop,
|
||||
netievent_tcpclose,
|
||||
netievent_tcpdnsclose,
|
||||
|
||||
netievent_closecb,
|
||||
netievent_shutdown,
|
||||
netievent_stop,
|
||||
netievent_prio = 0xff, /* event type values higher than this
|
||||
* will be treated as high-priority
|
||||
* events, which can be processed
|
||||
@@ -178,6 +181,7 @@ typedef union {
|
||||
|
||||
typedef struct isc__nm_uvreq {
|
||||
int magic;
|
||||
isc_nm_t *mgr;
|
||||
isc_nmsocket_t *sock;
|
||||
isc_nmhandle_t *handle;
|
||||
uv_buf_t uvbuf; /* translated isc_region_t, to be
|
||||
@@ -186,8 +190,7 @@ typedef struct isc__nm_uvreq {
|
||||
isc_sockaddr_t peer; /* peer address */
|
||||
isc__nm_cb_t cb; /* callback */
|
||||
void *cbarg; /* callback argument */
|
||||
uv_pipe_t ipc; /* used for sending socket
|
||||
* uv_handles to other threads */
|
||||
|
||||
union {
|
||||
uv_req_t req;
|
||||
uv_getaddrinfo_t getaddrinfo;
|
||||
@@ -209,11 +212,11 @@ typedef struct isc__netievent__socket {
|
||||
typedef isc__netievent__socket_t isc__netievent_udplisten_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_udpstop_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_tcpstop_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_tcpchildstop_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_tcpclose_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_tcpdnsclose_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_startread_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_pauseread_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_closecb_t;
|
||||
|
||||
typedef struct isc__netievent__socket_req {
|
||||
isc__netievent_type type;
|
||||
@@ -225,13 +228,15 @@ typedef isc__netievent__socket_req_t isc__netievent_tcpconnect_t;
|
||||
typedef isc__netievent__socket_req_t isc__netievent_tcplisten_t;
|
||||
typedef isc__netievent__socket_req_t isc__netievent_tcpsend_t;
|
||||
|
||||
typedef struct isc__netievent__socket_streaminfo {
|
||||
typedef struct isc__netievent__socket_streaminfo_quota {
|
||||
isc__netievent_type type;
|
||||
isc_nmsocket_t *sock;
|
||||
isc_uv_stream_info_t streaminfo;
|
||||
} isc__netievent__socket_streaminfo_t;
|
||||
isc_quota_t *quota;
|
||||
} isc__netievent__socket_streaminfo_quota_t;
|
||||
|
||||
typedef isc__netievent__socket_streaminfo_t isc__netievent_tcpchildlisten_t;
|
||||
typedef isc__netievent__socket_streaminfo_quota_t
|
||||
isc__netievent_tcpchildaccept_t;
|
||||
|
||||
typedef struct isc__netievent__socket_handle {
|
||||
isc__netievent_type type;
|
||||
@@ -239,7 +244,13 @@ typedef struct isc__netievent__socket_handle {
|
||||
isc_nmhandle_t *handle;
|
||||
} isc__netievent__socket_handle_t;
|
||||
|
||||
typedef isc__netievent__socket_handle_t isc__netievent_closecb_t;
|
||||
typedef struct isc__netievent__socket_quota {
|
||||
isc__netievent_type type;
|
||||
isc_nmsocket_t *sock;
|
||||
isc_quota_t *quota;
|
||||
} isc__netievent__socket_quota_t;
|
||||
|
||||
typedef isc__netievent__socket_quota_t isc__netievent_tcpaccept_t;
|
||||
|
||||
typedef struct isc__netievent_udpsend {
|
||||
isc__netievent_type type;
|
||||
@@ -260,7 +271,8 @@ typedef union {
|
||||
isc__netievent__socket_t nis;
|
||||
isc__netievent__socket_req_t nisr;
|
||||
isc__netievent_udpsend_t nius;
|
||||
isc__netievent__socket_streaminfo_t niss;
|
||||
isc__netievent__socket_quota_t nisq;
|
||||
isc__netievent__socket_streaminfo_quota_t nissq;
|
||||
} isc__netievent_storage_t;
|
||||
|
||||
/*
|
||||
@@ -323,7 +335,6 @@ typedef enum isc_nmsocket_type {
|
||||
isc_nm_udplistener, /* Aggregate of nm_udpsocks */
|
||||
isc_nm_tcpsocket,
|
||||
isc_nm_tcplistener,
|
||||
isc_nm_tcpchildlistener,
|
||||
isc_nm_tcpdnslistener,
|
||||
isc_nm_tcpdnssocket
|
||||
} isc_nmsocket_type;
|
||||
@@ -369,16 +380,7 @@ struct isc_nmsocket {
|
||||
*/
|
||||
isc_quota_t *quota;
|
||||
isc_quota_t *pquota;
|
||||
|
||||
/*%
|
||||
* How many connections we have not accepted due to quota?
|
||||
* When we close a connection we need to accept a new one.
|
||||
*/
|
||||
int overquota;
|
||||
/*%
|
||||
* How many active connections we have?
|
||||
*/
|
||||
int conns;
|
||||
isc_quota_cb_t quotacb;
|
||||
|
||||
/*%
|
||||
* Socket statistics
|
||||
@@ -597,11 +599,11 @@ isc__nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock);
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_uvreq_put(isc__nm_uvreq_t **req, isc_nmsocket_t *sock);
|
||||
isc__nm_uvreq_put(isc__nm_uvreq_t **req);
|
||||
/*%<
|
||||
* Completes the use of a UV request structure, setting '*req' to NULL.
|
||||
*
|
||||
* The UV request is pushed onto the 'sock->inactivereqs' stack or,
|
||||
* The UV request is pushed onto the 'req->sock->inactivereqs' stack or,
|
||||
* if that doesn't work, freed.
|
||||
*/
|
||||
|
||||
@@ -647,6 +649,9 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
* Back-end implementation of isc_nm_send() for UDP handles.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_udp_stoplistening(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
@@ -665,11 +670,26 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
* Back-end implementation of isc_nm_send() for TCP handles.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
|
||||
|
||||
void
|
||||
isc__nm_tcp_close(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Close a TCP socket.
|
||||
*/
|
||||
isc_result_t
|
||||
isc__nm_tcp_pauseread(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Pause reading on this socket, while still remembering the callback.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tcp_resumeread(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Resume reading from socket.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tcp_shutdown(isc_nmsocket_t *sock);
|
||||
@@ -677,23 +697,30 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock);
|
||||
* Called on shutdown to close and clean up a listening TCP socket.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tcp_stoplistening(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcpchildlisten(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
isc__nm_async_tcpaccept(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcpstop(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcpchildstop(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcpsend(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_startread(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_pauseread(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcp_startread(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcp_pauseread(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
/*%<
|
||||
* Callback handlers for asynchronous TCP events (connect, listen,
|
||||
@@ -713,6 +740,9 @@ isc__nm_tcpdns_close(isc_nmsocket_t *sock);
|
||||
* Close a TCPDNS socket.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
|
||||
+100
-38
@@ -603,14 +603,17 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
|
||||
case netievent_tcplisten:
|
||||
isc__nm_async_tcplisten(worker, ievent);
|
||||
break;
|
||||
case netievent_tcpchildlisten:
|
||||
isc__nm_async_tcpchildlisten(worker, ievent);
|
||||
case netievent_tcpchildaccept:
|
||||
isc__nm_async_tcpchildaccept(worker, ievent);
|
||||
break;
|
||||
case netievent_tcpaccept:
|
||||
isc__nm_async_tcpaccept(worker, ievent);
|
||||
break;
|
||||
case netievent_tcpstartread:
|
||||
isc__nm_async_startread(worker, ievent);
|
||||
isc__nm_async_tcp_startread(worker, ievent);
|
||||
break;
|
||||
case netievent_tcppauseread:
|
||||
isc__nm_async_pauseread(worker, ievent);
|
||||
isc__nm_async_tcp_pauseread(worker, ievent);
|
||||
break;
|
||||
case netievent_tcpsend:
|
||||
isc__nm_async_tcpsend(worker, ievent);
|
||||
@@ -618,9 +621,6 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
|
||||
case netievent_tcpstop:
|
||||
isc__nm_async_tcpstop(worker, ievent);
|
||||
break;
|
||||
case netievent_tcpchildstop:
|
||||
isc__nm_async_tcpchildstop(worker, ievent);
|
||||
break;
|
||||
case netievent_tcpclose:
|
||||
isc__nm_async_tcpclose(worker, ievent);
|
||||
break;
|
||||
@@ -927,6 +927,7 @@ isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
|
||||
sock->ah_size * sizeof(size_t));
|
||||
sock->ah_handles = isc_mem_allocate(
|
||||
mgr->mctx, sock->ah_size * sizeof(isc_nmhandle_t *));
|
||||
ISC_LINK_INIT(&sock->quotacb, link);
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
sock->ah_frees[i] = i;
|
||||
sock->ah_handles[i] = NULL;
|
||||
@@ -944,7 +945,6 @@ isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
|
||||
break;
|
||||
case isc_nm_tcpsocket:
|
||||
case isc_nm_tcplistener:
|
||||
case isc_nm_tcpchildlistener:
|
||||
if (family == AF_INET) {
|
||||
sock->statsindex = tcp4statsindex;
|
||||
} else {
|
||||
@@ -1164,7 +1164,15 @@ isc_nmhandle_unref(isc_nmhandle_t *handle) {
|
||||
}
|
||||
|
||||
/*
|
||||
* The handle is closed. If the socket has a callback configured
|
||||
* Temporarily reference the socket to ensure that it can't
|
||||
* be deleted by another thread while we're deactivating the
|
||||
* handle.
|
||||
*/
|
||||
isc_nmsocket_attach(sock, &tmp);
|
||||
nmhandle_deactivate(sock, handle);
|
||||
|
||||
/*
|
||||
* The handle is gone now. If the socket has a callback configured
|
||||
* for that (e.g., to perform cleanup after request processing),
|
||||
* call it now, or schedule it to run asynchronously.
|
||||
*/
|
||||
@@ -1174,27 +1182,16 @@ isc_nmhandle_unref(isc_nmhandle_t *handle) {
|
||||
} else {
|
||||
isc__netievent_closecb_t *event = isc__nm_get_ievent(
|
||||
sock->mgr, netievent_closecb);
|
||||
/*
|
||||
* The socket will be finally detached by the closecb
|
||||
* event handler.
|
||||
*/
|
||||
isc_nmsocket_attach(sock, &event->sock);
|
||||
event->handle = handle;
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)event);
|
||||
|
||||
/*
|
||||
* If we're doing this asynchronously, then the
|
||||
* async event will take care of cleaning up the
|
||||
* handle and closing the socket.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporarily reference the socket to ensure that it can't
|
||||
* be deleted by another thread while we're deactivating the
|
||||
* handle.
|
||||
*/
|
||||
isc_nmsocket_attach(sock, &tmp);
|
||||
nmhandle_deactivate(sock, handle);
|
||||
isc_nmsocket_detach(&tmp);
|
||||
}
|
||||
|
||||
@@ -1249,7 +1246,7 @@ isc__nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock) {
|
||||
isc__nm_uvreq_t *req = NULL;
|
||||
|
||||
REQUIRE(VALID_NM(mgr));
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock == NULL || VALID_NMSOCK(sock));
|
||||
|
||||
if (sock != NULL && atomic_load(&sock->active)) {
|
||||
/* Try to reuse one */
|
||||
@@ -1262,16 +1259,22 @@ isc__nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock) {
|
||||
|
||||
*req = (isc__nm_uvreq_t){ .magic = 0 };
|
||||
req->uv_req.req.data = req;
|
||||
isc_nmsocket_attach(sock, &req->sock);
|
||||
isc_nm_attach(mgr, &req->mgr);
|
||||
if (sock != NULL) {
|
||||
isc_nmsocket_attach(sock, &req->sock);
|
||||
}
|
||||
req->magic = UVREQ_MAGIC;
|
||||
|
||||
return (req);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_uvreq_put(isc__nm_uvreq_t **req0, isc_nmsocket_t *sock) {
|
||||
isc__nm_uvreq_put(isc__nm_uvreq_t **req0) {
|
||||
isc__nm_uvreq_t *req = NULL;
|
||||
isc_nmhandle_t *handle = NULL;
|
||||
isc_nmsocket_t *sock;
|
||||
isc_nm_t *mgr;
|
||||
bool reuse = false;
|
||||
|
||||
REQUIRE(req0 != NULL);
|
||||
REQUIRE(VALID_UVREQ(*req0));
|
||||
@@ -1279,8 +1282,6 @@ isc__nm_uvreq_put(isc__nm_uvreq_t **req0, isc_nmsocket_t *sock) {
|
||||
req = *req0;
|
||||
*req0 = NULL;
|
||||
|
||||
INSIST(sock == req->sock);
|
||||
|
||||
req->magic = 0;
|
||||
|
||||
/*
|
||||
@@ -1288,18 +1289,25 @@ isc__nm_uvreq_put(isc__nm_uvreq_t **req0, isc_nmsocket_t *sock) {
|
||||
* sock, and the netmgr won't all disappear.
|
||||
*/
|
||||
handle = req->handle;
|
||||
req->handle = NULL;
|
||||
|
||||
if (!atomic_load(&sock->active) ||
|
||||
!isc_astack_trypush(sock->inactivereqs, req)) {
|
||||
isc_mempool_put(sock->mgr->reqpool, req);
|
||||
sock = req->sock;
|
||||
mgr = req->mgr;
|
||||
|
||||
*req = (isc__nm_uvreq_t){ .magic = 0 };
|
||||
|
||||
if (sock != NULL && atomic_load(&sock->active)) {
|
||||
reuse = isc_astack_trypush(sock->inactivereqs, req);
|
||||
}
|
||||
if (!reuse) {
|
||||
isc_mempool_put(mgr->reqpool, req);
|
||||
}
|
||||
|
||||
if (handle != NULL) {
|
||||
isc_nmhandle_unref(handle);
|
||||
}
|
||||
|
||||
isc_nmsocket_detach(&sock);
|
||||
if (sock != NULL) {
|
||||
isc_nmsocket_detach(&sock);
|
||||
}
|
||||
isc_nm_detach(&mgr);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
@@ -1321,6 +1329,62 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
switch (handle->sock->type) {
|
||||
case isc_nm_tcpsocket:
|
||||
return (isc__nm_tcp_read(handle, cb, cbarg));
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_pauseread(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
switch (sock->type) {
|
||||
case isc_nm_tcpsocket:
|
||||
return (isc__nm_tcp_pauseread(sock));
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_resumeread(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
switch (sock->type) {
|
||||
case isc_nm_tcpsocket:
|
||||
return (isc__nm_tcp_resumeread(sock));
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc_nm_stoplistening(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
switch (sock->type) {
|
||||
case isc_nm_udplistener:
|
||||
isc__nm_udp_stoplistening(sock);
|
||||
break;
|
||||
case isc_nm_tcpdnslistener:
|
||||
isc__nm_tcpdns_stoplistening(sock);
|
||||
break;
|
||||
case isc_nm_tcplistener:
|
||||
isc__nm_tcp_stoplistening(sock);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_closecb_t *ievent = (isc__netievent_closecb_t *)ev0;
|
||||
@@ -1331,8 +1395,6 @@ isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
|
||||
UNUSED(worker);
|
||||
|
||||
nmhandle_deactivate(ievent->sock, ievent->handle);
|
||||
|
||||
ievent->sock->closehandle_cb(ievent->sock);
|
||||
isc_nmsocket_detach(&ievent->sock);
|
||||
}
|
||||
|
||||
+290
-314
@@ -49,7 +49,7 @@ can_log_tcp_quota() {
|
||||
}
|
||||
|
||||
static int
|
||||
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req);
|
||||
tcp_connect_direct(isc__nm_uvreq_t *req);
|
||||
|
||||
static void
|
||||
tcp_close_direct(isc_nmsocket_t *sock);
|
||||
@@ -68,21 +68,27 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
|
||||
static void
|
||||
tcp_close_cb(uv_handle_t *uvhandle);
|
||||
|
||||
static void
|
||||
stoplistening(isc_nmsocket_t *sock);
|
||||
static void
|
||||
tcp_listenclose_cb(uv_handle_t *handle);
|
||||
static isc_result_t
|
||||
accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota);
|
||||
|
||||
static int
|
||||
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
|
||||
isc__networker_t *worker = NULL;
|
||||
tcp_connect_direct(isc__nm_uvreq_t *req) {
|
||||
isc_nmsocket_t *sock;
|
||||
isc__networker_t *worker;
|
||||
int r;
|
||||
|
||||
REQUIRE(isc__nm_in_netthread());
|
||||
worker = &req->mgr->workers[isc_nm_tid()];
|
||||
|
||||
worker = &sock->mgr->workers[isc_nm_tid()];
|
||||
sock = isc_mem_get(req->mgr->mctx, sizeof(isc_nmsocket_t));
|
||||
isc__nmsocket_init(sock, req->mgr, isc_nm_tcpsocket, NULL);
|
||||
sock->tid = isc_nm_tid();
|
||||
sock->extrahandlesize = 0;
|
||||
|
||||
r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
|
||||
|
||||
if (r != 0) {
|
||||
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]);
|
||||
return (r);
|
||||
@@ -97,9 +103,13 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
|
||||
uv_handle_set_data(&sock->uv_handle.handle, sock);
|
||||
r = uv_tcp_connect(&req->uv_req.connect, &sock->uv_handle.tcp,
|
||||
&req->peer.type.sa, tcp_connect_cb);
|
||||
if (r != 0) {
|
||||
tcp_close_direct(sock);
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -107,14 +117,11 @@ void
|
||||
isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_tcpconnect_t *ievent =
|
||||
(isc__netievent_tcpconnect_t *)ev0;
|
||||
isc_nmsocket_t *sock = ievent->sock;
|
||||
isc__nm_uvreq_t *req = ievent->req;
|
||||
UNUSED(worker);
|
||||
int r;
|
||||
|
||||
REQUIRE(sock->type == isc_nm_tcpsocket);
|
||||
REQUIRE(worker->id == ievent->req->sock->mgr->workers[isc_nm_tid()].id);
|
||||
|
||||
r = tcp_connect_direct(sock, req);
|
||||
r = tcp_connect_direct(req);
|
||||
if (r != 0) {
|
||||
/* We need to issue callbacks ourselves */
|
||||
tcp_connect_cb(&req->uv_req.connect, r);
|
||||
@@ -153,9 +160,39 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
|
||||
req->cb.connect(NULL, isc__nm_uverr2result(status), req->cbarg);
|
||||
}
|
||||
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
isc__nm_uvreq_put(&req);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_connecttcp(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *remote, isc_nm_cb_t cb) {
|
||||
isc__nm_uvreq_t *req;
|
||||
isc__netievent_tcpconnect_t *ievent;
|
||||
|
||||
REQUIRE(VALID_NM(mgr));
|
||||
req = isc__nm_uvreq_get(mgr, NULL);
|
||||
if (local != NULL) {
|
||||
req->local = *local;
|
||||
}
|
||||
req->peer = *remote;
|
||||
req->cb.connect = cb;
|
||||
ievent = isc__nm_get_ievent(mgr, netievent_tcpconnect);
|
||||
ievent->req = req;
|
||||
/*
|
||||
* XXXWPK maybe we should always use random() and call connect
|
||||
* directly if random value == isc_nm_tid()?
|
||||
*/
|
||||
if (isc__nm_in_netthread()) {
|
||||
isc__nm_async_tcpconnect(&mgr->workers[isc_nm_tid()],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_put_ievent(mgr, ievent);
|
||||
} else {
|
||||
int w = isc_random_uniform(mgr->nworkers);
|
||||
isc__nm_enqueue_ievent(&mgr->workers[w],
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
|
||||
void *cbarg, size_t extrahandlesize, int backlog,
|
||||
@@ -167,11 +204,6 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
|
||||
|
||||
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
|
||||
isc__nmsocket_init(nsock, mgr, isc_nm_tcplistener, iface);
|
||||
nsock->nchildren = mgr->nworkers;
|
||||
atomic_init(&nsock->rchildren, mgr->nworkers);
|
||||
nsock->children = isc_mem_get(mgr->mctx,
|
||||
mgr->nworkers * sizeof(*nsock));
|
||||
memset(nsock->children, 0, mgr->nworkers * sizeof(*nsock));
|
||||
nsock->rcb.accept = cb;
|
||||
nsock->rcbarg = cbarg;
|
||||
nsock->extrahandlesize = extrahandlesize;
|
||||
@@ -216,15 +248,10 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
|
||||
}
|
||||
|
||||
/*
|
||||
* For multi-threaded TCP listening, we create a single "parent" socket,
|
||||
* bind to it, and then pass its uv_handle to a set of child sockets, one
|
||||
* per worker. For thread safety, the passing of the socket's uv_handle has
|
||||
* to be done via IPC socket.
|
||||
*
|
||||
* This design pattern is ugly but it's what's recommended by the libuv
|
||||
* documentation. (A prior version of libuv had uv_export() and
|
||||
* uv_import() functions which would have simplified this greatly, but
|
||||
* they have been deprecated and removed.)
|
||||
* For multi-threaded TCP listening, we create a single socket,
|
||||
* bind to it, and start listening. On an incoming connection we accept
|
||||
* it and then pass the accepted socket using uv_export/uv_import mechanism
|
||||
* to child threads.
|
||||
*/
|
||||
void
|
||||
isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
@@ -236,24 +263,6 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
REQUIRE(isc__nm_in_netthread());
|
||||
REQUIRE(sock->type == isc_nm_tcplistener);
|
||||
|
||||
/* Initialize children now to make cleaning up easier */
|
||||
for (int i = 0; i < sock->nchildren; i++) {
|
||||
isc_nmsocket_t *csock = &sock->children[i];
|
||||
|
||||
isc__nmsocket_init(csock, sock->mgr, isc_nm_tcpchildlistener,
|
||||
sock->iface);
|
||||
csock->parent = sock;
|
||||
csock->tid = i;
|
||||
csock->pquota = sock->pquota;
|
||||
csock->backlog = sock->backlog;
|
||||
csock->extrahandlesize = sock->extrahandlesize;
|
||||
|
||||
INSIST(csock->rcb.recv == NULL && csock->rcbarg == NULL);
|
||||
csock->rcb.accept = sock->rcb.accept;
|
||||
csock->rcbarg = sock->rcbarg;
|
||||
csock->fd = -1;
|
||||
}
|
||||
|
||||
r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
|
||||
if (r != 0) {
|
||||
/* It was never opened */
|
||||
@@ -295,39 +304,26 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
uv_handle_set_data(&sock->uv_handle.handle, sock);
|
||||
|
||||
/*
|
||||
* For each worker, we send a 'tcpchildlisten' event with
|
||||
* the exported socket.
|
||||
* We're in the network thread - tcp_connection_cb won't be called
|
||||
* until we leave, there's no race between this and the callback.
|
||||
*/
|
||||
for (int i = 0; i < sock->nchildren; i++) {
|
||||
isc_nmsocket_t *csock = &sock->children[i];
|
||||
isc__netievent_tcpchildlisten_t *event = NULL;
|
||||
r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog,
|
||||
tcp_connection_cb);
|
||||
|
||||
event = isc__nm_get_ievent(csock->mgr,
|
||||
netievent_tcpchildlisten);
|
||||
r = isc_uv_export(&sock->uv_handle.stream, &event->streaminfo);
|
||||
if (r != 0) {
|
||||
isc_log_write(
|
||||
isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
|
||||
"uv_export failed: %s",
|
||||
isc_result_totext(isc__nm_uverr2result(r)));
|
||||
isc__nm_put_ievent(sock->mgr, event);
|
||||
continue;
|
||||
}
|
||||
event->sock = csock;
|
||||
if (csock->tid == isc_nm_tid()) {
|
||||
isc__nm_async_tcpchildlisten(&sock->mgr->workers[i],
|
||||
(isc__netievent_t *)event);
|
||||
isc__nm_put_ievent(sock->mgr, event);
|
||||
} else {
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[i],
|
||||
(isc__netievent_t *)event);
|
||||
}
|
||||
if (r != 0) {
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
|
||||
"uv_listen failed: %s",
|
||||
isc_result_totext(isc__nm_uverr2result(r)));
|
||||
uv_close(&sock->uv_handle.handle, tcp_close_cb);
|
||||
sock->result = isc__nm_uverr2result(r);
|
||||
atomic_store(&sock->listen_error, true);
|
||||
goto done;
|
||||
}
|
||||
|
||||
uv_handle_set_data(&sock->uv_handle.handle, sock);
|
||||
|
||||
atomic_store(&sock->listening, true);
|
||||
|
||||
done:
|
||||
@@ -337,47 +333,112 @@ done:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to the parent socket and be ready to receive the uv_handle
|
||||
* for the socket we'll be listening on.
|
||||
*/
|
||||
static void
|
||||
tcp_connection_cb(uv_stream_t *server, int status) {
|
||||
isc_nmsocket_t *psock = uv_handle_get_data((uv_handle_t *)server);
|
||||
isc_result_t result;
|
||||
UNUSED(status);
|
||||
|
||||
result = accept_connection(psock, NULL);
|
||||
if (result != ISC_R_SUCCESS && result != ISC_R_NOCONN) {
|
||||
if ((result != ISC_R_QUOTA && result != ISC_R_SOFTQUOTA) ||
|
||||
can_log_tcp_quota()) {
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
|
||||
"TCP connection failed: %s",
|
||||
isc_result_totext(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_tcpchildlisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_tcpchildlisten_t *ievent =
|
||||
(isc__netievent_tcpchildlisten_t *)ev0;
|
||||
isc_nmsocket_t *sock = ievent->sock;
|
||||
isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
UNUSED(worker);
|
||||
isc__netievent_tcpchildaccept_t *ievent =
|
||||
(isc__netievent_tcpchildaccept_t *)ev0;
|
||||
isc_nmsocket_t *ssock = ievent->sock;
|
||||
isc_nmsocket_t *csock;
|
||||
isc_nmhandle_t *handle;
|
||||
isc_result_t result;
|
||||
struct sockaddr_storage ss;
|
||||
isc_sockaddr_t local;
|
||||
int r;
|
||||
|
||||
REQUIRE(isc__nm_in_netthread());
|
||||
REQUIRE(sock->type == isc_nm_tcpchildlistener);
|
||||
REQUIRE(ssock->type == isc_nm_tcplistener);
|
||||
|
||||
worker = &sock->mgr->workers[isc_nm_tid()];
|
||||
csock = isc_mem_get(ssock->mgr->mctx, sizeof(isc_nmsocket_t));
|
||||
isc__nmsocket_init(csock, ssock->mgr, isc_nm_tcpsocket, ssock->iface);
|
||||
csock->tid = isc_nm_tid();
|
||||
csock->extrahandlesize = ssock->extrahandlesize;
|
||||
csock->quota = ievent->quota;
|
||||
ievent->quota = NULL;
|
||||
|
||||
uv_tcp_init(&worker->loop, (uv_tcp_t *)&sock->uv_handle.tcp);
|
||||
uv_handle_set_data(&sock->uv_handle.handle, sock);
|
||||
r = isc_uv_import(&sock->uv_handle.stream, &ievent->streaminfo);
|
||||
worker = &ssock->mgr->workers[isc_nm_tid()];
|
||||
uv_tcp_init(&worker->loop, &csock->uv_handle.tcp);
|
||||
|
||||
r = isc_uv_import(&csock->uv_handle.stream, &ievent->streaminfo);
|
||||
if (r != 0) {
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
|
||||
"uv_import failed: %s",
|
||||
isc_result_totext(isc__nm_uverr2result(r)));
|
||||
return;
|
||||
result = isc__nm_uverr2result(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog,
|
||||
tcp_connection_cb);
|
||||
|
||||
r = uv_tcp_getpeername(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
|
||||
&(int){ sizeof(ss) });
|
||||
if (r != 0) {
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
|
||||
"uv_listen failed: %s",
|
||||
isc_result_totext(isc__nm_uverr2result(r)));
|
||||
return;
|
||||
result = isc__nm_uverr2result(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = isc_sockaddr_fromsockaddr(&csock->peer,
|
||||
(struct sockaddr *)&ss);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = uv_tcp_getsockname(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
|
||||
&(int){ sizeof(ss) });
|
||||
if (r != 0) {
|
||||
result = isc__nm_uverr2result(r);
|
||||
goto error;
|
||||
}
|
||||
result = isc_sockaddr_fromsockaddr(&local, (struct sockaddr *)&ss);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
isc_nmsocket_attach(ssock, &csock->server);
|
||||
|
||||
handle = isc__nmhandle_get(csock, NULL, &local);
|
||||
|
||||
INSIST(ssock->rcb.accept != NULL);
|
||||
csock->read_timeout = ssock->mgr->init;
|
||||
ssock->rcb.accept(handle, ISC_R_SUCCESS, ssock->rcbarg);
|
||||
isc_nmsocket_detach(&csock);
|
||||
return;
|
||||
|
||||
error:
|
||||
/*
|
||||
* Detach it early to make room for other connections, otherwise
|
||||
* it'd be detached later asynchronously clogging the quota.
|
||||
*/
|
||||
if (csock->quota != NULL) {
|
||||
isc_quota_detach(&csock->quota);
|
||||
}
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
|
||||
ISC_LOG_ERROR, "Accepting TCP connection failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
/* We need to detach it properly to make sure uv_close is called. */
|
||||
isc_nmsocket_detach(&csock);
|
||||
}
|
||||
|
||||
void
|
||||
isc_nm_tcp_stoplistening(isc_nmsocket_t *sock) {
|
||||
isc__nm_tcp_stoplistening(isc_nmsocket_t *sock) {
|
||||
isc__netievent_tcpstop_t *ievent = NULL;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
@@ -411,84 +472,23 @@ isc__nm_async_tcpstop(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)event);
|
||||
} else {
|
||||
stoplistening(sock);
|
||||
uv_close((uv_handle_t *)&sock->uv_handle.tcp,
|
||||
tcp_listenclose_cb);
|
||||
isc__nm_drop_interlocked(sock->mgr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stoplistening(isc_nmsocket_t *sock) {
|
||||
for (int i = 0; i < sock->nchildren; i++) {
|
||||
isc__netievent_tcpchildstop_t *event = NULL;
|
||||
|
||||
/*
|
||||
* We can ignore the overhead of event allocation because
|
||||
* stoplistening is a rare event, and doing it this way
|
||||
* simplifies sock reference counting.
|
||||
*/
|
||||
event = isc__nm_get_ievent(sock->mgr, netievent_tcpchildstop);
|
||||
isc_nmsocket_attach(&sock->children[i], &event->sock);
|
||||
|
||||
if (isc_nm_tid() == sock->children[i].tid) {
|
||||
isc__nm_async_tcpchildstop(&sock->mgr->workers[i],
|
||||
(isc__netievent_t *)event);
|
||||
isc__nm_put_ievent(sock->mgr, event);
|
||||
} else {
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[i],
|
||||
(isc__netievent_t *)event);
|
||||
}
|
||||
}
|
||||
|
||||
LOCK(&sock->lock);
|
||||
while (atomic_load_relaxed(&sock->rchildren) > 0) {
|
||||
WAIT(&sock->cond, &sock->lock);
|
||||
}
|
||||
UNLOCK(&sock->lock);
|
||||
uv_close((uv_handle_t *)&sock->uv_handle.tcp, tcp_listenclose_cb);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_tcpchildstop(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_tcpchildstop_t *ievent =
|
||||
(isc__netievent_tcpchildstop_t *)ev0;
|
||||
isc_nmsocket_t *sock = ievent->sock;
|
||||
|
||||
UNUSED(worker);
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(isc_nm_tid() == sock->tid);
|
||||
REQUIRE(sock->type == isc_nm_tcpchildlistener);
|
||||
REQUIRE(sock->parent != NULL);
|
||||
|
||||
/*
|
||||
* rchildren is atomic, but we still need to change it
|
||||
* under a lock because the parent is waiting on conditional
|
||||
* and without it we might deadlock.
|
||||
*/
|
||||
LOCK(&sock->parent->lock);
|
||||
atomic_fetch_sub(&sock->parent->rchildren, 1);
|
||||
UNLOCK(&sock->parent->lock);
|
||||
|
||||
uv_close((uv_handle_t *)&sock->uv_handle.tcp, tcp_listenclose_cb);
|
||||
BROADCAST(&sock->parent->cond);
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback is used for closing both child and parent listening
|
||||
* sockets; that's why we need to choose the proper lock.
|
||||
* This callback is used for closing listening sockets
|
||||
*/
|
||||
static void
|
||||
tcp_listenclose_cb(uv_handle_t *handle) {
|
||||
isc_nmsocket_t *sock = uv_handle_get_data(handle);
|
||||
isc_mutex_t *lock = ((sock->parent != NULL) ? &sock->parent->lock
|
||||
: &sock->lock);
|
||||
|
||||
LOCK(lock);
|
||||
LOCK(&sock->lock);
|
||||
atomic_store(&sock->closed, true);
|
||||
atomic_store(&sock->listening, false);
|
||||
sock->pquota = NULL;
|
||||
UNLOCK(lock);
|
||||
|
||||
UNLOCK(&sock->lock);
|
||||
isc_nmsocket_detach(&sock);
|
||||
}
|
||||
|
||||
@@ -519,7 +519,7 @@ readtimeout_cb(uv_timer_t *handle) {
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
||||
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
isc__netievent_startread_t *ievent = NULL;
|
||||
|
||||
@@ -534,8 +534,8 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
||||
ievent->sock = sock;
|
||||
|
||||
if (sock->tid == isc_nm_tid()) {
|
||||
isc__nm_async_startread(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_async_tcp_startread(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_put_ievent(sock->mgr, ievent);
|
||||
} else {
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
@@ -546,7 +546,7 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__nm_async_tcp_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_startread_t *ievent = (isc__netievent_startread_t *)ev0;
|
||||
isc_nmsocket_t *sock = ievent->sock;
|
||||
int r;
|
||||
@@ -569,7 +569,7 @@ isc__nm_async_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_pauseread(isc_nmsocket_t *sock) {
|
||||
isc__nm_tcp_pauseread(isc_nmsocket_t *sock) {
|
||||
isc__netievent_pauseread_t *ievent = NULL;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
@@ -583,8 +583,8 @@ isc_nm_pauseread(isc_nmsocket_t *sock) {
|
||||
ievent->sock = sock;
|
||||
|
||||
if (sock->tid == isc_nm_tid()) {
|
||||
isc__nm_async_pauseread(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_async_tcp_pauseread(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_put_ievent(sock->mgr, ievent);
|
||||
} else {
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
@@ -595,7 +595,7 @@ isc_nm_pauseread(isc_nmsocket_t *sock) {
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_pauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__nm_async_tcp_pauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_pauseread_t *ievent = (isc__netievent_pauseread_t *)ev0;
|
||||
isc_nmsocket_t *sock = ievent->sock;
|
||||
|
||||
@@ -609,7 +609,7 @@ isc__nm_async_pauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_resumeread(isc_nmsocket_t *sock) {
|
||||
isc__nm_tcp_resumeread(isc_nmsocket_t *sock) {
|
||||
isc__netievent_startread_t *ievent = NULL;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
@@ -625,8 +625,8 @@ isc_nm_resumeread(isc_nmsocket_t *sock) {
|
||||
ievent->sock = sock;
|
||||
|
||||
if (sock->tid == isc_nm_tid()) {
|
||||
isc__nm_async_startread(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_async_tcp_startread(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_put_ievent(sock->mgr, ievent);
|
||||
} else {
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
@@ -683,130 +683,29 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
|
||||
*/
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
accept_connection(isc_nmsocket_t *ssock) {
|
||||
isc_result_t result;
|
||||
isc_quota_t *quota = NULL;
|
||||
isc_nmsocket_t *csock = NULL;
|
||||
isc__networker_t *worker = NULL;
|
||||
isc_nmhandle_t *handle = NULL;
|
||||
struct sockaddr_storage ss;
|
||||
isc_sockaddr_t local;
|
||||
int r;
|
||||
bool overquota = false;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(ssock));
|
||||
REQUIRE(ssock->tid == isc_nm_tid());
|
||||
|
||||
if (!atomic_load_relaxed(&ssock->active) ||
|
||||
atomic_load_relaxed(&ssock->mgr->closing))
|
||||
{
|
||||
/* We're closing, bail */
|
||||
return (ISC_R_CANCELED);
|
||||
}
|
||||
|
||||
if (ssock->pquota != NULL) {
|
||||
result = isc_quota_attach(ssock->pquota, "a);
|
||||
|
||||
/*
|
||||
* We share the quota between all TCP sockets. Others
|
||||
* may have used up all the quota slots, in which case
|
||||
* this socket could starve. So we only fail here if we
|
||||
* already had at least one active connection on this
|
||||
* socket. This guarantees that we'll maintain some level
|
||||
* of service while over quota, and will resume normal
|
||||
* service when the quota comes back down.
|
||||
*/
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ssock->overquota++;
|
||||
overquota = true;
|
||||
if (ssock->conns > 0) {
|
||||
isc__nm_incstats(
|
||||
ssock->mgr,
|
||||
ssock->statsindex[STATID_ACCEPTFAIL]);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isc__nm_incstats(ssock->mgr, ssock->statsindex[STATID_ACCEPT]);
|
||||
|
||||
csock = isc_mem_get(ssock->mgr->mctx, sizeof(isc_nmsocket_t));
|
||||
isc__nmsocket_init(csock, ssock->mgr, isc_nm_tcpsocket, ssock->iface);
|
||||
csock->tid = isc_nm_tid();
|
||||
csock->extrahandlesize = ssock->extrahandlesize;
|
||||
csock->quota = quota;
|
||||
quota = NULL;
|
||||
|
||||
worker = &ssock->mgr->workers[isc_nm_tid()];
|
||||
uv_tcp_init(&worker->loop, &csock->uv_handle.tcp);
|
||||
|
||||
r = uv_accept(&ssock->uv_handle.stream, &csock->uv_handle.stream);
|
||||
if (r != 0) {
|
||||
result = isc__nm_uverr2result(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = uv_tcp_getpeername(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
|
||||
&(int){ sizeof(ss) });
|
||||
if (r != 0) {
|
||||
result = isc__nm_uverr2result(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = isc_sockaddr_fromsockaddr(&csock->peer,
|
||||
(struct sockaddr *)&ss);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = uv_tcp_getsockname(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
|
||||
&(int){ sizeof(ss) });
|
||||
if (r != 0) {
|
||||
result = isc__nm_uverr2result(r);
|
||||
goto error;
|
||||
}
|
||||
result = isc_sockaddr_fromsockaddr(&local, (struct sockaddr *)&ss);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
isc_nmsocket_attach(ssock, &csock->server);
|
||||
ssock->conns++;
|
||||
|
||||
handle = isc__nmhandle_get(csock, NULL, &local);
|
||||
|
||||
INSIST(ssock->rcb.accept != NULL);
|
||||
csock->read_timeout = ssock->mgr->init;
|
||||
ssock->rcb.accept(handle, ISC_R_SUCCESS, ssock->rcbarg);
|
||||
isc_nmsocket_detach(&csock);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
error:
|
||||
static void
|
||||
quota_accept_cb(isc_quota_t *quota, void *sock_) {
|
||||
isc_nmsocket_t *sock = (isc_nmsocket_t *)sock_;
|
||||
INSIST(VALID_NMSOCK(sock));
|
||||
/*
|
||||
* Detach it early to make room for other connections, otherwise
|
||||
* it'd be detached later asynchronously clogging the quota.
|
||||
* We need to create an event and pass it using async channel
|
||||
*/
|
||||
if (csock->quota != NULL) {
|
||||
isc_quota_detach(&csock->quota);
|
||||
}
|
||||
if (overquota) {
|
||||
ssock->overquota--;
|
||||
}
|
||||
/* We need to detach it properly to make sure uv_close is called. */
|
||||
isc_nmsocket_detach(&csock);
|
||||
return (result);
|
||||
isc__netievent_tcpaccept_t *ievent =
|
||||
isc__nm_get_ievent(sock->mgr, netievent_tcpaccept);
|
||||
ievent->sock = sock;
|
||||
ievent->quota = quota;
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_connection_cb(uv_stream_t *server, int status) {
|
||||
isc_nmsocket_t *ssock = uv_handle_get_data((uv_handle_t *)server);
|
||||
/* This is called when we get a quota callback. */
|
||||
void
|
||||
isc__nm_async_tcpaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc_result_t result;
|
||||
isc__netievent_tcpaccept_t *ievent = (isc__netievent_tcpaccept_t *)ev0;
|
||||
|
||||
UNUSED(status);
|
||||
|
||||
result = accept_connection(ssock);
|
||||
REQUIRE(worker->id == ievent->sock->tid);
|
||||
result = accept_connection(ievent->sock, ievent->quota);
|
||||
if (result != ISC_R_SUCCESS && result != ISC_R_NOCONN) {
|
||||
if ((result != ISC_R_QUOTA && result != ISC_R_SOFTQUOTA) ||
|
||||
can_log_tcp_quota()) {
|
||||
@@ -816,6 +715,104 @@ tcp_connection_cb(uv_stream_t *server, int status) {
|
||||
isc_result_totext(result));
|
||||
}
|
||||
}
|
||||
/* It was attached when we called isc_quota_attach_cb */
|
||||
isc_nmsocket_detach(&ievent->sock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to free uv_tcp_t that's used only to accept() and then export the
|
||||
* socket to a child thread.
|
||||
*/
|
||||
static void
|
||||
free_uvtcpt(uv_handle_t *uvs) {
|
||||
isc_mem_t *mctx = (isc_mem_t *)uv_handle_get_data(uvs);
|
||||
isc_mem_putanddetach(&mctx, uvs, sizeof(uv_tcp_t));
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
|
||||
isc_result_t result;
|
||||
int r;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(ssock));
|
||||
REQUIRE(ssock->tid == isc_nm_tid());
|
||||
|
||||
if (!atomic_load_relaxed(&ssock->active) ||
|
||||
atomic_load_relaxed(&ssock->mgr->closing))
|
||||
{
|
||||
/* We're closing, bail */
|
||||
if (quota != NULL) {
|
||||
isc_quota_detach("a);
|
||||
}
|
||||
return (ISC_R_CANCELED);
|
||||
}
|
||||
|
||||
/* We can be called directly or as a callback from quota */
|
||||
if (ssock->pquota != NULL && quota == NULL) {
|
||||
/*
|
||||
* We need to increase the reference on ssock, as might be
|
||||
* queued in quota. The proper way of doing it would be
|
||||
* to attach it here - before every call to quota_attach,
|
||||
* and detach it afterwards but that'd be very suboptimal -
|
||||
* instead, we just set it here, and attach it only if it'll
|
||||
* really be used.
|
||||
* XXXWPK do it 'the right way' for now, see what happens then.
|
||||
*/
|
||||
isc_nmsocket_t *tsock = NULL;
|
||||
isc_nmsocket_attach(ssock, &tsock);
|
||||
isc_quota_cb_init(&ssock->quotacb, quota_accept_cb, tsock);
|
||||
result = isc_quota_attach_cb(ssock->pquota, "a,
|
||||
&ssock->quotacb);
|
||||
if (result == ISC_R_QUOTA) {
|
||||
isc__nm_incstats(ssock->mgr,
|
||||
ssock->statsindex[STATID_ACCEPTFAIL]);
|
||||
return (result);
|
||||
}
|
||||
/* Deinitialize & detach, just to be safe */
|
||||
isc_quota_cb_init(&ssock->quotacb, NULL, NULL);
|
||||
isc_nmsocket_detach(&tsock);
|
||||
}
|
||||
|
||||
isc__nm_incstats(ssock->mgr, ssock->statsindex[STATID_ACCEPT]);
|
||||
|
||||
isc__networker_t *worker = &ssock->mgr->workers[isc_nm_tid()];
|
||||
uv_tcp_t *uvstream = isc_mem_get(ssock->mgr->mctx, sizeof(uv_tcp_t));
|
||||
isc_mem_t *mctx = NULL;
|
||||
isc_mem_attach(ssock->mgr->mctx, &mctx);
|
||||
uv_handle_set_data((uv_handle_t *)uvstream, mctx); /* pass it to free it
|
||||
*/
|
||||
mctx = NULL;
|
||||
uv_tcp_init(&worker->loop, uvstream);
|
||||
|
||||
r = uv_accept(&ssock->uv_handle.stream, (uv_stream_t *)uvstream);
|
||||
if (r != 0) {
|
||||
result = isc__nm_uverr2result(r);
|
||||
uv_close((uv_handle_t *)uvstream, free_uvtcpt);
|
||||
isc_quota_detach("a);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* We have an accepted TCP socket, pass it to a random worker */
|
||||
int w = isc_random_uniform(ssock->mgr->nworkers);
|
||||
isc__netievent_tcpchildaccept_t *event =
|
||||
isc__nm_get_ievent(ssock->mgr, netievent_tcpchildaccept);
|
||||
event->sock = ssock;
|
||||
event->quota = quota;
|
||||
|
||||
r = isc_uv_export((uv_stream_t *)uvstream, &event->streaminfo);
|
||||
INSIST(r == 0);
|
||||
uv_close((uv_handle_t *)uvstream, free_uvtcpt);
|
||||
|
||||
if (w == isc_nm_tid()) {
|
||||
isc__nm_async_tcpchildaccept(&ssock->mgr->workers[w],
|
||||
(isc__netievent_t *)event);
|
||||
isc__nm_put_ievent(ssock->mgr, event);
|
||||
} else {
|
||||
isc__nm_enqueue_ievent(&ssock->mgr->workers[w],
|
||||
(isc__netievent_t *)event);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
@@ -872,7 +869,7 @@ tcp_send_cb(uv_write_t *req, int status) {
|
||||
|
||||
uvreq->cb.send(uvreq->handle, result, uvreq->cbarg);
|
||||
isc_nmhandle_unref(uvreq->handle);
|
||||
isc__nm_uvreq_put(&uvreq, uvreq->handle->sock);
|
||||
isc__nm_uvreq_put(&uvreq);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -893,7 +890,7 @@ isc__nm_async_tcpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ievent->req->cb.send(ievent->req->handle, result,
|
||||
ievent->req->cbarg);
|
||||
isc__nm_uvreq_put(&ievent->req, ievent->req->handle->sock);
|
||||
isc__nm_uvreq_put(&ievent->req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -910,7 +907,7 @@ tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
|
||||
if (r < 0) {
|
||||
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]);
|
||||
req->cb.send(NULL, isc__nm_uverr2result(r), req->cbarg);
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
isc__nm_uvreq_put(&req);
|
||||
return (isc__nm_uverr2result(r));
|
||||
}
|
||||
|
||||
@@ -943,30 +940,9 @@ tcp_close_direct(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
REQUIRE(sock->type == isc_nm_tcpsocket);
|
||||
isc_nmsocket_t *ssock = sock->server;
|
||||
|
||||
if (sock->quota != NULL) {
|
||||
isc_quota_detach(&sock->quota);
|
||||
}
|
||||
if (ssock != NULL) {
|
||||
ssock->conns--;
|
||||
while (ssock->conns == 0 && ssock->overquota > 0) {
|
||||
ssock->overquota--;
|
||||
isc_result_t result = accept_connection(ssock);
|
||||
if (result == ISC_R_SUCCESS || result == ISC_R_NOCONN) {
|
||||
continue;
|
||||
}
|
||||
if ((result != ISC_R_QUOTA &&
|
||||
result != ISC_R_SOFTQUOTA) ||
|
||||
can_log_tcp_quota()) {
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_NETMGR,
|
||||
ISC_LOG_ERROR,
|
||||
"TCP connection failed: %s",
|
||||
isc_result_totext(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sock->timer_initialized) {
|
||||
sock->timer_initialized = false;
|
||||
uv_timer_stop(&sock->timer);
|
||||
|
||||
@@ -316,7 +316,7 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
||||
}
|
||||
|
||||
void
|
||||
isc_nm_tcpdns_stoplistening(isc_nmsocket_t *sock) {
|
||||
isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->type == isc_nm_tcpdnslistener);
|
||||
|
||||
@@ -326,7 +326,7 @@ isc_nm_tcpdns_stoplistening(isc_nmsocket_t *sock) {
|
||||
sock->rcbarg = NULL;
|
||||
|
||||
if (sock->outer != NULL) {
|
||||
isc_nm_tcp_stoplistening(sock->outer);
|
||||
isc_nm_stoplistening(sock->outer);
|
||||
isc_nmsocket_detach(&sock->outer);
|
||||
}
|
||||
}
|
||||
@@ -494,7 +494,7 @@ isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
*(uint16_t *)t->region.base = htons(region->length);
|
||||
memmove(t->region.base + 2, region->base, region->length);
|
||||
|
||||
return (isc__nm_tcp_send(t->handle, &t->region, tcpdnssend_cb, t));
|
||||
return (isc_nm_send(t->handle, &t->region, tcpdnssend_cb, t));
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -219,7 +219,7 @@ stoplistening(isc_nmsocket_t *sock) {
|
||||
}
|
||||
|
||||
void
|
||||
isc_nm_udp_stoplistening(isc_nmsocket_t *sock) {
|
||||
isc__nm_udp_stoplistening(isc_nmsocket_t *sock) {
|
||||
isc__netievent_udpstop_t *ievent = NULL;
|
||||
|
||||
/* We can't be launched from network thread, we'd deadlock */
|
||||
@@ -439,7 +439,7 @@ isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
} else {
|
||||
ievent->req->cb.send(ievent->req->handle, ISC_R_CANCELED,
|
||||
ievent->req->cbarg);
|
||||
isc__nm_uvreq_put(&ievent->req, ievent->req->sock);
|
||||
isc__nm_uvreq_put(&ievent->req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@ udp_send_cb(uv_udp_send_t *req, int status) {
|
||||
|
||||
uvreq->cb.send(uvreq->handle, result, uvreq->cbarg);
|
||||
isc_nmhandle_unref(uvreq->handle);
|
||||
isc__nm_uvreq_put(&uvreq, uvreq->sock);
|
||||
isc__nm_uvreq_put(&uvreq);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <isc/log.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/print.h>
|
||||
@@ -295,11 +294,6 @@ isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
|
||||
strerror_r(err, strbuf, sizeof(strbuf));
|
||||
isc_error_fatal(file, line, "pthread_mutex_init failed: %s",
|
||||
strbuf);
|
||||
} else {
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_OTHER, ISC_LOG_INFO,
|
||||
"Initialized mutex %p at %s:%d",
|
||||
mp, file, line);
|
||||
}
|
||||
}
|
||||
#endif /* if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && \
|
||||
|
||||
+82
-27
@@ -22,14 +22,20 @@ isc_quota_init(isc_quota_t *quota, unsigned int max) {
|
||||
atomic_init("a->max, max);
|
||||
atomic_init("a->used, 0);
|
||||
atomic_init("a->soft, 0);
|
||||
atomic_init("a->waiting, 0);
|
||||
ISC_LIST_INIT(quota->cbs);
|
||||
isc_mutex_init("a->cblock);
|
||||
}
|
||||
|
||||
void
|
||||
isc_quota_destroy(isc_quota_t *quota) {
|
||||
INSIST(atomic_load("a->used) == 0);
|
||||
INSIST(atomic_load("a->waiting) == 0);
|
||||
INSIST(ISC_LIST_EMPTY(quota->cbs));
|
||||
atomic_store_release("a->max, 0);
|
||||
atomic_store_release("a->used, 0);
|
||||
atomic_store_release("a->soft, 0);
|
||||
isc_mutex_destroy("a->cblock);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -57,43 +63,79 @@ isc_quota_getused(isc_quota_t *quota) {
|
||||
return (atomic_load_relaxed("a->used));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_quota_reserve(isc_quota_t *quota) {
|
||||
static isc_result_t
|
||||
quota_reserve(isc_quota_t *quota) {
|
||||
isc_result_t result;
|
||||
uint32_t max = atomic_load_acquire("a->max);
|
||||
uint32_t soft = atomic_load_acquire("a->soft);
|
||||
uint32_t used = atomic_fetch_add_relaxed("a->used, 1);
|
||||
if (max == 0 || used < max) {
|
||||
if (soft == 0 || used < soft) {
|
||||
result = ISC_R_SUCCESS;
|
||||
} else {
|
||||
result = ISC_R_SOFTQUOTA;
|
||||
uint_fast32_t max = atomic_load_acquire("a->max);
|
||||
uint_fast32_t soft = atomic_load_acquire("a->soft);
|
||||
uint_fast32_t used = atomic_load_acquire("a->used);
|
||||
do {
|
||||
if (max != 0 && used >= max) {
|
||||
return (ISC_R_QUOTA);
|
||||
}
|
||||
} else {
|
||||
INSIST(atomic_fetch_sub_release("a->used, 1) > 0);
|
||||
result = ISC_R_QUOTA;
|
||||
}
|
||||
if (soft != 0 && used >= soft) {
|
||||
result = ISC_R_SOFTQUOTA;
|
||||
} else {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
} while (!atomic_compare_exchange_weak_acq_rel("a->used, &used,
|
||||
used + 1));
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
isc_quota_release(isc_quota_t *quota) {
|
||||
/* Must be quota->cbslock locked */
|
||||
static void
|
||||
enqueue(isc_quota_t *quota, isc_quota_cb_t *cb) {
|
||||
REQUIRE(cb != NULL);
|
||||
ISC_LIST_ENQUEUE(quota->cbs, cb, link);
|
||||
atomic_fetch_add_release("a->waiting, 1);
|
||||
}
|
||||
|
||||
/* Must be quota->cbslock locked */
|
||||
static isc_quota_cb_t *
|
||||
dequeue(isc_quota_t *quota) {
|
||||
isc_quota_cb_t *cb = ISC_LIST_HEAD(quota->cbs);
|
||||
INSIST(cb != NULL);
|
||||
ISC_LIST_DEQUEUE(quota->cbs, cb, link);
|
||||
atomic_fetch_sub_relaxed("a->waiting, 1);
|
||||
return (cb);
|
||||
}
|
||||
|
||||
static void
|
||||
quota_release(isc_quota_t *quota) {
|
||||
/*
|
||||
* This is opportunistic - we might race with a failing quota_attach_cb
|
||||
* and not detect that something is waiting, but eventually someone will
|
||||
* be releasing quota and will detect it, so we don't need to worry -
|
||||
* and we're saving a lot by not locking cblock every time.
|
||||
*/
|
||||
|
||||
if (atomic_load_acquire("a->waiting) > 0) {
|
||||
isc_quota_cb_t *cb = NULL;
|
||||
LOCK("a->cblock);
|
||||
if (atomic_load_relaxed("a->waiting) > 0) {
|
||||
cb = dequeue(quota);
|
||||
}
|
||||
UNLOCK("a->cblock);
|
||||
if (cb != NULL) {
|
||||
cb->cb_func(quota, cb->data);
|
||||
cb->cb_func = NULL;
|
||||
cb->data = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
INSIST(atomic_fetch_sub_release("a->used, 1) > 0);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
doattach(isc_quota_t *quota, isc_quota_t **p, bool force) {
|
||||
doattach(isc_quota_t *quota, isc_quota_t **p) {
|
||||
isc_result_t result;
|
||||
REQUIRE(p != NULL && *p == NULL);
|
||||
|
||||
result = isc_quota_reserve(quota);
|
||||
result = quota_reserve(quota);
|
||||
if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) {
|
||||
*p = quota;
|
||||
} else if (result == ISC_R_QUOTA && force) {
|
||||
/* attach anyway */
|
||||
atomic_fetch_add_relaxed("a->used, 1);
|
||||
*p = quota;
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
return (result);
|
||||
@@ -101,17 +143,30 @@ doattach(isc_quota_t *quota, isc_quota_t **p, bool force) {
|
||||
|
||||
isc_result_t
|
||||
isc_quota_attach(isc_quota_t *quota, isc_quota_t **p) {
|
||||
return (doattach(quota, p, false));
|
||||
return (isc_quota_attach_cb(quota, p, NULL));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_quota_force(isc_quota_t *quota, isc_quota_t **p) {
|
||||
return (doattach(quota, p, true));
|
||||
isc_quota_attach_cb(isc_quota_t *quota, isc_quota_t **p, isc_quota_cb_t *cb) {
|
||||
isc_result_t result = doattach(quota, p);
|
||||
if (result == ISC_R_QUOTA && cb != NULL) {
|
||||
LOCK("a->cblock);
|
||||
enqueue(quota, cb);
|
||||
UNLOCK("a->cblock);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
isc_quota_cb_init(isc_quota_cb_t *cb, isc_quota_cb_func_t cb_func, void *data) {
|
||||
ISC_LINK_INIT(cb, link);
|
||||
cb->cb_func = cb_func;
|
||||
cb->data = data;
|
||||
}
|
||||
|
||||
void
|
||||
isc_quota_detach(isc_quota_t **p) {
|
||||
INSIST(p != NULL && *p != NULL);
|
||||
isc_quota_release(*p);
|
||||
quota_release(*p);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
+4
-14
@@ -20,7 +20,6 @@
|
||||
#endif /* if defined(sun) && (defined(__sparc) || defined(__sparc__)) */
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/platform.h>
|
||||
#include <isc/print.h>
|
||||
@@ -33,16 +32,11 @@
|
||||
#include <pthread.h>
|
||||
|
||||
isc_result_t
|
||||
isc__rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
|
||||
unsigned int write_quota, const char *file,
|
||||
unsigned int line) {
|
||||
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
|
||||
unsigned int write_quota) {
|
||||
UNUSED(read_quota);
|
||||
UNUSED(write_quota);
|
||||
REQUIRE(pthread_rwlock_init(&rwl->rwlock, NULL) == 0);
|
||||
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGMODULE_OTHER, ISC_LOG_INFO,
|
||||
"Initialized rwlock %p at %s:%d",
|
||||
&rwl->rwlock, file, line);
|
||||
atomic_init(&rwl->downgrade, false);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
@@ -196,14 +190,10 @@ print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
|
||||
#endif /* ISC_RWLOCK_TRACE */
|
||||
|
||||
isc_result_t
|
||||
isc__rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
|
||||
unsigned int write_quota, const char *file,
|
||||
unsigned int line) {
|
||||
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
|
||||
unsigned int write_quota) {
|
||||
REQUIRE(rwl != NULL);
|
||||
|
||||
UNUSED(file);
|
||||
UNUSED(line);
|
||||
|
||||
/*
|
||||
* In case there's trouble initializing, we zero magic now. If all
|
||||
* goes well, we'll set it to RWLOCK_MAGIC.
|
||||
|
||||
@@ -33,7 +33,7 @@ SRCS = isctest.c aes_test.c buffer_test.c \
|
||||
counter_test.c crc64_test.c errno_test.c file_test.c hash_test.c \
|
||||
heap_test.c hmac_test.c ht_test.c lex_test.c \
|
||||
mem_test.c md_test.c netaddr_test.c parse_test.c pool_test.c \
|
||||
radix_test.c random_test.c \
|
||||
quota_test.c radix_test.c random_test.c \
|
||||
regex_test.c result_test.c safe_test.c siphash_test.c sockaddr_test.c \
|
||||
socket_test.c socket_test.c symtab_test.c task_test.c \
|
||||
taskpool_test.c time_test.c timer_test.c
|
||||
@@ -46,7 +46,7 @@ TARGETS = aes_test@EXEEXT@ buffer_test@EXEEXT@ \
|
||||
ht_test@EXEEXT@ \
|
||||
lex_test@EXEEXT@ mem_test@EXEEXT@ md_test@EXEEXT@ \
|
||||
netaddr_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@ \
|
||||
radix_test@EXEEXT@ \
|
||||
quota_test@EXEEXT@ radix_test@EXEEXT@ \
|
||||
random_test@EXEEXT@ regex_test@EXEEXT@ result_test@EXEEXT@ \
|
||||
safe_test@EXEEXT@ siphash_test@EXEEXT@ sockaddr_test@EXEEXT@ socket_test@EXEEXT@ \
|
||||
socket_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \
|
||||
@@ -134,6 +134,11 @@ pool_test@EXEEXT@: pool_test.@O@ isctest.@O@ ${ISCDEPLIBS}
|
||||
${LDFLAGS} -o $@ pool_test.@O@ isctest.@O@ \
|
||||
${ISCLIBS} ${LIBS}
|
||||
|
||||
quota_test@EXEEXT@: quota_test.@O@ isctest.@O@ ${ISCDEPLIBS}
|
||||
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \
|
||||
${LDFLAGS} -o $@ quota_test.@O@ isctest.@O@ \
|
||||
${ISCLIBS} ${LIBS}
|
||||
|
||||
radix_test@EXEEXT@: radix_test.@O@ isctest.@O@ ${ISCDEPLIBS}
|
||||
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \
|
||||
${LDFLAGS} -o $@ radix_test.@O@ isctest.@O@ \
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#if HAVE_CMOCKA
|
||||
|
||||
#include <sched.h> /* IWYU pragma: keep */
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <isc/quota.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
static void
|
||||
isc_quota_get_set_test(void **state) {
|
||||
UNUSED(state);
|
||||
isc_quota_t quota;
|
||||
isc_quota_t *quota2 = NULL;
|
||||
isc_quota_init("a, 100);
|
||||
|
||||
assert_int_equal(isc_quota_getmax("a), 100);
|
||||
assert_int_equal(isc_quota_getsoft("a), 0);
|
||||
|
||||
isc_quota_max("a, 50);
|
||||
isc_quota_soft("a, 30);
|
||||
|
||||
assert_int_equal(isc_quota_getmax("a), 50);
|
||||
assert_int_equal(isc_quota_getsoft("a), 30);
|
||||
|
||||
assert_int_equal(isc_quota_getused("a), 0);
|
||||
isc_quota_attach("a, "a2);
|
||||
assert_int_equal(isc_quota_getused("a), 1);
|
||||
isc_quota_detach("a2);
|
||||
assert_int_equal(isc_quota_getused("a), 0);
|
||||
isc_quota_destroy("a);
|
||||
}
|
||||
|
||||
#define add_quota(quota, quotasp, exp, attached, exp_used) \
|
||||
{ \
|
||||
*quotasp = NULL; \
|
||||
isc_result_t result = isc_quota_attach(quota, quotasp); \
|
||||
assert_int_equal(result, exp); \
|
||||
if (attached) { \
|
||||
assert_ptr_equal(*quotasp, quota); \
|
||||
} else { \
|
||||
assert_null(*quotasp); \
|
||||
} \
|
||||
assert_int_equal(isc_quota_getused(quota), exp_used); \
|
||||
}
|
||||
|
||||
static void
|
||||
isc_quota_hard_test(void **state) {
|
||||
isc_quota_t quota;
|
||||
isc_quota_t *quotas[110];
|
||||
int i;
|
||||
UNUSED(state);
|
||||
|
||||
isc_quota_init("a, 100);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
add_quota("a, "as[i], ISC_R_SUCCESS, true, i + 1);
|
||||
}
|
||||
|
||||
add_quota("a, "as[100], ISC_R_QUOTA, false, 100);
|
||||
|
||||
assert_int_equal(isc_quota_getused("a), 100);
|
||||
|
||||
isc_quota_detach("as[0]);
|
||||
assert_null(quotas[0]);
|
||||
|
||||
add_quota("a, "as[100], ISC_R_SUCCESS, true, 100);
|
||||
add_quota("a, "as[101], ISC_R_QUOTA, false, 100);
|
||||
|
||||
for (i = 100; i > 0; i--) {
|
||||
isc_quota_detach("as[i]);
|
||||
assert_null(quotas[i]);
|
||||
assert_int_equal(isc_quota_getused("a), i - 1);
|
||||
}
|
||||
assert_int_equal(isc_quota_getused("a), 0);
|
||||
isc_quota_destroy("a);
|
||||
}
|
||||
|
||||
static void
|
||||
isc_quota_soft_test(void **state) {
|
||||
isc_quota_t quota;
|
||||
isc_quota_t *quotas[110];
|
||||
int i;
|
||||
UNUSED(state);
|
||||
|
||||
isc_quota_init("a, 100);
|
||||
isc_quota_soft("a, 50);
|
||||
|
||||
for (i = 0; i < 50; i++) {
|
||||
add_quota("a, "as[i], ISC_R_SUCCESS, true, i + 1);
|
||||
}
|
||||
for (i = 50; i < 100; i++) {
|
||||
add_quota("a, "as[i], ISC_R_SOFTQUOTA, true, i + 1);
|
||||
}
|
||||
|
||||
add_quota("a, "as[i], ISC_R_QUOTA, false, 100);
|
||||
|
||||
for (i = 99; i >= 0; i--) {
|
||||
isc_quota_detach("as[i]);
|
||||
assert_null(quotas[i]);
|
||||
assert_int_equal(isc_quota_getused("a), i);
|
||||
}
|
||||
assert_int_equal(isc_quota_getused("a), 0);
|
||||
isc_quota_destroy("a);
|
||||
}
|
||||
|
||||
static atomic_uint_fast32_t cb_calls = ATOMIC_VAR_INIT(0);
|
||||
static isc_quota_cb_t cbs[30];
|
||||
static isc_quota_t *qp;
|
||||
|
||||
static void
|
||||
callback(isc_quota_t *quota, void *data) {
|
||||
int val = *(int *)data;
|
||||
/* Callback is not called if we get the quota directly */
|
||||
assert_int_not_equal(val, -1);
|
||||
|
||||
/* We get the proper quota pointer */
|
||||
assert_ptr_equal(quota, qp);
|
||||
|
||||
/* Verify that the callbacks are called in order */
|
||||
int v = atomic_fetch_add_relaxed(&cb_calls, 1);
|
||||
assert_int_equal(v, val);
|
||||
|
||||
/*
|
||||
* First 5 will be detached by the test function,
|
||||
* for the last 5 - do a 'chain detach'.
|
||||
*/
|
||||
if (v >= 5) {
|
||||
isc_quota_detach("a);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isc_quota_callback_test(void **state) {
|
||||
isc_result_t result;
|
||||
isc_quota_t quota;
|
||||
isc_quota_t *quotas[30];
|
||||
qp = "a;
|
||||
/*
|
||||
* - 10 calls that end with SUCCESS
|
||||
* - 10 calls that end with SOFTQUOTA
|
||||
* - 10 callbacks
|
||||
*/
|
||||
int ints[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
int i;
|
||||
UNUSED(state);
|
||||
|
||||
isc_quota_init("a, 20);
|
||||
isc_quota_soft("a, 10);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
quotas[i] = NULL;
|
||||
isc_quota_cb_init(&cbs[i], callback, &ints[i]);
|
||||
result = isc_quota_attach_cb("a, "as[i], &cbs[i]);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_ptr_equal(quotas[i], "a);
|
||||
assert_int_equal(isc_quota_getused("a), i + 1);
|
||||
}
|
||||
for (i = 10; i < 20; i++) {
|
||||
quotas[i] = NULL;
|
||||
isc_quota_cb_init(&cbs[i], callback, &ints[i]);
|
||||
result = isc_quota_attach_cb("a, "as[i], &cbs[i]);
|
||||
assert_int_equal(result, ISC_R_SOFTQUOTA);
|
||||
assert_ptr_equal(quotas[i], "a);
|
||||
assert_int_equal(isc_quota_getused("a), i + 1);
|
||||
}
|
||||
|
||||
for (i = 20; i < 30; i++) {
|
||||
quotas[i] = NULL;
|
||||
isc_quota_cb_init(&cbs[i], callback, &ints[i]);
|
||||
result = isc_quota_attach_cb("a, "as[i], &cbs[i]);
|
||||
assert_int_equal(result, ISC_R_QUOTA);
|
||||
assert_ptr_equal(quotas[i], NULL);
|
||||
assert_int_equal(isc_quota_getused("a), 20);
|
||||
}
|
||||
assert_int_equal(atomic_load(&cb_calls), 0);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
isc_quota_detach("as[i]);
|
||||
assert_null(quotas[i]);
|
||||
assert_int_equal(isc_quota_getused("a), 20);
|
||||
assert_int_equal(atomic_load(&cb_calls), i + 1);
|
||||
}
|
||||
/* That should cause a chain reaction */
|
||||
isc_quota_detach("as[5]);
|
||||
assert_int_equal(atomic_load(&cb_calls), 10);
|
||||
|
||||
/* Release the quotas that we did not released in the callback */
|
||||
for (i = 0; i < 5; i++) {
|
||||
isc_quota_detach("as[i]);
|
||||
}
|
||||
|
||||
for (i = 6; i < 20; i++) {
|
||||
isc_quota_detach("as[i]);
|
||||
assert_null(quotas[i]);
|
||||
assert_int_equal(isc_quota_getused("a), 19 - i);
|
||||
}
|
||||
assert_int_equal(atomic_load(&cb_calls), 10);
|
||||
|
||||
assert_int_equal(isc_quota_getused("a), 0);
|
||||
isc_quota_destroy("a);
|
||||
}
|
||||
|
||||
/*
|
||||
* Multithreaded quota callback test:
|
||||
* - quota set to 100
|
||||
* - 10 threads, each trying to get 100 quotas.
|
||||
* - creates a separate thread to release it after 10ms
|
||||
*/
|
||||
|
||||
typedef struct qthreadinfo {
|
||||
atomic_uint_fast32_t direct;
|
||||
atomic_uint_fast32_t callback;
|
||||
isc_quota_t *quota;
|
||||
isc_quota_cb_t callbacks[100];
|
||||
} qthreadinfo_t;
|
||||
|
||||
static atomic_uint_fast32_t g_tnum = ATOMIC_VAR_INIT(0);
|
||||
/* at most 10 * 100 quota_detach threads */
|
||||
isc_thread_t g_threads[10 * 100];
|
||||
|
||||
static void *
|
||||
quota_detach(void *quotap) {
|
||||
isc_quota_t *quota = (isc_quota_t *)quotap;
|
||||
usleep(10000);
|
||||
isc_quota_detach("a);
|
||||
return ((isc_threadresult_t)0);
|
||||
}
|
||||
|
||||
static void
|
||||
quota_callback(isc_quota_t *quota, void *data) {
|
||||
qthreadinfo_t *qti = (qthreadinfo_t *)data;
|
||||
atomic_fetch_add_relaxed(&qti->callback, 1);
|
||||
int tnum = atomic_fetch_add_relaxed(&g_tnum, 1);
|
||||
isc_thread_create(quota_detach, quota, &g_threads[tnum]);
|
||||
}
|
||||
|
||||
static isc_threadresult_t
|
||||
quota_thread(void *qtip) {
|
||||
qthreadinfo_t *qti = (qthreadinfo_t *)qtip;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
isc_quota_cb_init(&qti->callbacks[i], quota_callback, qti);
|
||||
isc_quota_t *quota = NULL;
|
||||
isc_result_t result = isc_quota_attach_cb(qti->quota, "a,
|
||||
&qti->callbacks[i]);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
atomic_fetch_add_relaxed(&qti->direct, 1);
|
||||
int tnum = atomic_fetch_add_relaxed(&g_tnum, 1);
|
||||
isc_thread_create(quota_detach, quota,
|
||||
&g_threads[tnum]);
|
||||
}
|
||||
}
|
||||
return ((isc_threadresult_t)0);
|
||||
}
|
||||
|
||||
static void
|
||||
isc_quota_callback_mt_test(void **state) {
|
||||
UNUSED(state);
|
||||
isc_quota_t quota;
|
||||
int i;
|
||||
|
||||
isc_quota_init("a, 100);
|
||||
static qthreadinfo_t qtis[10];
|
||||
isc_thread_t threads[10];
|
||||
for (i = 0; i < 10; i++) {
|
||||
atomic_init(&qtis[i].direct, 0);
|
||||
atomic_init(&qtis[i].callback, 0);
|
||||
qtis[i].quota = "a;
|
||||
isc_thread_create(quota_thread, &qtis[i], &threads[i]);
|
||||
}
|
||||
for (i = 0; i < 10; i++) {
|
||||
isc_thread_join(threads[i], NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)atomic_load(&g_tnum); i++) {
|
||||
isc_thread_join(g_threads[i], NULL);
|
||||
}
|
||||
int direct = 0, callback = 0;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
direct += atomic_load(&qtis[i].direct);
|
||||
callback += atomic_load(&qtis[i].callback);
|
||||
}
|
||||
/* Total quota gained must be 10 threads * 100 tries */
|
||||
assert_int_equal(direct + callback, 10 * 100);
|
||||
/*
|
||||
* At least 100 must be direct, the rest is virtually random:
|
||||
* - in a regular run I'm constantly getting 100:900 ratio
|
||||
* - under rr - usually around ~120:880
|
||||
* - under rr -h - 1000:0
|
||||
*/
|
||||
assert_true(direct >= 100);
|
||||
|
||||
isc_quota_destroy("a);
|
||||
}
|
||||
|
||||
int
|
||||
main(void) {
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(isc_quota_get_set_test),
|
||||
cmocka_unit_test(isc_quota_hard_test),
|
||||
cmocka_unit_test(isc_quota_soft_test),
|
||||
cmocka_unit_test(isc_quota_callback_test),
|
||||
cmocka_unit_test(isc_quota_callback_mt_test),
|
||||
};
|
||||
|
||||
return (cmocka_run_group_tests(tests, NULL, NULL));
|
||||
}
|
||||
|
||||
#else /* HAVE_CMOCKA */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(void) {
|
||||
printf("1..0 # Skipped: cmocka not available\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif /* if HAVE_CMOCKA */
|
||||
@@ -45,7 +45,7 @@ isc_stdtime_get(isc_stdtime_t *t) {
|
||||
strbuf);
|
||||
}
|
||||
|
||||
REQUIRE(ts.tv_sec > 0 && ts.tv_nsec > 0 && ts.tv_nsec < NS_PER_S);
|
||||
REQUIRE(ts.tv_sec > 0 && ts.tv_nsec >= 0 && ts.tv_nsec < NS_PER_S);
|
||||
|
||||
*t = (unsigned int)ts.tv_sec;
|
||||
*t = (isc_stdtime_t)ts.tv_sec;
|
||||
}
|
||||
|
||||
@@ -461,14 +461,13 @@ isc_nm_maxudp
|
||||
isc_nm_send
|
||||
isc_nm_setstats
|
||||
isc_nm_start
|
||||
isc_nm_stoplistening
|
||||
isc_nm_tcp_gettimeouts
|
||||
isc_nm_tcp_settimeouts
|
||||
isc_nmsocket_detach
|
||||
isc_nm_tcpdns_keepalive
|
||||
isc_nm_tcpdns_sequential
|
||||
isc_nm_tcpdns_stoplistening
|
||||
isc_nm_tid
|
||||
isc_nm_udp_stoplistening
|
||||
isc_nmsocket_detach
|
||||
isc__nm_acquire_interlocked
|
||||
isc__nm_drop_interlocked
|
||||
isc__nm_acquire_interlocked_force
|
||||
@@ -498,16 +497,15 @@ isc_queue_dequeue
|
||||
isc_queue_destroy
|
||||
isc_queue_new
|
||||
isc_quota_attach
|
||||
isc_quota_attach_cb
|
||||
isc_quota_cb_init
|
||||
isc_quota_destroy
|
||||
isc_quota_detach
|
||||
isc_quota_force
|
||||
isc_quota_getmax
|
||||
isc_quota_getsoft
|
||||
isc_quota_getused
|
||||
isc_quota_init
|
||||
isc_quota_max
|
||||
isc_quota_release
|
||||
isc_quota_reserve
|
||||
isc_quota_soft
|
||||
isc_radix_create
|
||||
isc_radix_destroy
|
||||
|
||||
@@ -553,11 +553,11 @@ cleanup_interface:
|
||||
void
|
||||
ns_interface_shutdown(ns_interface_t *ifp) {
|
||||
if (ifp->udplistensocket != NULL) {
|
||||
isc_nm_udp_stoplistening(ifp->udplistensocket);
|
||||
isc_nm_stoplistening(ifp->udplistensocket);
|
||||
isc_nmsocket_detach(&ifp->udplistensocket);
|
||||
}
|
||||
if (ifp->tcplistensocket != NULL) {
|
||||
isc_nm_tcpdns_stoplistening(ifp->tcplistensocket);
|
||||
isc_nm_stoplistening(ifp->tcplistensocket);
|
||||
isc_nmsocket_detach(&ifp->tcplistensocket);
|
||||
}
|
||||
if (ifp->clientmgr != NULL) {
|
||||
|
||||
@@ -1471,6 +1471,7 @@
|
||||
./doc/arm/masters.grammar.xml SGML 2018,2019,2020
|
||||
./doc/arm/mirror.zoneopt.xml SGML 2018,2019,2020
|
||||
./doc/arm/notes-9.17.0.xml SGML 2020
|
||||
./doc/arm/notes-9.17.1.xml SGML 2020
|
||||
./doc/arm/notes-download.xml SGML 2019,2020
|
||||
./doc/arm/notes-eol.xml SGML 2019,2020
|
||||
./doc/arm/notes-intro.xml SGML 2019,2020
|
||||
@@ -2314,6 +2315,7 @@
|
||||
./lib/isc/tests/netaddr_test.c C 2016,2018,2019,2020
|
||||
./lib/isc/tests/parse_test.c C 2012,2013,2016,2018,2019,2020
|
||||
./lib/isc/tests/pool_test.c C 2013,2016,2018,2019,2020
|
||||
./lib/isc/tests/quota_test.c C 2020
|
||||
./lib/isc/tests/radix_test.c C 2014,2016,2018,2019,2020
|
||||
./lib/isc/tests/random_test.c C 2014,2015,2016,2017,2018,2019,2020
|
||||
./lib/isc/tests/regex_test.c C 2013,2015,2016,2018,2019,2020
|
||||
|
||||
Reference in New Issue
Block a user