summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOto Šťáva <oto.stava@nic.cz>2024-06-04 17:38:58 +0200
committerOto Šťáva <oto.stava@nic.cz>2024-06-04 17:38:58 +0200
commitb868b2584ef0bd3841256de596e3074443e9397b (patch)
tree2bcc576adb9edcf2e540b8bb237d8d9c434a7b50
parentMerge branch rrl-wip-sample into rrl-wip (diff)
parentMerge branch 'nits' into 'master' (diff)
downloadknot-resolver-b868b2584ef0bd3841256de596e3074443e9397b.tar.xz
knot-resolver-b868b2584ef0bd3841256de596e3074443e9397b.zip
Merge branch 'master' into 'rrl-wip'
-rw-r--r--.clang-tidy52
-rw-r--r--.gitignore1
-rw-r--r--.gitlab-ci.yml185
-rw-r--r--NEWS12
-rw-r--r--ci/images/README.md54
-rwxr-xr-xci/images/build.sh23
-rw-r--r--ci/images/debian-11-coverity/Dockerfile43
-rw-r--r--ci/images/debian-11/Dockerfile146
-rw-r--r--ci/images/debian-buster/Dockerfile146
-rwxr-xr-xci/images/push.sh8
-rwxr-xr-xci/images/update.sh22
-rwxr-xr-xci/images/vars.sh13
-rw-r--r--ci/pkgtest.yaml3
-rw-r--r--contrib/dynarray.h112
-rw-r--r--contrib/dynarray.spdx10
-rw-r--r--daemon/bindings/event.c16
-rw-r--r--daemon/bindings/net.c12
-rw-r--r--daemon/engine.c4
-rw-r--r--daemon/http.c38
-rw-r--r--daemon/io.c268
-rw-r--r--daemon/io.h2
-rw-r--r--daemon/main.c8
-rw-r--r--daemon/proxyv2.c175
-rw-r--r--daemon/proxyv2.h18
-rw-r--r--daemon/session2.c647
-rw-r--r--daemon/session2.h351
-rw-r--r--daemon/tls.c60
-rw-r--r--daemon/tls.h2
-rw-r--r--daemon/tls_ephemeral_credentials.c20
-rw-r--r--daemon/tls_session_ticket-srv.c2
-rw-r--r--daemon/udp_queue.c6
-rw-r--r--daemon/worker.c106
-rw-r--r--daemon/zimport.c6
-rw-r--r--distro/config/apkg.toml2
-rw-r--r--distro/pkg/deb/control60
-rw-r--r--distro/pkg/deb/knot-resolver-core.manpages1
-rw-r--r--distro/pkg/deb/knot-resolver-manager.install4
-rw-r--r--distro/pkg/deb/knot-resolver6-dev.install3
-rw-r--r--distro/pkg/deb/knot-resolver6-module-dnstap.install (renamed from distro/pkg/deb/knot-resolver-module-dnstap.install)0
-rw-r--r--distro/pkg/deb/knot-resolver6-module-http.install (renamed from distro/pkg/deb/knot-resolver-module-http.install)0
-rw-r--r--distro/pkg/deb/knot-resolver6-module-http.links (renamed from distro/pkg/deb/knot-resolver-module-http.links)0
-rw-r--r--distro/pkg/deb/knot-resolver6.dirs (renamed from distro/pkg/deb/knot-resolver-core.dirs)0
-rw-r--r--distro/pkg/deb/knot-resolver6.docs (renamed from distro/pkg/deb/knot-resolver-core.docs)0
-rw-r--r--distro/pkg/deb/knot-resolver6.install (renamed from distro/pkg/deb/knot-resolver-core.install)22
-rw-r--r--distro/pkg/deb/knot-resolver6.links (renamed from distro/pkg/deb/knot-resolver-manager.links)0
-rw-r--r--distro/pkg/deb/knot-resolver6.manpages (renamed from distro/pkg/deb/knot-resolver-manager.manpages)1
-rw-r--r--distro/pkg/deb/knot-resolver6.postinst (renamed from distro/pkg/deb/knot-resolver-core.postinst)0
-rw-r--r--distro/pkg/deb/knot-resolver6.postrm (renamed from distro/pkg/deb/knot-resolver-core.postrm)0
-rw-r--r--distro/pkg/deb/not-installed3
-rwxr-xr-xdistro/pkg/deb/rules21
-rw-r--r--distro/pkg/rpm/knot-resolver.spec88
-rw-r--r--doc/dev/build.rst47
-rw-r--r--lib/cache/api.c2
-rw-r--r--lib/cache/peek.c3
-rw-r--r--lib/dnssec.c2
-rw-r--r--lib/dnssec/nsec.c18
-rw-r--r--lib/dnssec/nsec3.c12
-rw-r--r--lib/dnssec/signature.c2
-rw-r--r--lib/dnssec/ta.c13
-rw-r--r--lib/generic/array.h14
-rw-r--r--lib/generic/lru.h5
-rw-r--r--lib/generic/queue.c10
-rw-r--r--lib/generic/queue.h6
-rw-r--r--lib/generic/trie.c4
-rw-r--r--lib/layer/iterate.c2
-rw-r--r--lib/layer/validate.c2
-rw-r--r--lib/log.c2
-rw-r--r--lib/meson.build2
-rw-r--r--lib/proto.c19
-rw-r--r--lib/proto.h53
-rw-r--r--lib/resolve-produce.c15
-rw-r--r--lib/resolve.c5
-rw-r--r--lib/rules/api.c16
-rw-r--r--lib/rules/api.h22
-rw-r--r--lib/rules/forward.c2
-rw-r--r--lib/rules/local-addr.c2
-rw-r--r--lib/rules/zonefile.c6
-rw-r--r--lib/selection.c2
-rw-r--r--lib/utils.c7
-rw-r--r--lib/utils.h6
-rw-r--r--lib/zonecut.c2
-rw-r--r--manager/README.md5
-rw-r--r--manager/knot_resolver_manager/datamodel/templates/dnssec.lua.j22
-rw-r--r--manager/pyproject.toml1
-rw-r--r--manager/scripts/_env.sh28
-rwxr-xr-xmanager/scripts/meson-configure11
-rw-r--r--meson.build10
-rw-r--r--meson_options.txt12
-rw-r--r--modules/dnstap/dnstap.c1
-rw-r--r--modules/hints/meson.build2
-rw-r--r--modules/http/meson.build2
-rw-r--r--modules/stats/stats.c143
-rw-r--r--tests/config/meson.build4
-rw-r--r--tests/dnstap/src/dnstap-test/go.mod2
-rw-r--r--tests/dnstap/src/dnstap-test/go.sum44
-rwxr-xr-xtests/dnstap/src/dnstap-test/run.sh17
-rw-r--r--tests/pytests/conftest.py2
-rw-r--r--tests/pytests/kresd.py6
-rw-r--r--tests/pytests/test_tls.py47
-rw-r--r--tests/pytests/utils.py19
-rw-r--r--utils/cache_gc/categories.c2
-rw-r--r--utils/cache_gc/db.c6
-rw-r--r--utils/cache_gc/kr_cache_gc.c77
-rw-r--r--utils/cache_gc/main.c26
104 files changed, 1543 insertions, 2005 deletions
diff --git a/.clang-tidy b/.clang-tidy
index b496044c..4d77c1a7 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,6 +1,54 @@
---
-Checks: 'bugprone-*,cert-*,-cert-dcl03-c,-clang-analyzer-unix.Malloc,-clang-analyzer-deadcode.DeadStores,-clang-analyzer-valist.Uninitialized,readability-*,-readability-braces-*,-readability-else-after-return,-readability-redundant-declaration,-readability-non-const-parameter,google-readability-casting,misc-*,-misc-static-assert,-misc-macro-parentheses,-misc-unused-parameters'
-WarningsAsErrors: 'cert-*,misc-*,readability-*,clang-analyzer-*,-readability-non-const-parameter'
+Checks: |-
+ bugprone-*,
+ cert-*,
+ google-readability-casting,
+ misc-*,
+ readability-*,
+
+ -bugprone-assignment-in-if-condition,
+ -bugprone-branch-clone,
+ -bugprone-easily-swappable-parameters,
+ -bugprone-inc-dec-in-conditions,
+ -bugprone-multi-level-implicit-pointer-conversion,
+ -bugprone-narrowing-conversions,
+ -bugprone-not-null-terminated-result,
+ -bugprone-sizeof-expression,
+ -bugprone-suspicious-string-compare,
+ -cert-dcl03-c,
+ -clang-analyzer-deadcode.DeadStores,
+ -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
+ -clang-analyzer-unix.Malloc,
+ -clang-analyzer-valist.Uninitialized,
+ -clang-analyzer-optin.core.EnumCastOutOfRange,
+ -misc-include-cleaner,
+ -misc-macro-parentheses,
+ -misc-no-recursion,
+ -misc-static-assert,
+ -misc-unused-parameters,
+ -readability-avoid-nested-conditional-operator,
+ -readability-avoid-unconditional-preprocessor-if,
+ -readability-braces-*,
+ -readability-cognitive-complexity,
+ -readability-else-after-return,
+ -readability-function-cognitive-complexity,
+ -readability-identifier-length,
+ -readability-isolate-declaration,
+ -readability-magic-numbers,
+ -readability-non-const-parameter,
+ -readability-redundant-declaration,
+ -clang-analyzer-core.UndefinedBinaryOperatorResult
+
+# TODO: remove `-clang-analyzer-core.UndefinedBinaryOperatorResult` when we
+# upgrade to Clang >=18 (it's a false positive )
+
+WarningsAsErrors: |-
+ cert-*,
+ clang-analyzer-*,
+ misc-*,
+ readability-*,
+ -readability-non-const-parameter,
+
HeaderFilterRegex: 'contrib/ucw/*.h'
CheckOptions:
- key: readability-identifier-naming
diff --git a/.gitignore b/.gitignore
index 32789e7c..569b0323 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@
/self.key
/stamp-h1
/tags
+/tests/dnstap/src/dnstap-test/go.sum
/tests/pytests/*/tcproxy
/tests/pytests/*/tlsproxy
/tests/pytests/pytests.*.html
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e8239a97..2395ebb0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,7 +17,13 @@ variables:
PREFIX: $CI_PROJECT_DIR/.local
EMAIL: 'ci@nic'
-image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11:knot-$KNOT_VERSION
+ # IMAGE_TAG is a Git branch/tag name from https://gitlab.nic.cz/knot/knot-resolver-ci
+ # In general, keep it pointing to a tag - use a branch only for development.
+ # More info in the knot-resolver-ci repository.
+ IMAGE_TAG: 'v20240604'
+ IMAGE_PREFIX: '$CI_REGISTRY/knot/knot-resolver-ci'
+
+image: $IMAGE_PREFIX/debian12-knot_3_3:$IMAGE_TAG
default:
interruptible: true
tags:
@@ -63,7 +69,7 @@ stages:
.after_build: &after_build
<<: *common
needs:
- - build
+ - build-stable
before_script:
# meson detects changes and performs useless rebuild; hide the log
- ninja -C build_ci* &>/dev/null
@@ -78,6 +84,12 @@ stages:
reports:
junit: build_ci*/meson-logs/integration.deckard.junit.xml
+.after_build_arch: &after_build_arch
+ <<: *after_build
+ image: $IMAGE_PREFIX/arch:$IMAGE_TAG
+ needs:
+ - build-arch
+
.nodep: &nodep
<<: *common
needs: []
@@ -94,6 +106,9 @@ stages:
- pkg
reports:
junit: build_ci*/meson-logs/testlog.junit.xml
+ before_script:
+ - "echo \"PATH: $PATH\""
+ - "echo \"Using Python at: $(which python)\""
after_script:
- ci/fix-meson-junit.sh build_ci*/meson-logs/testlog.junit.xml
@@ -103,38 +118,89 @@ archive:
script:
- apkg make-archive
-build:
+build-arch:
+ <<: *build
+ image: $IMAGE_PREFIX/arch:$IMAGE_TAG
+ script:
+ - meson build_ci_arch --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true
+ - ninja -C build_ci_arch
+ - ninja -C build_ci_arch install >/dev/null
+ - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake
+
+build-stable:
+ <<: *build
+ script:
+ - meson build_ci_stable --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
+ - ninja -C build_ci_stable
+ - ninja -C build_ci_stable install >/dev/null
+ - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake
+
+build-deb11-knot31:
<<: *build
+ image: $IMAGE_PREFIX/debian11-knot_3_1:$IMAGE_TAG
script:
- - meson build_ci --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
- - ninja -C build_ci
- - ninja -C build_ci install >/dev/null
+ - meson build_ci_deb11_knot31 --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
+ - ninja -C build_ci_deb11_knot31
+ - ninja -C build_ci_deb11_knot31 install >/dev/null
- ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake
-build-knot32:
+build-deb11-knot32:
<<: *build
- image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11:knot-3.2
+ image: $IMAGE_PREFIX/debian11-knot_3_2:$IMAGE_TAG
script:
- - meson build_ci_knot32 --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
- - ninja -C build_ci_knot32
- - ninja -C build_ci_knot32 install >/dev/null
+ - meson build_ci_deb11_knot32 --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
+ - ninja -C build_ci_deb11_knot32
+ - ninja -C build_ci_deb11_knot32 install >/dev/null
- ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake
-build-asan:
+build-deb12-knot32:
<<: *build
+ image: $IMAGE_PREFIX/debian12-knot_3_2:$IMAGE_TAG
script:
- # issues with UBSan and ASan in CI:
- # - `ahocorasick.so` causes C++ problems
- # - `--default-library=shared` causes link problems
- - CC=clang CXX=clang++ CFLAGS=-fno-sanitize-recover=all CXXFLAGS=-fno-sanitize=undefined meson build_ci_asan --default-library=static --prefix=$PREFIX -Dmalloc=jemalloc -Db_sanitize=address,undefined -Dextra_tests=enabled
- - ninja -C build_ci_asan
- - ninja -C build_ci_asan install >/dev/null
- # TODO _leaks: not sure what exactly is wrong in leak detection on config tests
- # TODO skip_asan: all three of these disappear locally when using gcc 9.1 (except some leaks)
- - MESON_TESTTHREADS=1 ASAN_OPTIONS=detect_leaks=0 ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite skip_asan --no-suite snowflake
+ - meson build_ci_deb12_knot32 --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
+ - ninja -C build_ci_deb12_knot32
+ - ninja -C build_ci_deb12_knot32 install >/dev/null
+ - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake
+
+build-deb12-knot-master:
+ <<: *build
+ image: $IMAGE_PREFIX/debian12-knot_master:$IMAGE_TAG
+ script:
+ - meson build_ci_deb12_knot_master --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
+ - ninja -C build_ci_deb12_knot_master
+ - ninja -C build_ci_deb12_knot_master install >/dev/null
+ - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake
+ allow_failure: true
+
+build-stable-asan-gcc:
+ <<: *build
+ script:
+ - CFLAGS=-fno-sanitize-recover=all meson build_ci_asan_gcc --prefix=$PREFIX -Dmalloc=jemalloc -Db_sanitize=address,undefined -Dextra_tests=enabled
+ - ninja -C build_ci_asan_gcc
+ - ninja -C build_ci_asan_gcc install >/dev/null
+ - MESON_TESTTHREADS=1 ${MESON_TEST} --suite unit --suite dnstap --no-suite skip_asan --no-suite snowflake
+ - MESON_TESTTHREADS=1 ASAN_OPTIONS=detect_leaks=0 ${MESON_TEST} --suite config --no-suite skip_asan --no-suite snowflake
+
+
+# TODO: Clang sanitizer seems to be broken in the current version of Debian. Use
+# GCC above and maybe re-enable the Clang one once we update at some point.
+
+#build-stable-asan-clang:
+# <<: *build
+# script:
+# # issues with UBSan and ASan in CI:
+# # - `ahocorasick.so` causes C++ problems
+# # - `--default-library=shared` causes link problems
+# - CC=clang CXX=clang++ CFLAGS=-fno-sanitize-recover=all CXXFLAGS=-fno-sanitize=undefined meson build_ci_asan_clang --default-library=static --prefix=$PREFIX -Dmalloc=jemalloc -Db_sanitize=address,undefined -Dextra_tests=enabled
+# - ninja -C build_ci_asan_clang
+# - ninja -C build_ci_asan_clang install >/dev/null
+# # TODO _leaks: not sure what exactly is wrong in leak detection on config tests
+# # TODO skip_asan: all three of these disappear locally when using gcc 9.1 (except some leaks)
+# - MESON_TESTTHREADS=1 ASAN_OPTIONS=detect_leaks=0 ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite skip_asan --no-suite snowflake
build:macOS:
<<: *nodep
+ image: python:3-alpine
only:
refs:
- branches@knot/knot-resolver
@@ -142,7 +208,8 @@ build:macOS:
when: delayed
start_in: 3 minutes # allow some time for mirroring, job creation
script:
- - ci/gh_actions.py ${CI_COMMIT_REF_NAME} ${CI_COMMIT_SHA}
+ - pip3 install -U requests
+ - python3 ./ci/gh_actions.py ${CI_COMMIT_REF_NAME} ${CI_COMMIT_SHA}
docker:
<<: *nodep
@@ -163,25 +230,6 @@ docker:
after_script: # remove dangling images to avoid running out of disk space
- docker rmi ${DOCKER_IMAGE_NAME}
- docker rmi $(docker images -f "dangling=true" -q)
-
-sonarcloud:
- <<: *nodep
- stage: build
- except: null
- only:
- - tags
- - master@knot/knot-resolver
- script:
- - meson build_sonarcloud --prefix=$PREFIX -Dmalloc=disabled
- - build-wrapper-linux-x86-64 --out-dir bw-output ninja -C build_sonarcloud
- - >
- sonar-scanner
- -Dsonar.organization=cz-nic
- -Dsonar.projectKey=CZ-NIC_knot-resolver
- -Dsonar.sources=.
- -Dsonar.cfamily.build-wrapper-output=bw-output
- -Dsonar.host.url=https://sonarcloud.io
- -Dsonar.projectVersion="$(git describe)"
# }}}
# sanity {{{
@@ -230,29 +278,8 @@ lint:pedantic:
-Wpedantic -Wno-newline-eof -Wno-gnu-zero-variadic-macro-arguments -Wno-gnu-folding-constant'
- ninja -C build_pedantic_clang
-lint:scan-build:
- <<: *after_build
- # TODO migrate lint to debian-11
- image: $CI_REGISTRY/knot/knot-resolver/ci/debian-buster:knot-$KNOT_VERSION
- before_script:
- # -- end TODO
- stage: sanity
- artifacts:
- when: on_failure
- expire_in: '1 day'
- paths:
- - build_ci*/meson-logs/scanbuild
- script:
- - export SCANBUILD="$(realpath ./scripts/run-scanbuild-with-args.sh)"
- - ninja -C build_ci* scan-build || true
- - test "$(ls build_ci*/meson-logs/scanbuild/*/report-*.html | wc -l)" = 23 # we have this many errors ATM :-)
-
lint:tidy:
- <<: *after_build
- # TODO migrate lint to debian-11
- image: $CI_REGISTRY/knot/knot-resolver/ci/debian-buster:knot-$KNOT_VERSION
- before_script:
- # -- end TODO
+ <<: *after_build_arch
stage: sanity
script:
- ninja -C build_ci* tidy
@@ -260,7 +287,7 @@ lint:tidy:
# Coverity reference: https://www.synopsys.com/blogs/software-security/integrating-coverity-scan-with-gitlab-ci/
lint:coverity:
<<: *sanity
- image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11-coverity:knot-$KNOT_VERSION
+ image: $IMAGE_PREFIX/coverity:$IMAGE_TAG
only:
refs:
- nightly@knot/knot-resolver
@@ -273,6 +300,7 @@ lint:coverity:
--form token=$COVERITY_SCAN_TOKEN --form email="knot-resolver@labs.nic.cz"
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
--form description="`git describe --tags` / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
+ --fail-with-body
.kres-gen: &kres-gen
<<: *sanity
@@ -281,15 +309,12 @@ lint:coverity:
- ninja -C build_ci_lib daemon/kresd
- ninja -C build_ci_lib kres-gen
- git diff --quiet || (git diff; exit 1)
-kres-gen-30:
- <<: *kres-gen
- image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11:knot-3.0
kres-gen-31:
<<: *kres-gen
- image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11:knot-3.1
+ image: $IMAGE_PREFIX/debian11-knot_3_1:$IMAGE_TAG
kres-gen-32:
<<: *kres-gen
- image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11:knot-3.2
+ image: $IMAGE_PREFIX/debian12-knot_3_2:$IMAGE_TAG
root.hints:
<<: *sanity
@@ -298,6 +323,21 @@ root.hints:
- /^release.*$/
script:
- scripts/update-root-hints.sh
+
+ci-image-is-tag:
+ <<: *sanity
+ image: alpine:3
+ variables:
+ GIT_STRATEGY: none
+ script:
+ - apk add git
+ - (
+ git ls-remote --tags --exit-code
+ https://gitlab.nic.cz/knot/knot-resolver-ci.git
+ refs/tags/$IMAGE_TAG
+ && echo "Everything is OK!"
+ )
+ || (echo "'$IMAGE_TAG' is not a tag (probably a branch). Make sure to set it to a tag in production!"; exit 2)
# }}}
# test {{{
@@ -328,7 +368,7 @@ respdiff:basic:
<<: *after_build
stage: test
needs:
- - build-asan
+ - build-stable-asan-gcc
script:
- ulimit -n "$(ulimit -Hn)" # applies only for kresd ATM
- ./ci/respdiff/start-resolvers.sh
@@ -381,7 +421,7 @@ manager:
pytests:
<<: *test_flaky
needs:
- - build-asan
+ - build-stable-asan-gcc
artifacts:
when: always
paths:
@@ -688,13 +728,10 @@ pkg:arch:
# docs: {{{
docs:build:
- image: $CI_REGISTRY/packaging/apkg/lxc/fedora-36
stage: deploy
needs: []
script:
- git submodule update --init --recursive
- - apkg build-dep -y
- - dnf install -y python3-sphinx texinfo doxygen
- pip3 install -U -r doc/requirements.txt
- pip3 install -U sphinx_rtd_theme
- meson build_doc -Ddoc=enabled
diff --git a/NEWS b/NEWS
index 9b3ed72a..b07e8d90 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Improvements
* predict module: prefetching expiring records moved to prefetch module
* prefetch module: new module to prefetch expiring records
+- stats: add separate metrics for IPv6 and IPv4 (!1545)
.. TODO: Change the link below to a versioned one when releasing.
@@ -25,6 +26,10 @@ Incompatible changes
<https://www.knot-resolver.cz/documentation/latest/config-cache-predict.html>`_
for more.
+Bugfixes
+--------
+- fix startup with `dnssec: false` (!1548)
+
Knot Resolver 6.0.7 (2024-03-27)
================================
@@ -100,6 +105,13 @@ https://www.knot-resolver.cz/documentation/latest/upgrading-to-6.html
5.x branch longterm support
~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Knot Resolver 5.7.3 (2024-0m-dd)
+================================
+
+Improvements
+------------
+- stats: add separate metrics for IPv6 and IPv4 (!1544)
+
Knot Resolver 5.7.2 (2024-03-27)
================================
diff --git a/ci/images/README.md b/ci/images/README.md
deleted file mode 100644
index 52e49faf..00000000
--- a/ci/images/README.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# Container images for CI
-
-## Image purpose
-
-### debian-11
-
-The main image used by shared runners to execute most CI builds and tests.
-
-### debian-11-coverity
-
-A stripped down version of `debian-11`. It only contains build (not test)
-dependencies of `kresd`. It also contains the `cov-build` tool for generating
-inputs for [Coverity Scan](https://scan.coverity.com/).
-
-It is used by the `coverity` CI job to generate and send data to Coverity Scan
-for analysis.
-
-To build this image, you need to retrieve the Coverity Scan token from the
-dashboard and pass it to the `build.sh` script using the `COVERITY_SCAN_TOKEN`
-environment variable, e.g.:
-
-```
-$ COVERITY_SCAN_TOKEN=the_secret_token ./build.sh debian-11-coverity
-```
-
-Sometimes, the Coverity Scan binaries need to be updated in order to maintain
-compatibility with the cloud service. Simply rebuild this image and push it to
-the registry to achieve this, no other changes (e.g. to the `Dockerfile`) are
-required.
-
-### debian-buster (10)
-
-Used to serve the same purpose as `debian-11`. As of 2022-03-09, it is still
-used by some jobs (linters).
-
-## Maintenance
-
-The `ci/images/` directory contains utility scripts to build, push or update
-the container images.
-
-```
-$ ./build.sh debian-11 # builds a debian-11 image locally
-$ ./push.sh debian-11 # pushes the local image into target registry
-$ ./update.sh debian-11 # utility wrapper that both builds and pushes the image
-$ ./update.sh */ # use shell expansion of dirnames to update all images
-```
-
-By default, a branch of Knot DNS deemed to be stable is selected according to
-the `vars.sh` file. To build an image for a different Knot DNS branch, set the
-`KNOT_BRANCH` environment variable to the name of the branch, e.g.:
-
-```
-$ KNOT_BRANCH='3.2' ./update.sh debian-11
-```
diff --git a/ci/images/build.sh b/ci/images/build.sh
deleted file mode 100755
index 1e9eabb5..00000000
--- a/ci/images/build.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# build specified docker image
-
-CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
-source "${CURRENT_DIR}"/vars.sh "$@"
-set -ex
-
-if [ -n "$COVERITY_SCAN_TOKEN" ]; then
- SECRETS="$SECRETS --secret id=coverity-token,env=COVERITY_SCAN_TOKEN"
-fi
-
-DOCKERFILE="$(realpath "${IMAGE}")/Dockerfile"
-
-cd "$CURRENT_DIR/../.."
-export DOCKER_BUILDKIT=1 # Enables using secrets in docker-build
-docker build \
- --pull \
- --no-cache \
- --tag "${FULL_NAME}" \
- --file "${DOCKERFILE}" \
- . \
- --build-arg KNOT_BRANCH=${KNOT_BRANCH} \
- $SECRETS
diff --git a/ci/images/debian-11-coverity/Dockerfile b/ci/images/debian-11-coverity/Dockerfile
deleted file mode 100644
index 19156145..00000000
--- a/ci/images/debian-11-coverity/Dockerfile
+++ /dev/null
@@ -1,43 +0,0 @@
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-FROM debian:bullseye
-MAINTAINER Knot Resolver <knot-resolver@labs.nic.cz>
-# >= 3.0 needed because of --enable-xdp=yes
-ARG KNOT_BRANCH=3.1
-ARG COVERITY_SCAN_PROJECT_NAME=CZ-NIC/knot-resolver
-ENV DEBIAN_FRONTEND=noninteractive
-
-WORKDIR /root
-CMD ["/bin/bash"]
-
-# generic cleanup
-RUN apt-get update -qq
-
-# Knot and Knot Resolver dependencies
-RUN apt-get install -y -qqq git make cmake pkg-config meson \
- build-essential bsdmainutils libtool autoconf libcmocka-dev \
- liburcu-dev libgnutls28-dev libedit-dev liblmdb-dev libcap-ng-dev libsystemd-dev \
- libelf-dev libmnl-dev libidn11-dev libuv1-dev \
- libluajit-5.1-dev lua-http libssl-dev libnghttp2-dev
-
-# LuaJIT binary for stand-alone scripting
-RUN apt-get install -y -qqq luajit
-
-# build and install latest version of Knot DNS
-RUN git clone --depth=1 --branch=$KNOT_BRANCH https://gitlab.nic.cz/knot/knot-dns.git /tmp/knot
-WORKDIR /tmp/knot
-RUN pwd
-RUN autoreconf -if
-RUN ./configure --prefix=/usr --enable-xdp=yes
-RUN CFLAGS="-g" make
-RUN make install
-RUN ldconfig
-
-# curl and tar (for downloading Coverity tools and uploading logs)
-RUN apt-get install -y curl tar
-
-RUN --mount=type=secret,id=coverity-token \
- curl -o /tmp/cov-analysis-linux64.tar.gz https://scan.coverity.com/download/cxx/linux64 \
- --form project=$COVERITY_SCAN_PROJECT_NAME --form token=$(cat /run/secrets/coverity-token)
-RUN tar xfz /tmp/cov-analysis-linux64.tar.gz
-RUN mv cov-analysis-linux64-* /opt/cov-analysis
diff --git a/ci/images/debian-11/Dockerfile b/ci/images/debian-11/Dockerfile
deleted file mode 100644
index 0241a6d4..00000000
--- a/ci/images/debian-11/Dockerfile
+++ /dev/null
@@ -1,146 +0,0 @@
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-FROM debian:bullseye
-MAINTAINER Knot Resolver <knot-resolver@labs.nic.cz>
-# >= 3.0 needed because of --enable-xdp=yes
-ARG KNOT_BRANCH=3.1
-ENV DEBIAN_FRONTEND=noninteractive
-
-WORKDIR /root
-CMD ["/bin/bash"]
-
-# generic cleanup
-RUN apt-get update -qq
-
-# Knot and Knot Resolver dependencies
-RUN apt-get install -y -qqq git make cmake pkg-config meson \
- build-essential bsdmainutils libtool autoconf libcmocka-dev \
- liburcu-dev libgnutls28-dev libedit-dev liblmdb-dev libcap-ng-dev libsystemd-dev \
- libelf-dev libmnl-dev libidn11-dev libuv1-dev libjemalloc-dev \
- libluajit-5.1-dev lua-http libssl-dev libnghttp2-dev
-
-# Build and testing deps for Resolver's dnstap module (go stuff is just for testing)
-RUN apt-get install -y -qqq \
- protobuf-c-compiler libprotobuf-c-dev libfstrm-dev \
- golang-any
-COPY ./tests/dnstap /root/tests/dnstap
-WORKDIR /root/tests/dnstap/src/dnstap-test
-RUN go get .
-WORKDIR /root
-
-# documentation dependencies
-RUN apt-get install -y -qqq doxygen python3-sphinx python3-breathe python3-sphinx-rtd-theme
-
-# Python packages required for Deckard CI
-# Python: grab latest versions from PyPi
-# (Augeas binding in Debian packages are slow and buggy)
-RUN apt-get install -y -qqq python3-pip wget augeas-tools
-RUN pip3 install --upgrade pip
-RUN pip3 install pylint
-RUN pip3 install pep8
-# FIXME replace with dnspython >= 2.2.0 once released
-RUN pip3 install git+https://github.com/bwelling/dnspython.git@72348d4698a8f8b209fbdf9e72738904ad31b930
-# tests/pytest dependencies: skip over broken versions
-RUN pip3 install jinja2 'pytest != 6.0.0' pytest-html pytest-xdist pytest-forked
-# apkg for packaging
-RUN pip3 install apkg
-
-# packet capture tools for Deckard
-RUN apt-get install --no-install-suggests --no-install-recommends -y -qqq tcpdump wireshark-common
-
-# Faketime for Deckard
-RUN apt-get install -y -qqq faketime
-
-# C dependencies for python-augeas
-RUN apt-get install -y -qqq libaugeas-dev libffi-dev
-# Python dependencies for Deckard
-RUN wget https://gitlab.nic.cz/knot/deckard/raw/master/requirements.txt -O /tmp/deckard-req.txt
-RUN pip3 install -r /tmp/deckard-req.txt
-
-# build and install latest version of Knot DNS
-RUN git clone --depth=1 --branch=$KNOT_BRANCH https://gitlab.nic.cz/knot/knot-dns.git /tmp/knot
-WORKDIR /tmp/knot
-RUN pwd
-RUN autoreconf -if
-RUN ./configure --prefix=/usr --enable-xdp=yes
-RUN CFLAGS="-g" make
-RUN make install
-RUN ldconfig
-
-# Valgrind for kresd CI
-RUN apt-get install valgrind -y -qqq
-RUN wget https://github.com/LuaJIT/LuaJIT/raw/v2.1.0-beta3/src/lj.supp -O /lj.supp
-# TODO: rebuild LuaJIT with Valgrind support
-
-# Lua lint for kresd CI
-RUN apt-get install luarocks -y -qqq
-RUN luarocks --lua-version 5.1 install luacheck
-
-# respdiff for kresd CI
-RUN apt-get install lmdb-utils -y -qqq
-RUN git clone --depth=1 https://gitlab.nic.cz/knot/respdiff /var/opt/respdiff
-RUN pip3 install -r /var/opt/respdiff/requirements.txt
-
-# Python static analysis for respdiff
-RUN pip3 install mypy
-RUN pip3 install flake8
-
-# Python requests for CI scripts
-RUN pip3 install requests
-
-# docker-py for packaging tests
-RUN pip3 install docker
-
-# Unbound for respdiff
-RUN apt-get install unbound unbound-anchor -y -qqq
-RUN printf "server:\n interface: 127.0.0.1@53535\n use-syslog: yes\n do-ip6: no\nremote-control:\n control-enable: no\n" >> /etc/unbound/unbound.conf
-
-# BIND for respdiff
-RUN apt-get install bind9 -y -qqq
-RUN printf '\nOPTIONS="-4 $OPTIONS"' >> /etc/default/bind9
-RUN printf 'options {\n directory "/var/cache/bind";\n listen-on port 53533 { 127.0.0.1; };\n listen-on-v6 port 53533 { ::1; };\n};\n' > /etc/bind/named.conf.options
-
-# PowerDNS Recursor for Deckard CI
-RUN apt-get install pdns-recursor -y -qqq
-
-# dnsdist for Deckard CI
-RUN apt-get install dnsdist -y -qqq
-
-# code coverage
-RUN apt-get install -y -qqq lcov
-RUN luarocks --lua-version 5.1 install luacov
-
-# LuaJIT binary for stand-alone scripting
-RUN apt-get install -y -qqq luajit
-
-# clang for kresd CI, version updated as debian updates it
-RUN apt-get install -y -qqq clang clang-tools clang-tidy
-
-# OpenBuildService CLI tool
-RUN apt-get install -y osc
-
-# curl (API)
-RUN apt-get install -y curl
-
-# configure knot-resolver-testing OBS repo for dependencies missing in Debian
-RUN echo 'deb http://download.opensuse.org/repositories/home:/CZ-NIC:/knot-resolver-testing/Debian_11/ /' > /etc/apt/sources.list.d/knot-resolver-testing.list
-RUN wget -nv https://download.opensuse.org/repositories/home:CZ-NIC:knot-resolver-testing/Debian_11/Release.key -O Release.key
-RUN APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add Release.key
-RUN rm Release.key
-RUN apt-get update -qq
-
-# packages from our knot-resolver-testing repo
-RUN apt-get update
-RUN apt-get install -y -qqq lua-psl
-
-# en_US.UTF-8 locale for scripts.update-authors.sh
-RUN apt-get install -y -qqq locales
-RUN sed -i "/en_US.UTF-8/ s/^#\(.*\)/\1/" /etc/locale.gen
-RUN locale-gen
-
-# SonarCloud scanner
-RUN wget -O /var/opt/wrapper.zip https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip
-RUN wget -O /var/opt/scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip
-RUN unzip -d /var/opt /var/opt/wrapper.zip
-RUN unzip -d /var/opt /var/opt/scanner.zip
-ENV PATH "$PATH:/var/opt/build-wrapper-linux-x86:/var/opt/sonar-scanner-5.0.1.3006-linux/bin"
diff --git a/ci/images/debian-buster/Dockerfile b/ci/images/debian-buster/Dockerfile
deleted file mode 100644
index 39f43277..00000000
--- a/ci/images/debian-buster/Dockerfile
+++ /dev/null
@@ -1,146 +0,0 @@
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-FROM debian:buster
-MAINTAINER Knot Resolver <knot-resolver@labs.nic.cz>
-# >= 3.0 needed because of --enable-xdp=yes
-ARG KNOT_BRANCH=3.0
-ENV DEBIAN_FRONTEND=noninteractive
-
-WORKDIR /root
-CMD ["/bin/bash"]
-
-# generic cleanup
-RUN apt-get update -qq
-# TODO: run upgrade once buster reaches a stable release
-# RUN apt-get upgrade -y -qqq
-
-# Knot and Knot Resolver dependencies
-RUN apt-get install -y -qqq git make cmake pkg-config meson \
- build-essential bsdmainutils libtool autoconf libcmocka-dev \
- liburcu-dev libgnutls28-dev libedit-dev liblmdb-dev libcap-ng-dev libsystemd-dev \
- libelf-dev libmnl-dev libidn11-dev libuv1-dev \
- libluajit-5.1-dev lua-http libssl-dev libnghttp2-dev
-
-# Build and testing deps for Resolver's dnstap module (go stuff is just for testing)
-RUN apt-get install -y -qqq \
- protobuf-c-compiler libprotobuf-c-dev libfstrm-dev \
- golang-any
-COPY ./tests/dnstap /root/tests/dnstap
-WORKDIR /root/tests/dnstap/src/dnstap-test
-RUN go get .
-WORKDIR /root
-
-# documentation dependencies
-RUN apt-get install -y -qqq doxygen python3-sphinx python3-breathe python3-sphinx-rtd-theme
-
-# Python packages required for Deckard CI
-# Python: grab latest versions from PyPi
-# (Augeas binding in Debian packages are slow and buggy)
-RUN apt-get install -y -qqq python3-pip wget augeas-tools
-RUN pip3 install --upgrade pip
-RUN pip3 install pylint
-RUN pip3 install pep8
-RUN pip3 install pytest-xdist
-# tests/pytest dependencies: skip over broken versions
-RUN pip3 install 'dnspython != 2.0.0' 'jinja2 == 2.11.3' 'pytest != 6.0.0' pytest-html pytest-xdist
-
-# packet capture tools for Deckard
-RUN apt-get install --no-install-suggests --no-install-recommends -y -qqq tcpdump wireshark-common
-
-# Faketime for Deckard
-RUN apt-get install -y -qqq faketime
-
-# C dependencies for python-augeas
-RUN apt-get install -y -qqq libaugeas-dev libffi-dev
-# Python dependencies for Deckard
-RUN wget https://gitlab.nic.cz/knot/deckard/raw/master/requirements.txt -O /tmp/deckard-req.txt
-RUN pip3 install -r /tmp/deckard-req.txt
-
-# build and install latest version of Knot DNS
-RUN git clone --depth=1 --branch=$KNOT_BRANCH https://gitlab.nic.cz/knot/knot-dns.git /tmp/knot
-WORKDIR /tmp/knot
-RUN pwd
-RUN autoreconf -if
-RUN ./configure --prefix=/usr --enable-xdp=yes
-RUN CFLAGS="-g" make
-RUN make install
-RUN ldconfig
-
-# Valgrind for kresd CI
-RUN apt-get install valgrind -y -qqq
-RUN wget https://github.com/LuaJIT/LuaJIT/raw/v2.1.0-beta3/src/lj.supp -O /lj.supp
-# TODO: rebuild LuaJIT with Valgrind support
-
-# Lua lint for kresd CI
-RUN apt-get install luarocks -y -qqq
-RUN luarocks --lua-version 5.1 install luacheck
-
-# respdiff for kresd CI
-RUN apt-get install lmdb-utils -y -qqq
-RUN git clone --depth=1 https://gitlab.nic.cz/knot/respdiff /var/opt/respdiff
-RUN pip3 install -r /var/opt/respdiff/requirements.txt
-
-# Python static analysis for respdiff
-RUN pip3 install mypy
-RUN pip3 install flake8
-
-# Python requests for CI scripts
-RUN pip3 install requests
-
-# docker-py for packaging tests
-RUN pip3 install docker
-
-# Unbound for respdiff
-RUN apt-get install unbound unbound-anchor -y -qqq
-RUN printf "server:\n interface: 127.0.0.1@53535\n use-syslog: yes\n do-ip6: no\nremote-control:\n control-enable: no\n" >> /etc/unbound/unbound.conf
-
-# BIND for respdiff
-RUN apt-get install bind9 -y -qqq
-RUN printf '\nOPTIONS="-4 $OPTIONS"' >> /etc/default/bind9
-RUN printf 'options {\n directory "/var/cache/bind";\n listen-on port 53533 { 127.0.0.1; };\n listen-on-v6 port 53533 { ::1; };\n};\n' > /etc/bind/named.conf.options
-
-# PowerDNS Recursor for Deckard CI
-RUN apt-get install pdns-recursor -y -qqq
-
-# code coverage
-RUN apt-get install -y -qqq lcov
-RUN luarocks --lua-version 5.1 install luacov
-
-# LuaJIT binary for stand-alone scripting
-RUN apt-get install -y -qqq luajit
-
-# clang for kresd CI, version updated as debian updates it
-RUN apt-get install -y -qqq clang clang-tools clang-tidy
-
-# OpenBuildService CLI tool
-RUN apt-get install -y osc
-
-# curl (API)
-RUN apt-get install -y curl
-
-# configure knot-resolver-testing OBS repo for dependencies missing in Debian
-RUN echo 'deb http://download.opensuse.org/repositories/home:/CZ-NIC:/knot-resolver-testing/Debian_10/ /' > /etc/apt/sources.list.d/knot-resolver-testing.list
-RUN wget -nv https://download.opensuse.org/repositories/home:CZ-NIC:knot-resolver-testing/Debian_10/Release.key -O Release.key
-RUN APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add Release.key
-RUN rm Release.key
-RUN apt-get update -qq
-
-# packages from our knot-resolver-testing repo
-RUN apt-get install -y -qqq lua-http lua-psl
-
-# en_US.UTF-8 locale for scripts.update-authors.sh
-RUN apt-get install -y -qqq locales
-RUN sed -i "/en_US.UTF-8/ s/^#\(.*\)/\1/" /etc/locale.gen
-RUN locale-gen
-
-# SonarCloud scanner
-RUN wget -O /var/opt/wrapper.zip https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip
-RUN wget -O /var/opt/scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.4.0.2170-linux.zip
-RUN unzip -d /var/opt /var/opt/wrapper.zip
-RUN unzip -d /var/opt /var/opt/scanner.zip
-ENV PATH "$PATH:/var/opt/build-wrapper-linux-x86:/var/opt/sonar-scanner-4.4.0.2170-linux/bin"
-
-# let's get newer meson from backports
-RUN echo 'deb http://deb.debian.org/debian buster-backports main' > /etc/apt/sources.list.d/backports.list
-RUN apt-get update -qq
-RUN apt-get -t buster-backports install -y -qqq meson
diff --git a/ci/images/push.sh b/ci/images/push.sh
deleted file mode 100755
index 75f5f878..00000000
--- a/ci/images/push.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-# upload docker image into registry
-
-CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
-source "${CURRENT_DIR}"/vars.sh "$@"
-set -ex
-
-docker push "${FULL_NAME}"
diff --git a/ci/images/update.sh b/ci/images/update.sh
deleted file mode 100755
index 7be51727..00000000
--- a/ci/images/update.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-# build and upload docker image(s) into registry
-#
-# this is a simple wrapper around build.sh and update.sh
-#
-# to build & upload all images: ./update.sh */
-
-if [[ $# -le 0 ]]; then
- echo "usage: $0 IMAGE..."
- exit 1
-fi
-set -e
-
-for ARG in "$@"
-do
- IMAGE=${ARG%/}
- echo "Building $IMAGE..."
- ./build.sh $IMAGE
- echo "Pushing $IMAGE..."
- ./push.sh $IMAGE
-done
-
diff --git a/ci/images/vars.sh b/ci/images/vars.sh
deleted file mode 100755
index f2ea4655..00000000
--- a/ci/images/vars.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-# define common variables for image build scripts
-
-KNOT_BRANCH="${KNOT_BRANCH:-3.1}"
-
-REGISTRY="registry.nic.cz/knot/knot-resolver/ci"
-IMAGE=$1
-if [ -z "${IMAGE}" ]; then
- echo "image name not provided"
- exit 1
-fi
-TAG="knot-${KNOT_BRANCH}"
-FULL_NAME="${REGISTRY}/${IMAGE}:${TAG}"
diff --git a/ci/pkgtest.yaml b/ci/pkgtest.yaml
index b7b87c35..2ac4d4cf 100644
--- a/ci/pkgtest.yaml
+++ b/ci/pkgtest.yaml
@@ -119,7 +119,8 @@ nixos-unstable:pkgbuild:
- docker
- linux
- ${PLATFORM}
- image: nixos/nix
+ # https://github.com/NixOS/nix/issues/10648#issuecomment-2101993746
+ image: docker.io/nixos/nix:latest-${PLATFORM}
variables:
NIX_PATH: nixpkgs=https://github.com/nixos/nixpkgs/archive/nixos-unstable.tar.gz
diff --git a/contrib/dynarray.h b/contrib/dynarray.h
deleted file mode 100644
index 7cbb686b..00000000
--- a/contrib/dynarray.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Copyright (C) CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-/*!
- * \brief Simple write-once allocation-optimal dynamic array.
- *
- * Include it into your .c file
- *
- * prefix - identifier prefix, e.g. ptr -> struct ptr_dynarray, ptr_dynarray_add(), ...
- * ntype - data type to be stored. Let it be a number, pointer or small struct
- * initial_capacity - how many data items will be allocated on stack and copied with assignment
- *
- * prefix_dynarray_add() - add a data item
- * prefix_dynarray_fix() - call EVERYTIME the array is copied from some already invalid stack
- * prefix_dynarray_free() - call EVERYTIME you dismiss all copies of the array
- *
- */
-
-#include <stdlib.h>
-#include <assert.h>
-
-#pragma once
-
-#define DYNARRAY_VISIBILITY_STATIC static
-#define DYNARRAY_VISIBILITY_PUBLIC
-#define DYNARRAY_VISIBILITY_LIBRARY __public__
-
-#define dynarray_declare(prefix, ntype, visibility, initial_capacity) \
- typedef struct prefix ## _dynarray { \
- ssize_t capacity; \
- ssize_t size; \
- ntype *(*arr)(struct prefix ## _dynarray *dynarray); \
- ntype init[initial_capacity]; \
- ntype *_arr; \
- } prefix ## _dynarray_t; \
- \
- visibility ntype *prefix ## _dynarray_arr(prefix ## _dynarray_t *dynarray); \
- visibility void prefix ## _dynarray_add(prefix ## _dynarray_t *dynarray, \
- ntype const *to_add); \
- visibility void prefix ## _dynarray_free(prefix ## _dynarray_t *dynarray);
-
-#define dynarray_foreach(prefix, ntype, ptr, array) \
- for (ntype *ptr = prefix ## _dynarray_arr(&(array)); \
- ptr < prefix ## _dynarray_arr(&(array)) + (array).size; ptr++)
-
-#define dynarray_define(prefix, ntype, visibility) \
- \
- static void prefix ## _dynarray_free__(struct prefix ## _dynarray *dynarray) \
- { \
- if (dynarray->capacity > sizeof(dynarray->init) / sizeof(*dynarray->init)) { \
- free(dynarray->_arr); \
- } \
- } \
- \
- __attribute__((unused)) \
- visibility ntype *prefix ## _dynarray_arr(struct prefix ## _dynarray *dynarray) \
- { \
- assert(dynarray->size <= dynarray->capacity); \
- return (dynarray->capacity <= sizeof(dynarray->init) / sizeof(*dynarray->init) ? \
- dynarray->init : dynarray->_arr); \
- } \
- \
- static ntype *prefix ## _dynarray_arr_init__(struct prefix ## _dynarray *dynarray) \
- { \
- assert(dynarray->capacity == sizeof(dynarray->init) / sizeof(*dynarray->init)); \
- return dynarray->init; \
- } \
- \
- static ntype *prefix ## _dynarray_arr_arr__(struct prefix ## _dynarray *dynarray) \
- { \
- assert(dynarray->capacity > sizeof(dynarray->init) / sizeof(*dynarray->init)); \
- return dynarray->_arr; \
- } \
- \
- __attribute__((unused)) \
- visibility void prefix ## _dynarray_add(struct prefix ## _dynarray *dynarray, \
- ntype const *to_add) \
- { \
- if (dynarray->capacity < 0) { \
- return; \
- } \
- if (dynarray->capacity == 0) { \
- dynarray->capacity = sizeof(dynarray->init) / sizeof(*dynarray->init); \
- dynarray->arr = prefix ## _dynarray_arr_init__; \
- } \
- if (dynarray->size >= dynarray->capacity) { \
- ssize_t new_capacity = dynarray->capacity * 2 + 1; \
- ntype *new_arr = calloc(new_capacity, sizeof(ntype)); \
- if (new_arr == NULL) { \
- prefix ## _dynarray_free__(dynarray); \
- dynarray->capacity = dynarray->size = -1; \
- return; \
- } \
- if (dynarray->capacity > 0) { \
- memcpy(new_arr, prefix ## _dynarray_arr(dynarray), \
- dynarray->capacity * sizeof(ntype)); \
- } \
- prefix ## _dynarray_free__(dynarray); \
- dynarray->_arr = new_arr; \
- dynarray->capacity = new_capacity; \
- dynarray->arr = prefix ## _dynarray_arr_arr__; \
- } \
- prefix ## _dynarray_arr(dynarray)[dynarray->size++] = *to_add; \
- } \
- \
- __attribute__((unused)) \
- visibility void prefix ## _dynarray_free(struct prefix ## _dynarray *dynarray) \
- { \
- prefix ## _dynarray_free__(dynarray); \
- memset(dynarray, 0, sizeof(*dynarray)); \
- }
diff --git a/contrib/dynarray.spdx b/contrib/dynarray.spdx
deleted file mode 100644
index 02911c9c..00000000
--- a/contrib/dynarray.spdx
+++ /dev/null
@@ -1,10 +0,0 @@
-SPDXVersion: SPDX-2.1
-DataLicense: CC0-1.0
-SPDXID: SPDXRef-DOCUMENT
-DocumentName: knotdns-dynarray
-DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-ce6423dd-ac6a-4e78-90c3-5cbdef1e252c
-
-PackageName: knotdns-dynarray
-PackageDownloadLocation: git+https://gitlab.nic.cz/knot/knot-dns.git@48c8b4f38cf5f7bf505c79b56adf7580688f6d3d#src/contrib/dynarray.h
-PackageOriginator: Organization: Knot DNS contributors
-PackageLicenseDeclared: GPL-3.0-or-later
diff --git a/daemon/bindings/event.c b/daemon/bindings/event.c
index 686e33e9..7e14dcd6 100644
--- a/daemon/bindings/event.c
+++ b/daemon/bindings/event.c
@@ -59,12 +59,12 @@ static int event_sched(lua_State *L, unsigned timeout, unsigned repeat)
/* Start timer with the reference */
uv_loop_t *loop = uv_default_loop();
- uv_timer_init(loop, timer);
- int ret = uv_timer_start(timer, event_callback, timeout, repeat);
- if (ret != 0) {
- free(timer);
- lua_error_p(L, "couldn't start the event");
- }
+ int ret = uv_timer_init(loop, timer);
+ if (ret != 0)
+ goto exit_err;
+ ret = uv_timer_start(timer, event_callback, timeout, repeat);
+ if (ret != 0)
+ goto exit_err;
/* Save callback and timer in registry */
lua_newtable(L);
@@ -78,6 +78,10 @@ static int event_sched(lua_State *L, unsigned timeout, unsigned repeat)
timer->data = (void *) (intptr_t)ref;
lua_pushinteger(L, ref);
return 1;
+
+exit_err:
+ free(timer);
+ lua_error_p(L, "couldn't start the event");
}
static int event_after(lua_State *L)
diff --git a/daemon/bindings/net.c b/daemon/bindings/net.c
index d278ed17..aaeef238 100644
--- a/daemon/bindings/net.c
+++ b/daemon/bindings/net.c
@@ -468,7 +468,7 @@ static int net_interfaces(lua_State *L)
/* Hardware address. */
char *p = buf;
for (int k = 0; k < sizeof(iface.phys_addr); ++k) {
- sprintf(p, "%.2x:", (uint8_t)iface.phys_addr[k]);
+ (void)sprintf(p, "%.2x:", (uint8_t)iface.phys_addr[k]);
p += 3;
}
p[-1] = '\0';
@@ -788,7 +788,7 @@ static int net_tls_client(lua_State *L)
/* Sort the strings for easier comparison later. */
if (newcfg->ca_files.len) {
qsort(&newcfg->ca_files.at[0], newcfg->ca_files.len,
- sizeof(newcfg->ca_files.at[0]), strcmp_p);
+ array_member_size(newcfg->ca_files), strcmp_p);
}
}
lua_pop(L, 1);
@@ -828,7 +828,7 @@ static int net_tls_client(lua_State *L)
/* Sort the raw strings for easier comparison later. */
if (newcfg->pins.len) {
qsort(&newcfg->pins.at[0], newcfg->pins.len,
- sizeof(newcfg->pins.at[0]), cmp_sha256);
+ array_member_size(newcfg->pins), cmp_sha256);
}
}
lua_pop(L, 1);
@@ -1031,7 +1031,11 @@ static int net_tls_sticket_secret_file(lua_State *L)
STR(net_tls_sticket_MIN_SECRET_LEN) " bytes",
file_name);
}
- fclose(fp);
+ if (fclose(fp) == EOF) {
+ lua_error_p(L,
+ "net.tls_sticket_secret_file - reading of file '%s' failed",
+ file_name);
+ }
tls_session_ticket_ctx_destroy(the_network->tls_session_ticket_ctx);
the_network->tls_session_ticket_ctx =
diff --git a/daemon/engine.c b/daemon/engine.c
index 275718ee..509915df 100644
--- a/daemon/engine.c
+++ b/daemon/engine.c
@@ -29,8 +29,6 @@
#include "lib/dnssec/ta.h"
#include "lib/log.h"
-/* Cleanup engine state every 5 minutes */
-const size_t CLEANUP_TIMER = 5*60*1000;
/* Execute byte code */
#define l_dobytecode(L, arr, len, name) \
@@ -544,7 +542,7 @@ int init_lua(void) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat" /* %1$ is not in C standard */
/* Save original package.path to package._path */
- snprintf(l_paths, MAXPATHLEN - 1,
+ (void)snprintf(l_paths, MAXPATHLEN - 1,
"if package._path == nil then package._path = package.path end\n"
"package.path = '%1$s/?.lua;%1$s/?/init.lua;'..package._path\n"
"if package._cpath == nil then package._cpath = package.cpath end\n"
diff --git a/daemon/http.c b/daemon/http.c
index 7d1f0899..61ebcf9e 100644
--- a/daemon/http.c
+++ b/daemon/http.c
@@ -298,7 +298,7 @@ static int http_send_response(struct pl_http_sess_data *http, int32_t stream_id,
max_age_len = asprintf(&max_age, "%s%" PRIu32, directive_max_age, ctx->payload.ttl);
kr_require(max_age_len >= 0);
- /* TODO: add a per-protolayer_grp option for content-type if we
+ /* TODO: add a per-kr_proto option for content-type if we
* need to support protocols other than DNS here */
push_nv(&hdrs, MAKE_STATIC_NV("content-type", "application/dns-message"));
push_nv(&hdrs, MAKE_STATIC_KEY_NV("content-length", size, size_len));
@@ -389,9 +389,9 @@ static ssize_t send_callback(nghttp2_session *h2, const uint8_t *data, size_t le
memcpy(send_ctx->data, data, length);
kr_log_debug(DOH, "[%p] send_callback: %p\n", (void *)h2, (void *)send_ctx->data);
- session2_wrap_after(http->h.session, PROTOLAYER_PROTOCOL_HTTP,
- protolayer_buffer(send_ctx->data, length, false), NULL,
- callback_finished_free_baton, send_ctx);
+ session2_wrap_after(http->h.session, PROTOLAYER_TYPE_HTTP,
+ protolayer_payload_buffer(send_ctx->data, length, false),
+ NULL, callback_finished_free_baton, send_ctx);
return length;
}
@@ -505,8 +505,8 @@ static int send_data_callback(nghttp2_session *h2, nghttp2_frame *frame, const u
dest_iov[cur++] = (struct iovec){ (void *)padding, padlen - 1 };
kr_assert(cur == iovcnt);
- int ret = session2_wrap_after(http->h.session, PROTOLAYER_PROTOCOL_HTTP,
- protolayer_iovec(dest_iov, cur, false),
+ int ret = session2_wrap_after(http->h.session, PROTOLAYER_TYPE_HTTP,
+ protolayer_payload_iovec(dest_iov, cur, false),
NULL, callback_finished_free_baton, sdctx);
if (ret < 0)
@@ -732,8 +732,9 @@ static int submit_to_wirebuffer(struct pl_http_sess_data *ctx)
}
ret = 0;
- session2_unwrap_after(ctx->h.session, PROTOLAYER_PROTOCOL_HTTP,
- protolayer_wire_buf(wb, false), NULL, NULL, NULL);
+ session2_unwrap_after(ctx->h.session, PROTOLAYER_TYPE_HTTP,
+ protolayer_payload_wire_buf(wb, false),
+ NULL, NULL, NULL);
cleanup:
http_cleanup_stream(ctx);
return ret;
@@ -835,7 +836,7 @@ static ssize_t read_callback(nghttp2_session *h2, int32_t stream_id, uint8_t *bu
return send;
}
-static int pl_http_sess_init(struct protolayer_manager *manager,
+static int pl_http_sess_init(struct session2 *session,
void *data, void *param)
{
struct pl_http_sess_data *http = data;
@@ -867,17 +868,17 @@ static int pl_http_sess_init(struct protolayer_manager *manager,
http->current_method = HTTP_METHOD_NONE;
http->uri_path = NULL;
http->status = HTTP_STATUS_OK;
- wire_buf_init(&http->wire_buf, manager->wire_buf.size);
+ wire_buf_init(&http->wire_buf, session->wire_buf.size);
ret = nghttp2_session_server_new(&http->h2, callbacks, http);
if (ret < 0)
goto exit_callbacks;
nghttp2_submit_settings(http->h2, NGHTTP2_FLAG_NONE, iv, ARRAY_SIZE(iv));
- struct sockaddr *peer = session2_get_peer(manager->session);
+ struct sockaddr *peer = session2_get_peer(session);
kr_log_debug(DOH, "[%p] h2 session created for %s\n", (void *)http->h2, kr_straddr(peer));
- manager->session->custom_emalf_handling = true;
+ session->custom_emalf_handling = true;
ret = kr_ok();
@@ -902,8 +903,7 @@ static int stream_write_data_break_err(trie_val_t *val, void *baton)
return 0;
}
-static int pl_http_sess_deinit(struct protolayer_manager *manager,
- void *data)
+static int pl_http_sess_deinit(struct session2 *session, void *data)
{
struct pl_http_sess_data *http = data;
@@ -938,7 +938,7 @@ static enum protolayer_iter_cb_result pl_http_unwrap(
struct protolayer_payload pld = ctx->payload;
if (pld.type == PROTOLAYER_PAYLOAD_WIRE_BUF) {
- pld = protolayer_as_buffer(&pld);
+ pld = protolayer_payload_as_buffer(&pld);
}
if (pld.type == PROTOLAYER_PAYLOAD_BUFFER) {
@@ -969,7 +969,7 @@ static enum protolayer_iter_cb_result pl_http_unwrap(
if (ret < 0) {
kr_log_debug(DOH, "[%p] nghttp2_session_send failed: %s (%zd)\n",
(void *)http->h2, nghttp2_strerror(ret), ret);
- return kr_error(EIO);
+ return protolayer_break(ctx, kr_error(EIO));
}
if (!http_status_has_category(http->status, 2)) {
@@ -1001,7 +1001,7 @@ static enum protolayer_iter_cb_result pl_http_wrap(
static enum protolayer_event_cb_result pl_http_event_unwrap(
enum protolayer_event_type event, void **baton,
- struct protolayer_manager *manager, void *sess_data)
+ struct session2 *session, void *sess_data)
{
struct pl_http_sess_data *http = sess_data;
@@ -1013,7 +1013,7 @@ static enum protolayer_event_cb_result pl_http_event_unwrap(
return PROTOLAYER_EVENT_PROPAGATE;
}
-static void pl_http_request_init(struct protolayer_manager *manager,
+static void pl_http_request_init(struct session2 *session,
struct kr_request *req,
void *sess_data)
{
@@ -1032,7 +1032,7 @@ static void pl_http_request_init(struct protolayer_manager *manager,
void http_protolayers_init(void)
{
- protolayer_globals[PROTOLAYER_PROTOCOL_HTTP] = (struct protolayer_globals) {
+ protolayer_globals[PROTOLAYER_TYPE_HTTP] = (struct protolayer_globals) {
.sess_size = sizeof(struct pl_http_sess_data),
.sess_deinit = pl_http_sess_deinit,
.wire_buf_overhead = HTTP_MAX_FRAME_SIZE,
diff --git a/daemon/io.c b/daemon/io.c
index ea98a7f0..b6b289ae 100644
--- a/daemon/io.c
+++ b/daemon/io.c
@@ -17,7 +17,6 @@
#endif
#include "daemon/network.h"
-#include "daemon/proxyv2.h"
#include "daemon/worker.h"
#include "daemon/tls.h"
#include "daemon/http.h"
@@ -40,7 +39,7 @@ static void check_bufsize(uv_handle_t* handle)
* This is magic presuming we can pull in a whole recvmmsg width in one wave.
* Linux will double this the bufsize wanted.
*/
- const int BUF_SIZE = 2 * sizeof(RECVMMSG_BATCH * KNOT_WIRE_MAX_PKTSIZE);
+ const int BUF_SIZE = 2 * RECVMMSG_BATCH * KNOT_WIRE_MAX_PKTSIZE;
negotiate_bufsize(uv_recv_buffer_size, handle, BUF_SIZE);
negotiate_bufsize(uv_send_buffer_size, handle, BUF_SIZE);
}
@@ -50,7 +49,7 @@ static void check_bufsize(uv_handle_t* handle)
static void handle_getbuf(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
struct session2 *s = handle->data;
- struct wire_buf *wb = &s->layers->wire_buf;
+ struct wire_buf *wb = &s->wire_buf;
buf->base = wire_buf_free_space(wb);
buf->len = wire_buf_free_space_length(wb);
@@ -59,7 +58,7 @@ static void handle_getbuf(uv_handle_t* handle, size_t suggested_size, uv_buf_t*
static void udp_on_unwrapped(int status, struct session2 *session,
const struct comm_info *comm, void *baton)
{
- wire_buf_reset(&session->layers->wire_buf);
+ wire_buf_reset(&session->wire_buf);
}
void udp_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf,
@@ -88,9 +87,9 @@ void udp_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf,
return;
}
- int ret = wire_buf_consume(&s->layers->wire_buf, nread);
+ int ret = wire_buf_consume(&s->wire_buf, nread);
if (ret) {
- wire_buf_reset(&s->layers->wire_buf);
+ wire_buf_reset(&s->wire_buf);
return;
}
@@ -98,7 +97,7 @@ void udp_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf,
.comm_addr = comm_addr,
.src_addr = comm_addr
};
- session2_unwrap(s, protolayer_wire_buf(&s->layers->wire_buf, false),
+ session2_unwrap(s, protolayer_payload_wire_buf(&s->wire_buf, true),
&in_comm, udp_on_unwrapped, NULL);
}
@@ -107,7 +106,7 @@ static int family_to_freebind_option(sa_family_t sa_family, int *level, int *nam
#define LOG_NO_FB kr_log_error(NETWORK, "your system does not support 'freebind', " \
"please remove it from your configuration\n")
switch (sa_family) {
- case AF_INET:
+ case AF_INET: // NOLINT(bugprone-branch-clone): The branches are only cloned for specific macro configs
*level = IPPROTO_IP;
#if defined(IP_FREEBIND)
*name = IP_FREEBIND;
@@ -137,76 +136,9 @@ static int family_to_freebind_option(sa_family_t sa_family, int *level, int *nam
}
-struct pl_udp_iter_data {
- struct protolayer_data h;
- struct proxy_result proxy;
- bool has_proxy;
-};
-
-static enum protolayer_iter_cb_result pl_udp_unwrap(
- void *sess_data, void *iter_data, struct protolayer_iter_ctx *ctx)
-{
- ctx->payload = protolayer_as_buffer(&ctx->payload);
- if (kr_fails_assert(ctx->payload.type == PROTOLAYER_PAYLOAD_BUFFER)) {
- /* unsupported payload */
- return protolayer_break(ctx, kr_error(EINVAL));
- }
-
- struct session2 *s = ctx->manager->session;
- struct pl_udp_iter_data *udp = iter_data;
-
- char *data = ctx->payload.buffer.buf;
- ssize_t data_len = ctx->payload.buffer.len;
- struct comm_info *comm = &ctx->comm;
- if (!s->outgoing && proxy_header_present(data, data_len)) {
- if (!proxy_allowed(comm->comm_addr)) {
- kr_log_debug(IO, "<= ignoring PROXYv2 UDP from disallowed address '%s'\n",
- kr_straddr(comm->comm_addr));
- return protolayer_break(ctx, kr_error(EPERM));
- }
-
- ssize_t trimmed = proxy_process_header(&udp->proxy, data, data_len);
- if (trimmed == KNOT_EMALF) {
- if (kr_log_is_debug(IO, NULL)) {
- kr_log_debug(IO, "<= ignoring malformed PROXYv2 UDP "
- "from address '%s'\n",
- kr_straddr(comm->comm_addr));
- }
- return protolayer_break(ctx, kr_error(EINVAL));
- } else if (trimmed < 0) {
- if (kr_log_is_debug(IO, NULL)) {
- kr_log_debug(IO, "<= error processing PROXYv2 UDP "
- "from address '%s', ignoring\n",
- kr_straddr(comm->comm_addr));
- }
- return protolayer_break(ctx, kr_error(EINVAL));
- }
-
- if (udp->proxy.command == PROXY2_CMD_PROXY && udp->proxy.family != AF_UNSPEC) {
- udp->has_proxy = true;
-
- comm->src_addr = &udp->proxy.src_addr.ip;
- comm->dst_addr = &udp->proxy.dst_addr.ip;
- comm->proxy = &udp->proxy;
-
- if (kr_log_is_debug(IO, NULL)) {
- kr_log_debug(IO, "<= UDP query from '%s'\n",
- kr_straddr(comm->src_addr));
- kr_log_debug(IO, "<= proxied through '%s'\n",
- kr_straddr(comm->comm_addr));
- }
- }
-
- ctx->payload = protolayer_buffer(
- data + trimmed, data_len - trimmed, false);
- }
-
- return protolayer_continue(ctx);
-}
-
static enum protolayer_event_cb_result pl_udp_event_wrap(
enum protolayer_event_type event, void **baton,
- struct protolayer_manager *manager, void *sess_data)
+ struct session2 *session, void *sess_data)
{
if (event == PROTOLAYER_EVENT_STATS_SEND_ERR) {
the_worker->stats.err_udp += 1;
@@ -219,132 +151,20 @@ static enum protolayer_event_cb_result pl_udp_event_wrap(
return PROTOLAYER_EVENT_PROPAGATE;
}
-
-struct pl_tcp_sess_data {
- struct protolayer_data h;
- struct proxy_result proxy;
- struct wire_buf wire_buf;
- bool had_data : 1;
- bool has_proxy : 1;
-};
-
-static int pl_tcp_sess_init(struct protolayer_manager *manager,
- void *data,
- void *param)
+static int pl_tcp_sess_init(struct session2 *session,
+ void *data, void *param)
{
- struct sockaddr *peer = session2_get_peer(manager->session);
- manager->session->comm = (struct comm_info) {
+ struct sockaddr *peer = session2_get_peer(session);
+ session->comm_storage = (struct comm_info) {
.comm_addr = peer,
.src_addr = peer
};
return 0;
}
-static int pl_tcp_sess_deinit(struct protolayer_manager *manager, void *sess_data)
-{
- struct pl_tcp_sess_data *tcp = sess_data;
- wire_buf_deinit(&tcp->wire_buf);
- return 0;
-}
-
-static enum protolayer_iter_cb_result pl_tcp_unwrap(
- void *sess_data, void *iter_data, struct protolayer_iter_ctx *ctx)
-{
- struct session2 *s = ctx->manager->session;
- struct pl_tcp_sess_data *tcp = sess_data;
- struct sockaddr *peer = session2_get_peer(s);
-
- if (ctx->payload.type == PROTOLAYER_PAYLOAD_BUFFER) {
- const char *buf = ctx->payload.buffer.buf;
- const size_t len = ctx->payload.buffer.len;
-
- /* Copy a simple buffer into internal wirebuffer. */
- if (len > KNOT_WIRE_MAX_PKTSIZE)
- return protolayer_break(ctx, kr_error(EMSGSIZE));
-
- if (!tcp->wire_buf.buf) {
- int ret = wire_buf_reserve(&tcp->wire_buf,
- KNOT_WIRE_MAX_PKTSIZE);
- if (ret)
- return protolayer_break(ctx, ret);
- }
-
- /* Try to make space */
- while (len > wire_buf_free_space_length(&tcp->wire_buf)) {
- if (wire_buf_data_length(&tcp->wire_buf) > 0 ||
- tcp->wire_buf.start == 0)
- return protolayer_break(ctx, kr_error(EMSGSIZE));
-
- wire_buf_movestart(&tcp->wire_buf);
- }
-
- memcpy(wire_buf_free_space(&tcp->wire_buf), buf, len);
- wire_buf_consume(&tcp->wire_buf, ctx->payload.buffer.len);
- ctx->payload = protolayer_wire_buf(&tcp->wire_buf, false);
- }
-
- if (kr_fails_assert(ctx->payload.type == PROTOLAYER_PAYLOAD_WIRE_BUF)) {
- /* TODO: iovec support unimplemented */
- return protolayer_break(ctx, kr_error(EINVAL));
- }
-
- char *data = wire_buf_data(ctx->payload.wire_buf); /* layer's or session's wirebuf */
- ssize_t data_len = wire_buf_data_length(ctx->payload.wire_buf);
- struct comm_info *comm = &ctx->manager->session->comm;
- if (!s->outgoing && !tcp->had_data && proxy_header_present(data, data_len)) {
- if (!proxy_allowed(comm->src_addr)) {
- if (kr_log_is_debug(IO, NULL)) {
- kr_log_debug(IO, "<= connection to '%s': PROXYv2 not allowed "
- "for this peer, close\n",
- kr_straddr(peer));
- }
- worker_end_tcp(s);
- return protolayer_break(ctx, kr_error(ECONNRESET));
- }
-
- ssize_t trimmed = proxy_process_header(&tcp->proxy, data, data_len);
- if (trimmed < 0) {
- if (kr_log_is_debug(IO, NULL)) {
- if (trimmed == KNOT_EMALF) {
- kr_log_debug(IO, "<= connection to '%s': "
- "malformed PROXYv2 header, close\n",
- kr_straddr(comm->src_addr));
- } else {
- kr_log_debug(IO, "<= connection to '%s': "
- "error processing PROXYv2 header, close\n",
- kr_straddr(comm->src_addr));
- }
- }
- worker_end_tcp(s);
- return protolayer_break(ctx, kr_error(ECONNRESET));
- } else if (trimmed == 0) {
- session2_close(s);
- return protolayer_break(ctx, kr_error(ECONNRESET));
- }
-
- if (tcp->proxy.command != PROXY2_CMD_LOCAL && tcp->proxy.family != AF_UNSPEC) {
- comm->src_addr = &tcp->proxy.src_addr.ip;
- comm->dst_addr = &tcp->proxy.dst_addr.ip;
-
- if (kr_log_is_debug(IO, NULL)) {
- kr_log_debug(IO, "<= TCP stream from '%s'\n",
- kr_straddr(comm->src_addr));
- kr_log_debug(IO, "<= proxied through '%s'\n",
- kr_straddr(comm->comm_addr));
- }
- }
-
- wire_buf_trim(ctx->payload.wire_buf, trimmed);
- }
-
- tcp->had_data = true;
- ctx->comm = ctx->manager->session->comm;
- return protolayer_continue(ctx);
-}
-
static enum protolayer_event_cb_result pl_tcp_event_wrap(
enum protolayer_event_type event, void **baton,
- struct protolayer_manager *manager, void *sess_data)
+ struct session2 *session, void *sess_data)
{
if (event == PROTOLAYER_EVENT_STATS_SEND_ERR) {
the_worker->stats.err_tcp += 1;
@@ -359,17 +179,12 @@ static enum protolayer_event_cb_result pl_tcp_event_wrap(
void io_protolayers_init(void)
{
- protolayer_globals[PROTOLAYER_PROTOCOL_UDP] = (struct protolayer_globals){
- .iter_size = sizeof(struct pl_udp_iter_data),
- .unwrap = pl_udp_unwrap,
+ protolayer_globals[PROTOLAYER_TYPE_UDP] = (struct protolayer_globals){
.event_wrap = pl_udp_event_wrap,
};
- protolayer_globals[PROTOLAYER_PROTOCOL_TCP] = (struct protolayer_globals){
- .sess_size = sizeof(struct pl_tcp_sess_data),
+ protolayer_globals[PROTOLAYER_TYPE_TCP] = (struct protolayer_globals){
.sess_init = pl_tcp_sess_init,
- .sess_deinit = pl_tcp_sess_deinit,
- .unwrap = pl_tcp_unwrap,
.event_wrap = pl_tcp_event_wrap,
};
}
@@ -460,7 +275,7 @@ int io_listen_udp(uv_loop_t *loop, uv_udp_t *handle, int fd)
uv_handle_t *h = (uv_handle_t *)handle;
check_bufsize(h);
/* Handle is already created, just create context. */
- struct session2 *s = session2_new_io(h, PROTOLAYER_GRP_DOUDP, NULL, 0, false);
+ struct session2 *s = session2_new_io(h, KR_PROTO_UDP53, NULL, 0, false);
kr_require(s);
int socklen = sizeof(union kr_sockaddr);
@@ -503,21 +318,21 @@ static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
return;
}
- if (kr_fails_assert(buf->base == wire_buf_free_space(&s->layers->wire_buf))) {
+ if (kr_fails_assert(buf->base == wire_buf_free_space(&s->wire_buf))) {
return;
}
- int ret = wire_buf_consume(&s->layers->wire_buf, nread);
+ int ret = wire_buf_consume(&s->wire_buf, nread);
if (ret) {
- wire_buf_reset(&s->layers->wire_buf);
+ wire_buf_reset(&s->wire_buf);
return;
}
- session2_unwrap(s, protolayer_wire_buf(&s->layers->wire_buf, false),
+ session2_unwrap(s, protolayer_payload_wire_buf(&s->wire_buf, false),
NULL, NULL, NULL);
}
-static void _tcp_accept(uv_stream_t *master, int status, enum protolayer_grp grp)
+static void tcp_accept_internal(uv_stream_t *master, int status, enum kr_proto grp)
{
if (status != 0) {
return;
@@ -578,18 +393,18 @@ static void _tcp_accept(uv_stream_t *master, int status, enum protolayer_grp grp
static void tcp_accept(uv_stream_t *master, int status)
{
- _tcp_accept(master, status, PROTOLAYER_GRP_DOTCP);
+ tcp_accept_internal(master, status, KR_PROTO_TCP53);
}
static void tls_accept(uv_stream_t *master, int status)
{
- _tcp_accept(master, status, PROTOLAYER_GRP_DOTLS);
+ tcp_accept_internal(master, status, KR_PROTO_DOT);
}
#if ENABLE_DOH2
static void https_accept(uv_stream_t *master, int status)
{
- _tcp_accept(master, status, PROTOLAYER_GRP_DOHTTPS);
+ tcp_accept_internal(master, status, KR_PROTO_DOH);
}
#endif
@@ -790,18 +605,27 @@ void io_tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t *bu
len_s = 0;
}
uint32_t len_n = htonl(len_s);
- fwrite(&len_n, sizeof(len_n), 1, out);
- if (len_s > 0)
- fwrite(message, len_s, 1, out);
+ if (fwrite(&len_n, sizeof(len_n), 1, out) != 1)
+ goto finish;
+ if (len_s > 0) {
+ if (fwrite(message, len_s, 1, out) != 1)
+ goto finish;
+ }
break;
case IO_MODE_TEXT:
/* Human-readable and console-printable mode */
- if (message)
- fprintf(out, "%s", message);
- if (message || !args->quiet)
- fprintf(out, "\n");
- if (!args->quiet)
- fprintf(out, "> ");
+ if (message) {
+ if (fprintf(out, "%s", message) < 0)
+ goto finish;
+ }
+ if (message || !args->quiet) {
+ if (fprintf(out, "\n") < 0)
+ goto finish;
+ }
+ if (!args->quiet) {
+ if (fprintf(out, "> ") < 0)
+ goto finish;
+ }
break;
}
@@ -824,7 +648,7 @@ void io_tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t *bu
finish:
/* Close if redirected */
if (stream_fd != STDIN_FILENO) {
- fclose(out);
+ (void)fclose(out);
}
/* If a LMDB transaction got open, we can't leave it hanging.
* We accept the changes, if any. */
@@ -943,7 +767,7 @@ static void xdp_rx(uv_poll_t* handle, int status, int events)
memcpy(comm.eth_from, msg->eth_from, sizeof(comm.eth_from));
memcpy(comm.eth_to, msg->eth_to, sizeof(comm.eth_to));
session2_unwrap(xhd->session,
- protolayer_buffer(
+ protolayer_payload_buffer(
msg->payload.iov_base,
msg->payload.iov_len, false),
&comm, NULL, NULL);
@@ -1034,7 +858,7 @@ int io_listen_xdp(uv_loop_t *loop, struct endpoint *ep, const char *ifname)
return kr_error(ret);
}
- xhd->session = session2_new_io(ep->handle, PROTOLAYER_GRP_DOUDP,
+ xhd->session = session2_new_io(ep->handle, KR_PROTO_UDP53,
NULL, 0, false);
kr_require(xhd->session);
session2_get_sockname(xhd->session)->sa_family = AF_XDP; // to have something in there
@@ -1046,7 +870,7 @@ int io_listen_xdp(uv_loop_t *loop, struct endpoint *ep, const char *ifname)
#endif
int io_create(uv_loop_t *loop, struct session2 **out_session, int type,
- unsigned family, enum protolayer_grp grp,
+ unsigned family, enum kr_proto grp,
struct protolayer_data_param *layer_param,
size_t layer_param_count, bool outgoing)
{
diff --git a/daemon/io.h b/daemon/io.h
index 305f26cf..b03c6aae 100644
--- a/daemon/io.h
+++ b/daemon/io.h
@@ -45,7 +45,7 @@ void tcp_timeout_trigger(uv_timer_t *timer);
* \param family = AF_*
* \param has_tls has meanings only when type is SOCK_STREAM */
int io_create(uv_loop_t *loop, struct session2 **out_session, int type,
- unsigned family, enum protolayer_grp grp,
+ unsigned family, enum kr_proto grp,
struct protolayer_data_param *layer_param,
size_t layer_param_count, bool outgoing);
void io_free(uv_handle_t *handle);
diff --git a/daemon/main.c b/daemon/main.c
index 1f65ea77..6ea94310 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -7,6 +7,7 @@
#include "contrib/ucw/mempool.h"
#include "daemon/engine.h"
#include "daemon/io.h"
+#include "daemon/proxyv2.h"
#include "daemon/network.h"
#include "daemon/udp_queue.h"
#include "daemon/worker.h"
@@ -448,9 +449,9 @@ int main(int argc, char **argv)
{
kr_log_group_reset();
if (setvbuf(stdout, NULL, _IONBF, 0) || setvbuf(stderr, NULL, _IONBF, 0)) {
- kr_log_error(SYSTEM, "failed to to set output buffering (ignored): %s\n",
+ kr_log_error(SYSTEM, "failed to set output buffering (ignored): %s\n",
strerror(errno));
- fflush(stderr);
+ (void)fflush(stderr);
}
if (strcmp("linux", OPERATING_SYSTEM) != 0)
kr_log_warning(SYSTEM, "Knot Resolver is tested on Linux, other platforms might exhibit bugs.\n"
@@ -513,7 +514,7 @@ int main(int argc, char **argv)
if (ret) {
kr_log_error(SYSTEM, "failed to get or set file-descriptor limit: %s\n",
strerror(errno));
- } else if (rlim.rlim_cur < 512*1024) {
+ } else if (rlim.rlim_cur < (rlim_t)512 * 1024) {
kr_log_warning(SYSTEM, "warning: hard limit for number of file-descriptors is only %ld but recommended value is 524288\n",
(long)rlim.rlim_cur);
}
@@ -586,6 +587,7 @@ int main(int argc, char **argv)
io_protolayers_init();
tls_protolayers_init();
+ proxy_protolayers_init();
#ifdef ENABLE_DOH2
http_protolayers_init();
#endif
diff --git a/daemon/proxyv2.c b/daemon/proxyv2.c
index 73eb5769..8f1ca8f1 100644
--- a/daemon/proxyv2.c
+++ b/daemon/proxyv2.c
@@ -3,14 +3,17 @@
*/
#include "daemon/network.h"
+#include "daemon/session2.h"
+#include "daemon/worker.h"
#include "lib/generic/trie.h"
#include "daemon/proxyv2.h"
-const char PROXY2_SIGNATURE[12] = {
+static const char PROXY2_SIGNATURE[12] = {
0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A
};
+#define PROXY2_MIN_SIZE 16
#define PROXY2_IP6_ADDR_SIZE 16
#define PROXY2_UNIX_ADDR_SIZE 108
@@ -167,7 +170,10 @@ bool proxy_allowed(const struct sockaddr *saddr)
return kr_bitcmp((char *)&addr, (char *)&found->addr, found->netmask) == 0;
}
-ssize_t proxy_process_header(struct proxy_result *out,
+/** Parses the PROXYv2 header from buf of size nread and writes the result into
+ * out. The function assumes that the PROXYv2 signature is present
+ * and has been already checked by the caller (like `udp_recv` or `tcp_recv`). */
+static ssize_t proxy_process_header(struct proxy_result *out,
const void *buf, const ssize_t nread)
{
if (!buf)
@@ -277,6 +283,7 @@ ssize_t proxy_process_header(struct proxy_result *out,
&addr->ipv6_addr.dst_addr,
sizeof(out->dst_addr.ip6.sin6_addr.s6_addr));
break;
+ default:; /* Keep zero from initializer. */
}
/* Process additional information */
@@ -285,10 +292,172 @@ ssize_t proxy_process_header(struct proxy_result *out,
case TLV_TYPE_SSL:
out->has_tls = true;
break;
- /* TODO: add more TLV types if needed */
+ default:; /* Ignore others - add more if needed */
}
}
fill_wirebuf:
return hdr_len;
}
+
+/** Checks for a PROXY protocol version 2 signature in the specified buffer. */
+static inline bool proxy_header_present(const void* buf, const ssize_t nread)
+{
+ return nread >= PROXY2_MIN_SIZE &&
+ memcmp(buf, PROXY2_SIGNATURE, sizeof(PROXY2_SIGNATURE)) == 0;
+}
+
+
+struct pl_proxyv2_dgram_iter_data {
+ struct protolayer_data h;
+ struct proxy_result proxy;
+ bool has_proxy;
+};
+
+static enum protolayer_iter_cb_result pl_proxyv2_dgram_unwrap(
+ void *sess_data, void *iter_data, struct protolayer_iter_ctx *ctx)
+{
+ ctx->payload = protolayer_payload_as_buffer(&ctx->payload);
+ if (kr_fails_assert(ctx->payload.type == PROTOLAYER_PAYLOAD_BUFFER)) {
+ /* unsupported payload */
+ return protolayer_break(ctx, kr_error(EINVAL));
+ }
+
+ struct session2 *s = ctx->session;
+ struct pl_proxyv2_dgram_iter_data *udp = iter_data;
+
+ char *data = ctx->payload.buffer.buf;
+ ssize_t data_len = ctx->payload.buffer.len;
+ struct comm_info *comm = ctx->comm;
+ if (!s->outgoing && proxy_header_present(data, data_len)) {
+ if (!proxy_allowed(comm->comm_addr)) {
+ kr_log_debug(IO, "<= ignoring PROXYv2 UDP from disallowed address '%s'\n",
+ kr_straddr(comm->comm_addr));
+ return protolayer_break(ctx, kr_error(EPERM));
+ }
+
+ ssize_t trimmed = proxy_process_header(&udp->proxy, data, data_len);
+ if (trimmed == KNOT_EMALF) {
+ if (kr_log_is_debug(IO, NULL)) {
+ kr_log_debug(IO, "<= ignoring malformed PROXYv2 UDP "
+ "from address '%s'\n",
+ kr_straddr(comm->comm_addr));
+ }
+ return protolayer_break(ctx, kr_error(EINVAL));
+ } else if (trimmed < 0) {
+ if (kr_log_is_debug(IO, NULL)) {
+ kr_log_debug(IO, "<= error processing PROXYv2 UDP "
+ "from address '%s', ignoring\n",
+ kr_straddr(comm->comm_addr));
+ }
+ return protolayer_break(ctx, kr_error(EINVAL));
+ }
+
+ if (udp->proxy.command == PROXY2_CMD_PROXY && udp->proxy.family != AF_UNSPEC) {
+ udp->has_proxy = true;
+
+ comm->src_addr = &udp->proxy.src_addr.ip;
+ comm->dst_addr = &udp->proxy.dst_addr.ip;
+ comm->proxy = &udp->proxy;
+
+ if (kr_log_is_debug(IO, NULL)) {
+ kr_log_debug(IO, "<= UDP query from '%s'\n",
+ kr_straddr(comm->src_addr));
+ kr_log_debug(IO, "<= proxied through '%s'\n",
+ kr_straddr(comm->comm_addr));
+ }
+ }
+
+ ctx->payload = protolayer_payload_buffer(
+ data + trimmed, data_len - trimmed, false);
+ }
+
+ return protolayer_continue(ctx);
+}
+
+
+struct pl_proxyv2_stream_sess_data {
+ struct protolayer_data h;
+ struct proxy_result proxy;
+ bool had_data : 1;
+ bool has_proxy : 1;
+};
+
+static enum protolayer_iter_cb_result pl_proxyv2_stream_unwrap(
+ void *sess_data, void *iter_data, struct protolayer_iter_ctx *ctx)
+{
+ struct session2 *s = ctx->session;
+ struct pl_proxyv2_stream_sess_data *tcp = sess_data;
+ struct sockaddr *peer = session2_get_peer(s);
+
+ if (kr_fails_assert(ctx->payload.type == PROTOLAYER_PAYLOAD_WIRE_BUF)) {
+ /* Only wire buffer is supported */
+ return protolayer_break(ctx, kr_error(EINVAL));
+ }
+
+ char *data = wire_buf_data(ctx->payload.wire_buf); /* layer's or session's wirebuf */
+ ssize_t data_len = wire_buf_data_length(ctx->payload.wire_buf);
+ struct comm_info *comm = ctx->comm;
+ if (!s->outgoing && !tcp->had_data && proxy_header_present(data, data_len)) {
+ if (!proxy_allowed(comm->src_addr)) {
+ if (kr_log_is_debug(IO, NULL)) {
+ kr_log_debug(IO, "<= connection to '%s': PROXYv2 not allowed "
+ "for this peer, close\n",
+ kr_straddr(peer));
+ }
+ worker_end_tcp(s);
+ return protolayer_break(ctx, kr_error(ECONNRESET));
+ }
+
+ ssize_t trimmed = proxy_process_header(&tcp->proxy, data, data_len);
+ if (trimmed < 0) {
+ if (kr_log_is_debug(IO, NULL)) {
+ if (trimmed == KNOT_EMALF) {
+ kr_log_debug(IO, "<= connection to '%s': "
+ "malformed PROXYv2 header, close\n",
+ kr_straddr(comm->src_addr));
+ } else {
+ kr_log_debug(IO, "<= connection to '%s': "
+ "error processing PROXYv2 header, close\n",
+ kr_straddr(comm->src_addr));
+ }
+ }
+ worker_end_tcp(s);
+ return protolayer_break(ctx, kr_error(ECONNRESET));
+ } else if (trimmed == 0) {
+ session2_close(s);
+ return protolayer_break(ctx, kr_error(ECONNRESET));
+ }
+
+ if (tcp->proxy.command != PROXY2_CMD_LOCAL && tcp->proxy.family != AF_UNSPEC) {
+ comm->src_addr = &tcp->proxy.src_addr.ip;
+ comm->dst_addr = &tcp->proxy.dst_addr.ip;
+
+ if (kr_log_is_debug(IO, NULL)) {
+ kr_log_debug(IO, "<= TCP stream from '%s'\n",
+ kr_straddr(comm->src_addr));
+ kr_log_debug(IO, "<= proxied through '%s'\n",
+ kr_straddr(comm->comm_addr));
+ }
+ }
+
+ wire_buf_trim(ctx->payload.wire_buf, trimmed);
+ }
+
+ tcp->had_data = true;
+ return protolayer_continue(ctx);
+}
+
+
+void proxy_protolayers_init(void)
+{
+ protolayer_globals[PROTOLAYER_TYPE_PROXYV2_DGRAM] = (struct protolayer_globals){
+ .iter_size = sizeof(struct pl_proxyv2_dgram_iter_data),
+ .unwrap = pl_proxyv2_dgram_unwrap,
+ };
+
+ protolayer_globals[PROTOLAYER_TYPE_PROXYV2_STREAM] = (struct protolayer_globals){
+ .sess_size = sizeof(struct pl_proxyv2_stream_sess_data),
+ .unwrap = pl_proxyv2_stream_unwrap,
+ };
+}
diff --git a/daemon/proxyv2.h b/daemon/proxyv2.h
index a21f14b1..9bba3476 100644
--- a/daemon/proxyv2.h
+++ b/daemon/proxyv2.h
@@ -8,10 +8,6 @@
#include "lib/utils.h"
-extern const char PROXY2_SIGNATURE[12];
-
-#define PROXY2_MIN_SIZE 16
-
enum proxy2_command {
PROXY2_CMD_LOCAL = 0x0,
PROXY2_CMD_PROXY = 0x1
@@ -35,19 +31,9 @@ struct proxy_result {
bool has_tls : 1;
};
-/** Checks for a PROXY protocol version 2 signature in the specified buffer. */
-static inline bool proxy_header_present(const void* buf, const ssize_t nread)
-{
- return nread >= PROXY2_MIN_SIZE &&
- memcmp(buf, PROXY2_SIGNATURE, sizeof(PROXY2_SIGNATURE)) == 0;
-}
-
/** Checks whether the use of PROXYv2 protocol is allowed for the specified
* address. */
bool proxy_allowed(const struct sockaddr *saddr);
-/** Parses the PROXYv2 header from buf of size nread and writes the result into
- * out. The function assumes that the PROXYv2 signature is present
- * and has been already checked by the caller (like `udp_recv` or `tcp_recv`). */
-ssize_t proxy_process_header(struct proxy_result *out,
- const void *buf, ssize_t nread);
+/** Initializes the protocol layers managed by the PROXYv2 "module". */
+void proxy_protolayers_init(void);
diff --git a/daemon/session2.c b/daemon/session2.c
index a2c519a0..5f6f7d00 100644
--- a/daemon/session2.c
+++ b/daemon/session2.c
@@ -32,73 +32,79 @@
static uint32_t next_log_id = 1;
-struct protolayer_globals protolayer_globals[PROTOLAYER_PROTOCOL_COUNT] = {{0}};
+struct protolayer_globals protolayer_globals[PROTOLAYER_TYPE_COUNT] = {{0}};
-static const enum protolayer_protocol protolayer_grp_doudp[] = {
- PROTOLAYER_PROTOCOL_UDP,
- PROTOLAYER_PROTOCOL_DNS_DGRAM,
- PROTOLAYER_PROTOCOL_NULL
+static const enum protolayer_type protolayer_grp_udp53[] = {
+ PROTOLAYER_TYPE_UDP,
+ PROTOLAYER_TYPE_PROXYV2_DGRAM,
+ PROTOLAYER_TYPE_DNS_DGRAM,
};
-static const enum protolayer_protocol protolayer_grp_dotcp[] = {
- PROTOLAYER_PROTOCOL_TCP,
- PROTOLAYER_PROTOCOL_DNS_MULTI_STREAM,
- PROTOLAYER_PROTOCOL_NULL
+static const enum protolayer_type protolayer_grp_tcp53[] = {
+ PROTOLAYER_TYPE_TCP,
+ PROTOLAYER_TYPE_PROXYV2_STREAM,
+ PROTOLAYER_TYPE_DNS_MULTI_STREAM,
};
-static const enum protolayer_protocol protolayer_grp_dot[] = {
- PROTOLAYER_PROTOCOL_TCP,
- PROTOLAYER_PROTOCOL_TLS,
- PROTOLAYER_PROTOCOL_DNS_MULTI_STREAM,
- PROTOLAYER_PROTOCOL_NULL
+static const enum protolayer_type protolayer_grp_dot[] = {
+ PROTOLAYER_TYPE_TCP,
+ PROTOLAYER_TYPE_PROXYV2_STREAM,
+ PROTOLAYER_TYPE_TLS,
+ PROTOLAYER_TYPE_DNS_MULTI_STREAM,
};
-static const enum protolayer_protocol protolayer_grp_doh[] = {
- PROTOLAYER_PROTOCOL_TCP,
- PROTOLAYER_PROTOCOL_TLS,
- PROTOLAYER_PROTOCOL_HTTP,
- PROTOLAYER_PROTOCOL_DNS_UNSIZED_STREAM,
- PROTOLAYER_PROTOCOL_NULL
+static const enum protolayer_type protolayer_grp_doh[] = {
+ PROTOLAYER_TYPE_TCP,
+ PROTOLAYER_TYPE_PROXYV2_STREAM,
+ PROTOLAYER_TYPE_TLS,
+ PROTOLAYER_TYPE_HTTP,
+ PROTOLAYER_TYPE_DNS_UNSIZED_STREAM,
};
-/** Sequences of layers, mapped by `enum protolayer_grp`.
+static const enum protolayer_type protolayer_grp_doq[] = {
+ // not yet used
+ PROTOLAYER_TYPE_NULL,
+};
+
+struct protolayer_grp {
+ const enum protolayer_type *layers;
+ size_t num_layers;
+};
+
+#define PROTOLAYER_GRP(p_array) { \
+ .layers = (p_array), \
+ .num_layers = sizeof((p_array)) / sizeof((p_array)[0]), \
+}
+
+/** Sequences of layers, or groups, mapped by `enum kr_proto`.
+ *
+ * Each group represents a sequence of layers in the unwrap direction (wrap
+ * direction being the opposite). The sequence dictates the order in which
+ * individual layers are processed. This macro is used to generate global data
+ * about groups.
*
- * To define a new group, add a new entry in the `PROTOLAYER_GRP_MAP` macro and
+ * To define a new group, add a new entry in the `KR_PROTO_MAP()` macro and
* create a new static `protolayer_grp_*` array above, similarly to the already
- * existing ones. Each array must end with `PROTOLAYER_GRP_NULL`, to indicate
- * the end of the list of protocol layers. The array name's suffix must be the
- * one defined as *Variable name* (2nd parameter) in the `PROTOLAYER_GRP_MAP`
- * macro. */
-static const enum protolayer_protocol *protolayer_grps[PROTOLAYER_GRP_COUNT] = {
-#define XX(cid, vid, name) [PROTOLAYER_GRP_ ## cid] = protolayer_grp_ ## vid,
- PROTOLAYER_GRP_MAP(XX)
+ * existing ones. Each array must end with `PROTOLAYER_TYPE_NULL`, to
+ * indicate the end of the list of protocol layers. The array name's suffix must
+ * be the one defined as *Variable name* (2nd parameter) in the
+ * `KR_PROTO_MAP` macro. */
+static const struct protolayer_grp protolayer_grps[KR_PROTO_COUNT] = {
+#define XX(cid, vid, name) [KR_PROTO_##cid] = PROTOLAYER_GRP(protolayer_grp_##vid),
+ KR_PROTO_MAP(XX)
#undef XX
};
-const char *protolayer_protocol_name(enum protolayer_protocol p)
+const char *protolayer_layer_name(enum protolayer_type p)
{
switch (p) {
- case PROTOLAYER_PROTOCOL_NULL:
+ case PROTOLAYER_TYPE_NULL:
return "(null)";
-#define XX(cid) case PROTOLAYER_PROTOCOL_ ## cid: \
+#define XX(cid) case PROTOLAYER_TYPE_ ## cid: \
return #cid;
- PROTOLAYER_PROTOCOL_MAP(XX)
-#undef XX
- default:
- return "(invalid)";
- }
-}
-
-const char *protolayer_grp_name(enum protolayer_grp g)
-{
- switch (g) {
- case PROTOLAYER_GRP_NULL:
- return "(null)";
-#define XX(cid, vid, name) case PROTOLAYER_GRP_ ## cid: \
- return (name);
- PROTOLAYER_GRP_MAP(XX)
+ PROTOLAYER_TYPE_MAP(XX)
#undef XX
default:
return "(invalid)";
@@ -228,7 +234,8 @@ size_t protolayer_payload_copy(void *dest,
}
}
-struct protolayer_payload protolayer_as_buffer(const struct protolayer_payload *payload)
+struct protolayer_payload protolayer_payload_as_buffer(
+ const struct protolayer_payload *payload)
{
if (payload->type == PROTOLAYER_PAYLOAD_BUFFER)
return *payload;
@@ -300,14 +307,15 @@ bool protolayer_queue_has_payload(const protolayer_iter_ctx_queue_t *queue)
/** Gets layer-specific session data for the layer with the specified index
* from the manager. */
static inline struct protolayer_data *protolayer_sess_data_get(
- struct protolayer_manager *m, size_t layer_ix)
+ struct session2 *s, size_t layer_ix)
{
- if (kr_fails_assert(layer_ix < m->num_layers))
+ const struct protolayer_grp *grp = &protolayer_grps[s->proto];
+ if (kr_fails_assert(layer_ix < grp->num_layers))
return NULL;
- /* See doc comment of `struct protolayer_manager::data` */
- const ssize_t *offsets = (ssize_t *)m->data;
- char *pl_data_beg = &m->data[2 * m->num_layers * sizeof(*offsets)];
+ /* See doc comment of `struct session2::layer_data` */
+ const ssize_t *offsets = (ssize_t *)s->layer_data;
+ char *pl_data_beg = &s->layer_data[2 * grp->num_layers * sizeof(*offsets)];
ssize_t offset = offsets[layer_ix];
if (offset < 0) /* No session data for this layer */
@@ -321,12 +329,13 @@ static inline struct protolayer_data *protolayer_sess_data_get(
static inline struct protolayer_data *protolayer_iter_data_get(
struct protolayer_iter_ctx *ctx, size_t layer_ix)
{
- struct protolayer_manager *m = ctx->manager;
- if (kr_fails_assert(layer_ix < m->num_layers))
+ struct session2 *s = ctx->session;
+ const struct protolayer_grp *grp = &protolayer_grps[s->proto];
+ if (kr_fails_assert(layer_ix < grp->num_layers))
return NULL;
- /* See doc comment of `struct protolayer_manager::data` */
- const ssize_t *offsets = (ssize_t *)&m->data[m->num_layers * sizeof(*offsets)];
+ /* See doc comment of `struct session2::layer_data` */
+ const ssize_t *offsets = (ssize_t *)&s->layer_data[grp->num_layers * sizeof(*offsets)];
ssize_t offset = offsets[layer_ix];
if (offset < 0) /* No iteration data for this layer */
@@ -335,11 +344,12 @@ static inline struct protolayer_data *protolayer_iter_data_get(
return (struct protolayer_data *)(ctx->data + offset);
}
-static inline ssize_t protolayer_manager_get_protocol(
- struct protolayer_manager *m, enum protolayer_protocol protocol)
+static inline ssize_t session2_get_protocol(
+ struct session2 *s, enum protolayer_type protocol)
{
- for (ssize_t i = 0; i < m->num_layers; i++) {
- enum protolayer_protocol found = protolayer_grps[m->grp][i];
+ const struct protolayer_grp *grp = &protolayer_grps[s->proto];
+ for (ssize_t i = 0; i < grp->num_layers; i++) {
+ enum protolayer_type found = grp->layers[i];
if (protocol == found)
return i;
}
@@ -350,7 +360,7 @@ static inline ssize_t protolayer_manager_get_protocol(
static inline bool protolayer_iter_ctx_is_last(struct protolayer_iter_ctx *ctx)
{
unsigned int last_ix = (ctx->direction == PROTOLAYER_UNWRAP)
- ? ctx->manager->num_layers - 1
+ ? protolayer_grps[ctx->session->proto].num_layers - 1
: 0;
return ctx->layer_ix == last_ix;
}
@@ -363,46 +373,45 @@ static inline void protolayer_iter_ctx_next(struct protolayer_iter_ctx *ctx)
ctx->layer_ix--;
}
-static inline const char *layer_name(enum protolayer_grp grp, ssize_t layer_ix)
+static inline const char *layer_name(enum kr_proto grp, ssize_t layer_ix)
{
- if (grp >= PROTOLAYER_GRP_COUNT)
+ if (grp >= KR_PROTO_COUNT)
return "(invalid)";
- enum protolayer_protocol p = protolayer_grps[grp][layer_ix];
- return protolayer_protocol_name(p);
+ enum protolayer_type p = protolayer_grps[grp].layers[layer_ix];
+ return protolayer_layer_name(p);
}
static inline const char *layer_name_ctx(struct protolayer_iter_ctx *ctx)
{
- return layer_name(ctx->manager->grp, ctx->layer_ix);
+ return layer_name(ctx->session->proto, ctx->layer_ix);
}
static int protolayer_iter_ctx_finish(struct protolayer_iter_ctx *ctx, int ret)
{
- struct session2 *session = ctx->manager->session;
-
- struct protolayer_manager *m = ctx->manager;
- struct protolayer_globals *globals = &protolayer_globals[m->grp];
- for (size_t i = 0; i < m->num_layers; i++) {
+ struct session2 *s = ctx->session;
+ const struct protolayer_globals *globals = &protolayer_globals[s->proto];
+ const struct protolayer_grp *grp = &protolayer_grps[s->proto];
+ for (size_t i = 0; i < grp->num_layers; i++) {
struct protolayer_data *d = protolayer_iter_data_get(ctx, i);
if (globals->iter_deinit)
- globals->iter_deinit(m, ctx, d);
+ globals->iter_deinit(ctx, d);
}
if (ret)
- VERBOSE_LOG(session, "layer context of group '%s' (on %u: %s) ended with return code %d\n",
- protolayer_grp_name(ctx->manager->grp),
+ VERBOSE_LOG(s, "layer context of group '%s' (on %u: %s) ended with return code %d\n",
+ kr_proto_name(s->proto),
ctx->layer_ix, layer_name_ctx(ctx), ret);
if (ctx->status)
- VERBOSE_LOG(session, "iteration of group '%s' (on %u: %s) ended with status %d\n",
- protolayer_grp_name(ctx->manager->grp),
+ VERBOSE_LOG(s, "iteration of group '%s' (on %u: %s) ended with status %d\n",
+ kr_proto_name(s->proto),
ctx->layer_ix, layer_name_ctx(ctx), ctx->status);
if (ctx->finished_cb)
- ctx->finished_cb(ret, session, &ctx->comm,
+ ctx->finished_cb(ret, s, ctx->comm,
ctx->finished_cb_baton);
- free(ctx->async_buffer);
+ mm_ctx_delete(&ctx->pool);
free(ctx);
return ret;
@@ -418,10 +427,10 @@ static void protolayer_push_finished(int status, struct session2 *s, const struc
/** Pushes the specified protocol layer's payload to the session's transport. */
static int protolayer_push(struct protolayer_iter_ctx *ctx)
{
- struct session2 *session = ctx->manager->session;
+ struct session2 *session = ctx->session;
if (ctx->payload.type == PROTOLAYER_PAYLOAD_WIRE_BUF) {
- ctx->payload = protolayer_as_buffer(&ctx->payload);
+ ctx->payload = protolayer_payload_as_buffer(&ctx->payload);
}
if (kr_log_is_debug(PROTOLAYER, NULL)) {
@@ -433,12 +442,12 @@ static int protolayer_push(struct protolayer_iter_ctx *ctx)
session2_transport_push(session,
ctx->payload.buffer.buf, ctx->payload.buffer.len,
ctx->payload.short_lived,
- &ctx->comm, protolayer_push_finished, ctx);
+ ctx->comm, protolayer_push_finished, ctx);
} else if (ctx->payload.type == PROTOLAYER_PAYLOAD_IOVEC) {
session2_transport_pushv(session,
ctx->payload.iovec.iov, ctx->payload.iovec.cnt,
ctx->payload.short_lived,
- &ctx->comm, protolayer_push_finished, ctx);
+ ctx->comm, protolayer_push_finished, ctx);
} else {
kr_assert(false && "Invalid payload type");
return kr_error(EINVAL);
@@ -447,7 +456,7 @@ static int protolayer_push(struct protolayer_iter_ctx *ctx)
return PROTOLAYER_RET_ASYNC;
}
-static void protolayer_ensure_long_lived(struct protolayer_iter_ctx *ctx)
+static void protolayer_payload_ensure_long_lived(struct protolayer_iter_ctx *ctx)
{
if (!ctx->payload.short_lived)
return;
@@ -456,60 +465,74 @@ static void protolayer_ensure_long_lived(struct protolayer_iter_ctx *ctx)
if (kr_fails_assert(buf_len))
return;
- void *buf = malloc(buf_len);
+ void *buf = mm_alloc(&ctx->pool, buf_len);
kr_require(buf);
protolayer_payload_copy(buf, &ctx->payload, buf_len);
- ctx->async_buffer = buf;
- ctx->payload = protolayer_buffer(buf, buf_len, false);
+ ctx->payload = protolayer_payload_buffer(buf, buf_len, false);
}
/** Processes as many layers as possible synchronously, returning when either
* a layer has gone asynchronous, or when the whole sequence has finished.
*
- * May be called multiple times on the same `ctx` to continue processing
- * after an asynchronous operation. */
+ * May be called multiple times on the same `ctx` to continue processing after
+ * an asynchronous operation - user code will do this via *layer sequence return
+ * functions*. */
static int protolayer_step(struct protolayer_iter_ctx *ctx)
{
while (true) {
- if (kr_fails_assert(ctx->manager->grp < PROTOLAYER_GRP_COUNT))
+ if (kr_fails_assert(ctx->session->proto < KR_PROTO_COUNT))
return kr_error(EFAULT);
- enum protolayer_protocol protocol = protolayer_grps[ctx->manager->grp][ctx->layer_ix];
+ enum protolayer_type protocol = protolayer_grps[ctx->session->proto].layers[ctx->layer_ix];
struct protolayer_globals *globals = &protolayer_globals[protocol];
+ bool was_async = ctx->async_mode;
ctx->async_mode = false;
- ctx->status = 0;
- ctx->action = PROTOLAYER_ITER_ACTION_NULL;
- protolayer_iter_cb cb = (ctx->direction == PROTOLAYER_UNWRAP)
- ? globals->unwrap : globals->wrap;
+ /* Basically if we went asynchronous, we want to "resume" from
+ * underneath this `if` block. */
+ if (!was_async) {
+ ctx->status = 0;
+ ctx->action = PROTOLAYER_ITER_ACTION_NULL;
- if (ctx->manager->session->closing) {
- return protolayer_iter_ctx_finish(
- ctx, kr_error(ECANCELED));
- }
+ protolayer_iter_cb cb = (ctx->direction == PROTOLAYER_UNWRAP)
+ ? globals->unwrap : globals->wrap;
- if (cb) {
- struct protolayer_data *sess_data = protolayer_sess_data_get(
- ctx->manager, ctx->layer_ix);
- struct protolayer_data *iter_data = protolayer_iter_data_get(
- ctx, ctx->layer_ix);
- enum protolayer_iter_cb_result result = cb(sess_data, iter_data, ctx);
- if (kr_fails_assert(result == PROTOLAYER_ITER_CB_RESULT_MAGIC)) {
- /* Callback did not use a continuation function to return. */
- return protolayer_iter_ctx_finish(ctx, kr_error(EINVAL));
+ if (ctx->session->closing) {
+ return protolayer_iter_ctx_finish(
+ ctx, kr_error(ECANCELED));
}
- } else {
- ctx->action = PROTOLAYER_ITER_ACTION_CONTINUE;
- }
+ if (cb) {
+ struct protolayer_data *sess_data = protolayer_sess_data_get(
+ ctx->session, ctx->layer_ix);
+ struct protolayer_data *iter_data = protolayer_iter_data_get(
+ ctx, ctx->layer_ix);
+ enum protolayer_iter_cb_result result = cb(sess_data, iter_data, ctx);
+ if (kr_fails_assert(result == PROTOLAYER_ITER_CB_RESULT_MAGIC)) {
+ /* Callback did not use a *layer
+ * sequence return function* (see
+ * glossary). */
+ return protolayer_iter_ctx_finish(ctx, kr_error(EINVAL));
+ }
+ } else {
+ ctx->action = PROTOLAYER_ITER_ACTION_CONTINUE;
+ }
- if (!ctx->action) {
- /* Next step is from a callback */
- ctx->async_mode = true;
- protolayer_ensure_long_lived(ctx);
- return PROTOLAYER_RET_ASYNC;
+ if (!ctx->action) {
+ /* We're going asynchronous - the next step is
+ * probably going to be from some sort of a
+ * callback and we will "resume" from underneath
+ * this `if` block. */
+ ctx->async_mode = true;
+ protolayer_payload_ensure_long_lived(ctx);
+ return PROTOLAYER_RET_ASYNC;
+ }
+ }
+
+ if (kr_fails_assert(ctx->action)) {
+ return protolayer_iter_ctx_finish(ctx, kr_error(EINVAL));
}
if (ctx->action == PROTOLAYER_ITER_ACTION_BREAK) {
@@ -519,7 +542,7 @@ static int protolayer_step(struct protolayer_iter_ctx *ctx)
if (kr_fails_assert(ctx->status == 0)) {
/* Status should be zero without a BREAK. */
- return protolayer_iter_ctx_finish(ctx, kr_error(ECANCELED));
+ return protolayer_iter_ctx_finish(ctx, kr_error(EINVAL));
}
if (ctx->action == PROTOLAYER_ITER_ACTION_CONTINUE) {
@@ -543,20 +566,25 @@ static int protolayer_step(struct protolayer_iter_ctx *ctx)
/** Submits the specified buffer to the sequence of layers represented by the
* specified protolayer manager. The sequence will be processed in the
- * specified direction.
+ * specified `direction`, starting by the layer specified by `layer_ix`.
*
* Returns PROTOLAYER_RET_NORMAL when all layers have finished,
* PROTOLAYER_RET_ASYNC when some layers are asynchronous and waiting for
* continuation, or a negative number for errors (kr_error). */
-static int protolayer_manager_submit(
- struct session2 *s,
+static int session2_submit(
+ struct session2 *session,
enum protolayer_direction direction, size_t layer_ix,
struct protolayer_payload payload, const struct comm_info *comm,
protolayer_finished_cb cb, void *baton)
{
- struct protolayer_manager *manager = s->layers;
- if (!comm)
- comm = &manager->session->comm;
+ if (session->closing)
+ return kr_error(ECANCELED);
+ if (kr_fails_assert(session->proto < KR_PROTO_COUNT))
+ return kr_error(EFAULT);
+
+ bool had_comm_param = (comm != NULL);
+ if (!had_comm_param)
+ comm = &session->comm_storage;
// RRL: at this point we might start doing nontrivial work,
// but we may not know the client's IP yet.
@@ -566,62 +594,72 @@ static int protolayer_manager_submit(
kr_rrl_sample_start();
// In particular we don't want to miss en/decryption work
// for regular connections from clients.
- if (!s->outgoing && s->secure && !proxy_allowed(comm->comm_addr))
+ if (!session->outgoing && session->secure && !proxy_allowed(comm->comm_addr))
kr_rrl_sample_addr((const union kr_sockaddr *)comm->comm_addr);
}
int ret;
- if (manager->session->closing) {
- ret = kr_error(ECANCELED);
- goto finish_ret;
- }
-
- struct protolayer_iter_ctx *ctx = malloc(manager->cb_ctx_size);
+ struct protolayer_iter_ctx *ctx = malloc(session->iter_ctx_size);
kr_require(ctx);
- VERBOSE_LOG(manager->session,
+ VERBOSE_LOG(session,
"%s submitted to grp '%s' in %s direction (%zu: %s)\n",
protolayer_payload_name(payload.type),
- protolayer_grp_name(manager->grp),
+ kr_proto_name(session->proto),
(direction == PROTOLAYER_UNWRAP) ? "unwrap" : "wrap",
- layer_ix, layer_name(manager->grp, layer_ix));
+ layer_ix, layer_name(session->proto, layer_ix));
*ctx = (struct protolayer_iter_ctx) {
.payload = payload,
- .comm = *comm,
.direction = direction,
.layer_ix = layer_ix,
- .manager = manager,
+ .session = session,
.finished_cb = cb,
.finished_cb_baton = baton
};
-
- for (size_t i = 0; i < manager->num_layers; i++) {
- if (kr_fails_assert(ctx->manager->grp < PROTOLAYER_GRP_COUNT)) {
- ret = kr_error(EFAULT);
- goto finish_ret;
+ if (had_comm_param) {
+ struct comm_addr_storage *addrst = &ctx->comm_addr_storage;
+ if (comm->src_addr) {
+ memcpy(&addrst->src_addr.ip, comm->src_addr,
+ kr_sockaddr_len(comm->src_addr));
+ ctx->comm_storage.src_addr = &addrst->src_addr.ip;
+ }
+ if (comm->comm_addr) {
+ memcpy(&addrst->comm_addr.ip, comm->comm_addr,
+ kr_sockaddr_len(comm->comm_addr));
+ ctx->comm_storage.comm_addr = &addrst->comm_addr.ip;
}
+ if (comm->dst_addr) {
+ memcpy(&addrst->dst_addr.ip, comm->dst_addr,
+ kr_sockaddr_len(comm->dst_addr));
+ ctx->comm_storage.dst_addr = &addrst->dst_addr.ip;
+ }
+ ctx->comm = &ctx->comm_storage;
+ } else {
+ ctx->comm = &session->comm_storage;
+ }
+ mm_ctx_mempool(&ctx->pool, CPU_PAGE_SIZE);
- enum protolayer_protocol p = protolayer_grps[manager->grp][i];
- struct protolayer_globals *globals = &protolayer_globals[p];
+ const struct protolayer_grp *grp = &protolayer_grps[session->proto];
+ for (size_t i = 0; i < grp->num_layers; i++) {
+ struct protolayer_globals *globals = &protolayer_globals[grp->layers[i]];
struct protolayer_data *iter_data = protolayer_iter_data_get(ctx, i);
if (iter_data) {
memset(iter_data, 0, globals->iter_size);
- iter_data->session = manager->session;
+ iter_data->session = session;
}
if (globals->iter_init)
- globals->iter_init(manager, ctx, iter_data);
+ globals->iter_init(ctx, iter_data);
}
ret = protolayer_step(ctx);
-finish_ret:
if (direction == PROTOLAYER_UNWRAP)
kr_rrl_sample_stop();
return ret;
}
-static void *get_init_param(enum protolayer_protocol p,
+static void *get_init_param(enum protolayer_type p,
struct protolayer_data_param *layer_param,
size_t layer_param_count)
{
@@ -634,127 +672,26 @@ static void *get_init_param(enum protolayer_protocol p,
return NULL;
}
-/** Allocates and initializes a new manager. */
-static struct protolayer_manager *protolayer_manager_new(
- struct session2 *s,
- enum protolayer_grp grp,
- struct protolayer_data_param *layer_param,
- size_t layer_param_count)
-{
- if (kr_fails_assert(s && grp))
- return NULL;
-
- size_t num_layers = 0;
- size_t manager_size = sizeof(struct protolayer_manager);
- size_t cb_ctx_size = sizeof(struct protolayer_iter_ctx);
-
- const enum protolayer_protocol *protocols = protolayer_grps[grp];
- if (kr_fails_assert(protocols))
- return NULL;
- const enum protolayer_protocol *p = protocols;
-
- /* Space for offset index */
- for (; *p; p++)
- num_layers++;
- if (kr_fails_assert(num_layers))
- return NULL;
-
- size_t wire_buf_length = 0;
- size_t wire_buf_max_length = 0;
- ssize_t offsets[2 * num_layers];
- manager_size += sizeof(offsets);
-
- ssize_t *sess_offsets = offsets;
- ssize_t *iter_offsets = &offsets[num_layers];
-
- /* Space for layer-specific data, guaranteeing alignment */
- size_t total_sess_data_size = 0;
- size_t total_iter_data_size = 0;
- for (size_t i = 0; i < num_layers; i++) {
- const struct protolayer_globals *g = &protolayer_globals[protocols[i]];
-
- sess_offsets[i] = g->sess_size ? total_sess_data_size : -1;
- total_sess_data_size += ALIGN_TO(g->sess_size, CPU_STRUCT_ALIGN);
-
- iter_offsets[i] = g->iter_size ? total_iter_data_size : -1;
- total_iter_data_size += ALIGN_TO(g->iter_size, CPU_STRUCT_ALIGN);
-
- size_t wire_buf_overhead = (g->wire_buf_overhead_cb)
- ? g->wire_buf_overhead_cb(s->outgoing)
- : g->wire_buf_overhead;
- wire_buf_length += wire_buf_overhead;
- wire_buf_max_length += MAX(g->wire_buf_max_overhead, wire_buf_overhead);
- }
- manager_size += total_sess_data_size;
- cb_ctx_size += total_iter_data_size;
-
- /* Allocate and initialize manager */
- struct protolayer_manager *m = calloc(1, manager_size);
- kr_require(m);
- m->grp = grp;
- m->session = s;
- m->num_layers = num_layers;
- m->cb_ctx_size = cb_ctx_size;
- memcpy(m->data, offsets, sizeof(offsets));
-
- m->wire_buf_max_length = wire_buf_max_length;
- int ret = wire_buf_init(&m->wire_buf, wire_buf_length);
- kr_require(!ret);
-
- /* Initialize the layer's session data */
- for (size_t i = 0; i < num_layers; i++) {
- struct protolayer_globals *globals = &protolayer_globals[protocols[i]];
- struct protolayer_data *sess_data = protolayer_sess_data_get(m, i);
- if (sess_data) {
- memset(sess_data, 0, globals->sess_size);
- sess_data->session = s;
- }
-
- void *param = get_init_param(protocols[i], layer_param, layer_param_count);
- if (globals->sess_init)
- globals->sess_init(m, sess_data, param);
- }
-
- return m;
-}
-
-/** Deinitializes all layer data in the manager and deallocates it. */
-static void protolayer_manager_free(struct protolayer_manager *m)
+/** Called by *Layer sequence return functions* to proceed with protolayer
+ * processing. If the */
+static inline void maybe_async_do_step(struct protolayer_iter_ctx *ctx)
{
- if (!m) return;
-
- for (size_t i = 0; i < m->num_layers; i++) {
- enum protolayer_protocol p = protolayer_grps[m->grp][i];
- struct protolayer_globals *globals = &protolayer_globals[p];
- if (globals->sess_deinit) {
- struct protolayer_data *sess_data = protolayer_sess_data_get(m, i);
- globals->sess_deinit(m, sess_data);
- }
- }
-
- wire_buf_deinit(&m->wire_buf);
- free(m);
+ if (ctx->async_mode)
+ protolayer_step(ctx);
}
enum protolayer_iter_cb_result protolayer_continue(struct protolayer_iter_ctx *ctx)
{
- if (ctx->async_mode) {
- protolayer_iter_ctx_next(ctx);
- protolayer_step(ctx);
- } else {
- ctx->action = PROTOLAYER_ITER_ACTION_CONTINUE;
- }
+ ctx->action = PROTOLAYER_ITER_ACTION_CONTINUE;
+ maybe_async_do_step(ctx);
return PROTOLAYER_ITER_CB_RESULT_MAGIC;
}
enum protolayer_iter_cb_result protolayer_break(struct protolayer_iter_ctx *ctx, int status)
{
ctx->status = status;
- if (ctx->async_mode) {
- protolayer_iter_ctx_finish(ctx, PROTOLAYER_RET_NORMAL);
- } else {
- ctx->action = PROTOLAYER_ITER_ACTION_BREAK;
- }
+ ctx->action = PROTOLAYER_ITER_ACTION_BREAK;
+ maybe_async_do_step(ctx);
return PROTOLAYER_ITER_CB_RESULT_MAGIC;
}
@@ -782,8 +719,9 @@ int wire_buf_reserve(struct wire_buf *wb, size_t size)
if (wb->buf && wb->size >= size)
return kr_ok();
- wb->buf = realloc(wb->buf, size);
- kr_require(wb->buf);
+ char *newbuf = realloc(wb->buf, size);
+ kr_require(newbuf);
+ wb->buf = newbuf;
wb->size = size;
return kr_ok();
}
@@ -836,14 +774,48 @@ int wire_buf_reset(struct wire_buf *wb)
struct session2 *session2_new(enum session2_transport_type transport_type,
- enum protolayer_grp layer_grp,
+ enum kr_proto proto,
struct protolayer_data_param *layer_param,
size_t layer_param_count,
bool outgoing)
{
- kr_require(transport_type && layer_grp);
+ kr_require(transport_type && proto);
+
+ size_t session_size = sizeof(struct session2);
+ size_t iter_ctx_size = sizeof(struct protolayer_iter_ctx);
- struct session2 *s = malloc(sizeof(*s));
+ const struct protolayer_grp *grp = &protolayer_grps[proto];
+ if (kr_fails_assert(grp->num_layers))
+ return NULL;
+
+ size_t wire_buf_length = 0;
+ ssize_t offsets[2 * grp->num_layers];
+ session_size += sizeof(offsets);
+
+ ssize_t *sess_offsets = offsets;
+ ssize_t *iter_offsets = &offsets[grp->num_layers];
+
+ /* Space for layer-specific data, guaranteeing alignment */
+ size_t total_sess_data_size = 0;
+ size_t total_iter_data_size = 0;
+ for (size_t i = 0; i < grp->num_layers; i++) {
+ const struct protolayer_globals *g = &protolayer_globals[grp->layers[i]];
+
+ sess_offsets[i] = g->sess_size ? total_sess_data_size : -1;
+ total_sess_data_size += ALIGN_TO(g->sess_size, CPU_STRUCT_ALIGN);
+
+ iter_offsets[i] = g->iter_size ? total_iter_data_size : -1;
+ total_iter_data_size += ALIGN_TO(g->iter_size, CPU_STRUCT_ALIGN);
+
+ size_t wire_buf_overhead = (g->wire_buf_overhead_cb)
+ ? g->wire_buf_overhead_cb(outgoing)
+ : g->wire_buf_overhead;
+ wire_buf_length += wire_buf_overhead;
+ }
+ session_size += total_sess_data_size;
+ iter_ctx_size += total_iter_data_size;
+
+ struct session2 *s = malloc(session_size);
kr_require(s);
*s = (struct session2) {
@@ -853,24 +825,35 @@ struct session2 *session2_new(enum session2_transport_type transport_type,
.log_id = next_log_id++,
.outgoing = outgoing,
.tasks = trie_create(NULL),
- };
- struct protolayer_manager *layers = protolayer_manager_new(s, layer_grp,
- layer_param, layer_param_count);
- if (!layers) {
- free(s);
- return NULL;
- }
- s->layers = layers;
+ .proto = proto,
+ .iter_ctx_size = iter_ctx_size,
+ };
- mm_ctx_mempool(&s->pool, CPU_PAGE_SIZE);
+ memcpy(&s->layer_data, offsets, sizeof(offsets));
queue_init(s->waiting);
+ int ret = wire_buf_init(&s->wire_buf, wire_buf_length);
+ kr_require(!ret);
- int ret = uv_timer_init(uv_default_loop(), &s->timer);
+ ret = uv_timer_init(uv_default_loop(), &s->timer);
kr_require(!ret);
s->timer.data = s;
s->uv_count++; /* Session owns the timer */
+ /* Initialize the layer's session data */
+ for (size_t i = 0; i < grp->num_layers; i++) {
+ struct protolayer_globals *globals = &protolayer_globals[grp->layers[i]];
+ struct protolayer_data *sess_data = protolayer_sess_data_get(s, i);
+ if (sess_data) {
+ memset(sess_data, 0, globals->sess_size);
+ sess_data->session = s;
+ }
+
+ void *param = get_init_param(grp->layers[i], layer_param, layer_param_count);
+ if (globals->sess_init)
+ globals->sess_init(s, sess_data, param);
+ }
+
session2_touch(s);
return s;
@@ -880,8 +863,16 @@ struct session2 *session2_new(enum session2_transport_type transport_type,
* and timer are already closed, otherwise may leak resources. */
static void session2_free(struct session2 *s)
{
- protolayer_manager_free(s->layers);
- mm_ctx_delete(&s->pool);
+ const struct protolayer_grp *grp = &protolayer_grps[s->proto];
+ for (size_t i = 0; i < grp->num_layers; i++) {
+ struct protolayer_globals *globals = &protolayer_globals[grp->layers[i]];
+ if (globals->sess_deinit) {
+ struct protolayer_data *sess_data = protolayer_sess_data_get(s, i);
+ globals->sess_deinit(s, sess_data);
+ }
+ }
+
+ wire_buf_deinit(&s->wire_buf);
trie_free(s->tasks);
queue_deinit(s->waiting);
free(s);
@@ -1206,53 +1197,52 @@ int session2_unwrap(struct session2 *s, struct protolayer_payload payload,
const struct comm_info *comm, protolayer_finished_cb cb,
void *baton)
{
- return protolayer_manager_submit(s, PROTOLAYER_UNWRAP, 0,
- payload, comm, cb, baton);
+ return session2_submit(s, PROTOLAYER_UNWRAP,
+ 0, payload, comm, cb, baton);
}
-int session2_unwrap_after(struct session2 *s, enum protolayer_protocol protocol,
+int session2_unwrap_after(struct session2 *s, enum protolayer_type protocol,
struct protolayer_payload payload,
const struct comm_info *comm,
protolayer_finished_cb cb, void *baton)
{
- ssize_t layer_ix = protolayer_manager_get_protocol(s->layers, protocol) + 1;
+ ssize_t layer_ix = session2_get_protocol(s, protocol) + 1;
if (layer_ix < 0)
return layer_ix;
- return protolayer_manager_submit(s, PROTOLAYER_UNWRAP, layer_ix,
- payload, comm, cb, baton);
+ return session2_submit(s, PROTOLAYER_UNWRAP,
+ layer_ix, payload, comm, cb, baton);
}
int session2_wrap(struct session2 *s, struct protolayer_payload payload,
const struct comm_info *comm, protolayer_finished_cb cb,
void *baton)
{
- return protolayer_manager_submit(s, PROTOLAYER_WRAP,
- s->layers->num_layers - 1,
+ return session2_submit(s, PROTOLAYER_WRAP,
+ protolayer_grps[s->proto].num_layers - 1,
payload, comm, cb, baton);
}
-int session2_wrap_after(struct session2 *s, enum protolayer_protocol protocol,
+int session2_wrap_after(struct session2 *s, enum protolayer_type protocol,
struct protolayer_payload payload,
const struct comm_info *comm,
protolayer_finished_cb cb, void *baton)
{
- ssize_t layer_ix = protolayer_manager_get_protocol(s->layers, protocol) - 1;
+ ssize_t layer_ix = session2_get_protocol(s, protocol) - 1;
if (layer_ix < 0)
return layer_ix;
- return protolayer_manager_submit(s, PROTOLAYER_WRAP, layer_ix,
+ return session2_submit(s, PROTOLAYER_WRAP, layer_ix,
payload, comm, cb, baton);
}
static void session2_event_wrap(struct session2 *s, enum protolayer_event_type event, void *baton)
{
bool cont;
- struct protolayer_manager *m = s->layers;
- for (ssize_t i = m->num_layers - 1; i >= 0; i--) {
- enum protolayer_protocol p = protolayer_grps[s->layers->grp][i];
- struct protolayer_globals *globals = &protolayer_globals[p];
+ const struct protolayer_grp *grp = &protolayer_grps[s->proto];
+ for (ssize_t i = grp->num_layers - 1; i >= 0; i--) {
+ struct protolayer_globals *globals = &protolayer_globals[grp->layers[i]];
if (globals->event_wrap) {
- struct protolayer_data *sess_data = protolayer_sess_data_get(m, i);
- cont = globals->event_wrap(event, &baton, m, sess_data);
+ struct protolayer_data *sess_data = protolayer_sess_data_get(s, i);
+ cont = globals->event_wrap(event, &baton, s, sess_data);
} else {
cont = true;
}
@@ -1267,13 +1257,12 @@ static void session2_event_wrap(struct session2 *s, enum protolayer_event_type e
void session2_event_unwrap(struct session2 *s, ssize_t start_ix, enum protolayer_event_type event, void *baton)
{
bool cont;
- struct protolayer_manager *m = s->layers;
- for (ssize_t i = start_ix; i < m->num_layers; i++) {
- enum protolayer_protocol p = protolayer_grps[s->layers->grp][i];
- struct protolayer_globals *globals = &protolayer_globals[p];
+ const struct protolayer_grp *grp = &protolayer_grps[s->proto];
+ for (ssize_t i = start_ix; i < grp->num_layers; i++) {
+ struct protolayer_globals *globals = &protolayer_globals[grp->layers[i]];
if (globals->event_unwrap) {
- struct protolayer_data *sess_data = protolayer_sess_data_get(m, i);
- cont = globals->event_unwrap(event, &baton, m, sess_data);
+ struct protolayer_data *sess_data = protolayer_sess_data_get(s, i);
+ cont = globals->event_unwrap(event, &baton, s, sess_data);
} else {
cont = true;
}
@@ -1296,10 +1285,10 @@ void session2_event(struct session2 *s, enum protolayer_event_type event, void *
session2_event_unwrap(s, 0, event, baton);
}
-void session2_event_after(struct session2 *s, enum protolayer_protocol protocol,
+void session2_event_after(struct session2 *s, enum protolayer_type protocol,
enum protolayer_event_type event, void *baton)
{
- ssize_t start_ix = protolayer_manager_get_protocol(s->layers, protocol);
+ ssize_t start_ix = session2_get_protocol(s, protocol);
if (kr_fails_assert(start_ix >= 0))
return;
session2_event_unwrap(s, start_ix + 1, event, baton);
@@ -1307,13 +1296,12 @@ void session2_event_after(struct session2 *s, enum protolayer_protocol protocol,
void session2_init_request(struct session2 *s, struct kr_request *req)
{
- struct protolayer_manager *m = s->layers;
- for (ssize_t i = 0; i < m->num_layers; i++) {
- enum protolayer_protocol p = protolayer_grps[s->layers->grp][i];
- struct protolayer_globals *globals = &protolayer_globals[p];
+ const struct protolayer_grp *grp = &protolayer_grps[s->proto];
+ for (ssize_t i = 0; i < grp->num_layers; i++) {
+ struct protolayer_globals *globals = &protolayer_globals[grp->layers[i]];
if (globals->request_init) {
- struct protolayer_data *sess_data = protolayer_sess_data_get(m, i);
- globals->request_init(m, req, sess_data);
+ struct protolayer_data *sess_data = protolayer_sess_data_get(s, i);
+ globals->request_init(s, req, sess_data);
}
}
}
@@ -1429,27 +1417,30 @@ static int session2_transport_pushv(struct session2 *s,
.baton = baton,
.comm = comm
};
+ int err_ret = kr_ok();
switch (s->transport.type) {
case SESSION2_TRANSPORT_IO:;
uv_handle_t *handle = s->transport.io.handle;
if (kr_fails_assert(handle)) {
- if (cb)
- cb(kr_error(EINVAL), s, comm, baton);
- free(ctx);
- return kr_error(EINVAL);
+ err_ret = kr_error(EINVAL);
+ goto exit_err;
}
if (handle->type == UV_UDP) {
if (ENABLE_SENDMMSG && !s->outgoing) {
int fd;
int ret = uv_fileno(handle, &fd);
- if (kr_fails_assert(!ret))
- return kr_error(EIO);
+ if (kr_fails_assert(!ret)) {
+ err_ret = kr_error(EIO);
+ goto exit_err;
+ }
/* TODO: support multiple iovecs properly? */
- if (kr_fails_assert(iovcnt == 1))
- return kr_error(EINVAL);
+ if (kr_fails_assert(iovcnt == 1)) {
+ err_ret = kr_error(EINVAL);
+ goto exit_err;
+ }
session2_transport_pushv_ensure_long_lived(
&iov, &iovcnt, iov_short_lived,
@@ -1496,12 +1487,16 @@ static int session2_transport_pushv(struct session2 *s,
#if ENABLE_XDP
} else if (handle->type == UV_POLL) {
xdp_handle_data_t *xhd = handle->data;
- if (kr_fails_assert(xhd && xhd->socket))
- return kr_error(EIO);
+ if (kr_fails_assert(xhd && xhd->socket)) {
+ err_ret = kr_error(EIO);
+ goto exit_err;
+ }
/* TODO: support multiple iovecs properly? */
- if (kr_fails_assert(iovcnt == 1))
- return kr_error(EINVAL);
+ if (kr_fails_assert(iovcnt == 1)) {
+ err_ret = kr_error(EINVAL);
+ goto exit_err;
+ }
session2_transport_pushv_ensure_long_lived(
&iov, &iovcnt, iov_short_lived,
@@ -1534,29 +1529,31 @@ static int session2_transport_pushv(struct session2 *s,
#endif
} else {
kr_assert(false && "Unsupported handle");
- if (cb)
- cb(kr_error(EINVAL), s, comm, baton);
- free(ctx);
- return kr_error(EINVAL);
+ err_ret = kr_error(EINVAL);
+ goto exit_err;
}
case SESSION2_TRANSPORT_PARENT:;
struct session2 *parent = s->transport.parent;
if (kr_fails_assert(parent)) {
- free(ctx);
- return kr_error(EINVAL);
+ err_ret = kr_error(EINVAL);
+ goto exit_err;
}
int ret = session2_wrap(parent,
- protolayer_iovec(iov, iovcnt, iov_short_lived),
+ protolayer_payload_iovec(iov, iovcnt, iov_short_lived),
comm, session2_transport_parent_pushv_finished,
ctx);
return (ret < 0) ? ret : kr_ok();
default:
kr_assert(false && "Invalid transport");
- free(ctx);
- return kr_error(EINVAL);
+ err_ret = kr_error(EINVAL);
+ goto exit_err;
}
+
+exit_err:
+ session2_transport_pushv_finished(err_ret, ctx);
+ return err_ret;
}
struct push_ctx {
diff --git a/daemon/session2.h b/daemon/session2.h
index 426f9b1f..dc602cca 100644
--- a/daemon/session2.h
+++ b/daemon/session2.h
@@ -2,8 +2,9 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
-/* HINT: If you are looking to implement a new protocol, start with the doc
- * comment of the `PROTOLAYER_PROTOCOL_MAP` macro and continue from there. */
+/* HINT: If you are looking to implement support for a new transport protocol,
+ * start with the doc comment of the `PROTOLAYER_TYPE_MAP` macro and
+ * continue from there. */
/* GLOSSARY:
*
@@ -21,6 +22,13 @@
* processing, it is also the lifetime of `struct protolayer_iter_ctx` and
* layer-specific data contained therein.
*
+ * Layer sequence return function:
+ * - One of `protolayer_break()`, `protolayer_continue()`, or
+ * `protolayer_async()` - a function that a protolayer's `_wrap` or `_unwrap`
+ * callback should call to get its return value. They may either be called
+ * synchronously directly in the callback to end/pause the processing, or, if
+ * the processing went asynchronous, called to resume the iteration of layers.
+ *
* Payload:
* - Data processed by protocol layers in a particular sequence. In the wrap
* direction, this data generally starts as a DNS packet, which is then
@@ -29,25 +37,26 @@
* is retrieved.
*
* Protocol layer:
- * - An implementation of a particular protocol. A layer transforms payloads
- * to conform to a particular protocol, e.g. UDP, TCP, TLS, HTTP, QUIC, etc.
- * While transforming a payload, a layer may also modify metadata - e.g. the
- * UDP and TCP layers in the Unwrap direction implement the PROXYv2 protocol,
- * using which they retrieve the IP address of the actual originating client
- * and store it in the appropriate struct.
+ * - Not to be confused with `struct kr_layer_api`. An implementation of a
+ * particular protocol. A protocol layer transforms payloads to conform to a
+ * particular protocol, e.g. UDP, TCP, TLS, HTTP, QUIC, etc. While
+ * transforming a payload, a layer may also modify metadata - e.g. the UDP and
+ * TCP layers in the Unwrap direction implement the PROXYv2 protocol, using
+ * which they retrieve the IP address of the actual originating client and
+ * store it in the appropriate struct.
*
* Protolayer:
- * - Same as 'Protocol layer'.
+ * - Short for 'protocol layer'.
*
* Unwrap:
- * - The direction of data transformation, starting with the transport (e.g.
- * data that came from the network), ending with an internal subsystem (e.g.
- * DNS query resolution).
+ * - The direction of data transformation, which starts with the transport
+ * (e.g. bytes that came from the network) and ends with an internal subsystem
+ * (e.g. DNS query resolution).
*
* Wrap:
- * - The direction of data transformation, starting with an internal
- * subsystem (e.g. an answer to a resolved DNS query), ending with the
- * transport (e.g. data that is going to be sent to the client). */
+ * - The direction of data transformation, which starts with an internal
+ * subsystem (e.g. an answer to a resolved DNS query) and ends with the
+ * transport (e.g. bytes that are going to be sent to the client). */
#pragma once
@@ -59,6 +68,7 @@
#include "contrib/mempattern.h"
#include "lib/generic/queue.h"
#include "lib/generic/trie.h"
+#include "lib/proto.h"
#include "lib/utils.h"
/* Forward declarations */
@@ -102,17 +112,26 @@ struct comm_info {
bool xdp:1;
};
+/** Just a simple struct able to hold three IPv6 or IPv4 addresses, so that we
+ * can hold them somewhere. */
+struct comm_addr_storage {
+ union kr_sockaddr src_addr;
+ union kr_sockaddr comm_addr;
+ union kr_sockaddr dst_addr;
+};
+
-/** A buffer, with indices marking the chunk containing as of yet unprocessed
- * data - this chunk is called "valid". The contents may be manipulated using
- * `wire_buf_` functions, which ensure the struct's validity.
+/** A buffer control struct, with indices marking a chunk containing received
+ * but as of yet unprocessed data - the data in this chunk is called "valid
+ * data". The struct may be manipulated using `wire_buf_` functions, which
+ * contain bounds checks to ensure correct behaviour.
*
- * The struct may be used to retrieve data piecewise, e.g. from a stream-based
- * transport like TCP, by writing data to the buffer's free space, then
+ * The struct may be used to retrieve data piecewise (e.g. from a stream-based
+ * transport like TCP) by writing data to the buffer's free space, then
* "consuming" that space with `wire_buf_consume`. It can also be handy for
* processing message headers, then trimming the beginning of the buffer (using
- * `wire_buf_trim`) so that the next part of the data may be processed by a
- * next part of a common pipeline.
+ * `wire_buf_trim`) so that the next part of the data may be processed by
+ * another part of a pipeline.
*
* May be initialized in two possible ways:
* - via `wire_buf_init`
@@ -155,7 +174,7 @@ int wire_buf_trim(struct wire_buf *wb, size_t length);
/** Moves the valid bytes of the buffer to the buffer's beginning. */
int wire_buf_movestart(struct wire_buf *wb);
-/** Resets the valid bytes of the buffer to zero. */
+/** Marks the wire buffer as empty. */
int wire_buf_reset(struct wire_buf *wb);
/** Gets a pointer to the data marked as valid in the wire buffer. */
@@ -188,7 +207,7 @@ static inline size_t wire_buf_free_space_length(const struct wire_buf *wb)
/** Protocol layer types map - an enumeration of individual protocol layer
* implementations
*
- * This macro is used to generate `enum protolayer_protocol` as well as other
+ * This macro is used to generate `enum protolayer_type` as well as other
* additional data on protocols, e.g. name string constants.
*
* To define a new protocol, add a new identifier to this macro, and, within
@@ -200,14 +219,18 @@ static inline size_t wire_buf_free_space_length(const struct wire_buf *wb)
*
* To use protocols within sessions, protocol layer groups also need to be
* defined, to indicate the order in which individual protocols are to be
- * processed. See `PROTOLAYER_GRP_MAP` below for more details. */
-#define PROTOLAYER_PROTOCOL_MAP(XX) \
+ * processed. See `KR_PROTO_MAP` below for more details. */
+#define PROTOLAYER_TYPE_MAP(XX) \
/* General transport protocols */\
XX(UDP)\
XX(TCP)\
XX(TLS)\
XX(HTTP)\
\
+ /* PROXYv2 */\
+ XX(PROXYV2_DGRAM)\
+ XX(PROXYV2_STREAM)\
+ \
/* DNS (`worker`) */\
XX(DNS_DGRAM) /**< Packets WITHOUT prepended size, one per (un)wrap,
* limited to UDP sizes, multiple sources (single
@@ -220,54 +243,16 @@ static inline size_t wire_buf_free_space_length(const struct wire_buf *wb)
* stream (may span multiple (un)wraps). */
/** The identifiers of protocol layer types. */
-enum protolayer_protocol {
- PROTOLAYER_PROTOCOL_NULL = 0,
-#define XX(cid) PROTOLAYER_PROTOCOL_ ## cid,
- PROTOLAYER_PROTOCOL_MAP(XX)
+enum protolayer_type {
+ PROTOLAYER_TYPE_NULL = 0,
+#define XX(cid) PROTOLAYER_TYPE_ ## cid,
+ PROTOLAYER_TYPE_MAP(XX)
#undef XX
- PROTOLAYER_PROTOCOL_COUNT /* must be the last! */
+ PROTOLAYER_TYPE_COUNT /* must be the last! */
};
/** Gets the constant string name of the specified protocol. */
-const char *protolayer_protocol_name(enum protolayer_protocol p);
-
-/** Protocol layer group map
- *
- * This macro is used to generate `enum protolayer_grp` as well as other
- * additional data on protocol layer groups, e.g. name string constants.
- *
- * Each group represents a sequence of layers in the unwrap direction (wrap
- * direction being the opposite). The sequence dictates the order in which
- * individual layers are processed. This macro is used to generate global data
- * about groups.
- *
- * For defining new groups, see the docs of `protolayer_grps[]` in
- * `daemon/session2.h`.
- *
- * TODO: probably unify enum protolayer_grp with enum kr_proto.
- *
- * Parameters for XX are:
- * 1. Constant name (for e.g. PROTOLAYER_GRP_* enum value identifiers)
- * 2. Variable name (for e.g. protolayer_grp_* array identifiers - defined in
- * `session2.c`)
- * 3. Human-readable name for logging */
-#define PROTOLAYER_GRP_MAP(XX) \
- XX(DOUDP, doudp, "DNS UDP") \
- XX(DOTCP, dotcp, "DNS TCP") \
- XX(DOTLS, dot, "DNS-over-TLS") \
- XX(DOHTTPS, doh, "DNS-over-HTTPS")
-
-/** The identifiers of pre-defined protocol layer sequences. */
-enum protolayer_grp {
- PROTOLAYER_GRP_NULL = 0,
-#define XX(cid, vid, name) PROTOLAYER_GRP_ ## cid,
- PROTOLAYER_GRP_MAP(XX)
-#undef XX
- PROTOLAYER_GRP_COUNT
-};
-
-/** Gets the constant string name of the specified protocol layer group. */
-const char *protolayer_grp_name(enum protolayer_grp g);
+const char *protolayer_layer_name(enum protolayer_type p);
/** Flow control indicators for protocol layer `wrap` and `unwrap` callbacks.
* Use via `protolayer_continue`, `protolayer_break`, and `protolayer_push`
@@ -372,7 +357,7 @@ const char *protolayer_event_name(enum protolayer_event_type e);
* valid. */
enum protolayer_payload_type {
PROTOLAYER_PAYLOAD_NULL = 0,
-#define XX(cid, name) PROTOLAYER_PAYLOAD_ ## cid,
+#define XX(cid, name) PROTOLAYER_PAYLOAD_##cid,
PROTOLAYER_PAYLOAD_MAP(XX)
#undef XX
PROTOLAYER_PAYLOAD_COUNT
@@ -391,9 +376,17 @@ struct protolayer_payload {
/** Time-to-live hint (e.g. for HTTP Cache-Control) */
unsigned int ttl;
- /** If `true`, the payload's memory may be freed early as kresd does not
- * completely control its lifetime. When going asynchronous, it needs to
- * be copied. */
+ /** If `true`, signifies that the memory this payload points to may
+ * become invalid when we return from one of the functions in the
+ * current stack. That is fine as long as all the protocol layer
+ * processing for this payload takes place in a single `session2_wrap()`
+ * or `session2_unwrap()` call, but may become a problem, when a layer
+ * goes asynchronous (via `protolayer_async()`).
+ *
+ * Setting this to `true` will ensure that the payload will get copied
+ * into a separate memory buffer if and only if a layer goes
+ * asynchronous. It makes sure that if all processing for the payload is
+ * synchronous, no copies or reallocations for the payload are done. */
bool short_lived;
union {
@@ -418,28 +411,43 @@ struct protolayer_payload {
* layer-specific data, and internal information for the protocol layer
* manager. */
struct protolayer_iter_ctx {
-/* read-write: */
+/* read-write for layers: */
/** The payload */
struct protolayer_payload payload;
- /** Communication information. Typically written into by one of the
- * first layers facilitating transport protocol processing. */
- struct comm_info comm;
+ /** Pointer to communication information. For TCP, this will generally
+ * point to the storage in the session. For UDP, this will generally
+ * point to the storage in this context. */
+ struct comm_info *comm;
+ /** Communication information storage. This will generally be set by one
+ * of the first layers in the sequence, if used, e.g. UDP PROXYv2. */
+ struct comm_info comm_storage;
+ struct comm_addr_storage comm_addr_storage;
+ /** Per-iter memory pool. Has no `free` procedure, gets freed as a whole
+ * when the context is being destroyed. Initialized and destroyed
+ * automatically - layers may use it to allocate memory. */
+ knot_mm_t pool;
-/* callback for when the layer iteration has ended - read-only: */
+/* callback for when the layer iteration has ended - read-only for layers: */
protolayer_finished_cb finished_cb;
void *finished_cb_baton;
-/* internal information for the manager - private: */
+/* internal information for the manager - should only be used by the protolayer
+ * system, never by layers: */
enum protolayer_direction direction;
+ /** If `true`, the processing of the layer sequence has been paused and
+ * is waiting to be resumed (`protolayer_continue()`) or cancelled
+ * (`protolayer_break()`). */
bool async_mode;
+ /** The index of the layer that is currently being (or has just been)
+ * processed. */
unsigned int layer_ix;
- struct protolayer_manager *manager;
+ struct session2 *session;
+ /** Status passed to the finish callback. */
int status;
enum protolayer_iter_action action;
- void *async_buffer;
/** Contains a sequence of variably-sized CPU-aligned layer-specific
- * structs. See `struct protolayer_manager::data`. */
+ * structs. See `struct session2::layer_data` for details. */
alignas(CPU_STRUCT_ALIGN) char data[];
};
@@ -455,8 +463,8 @@ size_t protolayer_payload_copy(void *dest,
size_t max_len);
/** Convenience function to get a buffer-type payload. */
-static inline struct protolayer_payload protolayer_buffer(void *buf, size_t len,
- bool short_lived)
+static inline struct protolayer_payload protolayer_payload_buffer(
+ void *buf, size_t len, bool short_lived)
{
return (struct protolayer_payload){
.type = PROTOLAYER_PAYLOAD_BUFFER,
@@ -469,7 +477,7 @@ static inline struct protolayer_payload protolayer_buffer(void *buf, size_t len,
}
/** Convenience function to get an iovec-type payload. */
-static inline struct protolayer_payload protolayer_iovec(
+static inline struct protolayer_payload protolayer_payload_iovec(
struct iovec *iov, int iovcnt, bool short_lived)
{
return (struct protolayer_payload){
@@ -483,7 +491,7 @@ static inline struct protolayer_payload protolayer_iovec(
}
/** Convenience function to get a wire-buf-type payload. */
-static inline struct protolayer_payload protolayer_wire_buf(
+static inline struct protolayer_payload protolayer_payload_wire_buf(
struct wire_buf *wire_buf, bool short_lived)
{
return (struct protolayer_payload){
@@ -500,7 +508,8 @@ static inline struct protolayer_payload protolayer_wire_buf(
* If the input payload is `_WIRE_BUF`, the pointed-to wire buffer is reset to
* indicate that all of its contents have been used up, and the buffer is ready
* to be reused. */
-struct protolayer_payload protolayer_as_buffer(const struct protolayer_payload *payload);
+struct protolayer_payload protolayer_payload_as_buffer(
+ const struct protolayer_payload *payload);
/** A predefined queue type for iteration context. */
typedef queue_t(struct protolayer_iter_ctx *) protolayer_iter_ctx_queue_t;
@@ -521,8 +530,8 @@ struct protolayer_data {
};
/** Return value of `protolayer_iter_cb` callbacks. To be returned by *layer
- * sequence return functions* as a sanity check. Not to be used directly by
- * user code. */
+ * sequence return functions* (see glossary) as a sanity check. Not to be used
+ * directly by user code. */
enum protolayer_iter_cb_result {
PROTOLAYER_ITER_CB_RESULT_MAGIC = 0x364F392E,
};
@@ -534,9 +543,9 @@ enum protolayer_iter_cb_result {
*
* The function (or another function, that the pointed-to function causes to be
* called, directly or through an asynchronous operation), must call one of the
- * *layer sequence return functions* (e.g. `protolayer_continue()`,
- * `protolayer_async()`, ...) to advance (or end) the layer sequence. The
- * function must return the result of such a return function. */
+ * *layer sequence return functions* (see glossary) to advance (or end) the
+ * layer sequence. The function must return the result of such a return
+ * function. */
typedef enum protolayer_iter_cb_result (*protolayer_iter_cb)(
void *sess_data,
void *iter_data,
@@ -561,7 +570,7 @@ enum protolayer_event_cb_result {
* stops. */
typedef enum protolayer_event_cb_result (*protolayer_event_cb)(
enum protolayer_event_type event, void **baton,
- struct protolayer_manager *manager, void *sess_data);
+ struct session2 *session, void *sess_data);
/** Function type for initialization callbacks of layer session data.
*
@@ -573,9 +582,8 @@ typedef enum protolayer_event_cb_result (*protolayer_event_cb)(
*
* Returning 0 means success, other return values mean error and halt the
* initialization. */
-typedef int (*protolayer_data_sess_init_cb)(struct protolayer_manager *manager,
- void *data,
- void *param);
+typedef int (*protolayer_data_sess_init_cb)(struct session2 *session,
+ void *data, void *param);
/** Function type for determining the size of a layer's wire buffer overhead. */
typedef size_t (*protolayer_wire_buf_overhead_cb)(bool outgoing);
@@ -588,8 +596,7 @@ typedef size_t (*protolayer_wire_buf_overhead_cb)(bool outgoing);
*
* Returning 0 means success, other return values mean error and halt the
* initialization. */
-typedef int (*protolayer_iter_data_cb)(struct protolayer_manager *manager,
- struct protolayer_iter_ctx *ctx,
+typedef int (*protolayer_iter_data_cb)(struct protolayer_iter_ctx *ctx,
void *data);
/** Function type for (de)initialization callbacks of layers.
@@ -598,57 +605,19 @@ typedef int (*protolayer_iter_data_cb)(struct protolayer_manager *manager,
*
* Returning 0 means success, other return values mean error and halt the
* initialization. */
-typedef int (*protolayer_data_cb)(struct protolayer_manager *manager,
- void *data);
+typedef int (*protolayer_data_cb)(struct session2 *session, void *data);
/** Function type for (de)initialization callbacks of DNS requests.
*
* `req` points to the request for initialization.
* `sess_data` points to layer-specific session data struct. */
-typedef void (*protolayer_request_cb)(struct protolayer_manager *manager,
+typedef void (*protolayer_request_cb)(struct session2 *session,
struct kr_request *req,
void *sess_data);
-/** A collection of protocol layers and their layer-specific data, tied to a
- * session. The manager contains a sequence of protocol layers (determined by
- * `grp`), which define how the data processed by the session is to be
- * interpreted. */
-struct protolayer_manager {
- enum protolayer_grp grp;
- struct wire_buf wire_buf;
- size_t wire_buf_max_length;
- struct session2 *session;
- size_t num_layers;
- size_t cb_ctx_size; /**< Size of a single callback context, including
- * layer-specific per-iteration data. */
-
- /** The following flexible array has basically this structure:
- *
- * struct {
- * size_t sess_offsets[num_layers];
- * size_t iter_offsets[num_layers];
- * variably-sized-data sess_data[num_layers];
- * }
- *
- * It is done this way, because different layer groups will have
- * different numbers of layers and differently-sized layer-specific
- * data. C does not have a convenient way to define this in structs, so
- * we do it via this flexible array.
- *
- * `sess_data` is a sequence of variably-sized CPU-aligned
- * layer-specific structs.
- *
- * `sess_offsets` determines data offsets in `sess_data` for pointer
- * retrieval.
- *
- * `iter_offsets` determines data offsets in `struct
- * protolayer_iter_ctx::data` for pointer retrieval. */
- alignas(CPU_STRUCT_ALIGN) char data[];
-};
-
/** Initialization parameters for protocol layer session data. */
struct protolayer_data_param {
- enum protolayer_protocol protocol; /**< Which protocol these parameters
+ enum protolayer_type protocol; /**< Which protocol these parameters
* are meant for. */
void *param; /**< Pointer to protolayer-related initialization
* parameters. Only needs to be valid during session
@@ -740,30 +709,30 @@ struct protolayer_globals {
protolayer_request_cb request_init;
};
-/** Global data about layered protocols. Mapped by `enum protolayer_protocol`.
+/** Global data about layered protocols. Mapped by `enum protolayer_type`.
* Individual protocols are to be initialized during resolver startup. */
-extern struct protolayer_globals protolayer_globals[PROTOLAYER_PROTOCOL_COUNT];
+extern struct protolayer_globals protolayer_globals[PROTOLAYER_TYPE_COUNT];
-/** *Layer sequence return function* - signalizes the protolayer manager to
- * continue processing the next layer. */
+/** *Layer sequence return function* (see glossary) - signalizes the protolayer
+ * manager to continue processing the next layer. */
enum protolayer_iter_cb_result protolayer_continue(struct protolayer_iter_ctx *ctx);
-/** *Layer sequence return function* - signalizes that the layer wants to stop
- * processing of the buffer and clean up, possibly due to an error (indicated
- * by a non-zero `status`). */
+/** *Layer sequence return function* (see glossary) - signalizes that the layer
+ * wants to stop processing of the buffer and clean up, possibly due to an error
+ * (indicated by a non-zero `status`). */
enum protolayer_iter_cb_result protolayer_break(struct protolayer_iter_ctx *ctx, int status);
-/** *Layer sequence return function* - signalizes that the current sequence
- * will continue in an asynchronous manner. The layer should store the context
- * and call another sequence return function at another point. This may be used
- * in layers that work through libraries whose operation is asynchronous, like
- * GnuTLS.
+/** *Layer sequence return function* (see glossary) - signalizes that the
+ * current sequence will continue in an asynchronous manner. The layer should
+ * store the context and call another sequence return function at another point.
+ * This may be used in layers that work through libraries whose operation is
+ * asynchronous, like GnuTLS.
*
- * Note that this return function is just a readability hint - another return
- * function may be called in another stack frame before it (generally during a
- * call to an external library function, e.g. GnuTLS or nghttp2) and the
- * sequence will continue correctly. */
+ * Note that this one is basically just a readability hint - another return
+ * function may be actually called before it (generally during a call to an
+ * external library function, e.g. GnuTLS or nghttp2). This is completely legal
+ * and the sequence will continue correctly. */
static inline enum protolayer_iter_cb_result protolayer_async(void)
{
return PROTOLAYER_ITER_CB_RESULT_MAGIC;
@@ -780,21 +749,22 @@ enum session2_transport_type {
/** A data unit for a single sequential data source. The data may be organized
* as a stream or a sequence of datagrams - this is up to the actual individual
- * protocols used by the session, as defined by the `layers` member - see
- * `struct protolayer_manager` and the types of its members for more info.
+ * protocols used by the session - see `enum kr_proto` and
+ * `protolayer_`-prefixed types and functions for more information.
*
* A session processes data in two directions:
*
* - `_UNWRAP` deals with raw data received from the session's transport. It
- * strips the ceremony of individual protocols from the buffers. The last
- * (bottommost) layer is generally responsible for submitting the unwrapped
- * data to be processed by an internal system, e.g. to be resolved as a DNS
- * query.
+ * strips the ceremony of individual protocols from the buffers, retaining any
+ * required metadata in an iteration context (`struct protolayer_iter_ctx`).
+ * The last layer (as defined by a `protolayer_grp_*` array in `session2.c`) in
+ * a sequence is generally responsible for submitting the unwrapped data to be
+ * processed by an internal system, e.g. to be resolved as a DNS query.
*
* - `_WRAP` deals with data generated by an internal system. It adds the
- * required protocol ceremony to it (e.g. encryption). The first (topmost)
- * layer is responsible for preparing the data to be sent through the
- * session's transport. */
+ * required protocol ceremony to it (e.g. encryption). The first layer (as
+ * defined by a `protolayer_grp_*` array in `session2.c`) is responsible for
+ * preparing the data to be sent through the session's transport. */
struct session2 {
/** Data for sending data out in the `wrap` direction and receiving new
* data in the `unwrap` direction. */
@@ -814,14 +784,12 @@ struct session2 {
};
} transport;
- struct protolayer_manager *layers; /**< Protocol layers of this session. */
- knot_mm_t pool;
uv_timer_t timer; /**< For session-wide timeout events. */
enum protolayer_event_type timer_event; /**< The event fired on timeout. */
trie_t *tasks; /**< List of tasks associated with given session. */
queue_t(struct qr_task *) waiting; /**< List of tasks waiting for
* sending to upstream. */
-
+ struct wire_buf wire_buf;
uint32_t log_id; /**< Session ID for logging. */
int uv_count; /**< Number of unclosed libUV handles owned by this
@@ -830,7 +798,7 @@ struct session2 {
/** Communication information. Typically written into by one of the
* first layers facilitating transport protocol processing.
* Zero-initialized by default. */
- struct comm_info comm;
+ struct comm_info comm_storage;
/** Time of last IO activity (if any occurs). Otherwise session
* creation time. */
@@ -866,6 +834,37 @@ struct session2 {
/** If true, session is being rate-limited. One of the protocol layers
* is going to be the writer for this flag. */
bool throttled : 1;
+
+ /* Protocol layers */
+
+ /** The set of protocol layers used by this session. */
+ enum kr_proto proto;
+ /** The size of a single iteration context
+ * (`struct protolayer_iter_ctx`), including layer-specific data. */
+ size_t iter_ctx_size;
+
+ /** The following flexible array has basically this structure:
+ *
+ * struct {
+ * size_t sess_offsets[num_layers];
+ * size_t iter_offsets[num_layers];
+ * variably-sized-data sess_data[num_layers];
+ * }
+ *
+ * It is done this way, because different layer groups will have
+ * different numbers of layers and differently-sized layer-specific
+ * data. C does not have a convenient way to define this in structs, so
+ * we do it via this flexible array.
+ *
+ * `sess_data` is a sequence of variably-sized CPU-aligned
+ * layer-specific structs.
+ *
+ * `sess_offsets` determines data offsets in `sess_data` for pointer
+ * retrieval.
+ *
+ * `iter_offsets` determines data offsets in `struct
+ * protolayer_iter_ctx::data` for pointer retrieval. */
+ alignas(CPU_STRUCT_ALIGN) char layer_data[];
};
/** Allocates and initializes a new session with the specified protocol layer
@@ -877,7 +876,7 @@ struct session2 {
* individual layer implementations to determine the lifetime of the data
* pointed to by the parameters. */
struct session2 *session2_new(enum session2_transport_type transport_type,
- enum protolayer_grp layer_grp,
+ enum kr_proto proto,
struct protolayer_data_param *layer_param,
size_t layer_param_count,
bool outgoing);
@@ -885,7 +884,7 @@ struct session2 *session2_new(enum session2_transport_type transport_type,
/** Allocates and initializes a new session with the specified protocol layer
* group, using a *libuv handle* as its transport. */
static inline struct session2 *session2_new_io(uv_handle_t *handle,
- enum protolayer_grp layer_grp,
+ enum kr_proto layer_grp,
struct protolayer_data_param *layer_param,
size_t layer_param_count,
bool outgoing)
@@ -901,7 +900,7 @@ static inline struct session2 *session2_new_io(uv_handle_t *handle,
/** Allocates and initializes a new session with the specified protocol layer
* group, using a *parent session* as its transport. */
static inline struct session2 *session2_new_child(struct session2 *parent,
- enum protolayer_grp layer_grp,
+ enum kr_proto layer_grp,
struct protolayer_data_param *layer_param,
size_t layer_param_count,
bool outgoing)
@@ -1019,7 +1018,7 @@ void session2_penalize(struct session2 *session);
* indicating an error. */
int session2_unwrap(struct session2 *s, struct protolayer_payload payload,
const struct comm_info *comm, protolayer_finished_cb cb,
- void *baton);
+ void *baton);
/** Same as `session2_unwrap`, but looks up the specified `protocol` in the
* session's assigned protocol group and sends the `payload` to the layer that
@@ -1027,7 +1026,7 @@ int session2_unwrap(struct session2 *s, struct protolayer_payload payload,
*
* Layers may use this to generate their own data to send in the sequence, e.g.
* for protocol-specific ceremony. */
-int session2_unwrap_after(struct session2 *s, enum protolayer_protocol protocol,
+int session2_unwrap_after(struct session2 *s, enum protolayer_type protocol,
struct protolayer_payload payload,
const struct comm_info *comm,
protolayer_finished_cb cb, void *baton);
@@ -1056,7 +1055,7 @@ int session2_wrap(struct session2 *s, struct protolayer_payload payload,
*
* Layers may use this to generate their own data to send in the sequence, e.g.
* for protocol-specific ceremony. */
-int session2_wrap_after(struct session2 *s, enum protolayer_protocol protocol,
+int session2_wrap_after(struct session2 *s, enum protolayer_type protocol,
struct protolayer_payload payload,
const struct comm_info *comm,
protolayer_finished_cb cb, void *baton);
@@ -1074,7 +1073,7 @@ void session2_event(struct session2 *s, enum protolayer_event_type event, void *
* NOTE: The bounced iteration does not exclude any layers - the layer
* specified by `protocol` and those before it are only skipped in the
* `_UNWRAP` direction! */
-void session2_event_after(struct session2 *s, enum protolayer_protocol protocol,
+void session2_event_after(struct session2 *s, enum protolayer_type protocol,
enum protolayer_event_type event, void *baton);
/** Sends a `PROTOLAYER_EVENT_CLOSE` event to be processed by the protocol
diff --git a/daemon/tls.c b/daemon/tls.c
index e8dff76c..a5169ae3 100644
--- a/daemon/tls.c
+++ b/daemon/tls.c
@@ -24,10 +24,10 @@
#include "daemon/worker.h"
#include "daemon/session2.h"
-#define EPHEMERAL_CERT_EXPIRATION_SECONDS_RENEW_BEFORE (60*60*24*7)
+#define EPHEMERAL_CERT_EXPIRATION_SECONDS_RENEW_BEFORE ((time_t)60*60*24*7)
#define GNUTLS_PIN_MIN_VERSION 0x030400
#define UNWRAP_BUF_SIZE 131072
-#define TLS_CHUNK_SIZE (16 * 1024)
+#define TLS_CHUNK_SIZE ((size_t)16 * 1024)
#define VERBOSE_MSG(cl_side, ...)\
if (cl_side) \
@@ -35,9 +35,9 @@
else \
kr_log_debug(TLS, __VA_ARGS__);
-static const gnutls_datum_t tls_grp_alpn[PROTOLAYER_GRP_COUNT] = {
- [PROTOLAYER_GRP_DOTLS] = { (uint8_t *)"dot", 3 },
- [PROTOLAYER_GRP_DOHTTPS] = { (uint8_t *)"h2", 2 },
+static const gnutls_datum_t tls_grp_alpn[KR_PROTO_COUNT] = {
+ [KR_PROTO_DOT] = { (uint8_t *)"dot", 3 },
+ [KR_PROTO_DOH] = { (uint8_t *)"h2", 2 },
};
typedef enum tls_client_hs_state {
@@ -218,6 +218,11 @@ static ssize_t kres_gnutls_vec_push(gnutls_transport_ptr_t h, const giovec_t * i
return 0;
}
+ if (kr_fails_assert(iovcnt > 0)) {
+ errno = EINVAL;
+ return -1;
+ }
+
size_t total_len = 0;
for (int i = 0; i < iovcnt; i++)
total_len += iov[i].iov_len;
@@ -228,9 +233,9 @@ static ssize_t kres_gnutls_vec_push(gnutls_transport_ptr_t h, const giovec_t * i
push_ctx->sess_data = tls;
memcpy(push_ctx->iov, iov, sizeof(struct iovec[iovcnt]));
- session2_wrap_after(tls->h.session, PROTOLAYER_PROTOCOL_TLS,
- protolayer_iovec(push_ctx->iov, iovcnt, true), NULL,
- kres_gnutls_push_finished, push_ctx);
+ session2_wrap_after(tls->h.session, PROTOLAYER_TYPE_TLS,
+ protolayer_payload_iovec(push_ctx->iov, iovcnt, true),
+ NULL, kres_gnutls_push_finished, push_ctx);
return total_len;
}
@@ -260,7 +265,7 @@ static void tls_handshake_success(struct pl_tls_sess_data *tls,
}
}
if (!tls->first_handshake_done) {
- session2_event_after(session, PROTOLAYER_PROTOCOL_TLS,
+ session2_event_after(session, PROTOLAYER_TYPE_TLS,
PROTOLAYER_EVENT_CONNECT, NULL);
tls->first_handshake_done = true;
}
@@ -442,7 +447,7 @@ static int str_replace(char **where_ptr, const char *with)
return kr_ok();
}
-static time_t _get_end_entity_expiration(gnutls_certificate_credentials_t creds)
+static time_t get_end_entity_expiration(gnutls_certificate_credentials_t creds)
{
gnutls_datum_t data;
gnutls_x509_crt_t cert = NULL;
@@ -514,7 +519,7 @@ int tls_certificate_set(const char *tls_cert, const char *tls_key)
return kr_error(EINVAL);
}
/* record the expiration date: */
- tls_credentials->valid_until = _get_end_entity_expiration(tls_credentials->credentials);
+ tls_credentials->valid_until = get_end_entity_expiration(tls_credentials->credentials);
/* Exchange the x509 credentials */
struct tls_credentials *old_credentials = the_network->tls_credentials;
@@ -889,7 +894,7 @@ static int pl_tls_sess_data_deinit(struct pl_tls_sess_data *tls)
return kr_ok();
}
-static int pl_tls_sess_server_init(struct protolayer_manager *manager,
+static int pl_tls_sess_server_init(struct session2 *session,
struct pl_tls_sess_data *tls)
{
if (kr_fails_assert(the_worker && the_engine))
@@ -967,7 +972,7 @@ static int pl_tls_sess_server_init(struct protolayer_manager *manager,
tls->tls_session);
}
- const gnutls_datum_t *alpn = &tls_grp_alpn[manager->grp];
+ const gnutls_datum_t *alpn = &tls_grp_alpn[session->proto];
if (alpn->size) { /* ALPN is a non-empty string */
flags = 0;
#if GNUTLS_VERSION_NUMBER >= 0x030500
@@ -987,7 +992,7 @@ static int pl_tls_sess_server_init(struct protolayer_manager *manager,
return kr_ok();
}
-static int pl_tls_sess_client_init(struct protolayer_manager *manager,
+static int pl_tls_sess_client_init(struct session2 *session,
struct pl_tls_sess_data *tls,
tls_client_param_t *param)
{
@@ -1042,21 +1047,21 @@ static int pl_tls_sess_client_init(struct protolayer_manager *manager,
return kr_ok();
}
-static int pl_tls_sess_init(struct protolayer_manager *manager,
+static int pl_tls_sess_init(struct session2 *session,
void *sess_data,
void *param)
{
struct pl_tls_sess_data *tls = sess_data;
- manager->session->secure = true;
+ session->secure = true;
queue_init(tls->unwrap_queue);
queue_init(tls->wrap_queue);
- if (manager->session->outgoing)
- return pl_tls_sess_client_init(manager, tls, param);
+ if (session->outgoing)
+ return pl_tls_sess_client_init(session, tls, param);
else
- return pl_tls_sess_server_init(manager, tls);
+ return pl_tls_sess_server_init(session, tls);
}
-static int pl_tls_sess_deinit(struct protolayer_manager *manager,
+static int pl_tls_sess_deinit(struct session2 *session,
void *sess_data)
{
return pl_tls_sess_data_deinit(sess_data);
@@ -1067,7 +1072,7 @@ static enum protolayer_iter_cb_result pl_tls_unwrap(void *sess_data, void *iter_
{
int brstatus = kr_ok();
struct pl_tls_sess_data *tls = sess_data;
- struct session2 *s = ctx->manager->session;
+ struct session2 *s = ctx->session;
queue_push(tls->unwrap_queue, ctx);
@@ -1160,7 +1165,7 @@ static enum protolayer_iter_cb_result pl_tls_unwrap(void *sess_data, void *iter_
struct protolayer_iter_ctx *ctx_head = queue_head(tls->unwrap_queue);
if (!kr_fails_assert(ctx == ctx_head))
queue_pop(tls->unwrap_queue);
- ctx->payload = protolayer_wire_buf(&tls->unwrap_buf, false);
+ ctx->payload = protolayer_payload_wire_buf(&tls->unwrap_buf, false);
return protolayer_continue(ctx);
exit_break:
@@ -1174,7 +1179,7 @@ static ssize_t pl_tls_submit(gnutls_session_t tls_session,
struct protolayer_payload payload)
{
if (payload.type == PROTOLAYER_PAYLOAD_WIRE_BUF)
- payload = protolayer_as_buffer(&payload);
+ payload = protolayer_payload_as_buffer(&payload);
if (payload.type == PROTOLAYER_PAYLOAD_BUFFER) {
ssize_t count = gnutls_record_send(tls_session,
@@ -1278,9 +1283,8 @@ static enum protolayer_event_cb_result pl_tls_client_connect_start(
static enum protolayer_event_cb_result pl_tls_event_unwrap(
enum protolayer_event_type event, void **baton,
- struct protolayer_manager *manager, void *sess_data)
+ struct session2 *s, void *sess_data)
{
- struct session2 *s = manager->session;
struct pl_tls_sess_data *tls = sess_data;
if (event == PROTOLAYER_EVENT_CLOSE) {
@@ -1308,7 +1312,7 @@ static enum protolayer_event_cb_result pl_tls_event_unwrap(
static enum protolayer_event_cb_result pl_tls_event_wrap(
enum protolayer_event_type event, void **baton,
- struct protolayer_manager *manager, void *sess_data)
+ struct session2 *session, void *sess_data)
{
if (event == PROTOLAYER_EVENT_STATS_SEND_ERR) {
the_worker->stats.err_tls += 1;
@@ -1321,7 +1325,7 @@ static enum protolayer_event_cb_result pl_tls_event_wrap(
return PROTOLAYER_EVENT_PROPAGATE;
}
-static void pl_tls_request_init(struct protolayer_manager *manager,
+static void pl_tls_request_init(struct session2 *session,
struct kr_request *req,
void *sess_data)
{
@@ -1330,7 +1334,7 @@ static void pl_tls_request_init(struct protolayer_manager *manager,
void tls_protolayers_init(void)
{
- protolayer_globals[PROTOLAYER_PROTOCOL_TLS] = (struct protolayer_globals){
+ protolayer_globals[PROTOLAYER_TYPE_TLS] = (struct protolayer_globals){
.sess_size = sizeof(struct pl_tls_sess_data),
.sess_deinit = pl_tls_sess_deinit,
.wire_buf_overhead = TLS_CHUNK_SIZE,
diff --git a/daemon/tls.h b/daemon/tls.h
index b8cf7af6..9fd45fb6 100644
--- a/daemon/tls.h
+++ b/daemon/tls.h
@@ -30,7 +30,7 @@
* So it takes 2 RTT.
* As we use session tickets, there are additional messages, add one RTT mode.
*/
-#define TLS_MAX_HANDSHAKE_TIME (KR_CONN_RTT_MAX * 3)
+#define TLS_MAX_HANDSHAKE_TIME (KR_CONN_RTT_MAX * (uint64_t)3)
/** Transport session (opaque). */
struct session2;
diff --git a/daemon/tls_ephemeral_credentials.c b/daemon/tls_ephemeral_credentials.c
index a27dcd2d..712e355b 100644
--- a/daemon/tls_ephemeral_credentials.c
+++ b/daemon/tls_ephemeral_credentials.c
@@ -17,19 +17,19 @@
#define EPHEMERAL_PRIVKEY_FILENAME "ephemeral_key.pem"
#define INVALID_HOSTNAME "dns-over-tls.invalid"
-#define EPHEMERAL_CERT_EXPIRATION_SECONDS (60*60*24*90)
+#define EPHEMERAL_CERT_EXPIRATION_SECONDS ((time_t)60*60*24*90)
/* This is an attempt to grab an exclusive, advisory, non-blocking
* lock based on a filename. At the moment it's POSIX-only, but it
* should be abstract enough of an interface to make an implementation
* for non-posix systems if anyone cares. */
typedef int lock_t;
-static bool _lock_is_invalid(lock_t lock)
+static bool lock_is_invalid(lock_t lock)
{
return lock == -1;
}
/* a blocking lock on a given filename */
-static lock_t _lock_filename(const char *fname)
+static lock_t lock_filename(const char *fname)
{
lock_t lockfd = open(fname, O_RDONLY|O_CREAT, 0400);
if (lockfd == -1)
@@ -41,9 +41,9 @@ static lock_t _lock_filename(const char *fname)
}
return lockfd; /* for cleanup later */
}
-static void _lock_unlock(lock_t *lock, const char *fname)
+static void lock_unlock(lock_t *lock, const char *fname)
{
- if (lock && !_lock_is_invalid(*lock)) {
+ if (lock && !lock_is_invalid(*lock)) {
flock(*lock, LOCK_UN);
close(*lock);
*lock = -1;
@@ -61,8 +61,8 @@ static gnutls_x509_privkey_t get_ephemeral_privkey (void)
/* Take a lock to ensure that two daemons started concurrently
* with a shared cache don't both create the same privkey: */
- lock = _lock_filename(EPHEMERAL_PRIVKEY_FILENAME ".lock");
- if (_lock_is_invalid(lock)) {
+ lock = lock_filename(EPHEMERAL_PRIVKEY_FILENAME ".lock");
+ if (lock_is_invalid(lock)) {
kr_log_error(TLS, "unable to lock lockfile " EPHEMERAL_PRIVKEY_FILENAME ".lock\n");
goto done;
}
@@ -91,7 +91,7 @@ static gnutls_x509_privkey_t get_ephemeral_privkey (void)
}
data.size = stat.st_size;
bytes_read = read(datafd, data.data, stat.st_size);
- if (bytes_read != stat.st_size) {
+ if (bytes_read < 0 || bytes_read != stat.st_size) {
kr_log_error(TLS, "unable to read ephemeral private key\n");
goto bad_data;
}
@@ -141,7 +141,7 @@ static gnutls_x509_privkey_t get_ephemeral_privkey (void)
}
}
done:
- _lock_unlock(&lock, EPHEMERAL_PRIVKEY_FILENAME ".lock");
+ lock_unlock(&lock, EPHEMERAL_PRIVKEY_FILENAME ".lock");
if (datafd != -1) {
close(datafd);
}
@@ -220,7 +220,7 @@ struct tls_credentials * tls_get_ephemeral_credentials(void)
if ((privkey = get_ephemeral_privkey()) == NULL) {
goto failure;
}
- if ((cert = get_ephemeral_cert(privkey, creds->ephemeral_servicename, now - 60*15, creds->valid_until)) == NULL) {
+ if ((cert = get_ephemeral_cert(privkey, creds->ephemeral_servicename, now - ((time_t)60 * 15), creds->valid_until)) == NULL) {
goto failure;
}
if ((err = gnutls_certificate_set_x509_key(creds->credentials, &cert, 1, privkey)) < 0) {
diff --git a/daemon/tls_session_ticket-srv.c b/daemon/tls_session_ticket-srv.c
index b1989030..26d41862 100644
--- a/daemon/tls_session_ticket-srv.c
+++ b/daemon/tls_session_ticket-srv.c
@@ -188,7 +188,7 @@ static void tst_key_check(uv_timer_t *timer, bool force_update)
const uint64_t remain_ms = (tv_sec_next - now.tv_sec - 1) * (uint64_t)1000
+ ms_until_second + 1;
/* ^ +1 because we don't want to wake up half a millisecond before the epoch! */
- if (kr_fails_assert(remain_ms < (TST_KEY_LIFETIME + 1 /*rounding tolerance*/) * 1000))
+ if (kr_fails_assert(remain_ms < ((uint64_t)TST_KEY_LIFETIME + 1 /*rounding tolerance*/) * 1000))
return;
kr_log_debug(TLS, "session ticket: epoch %"PRIu64
", scheduling rotation check in %"PRIu64" ms\n",
diff --git a/daemon/udp_queue.c b/daemon/udp_queue.c
index a03af8d7..68d67ec6 100644
--- a/daemon/udp_queue.c
+++ b/daemon/udp_queue.c
@@ -112,11 +112,11 @@ void udp_queue_push(int fd, const struct sockaddr *sa, char *buf, size_t buf_len
/* Get a valid correct queue. */
if (fd >= state.udp_queues_len) {
const int new_len = fd + 1;
- state.udp_queues = realloc(state.udp_queues,
- sizeof(state.udp_queues[0]) * new_len);
+ state.udp_queues = realloc(state.udp_queues, // NOLINT(bugprone-suspicious-realloc-usage): we just abort() below, so it's fine
+ sizeof(state.udp_queues[0]) * new_len); // NOLINT(bugprone-sizeof-expression): false-positive
if (!state.udp_queues) abort();
memset(state.udp_queues + state.udp_queues_len, 0,
- sizeof(state.udp_queues[0]) * (new_len - state.udp_queues_len));
+ sizeof(state.udp_queues[0]) * (new_len - state.udp_queues_len)); // NOLINT(bugprone-sizeof-expression): false-positive
state.udp_queues_len = new_len;
}
if (unlikely(state.udp_queues[fd] == NULL))
diff --git a/daemon/worker.c b/daemon/worker.c
index 0445d027..e81255b2 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -129,7 +129,7 @@ struct worker_ctx *the_worker = NULL;
/*! @internal Create a UDP/TCP handle for an outgoing AF_INET* connection.
* socktype is SOCK_* */
static struct session2 *ioreq_spawn(int socktype, sa_family_t family,
- enum protolayer_grp grp,
+ enum kr_proto grp,
struct protolayer_data_param *layer_param,
size_t layer_param_count)
{
@@ -195,7 +195,7 @@ static inline struct mempool *pool_borrow(void)
{
/* The implementation used to have extra caching layer,
* but it didn't work well. Now it's very simple. */
- return mp_new(16 * 1024);
+ return mp_new((size_t)16 * 1024);
}
/** Return a mempool. */
static inline void pool_release(struct mempool *mp)
@@ -635,9 +635,6 @@ static int qr_task_send(struct qr_task *task, struct session2 *session,
int ret = 0;
- if (comm == NULL)
- comm = &session->comm;
-
if (pkt == NULL)
pkt = worker_task_get_pktbuf(task);
@@ -664,7 +661,7 @@ static int qr_task_send(struct qr_task *task, struct session2 *session,
/* Pending '_finished' callback on current task */
qr_task_ref(task);
- struct protolayer_payload payload = protolayer_buffer(
+ struct protolayer_payload payload = protolayer_payload_buffer(
(char *)pkt->wire, pkt->size, false);
payload.ttl = packet_ttl(pkt);
ret = session2_wrap(session, payload, comm, qr_task_wrap_finished, task);
@@ -834,7 +831,7 @@ static int transmit(struct qr_task *task)
return ret;
struct session2 *session = ioreq_spawn(SOCK_DGRAM, choice->sin6_family,
- PROTOLAYER_GRP_DOUDP, NULL, 0);
+ KR_PROTO_UDP53, NULL, 0);
if (!session)
return kr_error(EINVAL);
@@ -1090,14 +1087,14 @@ static int tcp_task_make_connection(struct qr_task *task, const struct sockaddr
bool has_tls = tls_entry;
if (has_tls) {
struct protolayer_data_param param = {
- .protocol = PROTOLAYER_PROTOCOL_TLS,
+ .protocol = PROTOLAYER_TYPE_TLS,
.param = tls_entry
};
session = ioreq_spawn(SOCK_STREAM, addr->sa_family,
- PROTOLAYER_GRP_DOTLS, &param, 1);
+ KR_PROTO_DOT, &param, 1);
} else {
session = ioreq_spawn(SOCK_STREAM, addr->sa_family,
- PROTOLAYER_GRP_DOTCP, NULL, 0);
+ KR_PROTO_TCP53, NULL, 0);
}
if (!session) {
free(conn);
@@ -1715,12 +1712,11 @@ static inline knot_pkt_t *produce_packet(uint8_t *buf, size_t buf_len)
static enum protolayer_event_cb_result pl_dns_dgram_event_unwrap(
enum protolayer_event_type event, void **baton,
- struct protolayer_manager *manager, void *sess_data)
+ struct session2 *session, void *sess_data)
{
if (event != PROTOLAYER_EVENT_GENERAL_TIMEOUT)
return PROTOLAYER_EVENT_PROPAGATE;
- struct session2 *session = manager->session;
if (session2_tasklist_get_len(session) != 1 ||
!session2_waitinglist_is_empty(session))
return PROTOLAYER_EVENT_PROPAGATE;
@@ -1758,7 +1754,7 @@ static size_t pl_dns_dgram_wire_buf_overhead(bool outgoing)
static enum protolayer_iter_cb_result pl_dns_dgram_unwrap(
void *sess_data, void *iter_data, struct protolayer_iter_ctx *ctx)
{
- struct session2 *session = ctx->manager->session;
+ struct session2 *session = ctx->session;
if (ctx->payload.type == PROTOLAYER_PAYLOAD_IOVEC) {
int ret = kr_ok();
@@ -1777,7 +1773,7 @@ static enum protolayer_iter_cb_result pl_dns_dgram_unwrap(
break;
}
- ret = worker_submit(session, &ctx->comm, pkt);
+ ret = worker_submit(session, ctx->comm, pkt);
if (ret)
break;
}
@@ -1795,7 +1791,7 @@ static enum protolayer_iter_cb_result pl_dns_dgram_unwrap(
if (!pkt)
return protolayer_break(ctx, KNOT_EMALF);
- int ret = worker_submit(session, &ctx->comm, pkt);
+ int ret = worker_submit(session, ctx->comm, pkt);
mp_flush(the_worker->pkt_pool.ctx);
return protolayer_break(ctx, ret);
} else if (ctx->payload.type == PROTOLAYER_PAYLOAD_WIRE_BUF) {
@@ -1811,7 +1807,7 @@ static enum protolayer_iter_cb_result pl_dns_dgram_unwrap(
if (!pkt)
return protolayer_break(ctx, KNOT_EMALF);
- int ret = worker_submit(session, &ctx->comm, pkt);
+ int ret = worker_submit(session, ctx->comm, pkt);
wire_buf_reset(ctx->payload.wire_buf);
mp_flush(the_worker->pkt_pool.ctx);
return protolayer_break(ctx, ret);
@@ -1828,41 +1824,24 @@ struct pl_dns_stream_sess_data {
bool connected : 1; /**< True: The stream is connected */
};
-struct pl_dns_stream_iter_data {
- struct protolayer_data h;
- struct {
- knot_mm_t *pool;
- void *mem;
- } sent;
-};
-
-static int pl_dns_stream_sess_init(struct protolayer_manager *manager,
- void *sess_data, void *param)
+static int pl_dns_stream_sess_init(struct session2 *session,
+ void *sess_data, void *param)
{
/* _UNSIZED_STREAM and _MULTI_STREAM - don't forget to split if needed
* at some point */
- manager->session->stream = true;
+ session->stream = true;
return kr_ok();
}
-static int pl_dns_single_stream_sess_init(struct protolayer_manager *manager,
+static int pl_dns_single_stream_sess_init(struct session2 *session,
void *sess_data, void *param)
{
- manager->session->stream = true;
+ session->stream = true;
struct pl_dns_stream_sess_data *stream = sess_data;
stream->single = true;
return kr_ok();
}
-static int pl_dns_stream_iter_deinit(struct protolayer_manager *manager,
- struct protolayer_iter_ctx *ctx,
- void *iter_data)
-{
- struct pl_dns_stream_iter_data *stream = iter_data;
- mm_free(stream->sent.pool, stream->sent.mem);
- return kr_ok();
-}
-
static enum protolayer_event_cb_result pl_dns_stream_resolution_timeout(
struct session2 *s)
{
@@ -2051,9 +2030,8 @@ static enum protolayer_event_cb_result pl_dns_stream_disconnected(
static enum protolayer_event_cb_result pl_dns_stream_event_unwrap(
enum protolayer_event_type event, void **baton,
- struct protolayer_manager *manager, void *sess_data)
+ struct session2 *session, void *sess_data)
{
- struct session2 *session = manager->session;
if (session->closing)
return PROTOLAYER_EVENT_PROPAGATE;
@@ -2061,10 +2039,10 @@ static enum protolayer_event_cb_result pl_dns_stream_event_unwrap(
switch (event) {
case PROTOLAYER_EVENT_GENERAL_TIMEOUT:
- return pl_dns_stream_resolution_timeout(manager->session);
+ return pl_dns_stream_resolution_timeout(session);
case PROTOLAYER_EVENT_CONNECT_TIMEOUT:
- return pl_dns_stream_connection_fail(manager->session,
+ return pl_dns_stream_connection_fail(session,
KR_SELECTION_TCP_CONNECT_TIMEOUT);
case PROTOLAYER_EVENT_CONNECT:
@@ -2074,7 +2052,7 @@ static enum protolayer_event_cb_result pl_dns_stream_event_unwrap(
enum kr_selection_error err = (*baton)
? *(enum kr_selection_error *)baton
: KR_SELECTION_TCP_CONNECT_FAILED;
- return pl_dns_stream_connection_fail(manager->session, err);
+ return pl_dns_stream_connection_fail(session, err);
case PROTOLAYER_EVENT_DISCONNECT:
case PROTOLAYER_EVENT_CLOSE:
@@ -2176,7 +2154,7 @@ static enum protolayer_iter_cb_result pl_dns_stream_unwrap(
}
int status = kr_ok();
- struct session2 *session = ctx->manager->session;
+ struct session2 *session = ctx->session;
struct pl_dns_stream_sess_data *stream_sess = sess_data;
struct wire_buf *wb = ctx->payload.wire_buf;
@@ -2197,14 +2175,14 @@ static enum protolayer_iter_cb_result pl_dns_stream_unwrap(
if (stream_sess->single && stream_sess->produced) {
if (kr_log_is_debug(WORKER, NULL)) {
kr_log_debug(WORKER, "Unexpected extra data from %s\n",
- kr_straddr(ctx->comm.src_addr));
+ kr_straddr(ctx->comm->src_addr));
}
status = KNOT_EMALF;
goto exit;
}
stream_sess->produced = true;
- int ret = worker_submit(session, &ctx->comm, pkt);
+ int ret = worker_submit(session, ctx->comm, pkt);
/* Errors from worker_submit() are intentionally *not* handled
* in order to ensure the entire wire buffer is processed. */
@@ -2240,18 +2218,12 @@ struct sized_iovs {
static enum protolayer_iter_cb_result pl_dns_stream_wrap(
void *sess_data, void *iter_data, struct protolayer_iter_ctx *ctx)
{
- struct pl_dns_stream_iter_data *stream = iter_data;
- struct session2 *s = ctx->manager->session;
-
- if (kr_fails_assert(!stream->sent.mem))
- return protolayer_break(ctx, kr_error(EINVAL));
-
if (ctx->payload.type == PROTOLAYER_PAYLOAD_BUFFER) {
if (kr_fails_assert(ctx->payload.buffer.len <= UINT16_MAX))
return protolayer_break(ctx, kr_error(EMSGSIZE));
const int iovcnt = 2;
- struct sized_iovs *siov = mm_alloc(&s->pool,
+ struct sized_iovs *siov = mm_alloc(&ctx->pool,
sizeof(*siov) + iovcnt * sizeof(struct iovec));
kr_require(siov);
knot_wire_write_u16(siov->nlen, ctx->payload.buffer.len);
@@ -2264,14 +2236,11 @@ static enum protolayer_iter_cb_result pl_dns_stream_wrap(
.iov_len = ctx->payload.buffer.len
};
- stream->sent.mem = siov;
- stream->sent.pool = &s->pool;
-
- ctx->payload = protolayer_iovec(siov->iovs, iovcnt, false);
+ ctx->payload = protolayer_payload_iovec(siov->iovs, iovcnt, false);
return protolayer_continue(ctx);
} else if (ctx->payload.type == PROTOLAYER_PAYLOAD_IOVEC) {
const int iovcnt = 1 + ctx->payload.iovec.cnt;
- struct sized_iovs *siov = mm_alloc(&s->pool,
+ struct sized_iovs *siov = mm_alloc(&ctx->pool,
sizeof(*siov) + iovcnt * sizeof(struct iovec));
kr_require(siov);
@@ -2290,10 +2259,7 @@ static enum protolayer_iter_cb_result pl_dns_stream_wrap(
.iov_len = sizeof(siov->nlen)
};
- stream->sent.mem = siov;
- stream->sent.pool = &s->pool;
-
- ctx->payload = protolayer_iovec(siov->iovs, iovcnt, false);
+ ctx->payload = protolayer_payload_iovec(siov->iovs, iovcnt, false);
return protolayer_continue(ctx);
} else {
kr_assert(false && "Invalid payload");
@@ -2301,7 +2267,7 @@ static enum protolayer_iter_cb_result pl_dns_stream_wrap(
}
}
-static void pl_dns_stream_request_init(struct protolayer_manager *manager,
+static void pl_dns_stream_request_init(struct session2 *session,
struct kr_request *req,
void *sess_data)
{
@@ -2315,13 +2281,13 @@ int worker_init(void)
kr_bindings_register(the_engine->L); // TODO move
/* DNS protocol layers */
- protolayer_globals[PROTOLAYER_PROTOCOL_DNS_DGRAM] = (struct protolayer_globals){
+ protolayer_globals[PROTOLAYER_TYPE_DNS_DGRAM] = (struct protolayer_globals){
.wire_buf_overhead_cb = pl_dns_dgram_wire_buf_overhead,
.wire_buf_max_overhead = KNOT_WIRE_MAX_PKTSIZE,
.unwrap = pl_dns_dgram_unwrap,
.event_unwrap = pl_dns_dgram_event_unwrap
};
- protolayer_globals[PROTOLAYER_PROTOCOL_DNS_UNSIZED_STREAM] = (struct protolayer_globals){
+ protolayer_globals[PROTOLAYER_TYPE_DNS_UNSIZED_STREAM] = (struct protolayer_globals){
.sess_size = sizeof(struct pl_dns_stream_sess_data),
.wire_buf_overhead = KNOT_WIRE_MAX_PKTSIZE,
.sess_init = pl_dns_stream_sess_init,
@@ -2331,19 +2297,17 @@ int worker_init(void)
};
const struct protolayer_globals stream_common = {
.sess_size = sizeof(struct pl_dns_stream_sess_data),
- .iter_size = sizeof(struct pl_dns_stream_iter_data),
.wire_buf_overhead = KNOT_WIRE_MAX_PKTSIZE,
.sess_init = NULL, /* replaced in specific layers below */
- .iter_deinit = pl_dns_stream_iter_deinit,
.unwrap = pl_dns_stream_unwrap,
.wrap = pl_dns_stream_wrap,
.event_unwrap = pl_dns_stream_event_unwrap,
.request_init = pl_dns_stream_request_init
};
- protolayer_globals[PROTOLAYER_PROTOCOL_DNS_MULTI_STREAM] = stream_common;
- protolayer_globals[PROTOLAYER_PROTOCOL_DNS_MULTI_STREAM].sess_init = pl_dns_stream_sess_init;
- protolayer_globals[PROTOLAYER_PROTOCOL_DNS_SINGLE_STREAM] = stream_common;
- protolayer_globals[PROTOLAYER_PROTOCOL_DNS_SINGLE_STREAM].sess_init = pl_dns_single_stream_sess_init;
+ protolayer_globals[PROTOLAYER_TYPE_DNS_MULTI_STREAM] = stream_common;
+ protolayer_globals[PROTOLAYER_TYPE_DNS_MULTI_STREAM].sess_init = pl_dns_stream_sess_init;
+ protolayer_globals[PROTOLAYER_TYPE_DNS_SINGLE_STREAM] = stream_common;
+ protolayer_globals[PROTOLAYER_TYPE_DNS_SINGLE_STREAM].sess_init = pl_dns_single_stream_sess_init;
/* Create main worker. */
the_worker = &the_worker_value;
diff --git a/daemon/zimport.c b/daemon/zimport.c
index 8d395270..30edcaec 100644
--- a/daemon/zimport.c
+++ b/daemon/zimport.c
@@ -98,7 +98,7 @@ static int key_get(char buf[KEY_LEN], const knot_dname_t *name,
char *lf = (char *)knot_dname_lf(name, (uint8_t *)buf);
if (kr_fails_assert(lf && key_p))
return kr_error(EINVAL);
- int len = lf[0];
+ int len = (unsigned char)lf[0];
lf++; // point to start of data
*key_p = lf;
// Check that LF is right-aligned to KNOT_DNAME_MAXLEN in buf.
@@ -282,7 +282,7 @@ do_digest:
// hexdump the hash for logging
char hash_str[digs[i].size * 2 + 1];
for (ssize_t j = 0; j < digs[i].size; ++j)
- sprintf(hash_str + 2*j, "%02x", digs[i].data[j]);
+ (void)sprintf(hash_str + 2*j, "%02x", digs[i].data[j]);
if (!z_import->digests[i].expected) {
kr_log_error(PREFILL, "no ZONEMD found; computed hash: %s\n",
@@ -560,7 +560,7 @@ int zi_zone_import(const zi_config_t config)
if (kr_fails_assert(c && c->zone_file))
return kr_error(EINVAL);
- knot_mm_t *pool = mm_ctx_mempool2(1024 * 1024);
+ knot_mm_t *pool = mm_ctx_mempool2((size_t)1024 * 1024);
zone_import_ctx_t *z_import = mm_calloc(pool, 1, sizeof(*z_import));
if (!z_import) return kr_error(ENOMEM);
z_import->pool = pool;
diff --git a/distro/config/apkg.toml b/distro/config/apkg.toml
index dcf5e5e1..19d4d8be 100644
--- a/distro/config/apkg.toml
+++ b/distro/config/apkg.toml
@@ -10,4 +10,4 @@ signature_url = "https://secure.nic.cz/files/knot-resolver/knot-resolver-{{ vers
version_script = "scripts/upstream-version.sh"
[apkg]
-compat = 2
+compat = 4
diff --git a/distro/pkg/deb/control b/distro/pkg/deb/control
index 55ab26b6..19d95834 100644
--- a/distro/pkg/deb/control
+++ b/distro/pkg/deb/control
@@ -28,47 +28,33 @@ Build-Depends:
libssl-dev,
Homepage: https://www.knot-resolver.cz/
-Package: knot-resolver-manager
+Package: knot-resolver6
Architecture: any
-Provides:
- knot-resolver6,
Depends:
- knot-resolver-core (= ${binary:Version}),
+ adduser,
+ dns-root-data,
python3-aiohttp,
python3-jinja2,
python3-yaml,
supervisor,
- ${misc:Depends},
- ${python3:Depends},
-Recommends:
- python3-prometheus-client,
-Section: python
-Description: caching, DNSSEC-validating DNS resolver - config manager
- Knot Resolver is a caching full resolver implementation written in C and
- LuaJIT, including both a resolver library and a daemon.
- .
- This package contains Knot Resolver Manager - a configuration tool for Knot
- Resolver. The Manager hides the complexity of running several independent
- resolver processes while ensuring zero-downtime reconfiguration with YAML/JSON
- declarative configuration and an optional HTTP API for dynamic changes.
-
-Package: knot-resolver-core
-Architecture: any
-Depends:
- adduser,
- dns-root-data,
systemd,
${misc:Depends},
${shlibs:Depends},
+ ${python3:Depends},
Breaks:
knot-resolver (<< 6),
+ knot-resolver-core (<< 6.0.8),
+ knot-resolver-manager (<< 6.0.8),
Replaces:
knot-resolver (<< 6),
+ knot-resolver-core (<< 6.0.8),
+ knot-resolver-manager (<< 6.0.8),
Recommends:
lua-basexx,
lua-cqueues,
lua-http,
lua-psl,
+ python3-prometheus-client,
Suggests:
knot-resolver-module-http,
Description: caching, DNSSEC-validating DNS resolver - core binaries
@@ -88,12 +74,24 @@ Description: caching, DNSSEC-validating DNS resolver - core binaries
MVCC cache that may be shared). You can start and stop additional
nodes depending on the contention without downtime.
.
- This package contains the core resolver binaries.
+ Knot Resolver Manager hides the complexity of running several independent
+ resolver processes while ensuring zero-downtime reconfiguration with YAML/JSON
+ declarative configuration and an optional HTTP API for dynamic changes.
-Package: knot-resolver-core-dbg
+Package: knot-resolver6-dev
Architecture: any
Depends:
- knot-resolver-core (= ${binary:Version}),
+ knot-resolver6 (= ${binary:Version}),
+ ${misc:Depends}
+ ${shlibs:Depends},
+Section: libdevel
+Description: Knot Resolver development files
+ This package provides the development headers for Knot Resolver.
+
+Package: knot-resolver6-dbg
+Architecture: any
+Depends:
+ knot-resolver6 (= ${binary:Version}),
${misc:Depends}
Recommends: gdb
Section: debug
@@ -102,11 +100,11 @@ Description: Debug symbols for Knot Resolver
This package provides the debug symbols for Knot Resolver needed
for properly debugging errors in Knot Resolver with gdb.
-Package: knot-resolver-module-dnstap
+Package: knot-resolver6-module-dnstap
Architecture: any
Multi-Arch: same
Depends:
- knot-resolver-core (= ${binary:Version}),
+ knot-resolver6 (= ${binary:Version}),
libfstrm0,
libprotobuf-c1,
${misc:Depends},
@@ -122,10 +120,10 @@ Description: dnstap module for Knot Resolver
This package contains dnstap module for logging DNS responses
to a unix socket in dnstap format.
-Package: knot-resolver-module-http
+Package: knot-resolver6-module-http
Architecture: all
Depends:
- knot-resolver-core (= ${binary:Version}),
+ knot-resolver6 (= ${binary:Version}),
libjs-bootstrap,
libjs-d3,
libjs-jquery,
@@ -135,8 +133,6 @@ Depends:
systemd,
${misc:Depends},
${shlibs:Depends},
-Breaks:
- knot-resolver-module-tinyweb (<< 1.1.0~git20160713-1~),
Description: HTTP module for Knot Resolver
The Knot Resolver is a caching full resolver implementation
written in C and LuaJIT, including both a resolver library and a
diff --git a/distro/pkg/deb/knot-resolver-core.manpages b/distro/pkg/deb/knot-resolver-core.manpages
deleted file mode 100644
index f9ca908f..00000000
--- a/distro/pkg/deb/knot-resolver-core.manpages
+++ /dev/null
@@ -1 +0,0 @@
-debian/tmp/usr/share/man/man8/kresd.8*
diff --git a/distro/pkg/deb/knot-resolver-manager.install b/distro/pkg/deb/knot-resolver-manager.install
deleted file mode 100644
index 91068501..00000000
--- a/distro/pkg/deb/knot-resolver-manager.install
+++ /dev/null
@@ -1,4 +0,0 @@
-etc/knot-resolver/config.yaml
-usr/lib/systemd/system/knot-resolver.service
-usr/share/bash-completion/completions/kresctl
-usr/share/fish/completions/kresctl.fish
diff --git a/distro/pkg/deb/knot-resolver6-dev.install b/distro/pkg/deb/knot-resolver6-dev.install
new file mode 100644
index 00000000..d565b386
--- /dev/null
+++ b/distro/pkg/deb/knot-resolver6-dev.install
@@ -0,0 +1,3 @@
+usr/include/libkres/*.h
+usr/lib/*.so
+usr/lib/pkgconfig/libkres.pc
diff --git a/distro/pkg/deb/knot-resolver-module-dnstap.install b/distro/pkg/deb/knot-resolver6-module-dnstap.install
index ae5404e0..ae5404e0 100644
--- a/distro/pkg/deb/knot-resolver-module-dnstap.install
+++ b/distro/pkg/deb/knot-resolver6-module-dnstap.install
diff --git a/distro/pkg/deb/knot-resolver-module-http.install b/distro/pkg/deb/knot-resolver6-module-http.install
index ffa04d01..ffa04d01 100644
--- a/distro/pkg/deb/knot-resolver-module-http.install
+++ b/distro/pkg/deb/knot-resolver6-module-http.install
diff --git a/distro/pkg/deb/knot-resolver-module-http.links b/distro/pkg/deb/knot-resolver6-module-http.links
index 4963c5cb..4963c5cb 100644
--- a/distro/pkg/deb/knot-resolver-module-http.links
+++ b/distro/pkg/deb/knot-resolver6-module-http.links
diff --git a/distro/pkg/deb/knot-resolver-core.dirs b/distro/pkg/deb/knot-resolver6.dirs
index f8981d8d..f8981d8d 100644
--- a/distro/pkg/deb/knot-resolver-core.dirs
+++ b/distro/pkg/deb/knot-resolver6.dirs
diff --git a/distro/pkg/deb/knot-resolver-core.docs b/distro/pkg/deb/knot-resolver6.docs
index 8e919d0c..8e919d0c 100644
--- a/distro/pkg/deb/knot-resolver-core.docs
+++ b/distro/pkg/deb/knot-resolver6.docs
diff --git a/distro/pkg/deb/knot-resolver-core.install b/distro/pkg/deb/knot-resolver6.install
index 1e57ac9b..29d23032 100644
--- a/distro/pkg/deb/knot-resolver-core.install
+++ b/distro/pkg/deb/knot-resolver6.install
@@ -1,34 +1,38 @@
+etc/knot-resolver/config.yaml
usr/lib/*.so.*
-usr/lib/tmpfiles.d/knot-resolver.conf
-usr/lib/knot-resolver/*.so
usr/lib/knot-resolver/*.lua
+usr/lib/knot-resolver/*.so
usr/lib/knot-resolver/kres_modules/bogus_log.so
-usr/lib/knot-resolver/kres_modules/edns_keepalive.so
-usr/lib/knot-resolver/kres_modules/extended_error.so
-usr/lib/knot-resolver/kres_modules/hints.so
-usr/lib/knot-resolver/kres_modules/nsid.so
-usr/lib/knot-resolver/kres_modules/refuse_nord.so
-usr/lib/knot-resolver/kres_modules/stats.so
usr/lib/knot-resolver/kres_modules/daf.lua
usr/lib/knot-resolver/kres_modules/daf/*
usr/lib/knot-resolver/kres_modules/detect_time_jump.lua
usr/lib/knot-resolver/kres_modules/detect_time_skew.lua
usr/lib/knot-resolver/kres_modules/dns64.lua
+usr/lib/knot-resolver/kres_modules/edns_keepalive.so
usr/lib/knot-resolver/kres_modules/experimental_dot_auth.lua
+usr/lib/knot-resolver/kres_modules/extended_error.so
usr/lib/knot-resolver/kres_modules/graphite.lua
+usr/lib/knot-resolver/kres_modules/hints.so
+usr/lib/knot-resolver/kres_modules/nsid.so
usr/lib/knot-resolver/kres_modules/policy.lua
usr/lib/knot-resolver/kres_modules/predict.lua
usr/lib/knot-resolver/kres_modules/prefetch.lua
usr/lib/knot-resolver/kres_modules/prefill.lua
usr/lib/knot-resolver/kres_modules/priming.lua
usr/lib/knot-resolver/kres_modules/rebinding.lua
+usr/lib/knot-resolver/kres_modules/refuse_nord.so
usr/lib/knot-resolver/kres_modules/renumber.lua
usr/lib/knot-resolver/kres_modules/serve_stale.lua
+usr/lib/knot-resolver/kres_modules/stats.so
usr/lib/knot-resolver/kres_modules/ta_sentinel.lua
usr/lib/knot-resolver/kres_modules/ta_signal_query.lua
usr/lib/knot-resolver/kres_modules/ta_update.lua
usr/lib/knot-resolver/kres_modules/view.lua
usr/lib/knot-resolver/kres_modules/watchdog.lua
usr/lib/knot-resolver/kres_modules/workarounds.lua
-usr/sbin/kresd
+usr/lib/systemd/system/knot-resolver.service
+usr/lib/tmpfiles.d/knot-resolver.conf
usr/sbin/kres-cache-gc
+usr/sbin/kresd
+usr/share/bash-completion/completions/kresctl
+usr/share/fish/completions/kresctl.fish
diff --git a/distro/pkg/deb/knot-resolver-manager.links b/distro/pkg/deb/knot-resolver6.links
index c5467e84..c5467e84 100644
--- a/distro/pkg/deb/knot-resolver-manager.links
+++ b/distro/pkg/deb/knot-resolver6.links
diff --git a/distro/pkg/deb/knot-resolver-manager.manpages b/distro/pkg/deb/knot-resolver6.manpages
index a453f7e9..aa59efff 100644
--- a/distro/pkg/deb/knot-resolver-manager.manpages
+++ b/distro/pkg/deb/knot-resolver6.manpages
@@ -1 +1,2 @@
debian/tmp/usr/share/man/man8/kresctl.8*
+debian/tmp/usr/share/man/man8/kresd.8*
diff --git a/distro/pkg/deb/knot-resolver-core.postinst b/distro/pkg/deb/knot-resolver6.postinst
index e9852987..e9852987 100644
--- a/distro/pkg/deb/knot-resolver-core.postinst
+++ b/distro/pkg/deb/knot-resolver6.postinst
diff --git a/distro/pkg/deb/knot-resolver-core.postrm b/distro/pkg/deb/knot-resolver6.postrm
index e5814954..e5814954 100644
--- a/distro/pkg/deb/knot-resolver-core.postrm
+++ b/distro/pkg/deb/knot-resolver6.postrm
diff --git a/distro/pkg/deb/not-installed b/distro/pkg/deb/not-installed
index ceb8f20d..e653609e 100644
--- a/distro/pkg/deb/not-installed
+++ b/distro/pkg/deb/not-installed
@@ -1,6 +1,3 @@
usr/lib/knot-resolver/kres_modules/http/LICENSE
usr/lib/knot-resolver/kres_modules/etcd.lua
-usr/include/libkres/*.h
-usr/lib/*.so
-usr/lib/pkgconfig/libkres.pc
usr/lib/sysusers.d/knot-resolver.conf
diff --git a/distro/pkg/deb/rules b/distro/pkg/deb/rules
index cc925bf0..dff9df6f 100755
--- a/distro/pkg/deb/rules
+++ b/distro/pkg/deb/rules
@@ -10,17 +10,13 @@ export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic -fno-omit-frame-pointer
# package maintainers to append LDFLAGS
export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
-export PYKRES_NAME=knot_resolver
-export PYKRES_DEST=debian/knot-resolver-core/
-export KRES_MANAGER_NAME=knot_resolver_manager
-export KRES_MANAGER_DEST=debian/knot-resolver-manager/
+# include python modules in main package
+export PYKRES_DESTDIR=debian/knot-resolver6/
# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/default.mk
-export ARCH=$(DEB_HOST_GNU_CPU)
-
%:
dh $@ --with python3
@@ -39,16 +35,16 @@ override_dh_auto_build:
-Dc_args="$${CFLAGS}" \
-Dc_link_args="$${LDFLAGS}"
ninja -v -C build_deb
- PYBUILD_NAME="$${PYKRES_NAME}" PYBUILD_DESTDIR="$${PYKRES_DEST}" \
+ PYBUILD_NAME=knot_resolver PYBUILD_DESTDIR="$${PYKRES_DESTDIR}" \
dh_auto_build --buildsystem=pybuild --sourcedirectory build_deb/python
- PYBUILD_NAME="$${KRES_MANAGER_NAME}" PYBUILD_DESTDIR="$${KRES_MANAGER_DEST}" \
+ PYBUILD_NAME=knot_resoolver_manager PYBUILD_DESTDIR="$${PYKRES_DESTDIR}" \
dh_auto_build --buildsystem=pybuild --sourcedirectory manager
override_dh_auto_install:
DESTDIR="${PWD}/debian/tmp" ninja -v -C build_deb install
- PYBUILD_NAME="$${PYKRES_NAME}" PYBUILD_DESTDIR="$${PYKRES_DEST}" \
+ PYBUILD_NAME=knot_resolver PYBUILD_DESTDIR="$${PYKRES_DESTDIR}" \
dh_auto_install --buildsystem=pybuild --sourcedirectory build_deb/python
- PYBUILD_NAME="$${KRES_MANAGER_NAME}" PYBUILD_DESTDIR="$${KRES_MANAGER_DEST}" \
+ PYBUILD_NAME=knot_resolver_manager PYBUILD_DESTDIR="$${PYKRES_DESTDIR}" \
dh_auto_install --buildsystem=pybuild --sourcedirectory manager
install -m 644 -D manager/etc/knot-resolver/config.yaml debian/tmp/etc/knot-resolver/config.yaml
install -m 644 -D manager/shell-completion/client.bash debian/tmp/usr/share/bash-completion/completions/kresctl
@@ -57,8 +53,5 @@ override_dh_auto_install:
override_dh_auto_test:
meson test -C build_deb
-override_dh_missing:
- dh_missing --fail-missing
-
override_dh_strip:
- dh_strip --dbg-package=knot-resolver-core-dbg
+ dh_strip --dbg-package=knot-resolver6-dbg
diff --git a/distro/pkg/rpm/knot-resolver.spec b/distro/pkg/rpm/knot-resolver.spec
index 5fd08f8d..8b30059e 100644
--- a/distro/pkg/rpm/knot-resolver.spec
+++ b/distro/pkg/rpm/knot-resolver.spec
@@ -25,16 +25,11 @@ Source100: kresd-keyblock.asc
BuildRequires: gnupg2
%endif
-%description
-The Knot Resolver is a DNSSEC-enabled caching full resolver implementation
-written in C and LuaJIT, including both a resolver library and a daemon.
-Modular architecture of the library keeps the core tiny and efficient, and
-provides a state-machine like API for extensions.
-
+Provides: knot-resolver6 = %{version}-%{release}
-%package core
-Summary: Caching full DNS Resolver - core binaries
-Conflicts: knot-resolver < 6
+# alpha packaging compat, can be removed around 6.2
+Conflicts: knot-resolver-core
+Conflicts: knot-resolver-manager
# LuaJIT only on these arches
ExclusiveArch: %{arm} aarch64 %{ix86} x86_64
@@ -59,6 +54,19 @@ BuildRequires: python3-devel
Requires: systemd
Requires(post): systemd
+# manager dependencies
+Requires: python3
+Requires: python3-aiohttp
+Requires: supervisor
+%if 0%{?suse_version}
+Requires: python3-PyYAML
+Requires: python3-typing_extensions
+%else
+Requires: python3-pyyaml
+Requires: python3-typing-extensions
+%endif
+Recommends: python3-prometheus_client
+
# dnstap module dependencies
# SUSE is missing protoc-c protobuf compiler
%if "x%{?suse_version}" == "x"
@@ -96,15 +104,21 @@ BuildRequires: python3-setuptools
Requires(pre): shadow
%endif
-%description core
+%description
The Knot Resolver is a DNSSEC-enabled caching full resolver implementation
written in C and LuaJIT, including both a resolver library and a daemon.
Modular architecture of the library keeps the core tiny and efficient, and
provides a state-machine like API for extensions.
+Knot Resolver Manager is a configuration tool for Knot Resolver. The Manager
+hides the complexity of running several independent resolver processes while
+ensuring zero-downtime reconfiguration with YAML/JSON declarative
+configuration and an optional HTTP API for dynamic changes.
+
+
%package devel
Summary: Development headers for Knot Resolver
-Requires: %{name}-core%{?_isa} = %{version}-%{release}
+Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
The package contains development headers for Knot Resolver.
@@ -112,7 +126,7 @@ The package contains development headers for Knot Resolver.
%if "x%{?suse_version}" == "x"
%package module-dnstap
Summary: dnstap module for Knot Resolver
-Requires: %{name}-core = %{version}-%{release}
+Requires: %{name} = %{version}-%{release}
%description module-dnstap
dnstap module for Knot Resolver supports logging DNS responses to a unix socket
@@ -123,7 +137,7 @@ need effectively log all DNS traffic.
%if "x%{?suse_version}" == "x"
%package module-http
Summary: HTTP module for Knot Resolver
-Requires: %{name}-core = %{version}-%{release}
+Requires: %{name} = %{version}-%{release}
%if 0%{?fedora} || 0%{?rhel} > 7
Requires: lua5.1-http
Requires: lua5.1-mmdb
@@ -139,28 +153,6 @@ queries. It can also serve DNS-over-HTTPS, but it is deprecated in favor of
native C implementation, which doesn't require this package.
%endif
-%package -n knot-resolver-manager
-Summary: Configuration tool for Knot Resolver
-Provides: knot-resolver6 = %{version}-%{release}
-Requires: %{name}-core = %{version}-%{release}
-Requires: python3
-Requires: python3-aiohttp
-Requires: supervisor
-%if 0%{?suse_version}
-Requires: python3-PyYAML
-Requires: python3-typing_extensions
-%else
-Requires: python3-pyyaml
-Requires: python3-typing-extensions
-%endif
-Recommends: python3-prometheus_client
-
-%description -n knot-resolver-manager
-Knot Resolver Manager is a configuration tool for Knot Resolver. The Manager
-hides the complexity of running several independent resolver processes while
-ensuring zero-downtime reconfiguration with YAML/JSON declarative
-configuration and an optional HTTP API for dynamic changes.
-
%prep
%if 0%{GPG_CHECK}
export GNUPGHOME=./gpg-keyring
@@ -237,44 +229,48 @@ install -m 644 -D shell-completion/client.fish %{buildroot}%{_datarootdir}/fish/
popd
-%pre core
+%pre
getent group knot-resolver >/dev/null || groupadd -r knot-resolver
getent passwd knot-resolver >/dev/null || useradd -r -g knot-resolver -d %{_sysconfdir}/knot-resolver -s /sbin/nologin -c "Knot Resolver" knot-resolver
-%post core
+%post
# systemd_post macro is not needed for anything (calls systemctl preset)
%tmpfiles_create %{_tmpfilesdir}/knot-resolver.conf
%if "x%{?fedora}" == "x"
/sbin/ldconfig
%endif
-%preun manager
+%preun
%systemd_preun knot-resolver.service
-%postun manager
+%postun
%systemd_postun_with_restart knot-resolver.service
%if "x%{?fedora}" == "x"
/sbin/ldconfig
%endif
-%files core
+%files
%dir %{_pkgdocdir}
%license %{_pkgdocdir}/COPYING
%doc %{_pkgdocdir}/AUTHORS
%doc %{_pkgdocdir}/NEWS
%doc %{_pkgdocdir}/examples
%dir %{_sysconfdir}/knot-resolver
+%config(noreplace) %{_sysconfdir}/knot-resolver/config.yaml
%config(noreplace) %{_sysconfdir}/knot-resolver/root.hints
%{_sysconfdir}/knot-resolver/icann-ca.pem
%attr(750,knot-resolver,knot-resolver) %dir %{_sharedstatedir}/knot-resolver
%attr(640,knot-resolver,knot-resolver) %{_sharedstatedir}/knot-resolver/root.keys
%dir %{_unitdir}/multi-user.target.wants
+%{_unitdir}/knot-resolver.service
%{_unitdir}/multi-user.target.wants/knot-resolver.service
%{_tmpfilesdir}/knot-resolver.conf
%ghost /run/%{name}
%ghost %{_localstatedir}/cache/%{name}
%attr(750,knot-resolver,knot-resolver) %dir %{_libdir}/%{name}
+%{_bindir}/kresctl
+%{_bindir}/knot-resolver
%{_sbindir}/kresd
%{_sbindir}/kres-cache-gc
%{_libdir}/libkres.so.*
@@ -313,6 +309,7 @@ getent passwd knot-resolver >/dev/null || useradd -r -g knot-resolver -d %{_sysc
%{_libdir}/knot-resolver/kres_modules/workarounds.lua
%{python3_sitelib}/knot_resolver.py
%{python3_sitelib}/knot_resolver-*
+%{python3_sitearch}/knot_resolver_manager*
%if 0%{?suse_version}
%pycache_only %{python3_sitelib}/__pycache__/knot_resolver.*
%else
@@ -320,6 +317,8 @@ getent passwd knot-resolver >/dev/null || useradd -r -g knot-resolver -d %{_sysc
%endif
%{_mandir}/man8/kresd.8.gz
%{_mandir}/man8/kresctl.8.gz
+%{_datarootdir}/bash-completion/completions/kresctl
+%{_datarootdir}/fish/completions/kresctl.fish
%files devel
%{_includedir}/libkres
@@ -339,15 +338,6 @@ getent passwd knot-resolver >/dev/null || useradd -r -g knot-resolver -d %{_sysc
%{_libdir}/knot-resolver/kres_modules/prometheus.lua
%endif
-%files -n knot-resolver-manager
-%{python3_sitearch}/knot_resolver_manager*
-%config(noreplace) %{_sysconfdir}/knot-resolver/config.yaml
-%{_unitdir}/knot-resolver.service
-%{_bindir}/kresctl
-%{_bindir}/knot-resolver
-%{_datarootdir}/bash-completion/completions/kresctl
-%{_datarootdir}/fish/completions/kresctl.fish
-
%changelog
* {{ now }} Jakub Ružička <jakub.ruzicka@nic.cz> - {{ version }}-{{ release }}
- upstream package
diff --git a/doc/dev/build.rst b/doc/dev/build.rst
index b6bfd9f4..2e8e7d17 100644
--- a/doc/dev/build.rst
+++ b/doc/dev/build.rst
@@ -92,20 +92,6 @@ The following dependencies are needed to build and run Knot Resolver with core f
"lmdb", "Memory-mapped database for cache"
"GnuTLS", "TLS"
-Additional dependencies are needed to build and run Knot Resolver with ``manager``:
-All dependencies are also listed in `pyproject.toml <https://gitlab.nic.cz/knot/knot-resolver/-/blob/manager/manager/pyproject.toml>`_ which is our authoritative source.
-
-.. csv-table::
- :header: "Requirement", "Notes"
-
- "python3_ >=3.7", "Python language interpreter"
- "Jinja2_", "Template engine for Python"
- "PyYAML_", "YAML framework for Python"
- "aiohttp_", "HTTP Client/Server for Python."
- "prometheus-client_", "Prometheus client for Python"
- "typing-extensions_", "Compatibility module for Python"
-
-
There are also *optional* packages that enable specific functionality in Knot
Resolver:
@@ -168,7 +154,7 @@ You can also configure some :ref:`build-options`, in this case enable ``manager`
.. code-block:: bash
- $ meson build_dir --prefix=/tmp/kr --default-library=static -Dmanager=enabled
+ $ meson build_dir --prefix=/tmp/kr
After that it is possible to build and install Knot Resolver.
@@ -275,7 +261,6 @@ Recommended build options for packagers:
* ``-Dsystemd_files=enabled`` for systemd unit files
* ``-Ddoc=enabled`` for offline documentation (see :ref:`build-html-doc`)
* ``-Dinstall_kresd_conf=enabled`` to install default config file
-* ``-Dmanager=enabled`` to force build of the manager and its features
* ``-Dunit_tests=enabled`` to force build of unit tests
Systemd
@@ -308,6 +293,36 @@ In case you want to have automatically managed DNSSEC trust anchors instead,
set ``-Dmanaged_ta=enabled`` and make sure both ``keyfile_default`` file and
its parent directories are writable by kresd process (after package installation!).
+**********************************
+Installing the manager from source
+**********************************
+
+Additional dependencies are needed to run Knot Resolver with the ``manager``.
+All dependencies are also listed in `pyproject.toml <https://gitlab.nic.cz/knot/knot-resolver/-/blob/master/manager/pyproject.toml>`_ which is our authoritative source.
+
+.. csv-table::
+ :header: "Requirement", "Notes"
+
+ "python3_ >=3.8", "Python language interpreter"
+ "Jinja2_", "Template engine for Python"
+ "PyYAML_", "YAML framework for Python"
+ "aiohttp_", "HTTP Client/Server for Python."
+ "typing-extensions_", "Compatibility module for Python"
+ "prometheus-client_", "Prometheus client for Python (optional)"
+
+
+ You can install the ``manager`` using generated ``setup.py``.
+
+.. code-block:: bash
+
+ cd manager
+ python3 setup.py install
+
+.. tip::
+
+ For development, it is recommended to run the manager using the procedure described in `manager/README.md <https://gitlab.nic.cz/knot/knot-resolver/-/blob/master/manager/README.md>`_.
+
+
************
Docker image
************
diff --git a/lib/cache/api.c b/lib/cache/api.c
index 2143ceef..490f3d1c 100644
--- a/lib/cache/api.c
+++ b/lib/cache/api.c
@@ -529,7 +529,7 @@ static ssize_t stash_rrset(struct kr_cache *cache, const struct kr_query *qry,
goto return_needs_pkt;
const knot_dname_t *encloser = rr->owner; /**< the closest encloser name */
for (int i = 0; i < wild_labels; ++i) {
- encloser = knot_wire_next_label(encloser, NULL);
+ encloser = knot_dname_next_label(encloser);
}
/* Construct the key under which RRs will be stored,
diff --git a/lib/cache/peek.c b/lib/cache/peek.c
index 4b8e4acc..d12031fc 100644
--- a/lib/cache/peek.c
+++ b/lib/cache/peek.c
@@ -174,6 +174,7 @@ int peek_nosync(kr_layer_t *ctx, knot_pkt_t *pkt)
knot_db_val_bound(v), new_ttl);
return ret == kr_ok() ? KR_STATE_DONE : ctx->state;
}
+ default:; // Continue below
}
/* We have to try proving from NSEC*. */
@@ -359,7 +360,7 @@ static int peek_encloser(
/** Name of the closest (provable) encloser. */
const knot_dname_t *clencl_name = qry->sname;
for (int l = sname_labels; l > clencl_labels; --l)
- clencl_name = knot_wire_next_label(clencl_name, NULL);
+ clencl_name = knot_dname_next_label(clencl_name);
/**** 3. source of synthesis checks, in case the next closer name was covered.
**** 3a. We want to query for NSEC* of source of synthesis (SS) or its
diff --git a/lib/dnssec.c b/lib/dnssec.c
index 9f43bb83..77cec796 100644
--- a/lib/dnssec.c
+++ b/lib/dnssec.c
@@ -362,7 +362,7 @@ static int kr_rrset_validate_with_key(kr_rrset_validation_ctx_t *vctx,
const int covered_labels = knot_dname_labels(covered->owner, NULL)
- knot_dname_is_wildcard(covered->owner);
- for (uint16_t i = 0; i < vctx->rrs->len; ++i) {
+ for (size_t i = 0; i < vctx->rrs->len; ++i) {
/* Consider every RRSIG that matches and comes from the same query. */
const knot_rrset_t *rrsig = vctx->rrs->at[i]->rr;
const bool ok = vctx->rrs->at[i]->qry_uid == vctx->qry_uid
diff --git a/lib/dnssec/nsec.c b/lib/dnssec/nsec.c
index d798e3cf..be34d92d 100644
--- a/lib/dnssec/nsec.c
+++ b/lib/dnssec/nsec.c
@@ -81,15 +81,13 @@ static int dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2)
dname_reverse(d1, d1_len, d1_rev_arr);
dname_reverse(d2, d2_len, d2_rev_arr);
- int res = 0;
- while (res == 0 && d1_rev != NULL) {
- res = lf_cmp(d1_rev, d2_rev);
- d1_rev = knot_wire_next_label(d1_rev, NULL);
- d2_rev = knot_wire_next_label(d2_rev, NULL);
- }
-
- kr_require(res != 0 || d2_rev == NULL);
- return res;
+ do {
+ int res = lf_cmp(d1_rev, d2_rev);
+ if (res != 0 || d1_rev[0] == '\0')
+ return res;
+ d1_rev = knot_dname_next_label(d1_rev);
+ d2_rev = knot_dname_next_label(d2_rev);
+ } while (true);
}
@@ -251,7 +249,7 @@ int kr_nsec_negative(const ranked_rr_array_t *rrrs, uint32_t qry_uid,
ssynth[1] = '*';
const knot_dname_t *clencl = sname;
for (int l = sname_labels; l > clencl_labels; --l)
- clencl = knot_wire_next_label(clencl, NULL);
+ clencl = knot_dname_next_label(clencl);
(void)!!knot_dname_store(&ssynth[2], clencl);
// Try to (dis)prove the source of synthesis by a covering or matching NSEC.
diff --git a/lib/dnssec/nsec3.c b/lib/dnssec/nsec3.c
index 4199f25f..4ff27500 100644
--- a/lib/dnssec/nsec3.c
+++ b/lib/dnssec/nsec3.c
@@ -143,7 +143,7 @@ static int closest_encloser_match(int *flags, const knot_rrset_t *nsec3,
goto fail;
}
- const knot_dname_t *encloser = knot_wire_next_label(name, NULL);
+ const knot_dname_t *encloser = knot_dname_next_label(name);
*skipped = 1;
/* Avoid doing too much work on SHA1, mitigating:
@@ -154,7 +154,7 @@ static int closest_encloser_match(int *flags, const knot_rrset_t *nsec3,
const int max_labels = knot_dname_labels(nsec3->owner, NULL) - 1
+ kr_nsec3_max_depth(&params);
for (int l = knot_dname_labels(encloser, NULL); l > max_labels; --l) {
- encloser = knot_wire_next_label(encloser, NULL);
+ encloser = knot_dname_next_label(encloser);
++(*skipped);
}
@@ -174,7 +174,7 @@ static int closest_encloser_match(int *flags, const knot_rrset_t *nsec3,
if (!encloser[0])
break;
- encloser = knot_wire_next_label(encloser, NULL);
+ encloser = knot_dname_next_label(encloser);
++(*skipped);
}
@@ -404,7 +404,7 @@ static int closest_encloser_proof(const knot_pkt_t *pkt,
for (unsigned j = 0; j < skipped; ++j) {
if (kr_fails_assert(next_closer[0]))
return kr_error(EINVAL);
- next_closer = knot_wire_next_label(next_closer, NULL);
+ next_closer = knot_dname_next_label(next_closer);
}
for (unsigned j = 0; j < sec->count; ++j) {
const knot_rrset_t *rrset_j = knot_pkt_rr(sec, j);
@@ -425,7 +425,7 @@ static int closest_encloser_proof(const knot_pkt_t *pkt,
if ((flags & FLG_CLOSEST_PROVABLE_ENCLOSER) && (flags & FLG_NAME_COVERED) && next_closer) {
if (encloser_name && next_closer[0])
- *encloser_name = knot_wire_next_label(next_closer, NULL);
+ *encloser_name = knot_dname_next_label(next_closer);
if (matching_encloser_nsec3)
*matching_encloser_nsec3 = matching;
if (covering_next_nsec3)
@@ -569,7 +569,7 @@ int kr_nsec3_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_
for (int i = 0; i < trim_to_next; ++i) {
if (kr_fails_assert(sname[0]))
return kr_error(EINVAL);
- sname = knot_wire_next_label(sname, NULL);
+ sname = knot_dname_next_label(sname);
}
int flags = 0;
diff --git a/lib/dnssec/signature.c b/lib/dnssec/signature.c
index f80337fe..6e443cf9 100644
--- a/lib/dnssec/signature.c
+++ b/lib/dnssec/signature.c
@@ -224,7 +224,7 @@ static int sign_ctx_add_records(dnssec_sign_ctx_t *ctx, const knot_rrset_t *cove
for (int j = 0; j < trim_labels; ++j) {
if (kr_fails_assert(beginp[0]))
return kr_error(EINVAL);
- beginp = (uint8_t *) knot_wire_next_label(beginp, NULL);
+ beginp = (uint8_t *) knot_dname_next_label(beginp);
if (kr_fails_assert(beginp))
return kr_error(EFAULT);
}
diff --git a/lib/dnssec/ta.c b/lib/dnssec/ta.c
index 67f0a206..6593b2f3 100644
--- a/lib/dnssec/ta.c
+++ b/lib/dnssec/ta.c
@@ -28,9 +28,9 @@ const knot_dname_t * kr_ta_closest(const struct kr_context *ctx, const knot_dnam
kr_require(ctx && name);
if (type == KNOT_RRTYPE_DS && name[0] != '\0') {
/* DS is parent-side record, so the parent name needs to be covered. */
- name = knot_wire_next_label(name, NULL);
+ name = knot_dname_next_label(name);
}
- while (name) {
+ do {
struct kr_context *ctx_nc = (struct kr_context *)/*const-cast*/ctx;
if (kr_ta_get(ctx_nc->trust_anchors, name)) {
return name;
@@ -38,9 +38,12 @@ const knot_dname_t * kr_ta_closest(const struct kr_context *ctx, const knot_dnam
if (kr_ta_get(ctx_nc->negative_anchors, name)) {
return NULL;
}
- name = knot_wire_next_label(name, NULL);
- }
- return NULL;
+ if (name[0] == '\0') {
+ return NULL;
+ } else {
+ name = knot_dname_next_label(name);
+ }
+ } while (true);
}
/* @internal Create DS from DNSKEY, caller MUST free dst if successful. */
diff --git a/lib/generic/array.h b/lib/generic/array.h
index 9f351189..9bea546b 100644
--- a/lib/generic/array.h
+++ b/lib/generic/array.h
@@ -113,7 +113,7 @@ static inline void array_std_free(void *baton, void *p)
* Mempool usage: pass kr_memreserve and a knot_mm_t* .
* @return 0 if success, <0 on failure */
#define array_reserve_mm(array, n, reserve, baton) \
- (reserve)((baton), (void **) &(array).at, sizeof((array).at[0]), (n), &(array).cap)
+ (reserve)((baton), (void **) &(array).at, array_member_size((array)), (n), &(array).cap)
/**
* Push value at the end of the array, resize it if necessary.
@@ -122,9 +122,9 @@ static inline void array_std_free(void *baton, void *p)
* @return element index on success, <0 on failure
*/
#define array_push_mm(array, val, reserve, baton) \
- (int)((array).len < (array).cap ? ((array).at[(array).len] = val, (array).len++) \
+ (int)((array).len < (array).cap ? ((array).at[(array).len] = (val), (array).len++) \
: (array_reserve_mm(array, ((array).cap + 1), reserve, baton) < 0 ? -1 \
- : ((array).at[(array).len] = val, (array).len++)))
+ : ((array).at[(array).len] = (val), (array).len++)))
/**
* Push value at the end of the array, resize it if necessary (plain malloc/free).
@@ -152,6 +152,12 @@ static inline void array_std_free(void *baton, void *p)
* @warning Undefined if the array is empty.
*/
#define array_tail(array) \
- (array).at[(array).len - 1]
+ (array).at[(array).len - 1]
+
+/**
+ * Return the size of a singular member in the array.
+ */
+#define array_member_size(array) \
+ (sizeof((array).at[0])) // NOLINT(bugprone-sizeof-expression): usually a false-positive
/** @} */
diff --git a/lib/generic/lru.h b/lib/generic/lru.h
index 448c1b92..1c1dd81a 100644
--- a/lib/generic/lru.h
+++ b/lib/generic/lru.h
@@ -130,7 +130,10 @@
#define lru_get_new(table, key_, len_, is_new) \
(__typeof__((table)->pdata_t)) \
lru_get_impl(&(table)->lru, (key_), (len_), \
- sizeof(*(table)->pdata_t), true, is_new)
+ lru_member_size((table)), true, is_new)
+
+#define lru_member_size(table) \
+ (sizeof(*(table)->pdata_t)) // NOLINT(bugprone-sizeof-expression): usually a false-positive
/**
* @brief Apply a function to every item in LRU.
diff --git a/lib/generic/queue.c b/lib/generic/queue.c
index 5bed153e..29609dd2 100644
--- a/lib/generic/queue.c
+++ b/lib/generic/queue.c
@@ -62,7 +62,7 @@ void * queue_push_impl(struct queue *q)
if (t->begin * 2 >= t->cap) {
/* Utilization is below 50%, so let's shift (no overlap).
* (size_t cast is to avoid unintended sign-extension) */
- memcpy(t->data, t->data + t->begin * q->item_size,
+ memcpy(t->data, t->data + t->begin * (size_t)q->item_size,
(size_t) (t->end - t->begin) * (size_t) q->item_size);
t->end -= t->begin;
t->begin = 0;
@@ -76,7 +76,7 @@ void * queue_push_impl(struct queue *q)
kr_require(t->end < t->cap);
++(q->len);
++(t->end);
- return t->data + q->item_size * (t->end - 1);
+ return t->data + (size_t)q->item_size * (t->end - 1);
}
/* Return pointer to the space for the new element. */
@@ -98,8 +98,8 @@ void * queue_push_head_impl(struct queue *q)
* Computations here are simplified due to h->begin == 0.
* (size_t cast is to avoid unintended sign-extension) */
const int cnt = h->end;
- memcpy(h->data + (h->cap - cnt) * q->item_size, h->data,
- (size_t) cnt * (size_t) q->item_size);
+ memcpy(h->data + ((size_t)h->cap - cnt) * q->item_size, h->data,
+ (size_t)cnt * (size_t)q->item_size);
h->begin = h->cap - cnt;
h->end = h->cap;
} else {
@@ -113,7 +113,7 @@ void * queue_push_head_impl(struct queue *q)
kr_require(h->begin > 0);
--(h->begin);
++(q->len);
- return h->data + q->item_size * h->begin;
+ return h->data + (size_t)q->item_size * h->begin;
}
void queue_pop_impl(struct queue *q)
diff --git a/lib/generic/queue.h b/lib/generic/queue.h
index 3fa52cea..fc2a86f3 100644
--- a/lib/generic/queue.h
+++ b/lib/generic/queue.h
@@ -71,7 +71,7 @@
/** @brief Initialize a queue. You can malloc() it the usual way. */
#define queue_init(q) do { \
(void)(((__typeof__(((q).pdata_t)))0) == (void *)0); /* typecheck queue_t */ \
- queue_init_impl(&(q).queue, sizeof(*(q).pdata_t)); \
+ queue_init_impl(&(q).queue, queue_member_size((q))); \
} while (false)
/** @brief De-initialize a queue: make it invalid and free any inner allocations. */
@@ -105,6 +105,10 @@
#define queue_len(q) \
((const size_t)(q).queue.len)
+/** @brief Return the size of a single element in the queue. */
+#define queue_member_size(q) \
+ (sizeof(*(q).pdata_t)) // NOLINT(bugprone-sizeof-expression): usually a false-positive
+
/** @brief Type for queue iterator, parametrized by value type.
* It's a simple structure that owns no other resources.
diff --git a/lib/generic/trie.c b/lib/generic/trie.c
index f9aceda7..21254eb4 100644
--- a/lib/generic/trie.c
+++ b/lib/generic/trie.c
@@ -470,6 +470,10 @@ static int ns_longer_alloc(nstack_t *ns)
memcpy(st, ns->stack, ns->len * sizeof(node_t *));
} else {
st = realloc(ns->stack, new_size);
+ if (st == NULL) {
+ free(ns->stack); // left behind by realloc, callers bail out
+ ns->stack = NULL;
+ }
}
if (st == NULL)
return KNOT_ENOMEM;
diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c
index 4eacf86f..6f312ca7 100644
--- a/lib/layer/iterate.c
+++ b/lib/layer/iterate.c
@@ -51,7 +51,7 @@ static const knot_dname_t *minimized_qname(struct kr_query *query, uint16_t *qty
int cut_labels = knot_dname_labels(query->zone_cut.name, NULL);
int qname_labels = knot_dname_labels(qname, NULL);
while(qname[0] && qname_labels > cut_labels + 1) {
- qname = knot_wire_next_label(qname, NULL);
+ qname = knot_dname_next_label(qname);
qname_labels -= 1;
}
diff --git a/lib/layer/validate.c b/lib/layer/validate.c
index 3bdb205c..af20b2e4 100644
--- a/lib/layer/validate.c
+++ b/lib/layer/validate.c
@@ -709,7 +709,7 @@ static int check_validation_result(kr_layer_t *ctx, const knot_pkt_t *pkt, ranke
invalid_entry = entry;
break;
} else if (kr_rank_test(entry->rank, KR_RANK_MISSING) &&
- !invalid_entry) {
+ !invalid_entry) { // NOLINT(bugprone-branch-clone)
invalid_entry = entry;
} else if (kr_rank_test(entry->rank, KR_RANK_OMIT)) {
continue;
diff --git a/lib/log.c b/lib/log.c
index fa536036..f4244918 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -126,7 +126,7 @@ void kr_log_fmt(enum kr_log_group group, kr_log_level_t level, const char *file,
}
va_start(args, fmt);
- vfprintf(stream, fmt, args);
+ (void)vfprintf(stream, fmt, args);
va_end(args);
}
}
diff --git a/lib/meson.build b/lib/meson.build
index d8cbf1fa..60988f02 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -23,6 +23,7 @@ libkres_src = files([
'layer/iterate.c',
'layer/validate.c',
'log.c',
+ 'proto.c',
'rules/api.c',
'rules/defaults.c',
'rules/forward.c',
@@ -60,6 +61,7 @@ libkres_headers = files([
'layer/iterate.h',
'log.h',
'module.h',
+ 'proto.h',
'resolve.h',
'resolve-impl.h',
'rplan.h',
diff --git a/lib/proto.c b/lib/proto.c
new file mode 100644
index 00000000..cf12e94e
--- /dev/null
+++ b/lib/proto.c
@@ -0,0 +1,19 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "lib/proto.h"
+
+const char *kr_proto_name(enum kr_proto p)
+{
+ switch (p) {
+ case KR_PROTO_INTERNAL:
+ return "INTERNAL";
+#define XX(cid, vid, name) case KR_PROTO_##cid: \
+ return (name);
+ KR_PROTO_MAP(XX)
+#undef XX
+ default:
+ return "(default)";
+ }
+}
diff --git a/lib/proto.h b/lib/proto.h
new file mode 100644
index 00000000..875fe8e3
--- /dev/null
+++ b/lib/proto.h
@@ -0,0 +1,53 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+#pragma once
+
+#include <stdint.h>
+
+#include "lib/defines.h"
+
+/** DNS transport protocol map
+ *
+ * This macro is used to generate `enum kr_proto` as well as other additional
+ * data on protocols, like name string constants.
+ *
+ * It defines DNS transport protocols for use by `session2` (to define sequences
+ * of protocol layers) and `rules` (to filter requests based on them). To find
+ * out more, see the individual usages.
+ *
+ * Parameters for XX are:
+ * 1. Constant name (for e.g. KR_PROTO_* enum value identifiers)
+ * 2. Variable name (for e.g. kr_proto_* array identifiers, like those defined
+ * in `session2.c`)
+ * 3. Human-readable name for logging */
+#define KR_PROTO_MAP(XX) \
+ XX(UDP53, udp53, "DNS UDP") \
+ XX(TCP53, tcp53, "DNS TCP") \
+ XX(DOT, dot, "DNS-over-TLS") \
+ XX(DOH, doh, "DNS-over-HTTPS") \
+ XX(DOQ, doq, "DNS-over-QUIC") /* unused for now */ \
+ //
+
+/** DNS protocol set - mutually exclusive options, contrary to
+ * kr_request_qsource_flags
+ *
+ * The XDP flag is not discerned here, as it could apply to any protocol. (Not
+ * right now, but libknot does support it for TCP, so that would complete
+ * everything)
+ */
+enum kr_proto {
+ KR_PROTO_INTERNAL = 0, /// no protocol, e.g. useful to mark internal requests
+#define XX(cid, vid, name) KR_PROTO_ ## cid,
+ KR_PROTO_MAP(XX)
+#undef XX
+ KR_PROTO_COUNT,
+};
+
+/** Gets the constant string name of the specified transport protocol. */
+KR_EXPORT
+const char *kr_proto_name(enum kr_proto p);
+
+/** Bitmap of enum kr_proto options. */
+typedef uint8_t kr_proto_set;
+static_assert(sizeof(kr_proto_set) * 8 >= KR_PROTO_COUNT, "bad combination of type sizes");
diff --git a/lib/resolve-produce.c b/lib/resolve-produce.c
index d9bec433..563a2ca2 100644
--- a/lib/resolve-produce.c
+++ b/lib/resolve-produce.c
@@ -72,7 +72,7 @@ static void check_empty_nonterms(struct kr_query *qry, knot_pkt_t *pkt, struct k
* otherwise this would risk leaking information to parent if the NODATA TTD > zone cut TTD. */
int labels = knot_dname_labels(target, NULL) - knot_dname_labels(cut_name, NULL);
while (target[0] && labels > 2) {
- target = knot_wire_next_label(target, NULL);
+ target = knot_dname_next_label(target);
--labels;
}
for (int i = 0; i < labels; ++i) {
@@ -84,7 +84,7 @@ static void check_empty_nonterms(struct kr_query *qry, knot_pkt_t *pkt, struct k
break;
}
kr_assert(target[0]);
- target = knot_wire_next_label(target, NULL);
+ target = knot_dname_next_label(target);
}
kr_cache_commit(cache);
#endif
@@ -277,7 +277,7 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query
int cut_labels = knot_dname_labels(qry->zone_cut.name, NULL);
int wanted_name_labels = knot_dname_labels(wanted_name, NULL);
while (wanted_name[0] && wanted_name_labels > cut_labels + name_offset) {
- wanted_name = knot_wire_next_label(wanted_name, NULL);
+ wanted_name = knot_dname_next_label(wanted_name);
wanted_name_labels -= 1;
}
minimized = (wanted_name != qry->sname);
@@ -508,11 +508,11 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot
const knot_dname_t *parent = qry->parent->zone_cut.name;
if (parent[0] != '\0'
&& knot_dname_in_bailiwick(qry->sname, parent) >= 0) {
- requested_name = knot_wire_next_label(parent, NULL);
+ requested_name = knot_dname_next_label(parent);
}
- } else if ((qry->stype == KNOT_RRTYPE_DS) && (qry->sname[0] != '\0')) {
+ } else if ((qry->stype == KNOT_RRTYPE_DS) && (requested_name[0] != '\0')) {
/* If this is explicit DS query, start from encloser too. */
- requested_name = knot_wire_next_label(requested_name, NULL);
+ requested_name = knot_dname_next_label(requested_name);
}
int state = KR_STATE_FAIL;
@@ -521,7 +521,8 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot
if (state == KR_STATE_DONE || (state & KR_STATE_FAIL)) {
return state;
} else if (state == KR_STATE_CONSUME) {
- requested_name = knot_wire_next_label(requested_name, NULL);
+ kr_require(requested_name[0] != '\0');
+ requested_name = knot_dname_next_label(requested_name);
}
} while (state == KR_STATE_CONSUME);
diff --git a/lib/resolve.c b/lib/resolve.c
index e8a63489..ec00b215 100644
--- a/lib/resolve.c
+++ b/lib/resolve.c
@@ -715,6 +715,8 @@ int kr_resolve_consume(struct kr_request *request, struct kr_transport **transpo
if (transport && !qry->flags.CACHED) {
if (!(request->state & KR_STATE_FAIL)) {
/* Do not complete NS address resolution on soft-fail. */
+ if (kr_fails_assert(packet->wire))
+ return KR_STATE_FAIL;
const int rcode = knot_wire_get_rcode(packet->wire);
if (rcode != KNOT_RCODE_SERVFAIL && rcode != KNOT_RCODE_REFUSED) {
qry->flags.AWAIT_IPV6 = false;
@@ -748,7 +750,7 @@ int kr_resolve_consume(struct kr_request *request, struct kr_transport **transpo
}
/* Pop query if resolved. */
- if (request->state == KR_STATE_YIELD) {
+ if (request->state == KR_STATE_YIELD) { // NOLINT(bugprone-branch-clone)
return KR_STATE_PRODUCE; /* Requery */
} else if (qry->flags.RESOLVED) {
kr_rplan_pop(rplan, qry);
@@ -931,6 +933,7 @@ int kr_resolve_finish(struct kr_request *request, int state)
knot_wire_clear_ad(wire);
knot_wire_clear_aa(wire);
knot_wire_set_rcode(wire, KNOT_RCODE_SERVFAIL);
+ default:; // Do nothing
}
}
}
diff --git a/lib/rules/api.c b/lib/rules/api.c
index ca026879..8e908a7a 100644
--- a/lib/rules/api.c
+++ b/lib/rules/api.c
@@ -91,7 +91,7 @@ int kr_rule_tag_add(const char *tag, kr_rule_tags_t *tagset)
kr_log_error(RULES, "ERROR: invalid length: %d\n", (int)val.len);
return kr_error(EILSEQ);
}
- *tagset |= (1 << *tindex_p);
+ *tagset |= ((kr_rule_tags_t)1 << *tindex_p);
return kr_ok();
} else if (ret != kr_error(ENOENT)) {
return ret;
@@ -114,7 +114,7 @@ int kr_rule_tag_add(const char *tag, kr_rule_tags_t *tagset)
int ix = ffsll(~bmp) - 1;
if (ix < 0 || ix >= 8 * sizeof(bmp))
return kr_error(E2BIG);
- const kr_rule_tags_t tag_new = 1 << ix;
+ const kr_rule_tags_t tag_new = (kr_rule_tags_t)1 << ix;
kr_require((tag_new & bmp) == 0);
// Update the bitmap. ATM ruledb does not overwrite, so we `remove` before `write`.
@@ -158,7 +158,7 @@ int kr_rules_init(const char *path, size_t maxsize)
// Later we might improve it to auto-resize in case of running out of space.
// Caveat: mdb_env_set_mapsize() can only be called without transactions open.
.maxsize = maxsize ? maxsize :
- (sizeof(size_t) > 4 ? 2048 : 500) * 1024*(size_t)1024,
+ (size_t)(sizeof(size_t) > 4 ? 2048 : 500) * 1024*1024,
};
int ret = the_rules->api->open(&the_rules->db, &the_rules->stats, &opts, NULL);
/* No persistence - we always refill from config for now.
@@ -848,8 +848,8 @@ static int subnet_encode(const struct sockaddr *addr, int sub_len, uint8_t buf[3
uint16_t x = a[i] * 85; // interleave by zero bits
uint8_t sub_mask = 255 >> (8 - MIN(sub_len, 8));
uint16_t r = x | (sub_mask * 85 * 2);
- buf[2*i] = r / 256;
- buf[2*i + 1] = r % 256;
+ buf[(ssize_t)2*i] = r / 256;
+ buf[(ssize_t)2*i + 1] = r % 256;
}
return i * 2;
}
@@ -870,9 +870,9 @@ bool subnet_is_prefix(uint8_t a, uint8_t b)
}
#define KEY_PREPEND(key, arr) do { \
- key.data -= sizeof(arr); \
- key.len += sizeof(arr); \
- memcpy(key.data, arr, sizeof(arr)); \
+ (key).data -= sizeof(arr); \
+ (key).len += sizeof(arr); \
+ memcpy((key).data, arr, sizeof(arr)); \
} while (false)
int kr_view_insert_action(const char *subnet, const char *dst_subnet,
diff --git a/lib/rules/api.h b/lib/rules/api.h
index bf51e4d5..1069ef4d 100644
--- a/lib/rules/api.h
+++ b/lib/rules/api.h
@@ -4,6 +4,7 @@
#pragma once
#include "lib/defines.h"
+#include "lib/proto.h"
struct kr_query;
struct kr_request;
struct knot_pkt;
@@ -16,27 +17,6 @@ typedef uint64_t kr_rule_tags_t;
/// Tags "capacity", i.e. numbered from 0 to _CAP - 1.
#define KR_RULE_TAGS_CAP (sizeof(kr_rule_tags_t) * 8)
-/** DNS protocol set - mutually exclusive options, contrary to kr_request_qsource_flags
- *
- * The XDP flag is not discerned here, as it could apply to any protocol.
- * (not right now, but libknot does support it for TCP, so that would complete everything)
- *
- * TODO: probably unify with enum protolayer_grp.
- */
-enum kr_proto {
- KR_PROTO_INTERNAL = 0, /// no protocol, e.g. useful to mark internal requests
- KR_PROTO_UDP53,
- KR_PROTO_TCP53,
- KR_PROTO_DOT,
- KR_PROTO_DOH,
- KR_PROTO_DOQ, /// unused for now
- KR_PROTO_COUNT,
-};
-/** Bitmap of enum kr_proto options. */
-typedef uint8_t kr_proto_set;
-static_assert(sizeof(kr_proto_set) * 8 >= KR_PROTO_COUNT, "bad combination of type sizes");
-
-
/** Open the rule DB.
*
* You can call this to override the path or size (NULL/0 -> default).
diff --git a/lib/rules/forward.c b/lib/rules/forward.c
index 12ad14d5..ef2cf9da 100644
--- a/lib/rules/forward.c
+++ b/lib/rules/forward.c
@@ -95,7 +95,7 @@ int kr_rule_data_src_check(struct kr_query *qry, struct knot_pkt *pkt)
const knot_dname_t *apex = qry->sname;
for (int labels = knot_dname_labels(apex, NULL);
labels > qry->data_src.rule_depth;
- --labels, apex = knot_wire_next_label(apex, NULL));
+ --labels, apex = knot_dname_next_label(apex));
kr_zonecut_set(&qry->zone_cut, apex);
qry->zone_cut.avoid_resolving = true;
knot_db_val_t targets = qry->data_src.targets_ptr;
diff --git a/lib/rules/local-addr.c b/lib/rules/local-addr.c
index 787639df..cd5d456b 100644
--- a/lib/rules/local-addr.c
+++ b/lib/rules/local-addr.c
@@ -67,7 +67,7 @@ static const knot_dname_t * raw_addr2reverse(const uint8_t *raw_addr, int family
#undef REV_MAXLEN
if (family == AF_INET) {
- snprintf(reverse_addr, sizeof(reverse_addr),
+ (void)snprintf(reverse_addr, sizeof(reverse_addr),
"%d.%d.%d.%d.in-addr.arpa.",
raw_addr[3], raw_addr[2], raw_addr[1], raw_addr[0]);
} else if (family == AF_INET6) {
diff --git a/lib/rules/zonefile.c b/lib/rules/zonefile.c
index cfd2bc27..d308f375 100644
--- a/lib/rules/zonefile.c
+++ b/lib/rules/zonefile.c
@@ -50,7 +50,8 @@ static void rr_scan2trie(zs_scanner_t *s)
knot_rrset_init(rr, NULL, s->r_type, KNOT_CLASS_IN, s->r_ttl);
// we don't ^^ need owner so save allocation
}
- knot_rrset_add_rdata(rr, s->r_data, s->r_data_length, s_data->pool);
+ int ret = knot_rrset_add_rdata(rr, s->r_data, s->r_data_length, s_data->pool);
+ kr_assert(!ret);
}
/// Process an RRset of other types into a rule
static int rr_trie2rule(const char *key_data, uint32_t key_len, trie_val_t *rr_p, void *config)
@@ -202,6 +203,7 @@ static void process_record(zs_scanner_t *s)
KR_RRTYPE_GET_STR(type_str, s->r_type);
kr_log_warning(RULES, "skipping unsupported RR type %s\n", type_str);
return;
+ default:; // Continue below
}
if (knot_rrtype_is_metatype(s->r_type))
goto unsupported_type;
@@ -244,7 +246,7 @@ int kr_rule_zonefile(const struct kr_rule_zonefile_config *c)
s_data_t s_data = { 0 };
s_data.c = c;
- s_data.pool = mm_ctx_mempool2(64 * 1024);
+ s_data.pool = mm_ctx_mempool2((size_t)64 * 1024);
s_data.rrs = trie_create(s_data.pool);
ret = zs_set_processing(s, process_record, NULL, &s_data);
if (kr_fails_assert(ret == 0))
diff --git a/lib/selection.c b/lib/selection.c
index ea3a85ae..9cdd1a60 100644
--- a/lib/selection.c
+++ b/lib/selection.c
@@ -149,7 +149,7 @@ struct rtt_state get_rtt_state(const uint8_t *ip, size_t len,
knot_db_val_t key = cache_key(ip, len);
- if (cache->api->read(db, stats, &key, &value, 1)) {
+ if (cache->api->read(db, stats, &key, &value, 1)) { // NOLINT(bugprone-branch-clone)
state = default_rtt_state;
} else if (kr_fails_assert(value.len == sizeof(struct rtt_state))) {
// shouldn't happen but let's be more robust
diff --git a/lib/utils.c b/lib/utils.c
index 6d215760..04b1bcb9 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -955,9 +955,8 @@ int kr_ranked_rrarray_add(ranked_rr_array_t *array, const knot_rrset_t *rr,
static int rdata_p_cmp(const void *rp1, const void *rp2)
{
/* Just correct types of the parameters and pass them dereferenced. */
- const knot_rdata_t
- *const *r1 = rp1,
- *const *r2 = rp2;
+ const knot_rdata_t *const *r1 = (const knot_rdata_t *const *)rp1;
+ const knot_rdata_t *const *r2 = (const knot_rdata_t *const *)rp2;
return knot_rdata_cmp(*r1, *r2);
}
int kr_ranked_rrarray_finalize(ranked_rr_array_t *array, uint32_t qry_uid, knot_mm_t *pool)
@@ -982,7 +981,7 @@ int kr_ranked_rrarray_finalize(ranked_rr_array_t *array, uint32_t qry_uid, knot_
} else {
/* Multiple RRs; first: sort the array. */
stashed->rr->additional = NULL;
- qsort(ra->at, ra->len, sizeof(ra->at[0]), rdata_p_cmp);
+ qsort((void *)ra->at, ra->len, array_member_size(*ra), rdata_p_cmp);
/* Prune duplicates: NULL all except the last instance. */
int dup_count = 0;
for (int i = 0; i + 1 < ra->len; ++i) {
diff --git a/lib/utils.h b/lib/utils.h
index 8f84fc46..9fdc2d48 100644
--- a/lib/utils.h
+++ b/lib/utils.h
@@ -618,4 +618,10 @@ static inline size_t kr_dname_prefixlen(const uint8_t *name, unsigned nlabels)
#endif
);
}
+#if KNOT_VERSION_HEX < 0x030400
+static inline const knot_dname_t * knot_dname_next_label(const knot_dname_t *dname)
+{
+ return knot_wire_next_label(dname, NULL);
+}
+#endif
diff --git a/lib/zonecut.c b/lib/zonecut.c
index 2bbd26fc..aea38e46 100644
--- a/lib/zonecut.c
+++ b/lib/zonecut.c
@@ -580,7 +580,7 @@ int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut,
trie_clear(cut->nsset);
/* Subtract label from QNAME. */
if (!is_root) {
- label = knot_wire_next_label(label, NULL);
+ label = knot_dname_next_label(label);
} else {
ret = kr_error(ENOENT);
break;
diff --git a/manager/README.md b/manager/README.md
index 805a563e..7f323337 100644
--- a/manager/README.md
+++ b/manager/README.md
@@ -32,9 +32,10 @@ Please note that Python's development files are also required, since the Manager
### Common tasks and interactions with the project
-After setting up the environment, you should be able to interract with the project by using `./poe` script. Common actions are:
+After setting up the environment, you should be able to interact with the project by using the `./poe` script. Common actions are:
-* `poe run` - runs the manager from the source
+* `poe configure` - configures Knot Resolver daemon for use with the manager
+* `poe run` - runs the manager from the source (requires the daemon to be configured)
* `poe docs` - creates HTML documentation
* `poe test` - unit tests
* `poe tox` - unit tests in all supported Python versions (must not be run outside of virtualenv, otherwise it fails to find multiple versions of Python)
diff --git a/manager/knot_resolver_manager/datamodel/templates/dnssec.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/dnssec.lua.j2
index 31a29bea..05d1fa68 100644
--- a/manager/knot_resolver_manager/datamodel/templates/dnssec.lua.j2
+++ b/manager/knot_resolver_manager/datamodel/templates/dnssec.lua.j2
@@ -26,8 +26,10 @@ modules.load('detect_time_skew')
modules.unload('detect_time_skew')
{% endif %}
+{% if cfg.dnssec.keep_removed %}
-- dnssec.keep-removed
trust_anchors.keep_removed = {{ cfg.dnssec.keep_removed }}
+{% endif %}
{% if cfg.dnssec.refresh_time %}
-- dnssec.refresh-time
diff --git a/manager/pyproject.toml b/manager/pyproject.toml
index 3b63350f..1da53a48 100644
--- a/manager/pyproject.toml
+++ b/manager/pyproject.toml
@@ -58,6 +58,7 @@ kresctl = 'knot_resolver_manager.cli.main:main'
knot-resolver = 'knot_resolver_manager.__main__:run'
[tool.poe.tasks]
+configure = { cmd = "scripts/meson-configure", help = "Configure Knot Resolver daemon" }
run = { cmd = "scripts/run", help = "Run the manager" }
run-debug = { cmd = "scripts/run-debug", help = "Run the manager under debugger" }
docs = { cmd = "scripts/docs", help = "Create HTML documentation" }
diff --git a/manager/scripts/_env.sh b/manager/scripts/_env.sh
index ddbbcf55..cabc0025 100644
--- a/manager/scripts/_env.sh
+++ b/manager/scripts/_env.sh
@@ -36,17 +36,23 @@ set -o nounset
function build_kresd {
- echo
- echo Building Knot Resolver
- echo ----------------------
- echo -e "${blue}In case of an compilation error, run this command to try to fix it:${reset}"
- echo -e "\t${blue}rm -r $(realpath .install_kresd) $(realpath .build_kresd)${reset}"
- echo
pushd ..
- mkdir -p manager/.build_kresd manager/.install_kresd
- meson manager/.build_kresd --prefix=$(realpath manager/.install_kresd) --default-library=static --buildtype=debug
- ninja -C manager/.build_kresd
- ninja install -C manager/.build_kresd
- export PYTHONPATH="$(realpath manager/.build_kresd/python):${PYTHONPATH:-}"
+ if [ -d manager/.build_kresd ]; then
+ echo
+ echo Building Knot Resolver
+ echo ----------------------
+ echo -e "${blue}In case of an compilation error, run this command to try to fix it:${reset}"
+ echo -e "\t${blue}rm -r $(realpath .install_kresd) $(realpath .build_kresd)${reset}"
+ echo
+ ninja -C manager/.build_kresd
+ ninja install -C manager/.build_kresd
+ export PYTHONPATH="$(realpath manager/.build_kresd/python):${PYTHONPATH:-}"
+ else
+ echo
+ echo Knot Resolver daemon is not configured.
+ echo "Please run './poe configure' (optionally with additional Meson arguments)"
+ echo
+ exit 2
+ fi
popd
}
diff --git a/manager/scripts/meson-configure b/manager/scripts/meson-configure
new file mode 100755
index 00000000..c99ddea7
--- /dev/null
+++ b/manager/scripts/meson-configure
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# ensure consistent behaviour
+src_dir="$(dirname "$(realpath "$0")")"
+source $src_dir/_env.sh
+
+pushd ..
+meson setup manager/.build_kresd --reconfigure --prefix=$(realpath manager/.install_kresd) "$@"
+popd
+
+build_kresd
diff --git a/meson.build b/meson.build
index 77ca8138..b5158fb1 100644
--- a/meson.build
+++ b/meson.build
@@ -181,6 +181,13 @@ add_project_arguments(
language: 'c',
)
+if meson.get_compiler('c').get_id() == 'gcc'
+ add_project_arguments(
+ '-Wno-nonnull-compare', # reasonable to do in assertions
+ language: 'c',
+ )
+endif
+
# Files for clang-tidy lint
c_src_lint = files()
@@ -255,7 +262,6 @@ subdir('lib')
## Remaining code
subdir('daemon')
subdir('modules')
-subdir('manager')
subdir('python')
subdir('utils')
if get_option('bench') == 'enabled'
@@ -341,7 +347,6 @@ run_target(
# https://github.com/mesonbuild/meson/issues/2404
s_managed_ta = managed_ta ? 'enabled' : 'disabled'
s_install_root_keys = install_root_keys ? 'enabled' : 'disabled'
-s_build_manager = build_manager ? 'enabled' : 'disabled'
s_build_utils = build_utils ? 'enabled' : 'disabled'
s_build_dnstap = build_dnstap ? 'enabled' : 'disabled'
s_build_unit_tests = build_unit_tests ? 'enabled' : 'disabled'
@@ -376,7 +381,6 @@ message('''
cache_dir: @0@'''.format(systemd_cache_dir) + '''
optional components
- manager: @0@'''.format(s_build_manager) + '''
utils: @0@'''.format(s_build_utils) + '''
dnstap: @0@'''.format(s_build_dnstap) + '''
unit_tests: @0@'''.format(s_build_unit_tests) + '''
diff --git a/meson_options.txt b/meson_options.txt
index 428d5aaa..0f404850 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -126,18 +126,6 @@ option(
)
option(
- 'manager',
- type: 'combo',
- choices: [
- 'auto',
- 'enabled',
- 'disabled',
- ],
- value: 'disabled',
- description: 'build manager and its features',
-)
-
-option(
'utils',
type: 'combo',
choices: [
diff --git a/modules/dnstap/dnstap.c b/modules/dnstap/dnstap.c
index ab52bca3..6fcc192c 100644
--- a/modules/dnstap/dnstap.c
+++ b/modules/dnstap/dnstap.c
@@ -193,6 +193,7 @@ static int dnstap_log(kr_layer_t *ctx, enum dnstap_log_phase phase) {
m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
m.has_socket_family = true;
break;
+ default:;
}
}
diff --git a/modules/hints/meson.build b/modules/hints/meson.build
index d5046cb4..7e681f11 100644
--- a/modules/hints/meson.build
+++ b/modules/hints/meson.build
@@ -18,5 +18,5 @@ hints_mod = shared_module(
)
config_tests += [
- ['hints', files('tests/hints.test.lua'), ['skip_asan']],
+ ['hints', files('tests/hints.test.lua')],
]
diff --git a/modules/http/meson.build b/modules/http/meson.build
index 9d20c929..7d892159 100644
--- a/modules/http/meson.build
+++ b/modules/http/meson.build
@@ -21,7 +21,7 @@ lua_mod_src += [
config_tests += [
['http', files('http.test.lua')],
['http.doh', files('http_doh.test.lua')],
- ['http.tls', files('test_tls/tls.test.lua')],
+ ['http.tls', files('test_tls/tls.test.lua'), ['skip_asan']],
]
# install static files
diff --git a/modules/stats/stats.c b/modules/stats/stats.c
index a8a29de2..deed9c94 100644
--- a/modules/stats/stats.c
+++ b/modules/stats/stats.c
@@ -46,8 +46,9 @@
X(answer,aa) X(answer,tc) X(answer,rd) X(answer,ra) X(answer, ad) X(answer,cd) \
X(answer,edns0) X(answer,do) \
X(query,edns) X(query,dnssec) \
- X(request,total) X(request,udp) X(request,tcp) X(request,xdp) \
- X(request,dot) X(request,doh) X(request,internal) \
+ X(request,total) X(request,total4) X(request,total6) X(request,internal) \
+ X(request,udp4) X(request,tcp4) X(request,xdp4) X(request,dot4) X(request,doh4) \
+ X(request,udp6) X(request,tcp6) X(request,xdp6) X(request,dot6) X(request,doh6) \
X(const,end)
enum const_metric {
@@ -72,6 +73,29 @@ static struct const_metric_elm const_metrics[] = {
CONST_METRICS(X)
#undef X
};
+
+/// These metrics are read-only views, each simply summing a pair of const_metrics items.
+struct sum_metric {
+ const char *sub_key;
+ const size_t *val1, *val2;
+};
+static const struct sum_metric sum_metrics[] = {
+ // We're using this to aggregate v4 + v6 pairs.
+ #define DEF(proto) { \
+ .sub_key = #proto, \
+ .val1 = &const_metrics[metric_request_ ## proto ## 4].val, \
+ .val2 = &const_metrics[metric_request_ ## proto ## 6].val, \
+ }
+ DEF(udp),
+ DEF(tcp),
+ DEF(xdp),
+ DEF(dot),
+ DEF(doh),
+ #undef DEF
+};
+static const size_t sum_metrics_len = sizeof(sum_metrics) / sizeof(sum_metrics[0]);
+#define SUM_METRICS_SUP_KEY "request"
+
/** @endcond */
/** @internal LRU hash of most frequent names. */
@@ -125,7 +149,7 @@ static inline int collect_key(char *key, const knot_dname_t *name, uint16_t type
if (key_len < 0) {
return kr_error(key_len);
}
- return key_len + sizeof(type);
+ return key_len + (int)sizeof(type);
}
static void collect_sample(struct stat_data *data, struct kr_rplan *rplan)
@@ -193,19 +217,26 @@ static int collect_transport(kr_layer_t *ctx)
}
/**
- * Count each transport only once,
+ * Apart from the "total" stats, count each transport only once,
* i.e. DoT does not count as TCP and XDP does not count as UDP.
+ * We have two counts for each - IPv6 and IPv4 separately.
*/
+ const bool isIPv6 = req->qsource.addr->sa_family == AF_INET6;
+ #define INC_PROTO(proto) \
+ stat_const_add(data, isIPv6 ? metric_request_ ## proto ## 6 \
+ : metric_request_ ## proto ## 4, 1)
+ INC_PROTO(total);
if (req->qsource.flags.http)
- stat_const_add(data, metric_request_doh, 1);
+ INC_PROTO(doh);
else if (req->qsource.flags.tls)
- stat_const_add(data, metric_request_dot, 1);
+ INC_PROTO(dot);
else if (req->qsource.flags.tcp)
- stat_const_add(data, metric_request_tcp, 1);
+ INC_PROTO(tcp);
else if (req->qsource.flags.xdp)
- stat_const_add(data, metric_request_xdp, 1);
+ INC_PROTO(xdp);
else
- stat_const_add(data, metric_request_udp, 1);
+ INC_PROTO(udp);
+ #undef INC_PROTO
return ctx->state;
}
@@ -282,6 +313,7 @@ static int collect(kr_layer_t *ctx)
* Set nominal value of a key.
*
* Input: { key, val }
+ * Aggregate metrics can't be set.
*
*/
static char* stats_set(void *env, struct kr_module *module, const char *args)
@@ -323,26 +355,36 @@ static char* stats_get(void *env, struct kr_module *module, const char *args)
struct stat_data *data = module->data;
/* Expecting CHAR_BIT to be 8, this is a safe bet */
- char *ret = malloc(3 * sizeof(size_t) + 2);
- if (!ret) {
- return NULL;
- }
+ char *str_value = NULL;
+ int ret = 0;
/* Check if it exists in const map. */
for (unsigned i = 0; i < metric_const_end; ++i) {
if (strcmp(const_metrics[i].key, args) == 0) {
- sprintf(ret, "%zu", const_metrics[i].val);
- return ret;
+ ret = asprintf(&str_value, "%zu", const_metrics[i].val);
+ if (ret < 0)
+ return NULL;
+ return str_value;
+ }
+ }
+ /* Check if it exists in aggregate metrics. */
+ for (int i = 0; i < sum_metrics_len; ++i) {
+ const struct sum_metric *smi = &sum_metrics[i];
+ if (strcmp(smi->sub_key, args) == 0) {
+ ret = asprintf(&str_value, "%zu", *smi->val1 + *smi->val2);
+ if (ret < 0)
+ return NULL;
+ return str_value;
}
}
/* Check in variable map */
trie_val_t *val = trie_get_try(data->trie, args, strlen(args));
- if (!val) {
- free(ret);
+ if (!val)
return NULL;
- }
- sprintf(ret, "%zu", (size_t) *val);
- return ret;
+ ret = asprintf(&str_value, "%zu", (size_t) *val);
+ if (ret < 0)
+ return NULL;
+ return str_value;
}
/** Checks whether:
@@ -360,13 +402,31 @@ struct list_entry_context {
size_t key_prefix_len; /**< Prefix length. Prefix is a wildcard if zero. */
};
+/** Ensures that the `root` node contains an object (and only an object - not a
+ * number, array, or anything else) with the specified `key`. If this cannot be
+ * ensured, fails on an assertion, or returns `NULL` if asserts are disabled. */
+static JsonNode *ensure_object(JsonNode *root, const char *key)
+{
+ JsonNode *node = json_find_member(root, key);
+ if (node) {
+ if (kr_fails_assert(node->tag == JSON_OBJECT))
+ return NULL;
+ } else {
+ node = json_mkobject();
+ if (kr_fails_assert(node))
+ return NULL;
+ json_append_member(root, key, node);
+ }
+ return node;
+}
+
/** Inserts the entry with a matching key into the JSON object. */
static int list_entry(const char *key, uint32_t key_len, trie_val_t *val, void *baton)
{
struct list_entry_context *ctx = baton;
if (!key_matches_prefix(key, key_len, ctx->key_prefix, ctx->key_prefix_len))
return 0;
- size_t number = (size_t) *val;
+ size_t number = (size_t)*val;
uint32_t dot_index = 0;
for (uint32_t i = 0; i < key_len; i++) {
@@ -380,17 +440,13 @@ static int list_entry(const char *key, uint32_t key_len, trie_val_t *val, void *
if (dot_index) {
auto_free char *sup_key_nt = strndup(key, dot_index);
auto_free char *sub_key_nt = strndup(key + dot_index + 1, key_len - dot_index - 1);
- JsonNode *sup = json_find_member(ctx->root, sup_key_nt);
- if (!sup) {
- sup = json_mkobject();
- json_append_member(ctx->root, sup_key_nt, sup);
- }
- if (kr_fails_assert(sup))
+ JsonNode *sup = ensure_object(ctx->root, sup_key_nt);
+ if (!sup)
return 0;
- json_append_member(sup, sub_key_nt, json_mknumber(number));
+ json_append_member(sup, sub_key_nt, json_mknumber((double)number));
} else {
auto_free char *key_nt = strndup(key, key_len);
- json_append_member(ctx->root, key_nt, json_mknumber(number));
+ json_append_member(ctx->root, key_nt, json_mknumber((double)number));
}
return 0;
}
@@ -402,22 +458,36 @@ static int list_entry(const char *key, uint32_t key_len, trie_val_t *val, void *
*/
static char* stats_list(void *env, struct kr_module *module, const char *args)
{
+ char *ret;
JsonNode *root = json_mkobject();
/* Walk const metrics map */
size_t args_len = args ? strlen(args) : 0;
for (unsigned i = 0; i < metric_const_end; ++i) {
struct const_metric_elm *elm = &const_metrics[i];
if (!args || strcmp(elm->sup_key, args) == 0) {
- JsonNode *sup = json_find_member(root, elm->sup_key);
+ JsonNode *sup = ensure_object(root, elm->sup_key);
if (!sup) {
- sup = json_mkobject();
- json_append_member(root, elm->sup_key, sup);
+ ret = strdup("\"ERROR\"");
+ goto exit;
}
- if (kr_fails_assert(sup))
- break;
- json_append_member(sup, elm->sub_key, json_mknumber(elm->val));
+ json_append_member(sup, elm->sub_key, json_mknumber((double)elm->val));
}
}
+
+ /* Walk sum metrics map */
+ JsonNode *sum_sup = ensure_object(root, SUM_METRICS_SUP_KEY);
+ if (!sum_sup) {
+ ret = strdup("\"ERROR\"");
+ goto exit;
+ }
+ for (int i = 0; i < sum_metrics_len; ++i) {
+ const struct sum_metric *elm = &sum_metrics[i];
+ if (!args || strncmp(elm->sub_key, args, args_len) == 0) {
+ size_t val = *elm->val1 + *elm->val2;
+ json_append_member(sum_sup, elm->sub_key, json_mknumber(val));
+ }
+ }
+
struct list_entry_context ctx = {
.root = root,
.key_prefix = args,
@@ -425,7 +495,8 @@ static char* stats_list(void *env, struct kr_module *module, const char *args)
};
struct stat_data *data = module->data;
trie_apply_with_key(data->trie, list_entry, &ctx);
- char *ret = json_encode(root);
+ ret = json_encode(root);
+exit:
json_delete(root);
return ret;
}
diff --git a/tests/config/meson.build b/tests/config/meson.build
index a739222d..dc345a88 100644
--- a/tests/config/meson.build
+++ b/tests/config/meson.build
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
config_tests += [
- ['basic', files('basic.test.lua'), ['skip_asan']],
- ['cache', files('cache.test.lua'), ['skip_asan']],
+ ['basic', files('basic.test.lua')],
+ ['cache', files('cache.test.lua')],
['net', files('net.test.lua'), ['config_net']],
['doh2', files('doh2.test.lua')],
['lru', files('lru.test.lua')],
diff --git a/tests/dnstap/src/dnstap-test/go.mod b/tests/dnstap/src/dnstap-test/go.mod
index 6b650889..2eb72879 100644
--- a/tests/dnstap/src/dnstap-test/go.mod
+++ b/tests/dnstap/src/dnstap-test/go.mod
@@ -1,6 +1,6 @@
module gitlab.nic.cz/knot/knot-resolver/tests/dnstap-test
-go 1.17
+go 1.15
require (
github.com/cloudflare/dns v0.0.0-20151007113418-e20ffa3da443
diff --git a/tests/dnstap/src/dnstap-test/go.sum b/tests/dnstap/src/dnstap-test/go.sum
deleted file mode 100644
index 1860f9ef..00000000
--- a/tests/dnstap/src/dnstap-test/go.sum
+++ /dev/null
@@ -1,44 +0,0 @@
-github.com/cloudflare/dns v0.0.0-20151007113418-e20ffa3da443 h1:dYR6/V5rx/uaHsy4m1JuWfKYZO0r+G89BLD+XN7s9AI=
-github.com/cloudflare/dns v0.0.0-20151007113418-e20ffa3da443/go.mod h1:pa4p3oKOxzbXjrV5AGD1v5xjL7skv9BvO4J0Llo3P+s=
-github.com/dnstap/golang-dnstap v0.4.0 h1:KRHBoURygdGtBjDI2w4HifJfMAhhOqDuktAokaSa234=
-github.com/dnstap/golang-dnstap v0.4.0/go.mod h1:FqsSdH58NAmkAvKcpyxht7i4FoBjKu8E4JUPt8ipSUs=
-github.com/farsightsec/golang-framestream v0.3.0 h1:/spFQHucTle/ZIPkYqrfshQqPe2VQEzesH243TjIwqA=
-github.com/farsightsec/golang-framestream v0.3.0/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
-github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
diff --git a/tests/dnstap/src/dnstap-test/run.sh b/tests/dnstap/src/dnstap-test/run.sh
index 37822b75..70d82254 100755
--- a/tests/dnstap/src/dnstap-test/run.sh
+++ b/tests/dnstap/src/dnstap-test/run.sh
@@ -8,16 +8,13 @@ echo "$GOPATH"
cd "$(dirname $0)"
DNSTAP_TEST=dnstap-test
-if [ -z "$GITLAB_CI" ]; then
- type -P go >/dev/null || exit 77
- echo "Building the dnstap test and its dependencies..."
- # some packages may be missing on the system right now
- go get .
-else
- # In CI we've prebuilt dependencies into the default GOPATH.
- # We're in a scratch container, so we just add the dnstap test inside.
- export GOPATH=/root/go
-fi
+go mod tidy
+
+type -P go >/dev/null || exit 77
+echo "Building the dnstap test and its dependencies..."
+# some packages may be missing on the system right now
+go get .
+
DTAP_DIR="$GOPATH/src"
DTAP="$DTAP_DIR/$DNSTAP_TEST"
mkdir -p "$DTAP_DIR"
diff --git a/tests/pytests/conftest.py b/tests/pytests/conftest.py
index 4c711f84..fcf4b05f 100644
--- a/tests/pytests/conftest.py
+++ b/tests/pytests/conftest.py
@@ -86,7 +86,7 @@ def query_before(request): # whether to send an initial query
return request.param
-@pytest.mark.optionalhook
+@pytest.hookimpl(optionalhook=True)
def pytest_metadata(metadata): # filter potentially sensitive data from GitLab CI
keys_to_delete = []
for key in metadata.keys():
diff --git a/tests/pytests/kresd.py b/tests/pytests/kresd.py
index ca15e0d7..21d96455 100644
--- a/tests/pytests/kresd.py
+++ b/tests/pytests/kresd.py
@@ -312,5 +312,7 @@ KRESD_LOG_IO_CLOSE = re.compile(r'^\[io \].*closed by peer.*')
@contextmanager
def make_kresd(workdir, certname=None, ip='127.0.0.1', ip6='::1', **kwargs):
with Kresd(workdir, ip=ip, ip6=ip6, certname=certname, **kwargs) as kresd:
- yield kresd
- print(kresd.partial_log())
+ try:
+ yield kresd
+ finally:
+ print(kresd.partial_log())
diff --git a/tests/pytests/test_tls.py b/tests/pytests/test_tls.py
index 3e1328ab..2187efbc 100644
--- a/tests/pytests/test_tls.py
+++ b/tests/pytests/test_tls.py
@@ -1,15 +1,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later
"""TLS-specific tests"""
-import itertools
-import os
-from socket import AF_INET, AF_INET6
import ssl
-import sys
-
import pytest
-
-from kresd import make_kresd
import utils
@@ -41,43 +34,3 @@ def test_tls_cert_hostname_mismatch(kresd_tt, sock_family):
with pytest.raises(ssl.CertificateError):
ssock.connect(dest)
-
-
-@pytest.mark.skipif(sys.version_info < (3, 6),
- reason="requires python3.6 or higher")
-@pytest.mark.parametrize('sf1, sf2, sf3', itertools.product(
- [AF_INET, AF_INET6], [AF_INET, AF_INET6], [AF_INET, AF_INET6]))
-def test_tls_session_resumption(tmpdir, sf1, sf2, sf3):
- """Attempt TLS session resumption against the same kresd instance and a different one."""
- # TODO ensure that session can't be resumed after session ticket key regeneration
- # at the first kresd instance
-
- # NOTE TLS 1.3 is intentionally disabled for session resumption tests,
- # because python's SSLSocket.session isn't compatible with TLS 1.3
- # https://docs.python.org/3/library/ssl.html?highlight=ssl%20ticket#tls-1-3
-
- def connect(kresd, ctx, sf, session=None):
- sock, dest = kresd.stream_socket(sf, tls=True)
- ssock = ctx.wrap_socket(
- sock, server_hostname='transport-test-server.com', session=session)
- ssock.connect(dest)
- new_session = ssock.session
- assert new_session.has_ticket
- assert ssock.session_reused == (session is not None)
- utils.ping_alive(ssock)
- ssock.close()
- return new_session
-
- workdir = os.path.join(str(tmpdir), 'kresd')
- os.makedirs(workdir)
-
- with make_kresd(workdir, 'tt') as kresd:
- ctx = utils.make_ssl_context(
- verify_location=kresd.tls_cert_path, extra_options=[ssl.OP_NO_TLSv1_3])
- session = connect(kresd, ctx, sf1) # initial conn
- connect(kresd, ctx, sf2, session) # resume session on the same instance
-
- workdir2 = os.path.join(str(tmpdir), 'kresd2')
- os.makedirs(workdir2)
- with make_kresd(workdir2, 'tt') as kresd2:
- connect(kresd2, ctx, sf3, session) # resume session on a different instance
diff --git a/tests/pytests/utils.py b/tests/pytests/utils.py
index 4b995d4b..8af71aad 100644
--- a/tests/pytests/utils.py
+++ b/tests/pytests/utils.py
@@ -99,7 +99,7 @@ def ping_alive(sock, msgid=None):
@contextmanager
def expect_kresd_close(rst_ok=False):
- with pytest.raises(BrokenPipeError):
+ with pytest.raises((BrokenPipeError, ssl.SSLEOFError)):
try:
time.sleep(0.2) # give kresd time to close connection with TCP FIN
yield
@@ -110,17 +110,12 @@ def expect_kresd_close(rst_ok=False):
pytest.fail("kresd didn't close the connection")
-def make_ssl_context(insecure=False, verify_location=None, extra_options=None):
- # set TLS v1.2+
- context = ssl.SSLContext(ssl.PROTOCOL_TLS)
- context.options |= ssl.OP_NO_SSLv2
- context.options |= ssl.OP_NO_SSLv3
- context.options |= ssl.OP_NO_TLSv1
- context.options |= ssl.OP_NO_TLSv1_1
-
- if extra_options is not None:
- for option in extra_options:
- context.options |= option
+def make_ssl_context(insecure=False, verify_location=None,
+ minimum_tls=ssl.TLSVersion.TLSv1_2,
+ maximum_tls=ssl.TLSVersion.MAXIMUM_SUPPORTED):
+ context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+ context.minimum_version = minimum_tls
+ context.maximum_version = maximum_tls
if insecure:
# turn off certificate verification
diff --git a/utils/cache_gc/categories.c b/utils/cache_gc/categories.c
index 19dec45c..aaa1ae53 100644
--- a/utils/cache_gc/categories.c
+++ b/utils/cache_gc/categories.c
@@ -18,7 +18,7 @@ static bool rrtype_is_infrastructure(uint16_t r)
}
}
-static int get_random(int to)
+static unsigned int get_random(int to)
{
// We don't need these to be really unpredictable,
// but this should be cheap enough not to be noticeable.
diff --git a/utils/cache_gc/db.c b/utils/cache_gc/db.c
index 76a2b5fa..0e8f90c1 100644
--- a/utils/cache_gc/db.c
+++ b/utils/cache_gc/db.c
@@ -9,11 +9,13 @@
#include <time.h>
#include <sys/stat.h>
+#define MDB_FILE "/data.mdb"
+
int kr_gc_cache_open(const char *cache_path, struct kr_cache *kres_db,
knot_db_t ** libknot_db)
{
- char cache_data[strlen(cache_path) + 10];
- snprintf(cache_data, sizeof(cache_data), "%s/data.mdb", cache_path);
+ char cache_data[strlen(cache_path) + sizeof(MDB_FILE)];
+ (void)snprintf(cache_data, sizeof(cache_data), "%s" MDB_FILE, cache_path);
struct stat st = { 0 };
if (stat(cache_path, &st) || !(st.st_mode & S_IFDIR)
diff --git a/utils/cache_gc/kr_cache_gc.c b/utils/cache_gc/kr_cache_gc.c
index 5978345c..4097c802 100644
--- a/utils/cache_gc/kr_cache_gc.c
+++ b/utils/cache_gc/kr_cache_gc.c
@@ -8,20 +8,12 @@
// libknot includes
#include <libknot/libknot.h>
-// dynarray is inside libknot since 3.1, but it's differently named
-#ifdef knot_dynarray_declare
- #define dynarray_declare knot_dynarray_declare
- #define dynarray_define knot_dynarray_define
- #define dynarray_foreach knot_dynarray_foreach
-#else
- #include <contrib/dynarray.h>
-#endif
-
// resolver includes
#include <lib/cache/api.h>
#include <lib/cache/impl.h>
#include <lib/defines.h>
#include "lib/cache/cdb_lmdb.h"
+#include "lib/generic/array.h"
#include "lib/utils.h"
#include "kr_cache_gc.h"
@@ -43,41 +35,40 @@ static knot_db_val_t *dbval_copy(const knot_db_val_t * from)
}
// section: rrtype list
+typedef array_t(uint16_t) rrtype_array_t;
-dynarray_declare(rrtype, uint16_t, DYNARRAY_VISIBILITY_STATIC, 64)
- dynarray_define(rrtype, uint16_t, DYNARRAY_VISIBILITY_STATIC)
-static void rrtypelist_add(rrtype_dynarray_t * arr, uint16_t add_type)
+static void rrtypelist_add(rrtype_array_t *arr, uint16_t add_type)
{
bool already_present = false;
- dynarray_foreach(rrtype, uint16_t, i, *arr) {
- if (*i == add_type) {
+ for (size_t i = 0; i < arr->len; i++) {
+ if (arr->at[i] == add_type) {
already_present = true;
break;
}
}
if (!already_present) {
- rrtype_dynarray_add(arr, &add_type);
+ kr_require(array_push(*arr, add_type) >= 0);
}
}
-static void rrtypelist_print(rrtype_dynarray_t * arr)
+static void rrtypelist_print(rrtype_array_t *arr)
{
char type_s[32] = { 0 };
- dynarray_foreach(rrtype, uint16_t, i, *arr) {
- knot_rrtype_to_string(*i, type_s, sizeof(type_s));
+ for (size_t i = 0; i < arr->len; i++) {
+ knot_rrtype_to_string(arr->at[i], type_s, sizeof(type_s));
printf(" %s", type_s);
}
printf("\n");
}
-dynarray_declare(entry, knot_db_val_t *, DYNARRAY_VISIBILITY_STATIC, 256)
- dynarray_define(entry, knot_db_val_t *, DYNARRAY_VISIBILITY_STATIC)
-static void entry_dynarray_deep_free(entry_dynarray_t * d)
+typedef array_t(knot_db_val_t *) entry_array_t;
+
+static void entry_array_deep_free(entry_array_t *d)
{
- dynarray_foreach(entry, knot_db_val_t *, i, *d) {
- free(*i);
+ for (size_t i = 0; i < d->len; i++) {
+ free(d->at[i]);
}
- entry_dynarray_free(d);
+ array_clear(*d);
}
typedef struct {
@@ -98,7 +89,7 @@ int cb_compute_categories(const knot_db_val_t * key, gc_record_info_t * info,
typedef struct {
category_t limit_category;
- entry_dynarray_t to_delete;
+ entry_array_t to_delete;
size_t cfg_temp_keys_space;
size_t used_space;
size_t oversize_records;
@@ -117,7 +108,7 @@ int cb_delete_categories(const knot_db_val_t * key, gc_record_info_t * info,
ctx->oversize_records++;
free(todelete);
} else {
- entry_dynarray_add(&ctx->to_delete, &todelete);
+ kr_require(array_push(ctx->to_delete, todelete) >= 0);
ctx->used_space = used;
}
}
@@ -194,12 +185,12 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg, kr_cache_gc_state_t **state)
// Mixing ^^ page usage and entry sizes (key+value lengths) didn't work
// too well, probably due to internal fragmentation after some GC cycles.
// Therefore let's scale this by the ratio of these two sums.
- ssize_t cats_sumsize = 0;
+ size_t cats_sumsize = 0;
for (int i = 0; i < CATEGORIES; ++i) {
cats_sumsize += cats.categories_sizes[i];
}
/* use less precise variant to avoid 32-bit overflow */
- ssize_t amount_tofree = cats_sumsize / 100 * cfg->cache_to_be_freed;
+ size_t amount_tofree = cats_sumsize / 100 * cfg->cache_to_be_freed;
kr_log_debug(CACHE, "tofree: %zd / %zd\n", amount_tofree, cats_sumsize);
if (VERBOSE_STATUS) {
@@ -212,8 +203,11 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg, kr_cache_gc_state_t **state)
}
category_t limit_category = CATEGORIES;
- while (limit_category > 0 && amount_tofree > 0) {
- amount_tofree -= cats.categories_sizes[--limit_category];
+ while (limit_category > 0) {
+ size_t cat_size = cats.categories_sizes[--limit_category];
+ if (cat_size > amount_tofree)
+ break;
+ amount_tofree -= cat_size;
}
printf("Cache analyzed in %.0lf msecs, %zu records, limit category is %d.\n",
@@ -226,13 +220,13 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg, kr_cache_gc_state_t **state)
to_del.limit_category = limit_category;
ret = kr_gc_cache_iter(db, cfg, cb_delete_categories, &to_del);
if (ret != KNOT_EOK) {
- entry_dynarray_deep_free(&to_del.to_delete);
+ entry_array_deep_free(&to_del.to_delete);
kr_cache_gc_free_state(state);
return ret;
}
printf
("%zu records to be deleted using %.2lf MBytes of temporary memory, %zu records skipped due to memory limit.\n",
- to_del.to_delete.size, ((double)to_del.used_space / 1048576.0),
+ to_del.to_delete.len, ((double)to_del.used_space / 1048576.0),
to_del.oversize_records);
//// 4. execute the planned deletions.
@@ -242,23 +236,24 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg, kr_cache_gc_state_t **state)
kr_timer_start(&timer_delete);
kr_timer_start(&timer_rw_txn);
- rrtype_dynarray_t deleted_rrtypes = { 0 };
+ rrtype_array_t deleted_rrtypes = { 0 };
ret = api->txn_begin(db, &txn, 0);
if (ret != KNOT_EOK) {
printf("Error starting R/W DB transaction (%s).\n",
knot_strerror(ret));
- entry_dynarray_deep_free(&to_del.to_delete);
+ entry_array_deep_free(&to_del.to_delete);
kr_cache_gc_free_state(state);
return ret;
}
- dynarray_foreach(entry, knot_db_val_t *, i, to_del.to_delete) {
- ret = api->del(&txn, *i);
+ for (size_t i = 0; i < to_del.to_delete.len; i++) {
+ knot_db_val_t *val = to_del.to_delete.at[i];
+ ret = api->del(&txn, val);
switch (ret) {
case KNOT_EOK:
deleted_records++;
- const int entry_type = kr_gc_key_consistent(**i);
+ const int entry_type = kr_gc_key_consistent(*val);
if (entry_type >= 0) // some "inconsistent" entries are OK
rrtypelist_add(&deleted_rrtypes, entry_type);
break;
@@ -267,8 +262,8 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg, kr_cache_gc_state_t **state)
if (VERBOSE_STATUS) {
// kresd normally only inserts (or overwrites),
// so it's generally suspicious when a key goes missing.
- printf("Record already gone (key len %zu): ", (*i)->len);
- debug_printbin((*i)->data, (*i)->len);
+ printf("Record already gone (key len %zu): ", val->len);
+ debug_printbin(val->data, val->len);
printf("\n");
}
break;
@@ -316,8 +311,8 @@ finish:
printf("It took %.0lf msecs, %zu transactions (%s)\n\n",
kr_timer_elapsed(&timer_delete) * 1000, rw_txn_count, knot_strerror(ret));
- rrtype_dynarray_free(&deleted_rrtypes);
- entry_dynarray_deep_free(&to_del.to_delete);
+ array_clear(deleted_rrtypes);
+ entry_array_deep_free(&to_del.to_delete);
// OK, let's close it in this case.
kr_cache_gc_free_state(state);
diff --git a/utils/cache_gc/main.c b/utils/cache_gc/main.c
index 5adf19f0..fe131cd0 100644
--- a/utils/cache_gc/main.c
+++ b/utils/cache_gc/main.c
@@ -13,6 +13,7 @@
#include "kr_cache_gc.h"
static volatile int killed = 0;
+static volatile int exit_code = 0;
static void got_killed(int signum)
{
@@ -21,12 +22,10 @@ static void got_killed(int signum)
case 1:
break;
case 2:
- exit(5);
+ exit_code = 5;
break;
- case 3:
- abort();
default:
- kr_assert(false);
+ abort();
}
}
@@ -60,16 +59,20 @@ int main(int argc, char *argv[])
{
printf("Knot Resolver Cache Garbage Collector, version %s\n", PACKAGE_VERSION);
if (setvbuf(stdout, NULL, _IONBF, 0) || setvbuf(stderr, NULL, _IONBF, 0)) {
- fprintf(stderr, "Failed to to set output buffering (ignored): %s\n",
+ (void)fprintf(stderr, "Failed to to set output buffering (ignored): %s\n",
strerror(errno));
- fflush(stderr);
+ (void)fflush(stderr);
}
- signal(SIGTERM, got_killed);
- signal(SIGKILL, got_killed);
- signal(SIGPIPE, got_killed);
- signal(SIGCHLD, got_killed);
- signal(SIGINT, got_killed);
+ struct sigaction act = {
+ .sa_handler = got_killed,
+ .sa_flags = SA_RESETHAND,
+ };
+ sigemptyset(&act.sa_mask);
+ kr_assert(!sigaction(SIGTERM, &act, NULL));
+ kr_assert(!sigaction(SIGPIPE, &act, NULL));
+ kr_assert(!sigaction(SIGCHLD, &act, NULL));
+ kr_assert(!sigaction(SIGINT, &act, NULL));
kr_cache_gc_cfg_t cfg = {
.ro_txn_items = 200,
@@ -131,7 +134,6 @@ int main(int argc, char *argv[])
return 1;
}
- int exit_code = 0;
kr_cache_gc_state_t *gc_state = NULL;
bool last_espace = false;
do {