diff options
106 files changed, 1545 insertions, 2894 deletions
diff --git a/.github/workflows/macOS.yaml b/.github/workflows/macOS.yaml index f7fe0907..6f022d32 100644 --- a/.github/workflows/macOS.yaml +++ b/.github/workflows/macOS.yaml @@ -8,7 +8,7 @@ jobs: runs-on: macOS-latest strategy: matrix: - knot-version: ['3.2', '3.3'] + knot-version: ['3.3'] steps: - name: Checkout resolver code diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2395ebb0..8531e5cc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,7 @@ variables: RESPDIFF_COUNT: 1 RESPDIFF_FORCE: 0 RESPERF_FORCE: 0 - KNOT_VERSION: '3.1' + KNOT_VERSION: '3.3' LIBKRES_ABI: 9 LIBKRES_NAME: libkres MESON_TEST: meson test -C build_ci* -t 4 --print-errorlogs @@ -20,7 +20,7 @@ variables: # 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_TAG: 'v20240606' IMAGE_PREFIX: '$CI_REGISTRY/knot/knot-resolver-ci' image: $IMAGE_PREFIX/debian12-knot_3_3:$IMAGE_TAG @@ -135,32 +135,18 @@ build-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_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-deb11-knot32: - <<: *build - image: $IMAGE_PREFIX/debian11-knot_3_2:$IMAGE_TAG - script: - - 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-deb12-knot32: - <<: *build - image: $IMAGE_PREFIX/debian12-knot_3_2:$IMAGE_TAG - script: - - 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 +# This is currently the same as stable - uncomment this once Knot 3.4 is +# released and we are building against that, to keep sanity-checking the 3.3 +# support. +# +#build-deb12-knot33: +# <<: *build +# image: $IMAGE_PREFIX/debian12-knot_3_3:$IMAGE_TAG +# script: +# - meson build_ci_deb12_knot33 --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled +# - ninja -C build_ci_deb12_knot33 +# - ninja -C build_ci_deb12_knot33 install >/dev/null +# - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake build-deb12-knot-master: <<: *build @@ -309,12 +295,9 @@ 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-31: +kres-gen-33: <<: *kres-gen - image: $IMAGE_PREFIX/debian11-knot_3_1:$IMAGE_TAG -kres-gen-32: - <<: *kres-gen - image: $IMAGE_PREFIX/debian12-knot_3_2:$IMAGE_TAG + image: $IMAGE_PREFIX/debian12-knot_3_3:$IMAGE_TAG root.hints: <<: *sanity @@ -623,7 +606,7 @@ obs:odvr: .enable_repo_build: &enable_repo_build before_script: - - ./scripts/enable-repo.py build + - ./scripts/enable-repo-cznic-labs.sh knot-dns .pkg_test: &pkg_test stage: pkg @@ -637,6 +620,10 @@ obs:odvr: - apkg info cache | grep archive/dev - apkg install --build-dep - apkg test --test-dep + artifacts: + expire_in: 1 week + paths: + - pkg/pkgs/ .pkg_test_user: &pkg_test_user <<: *pkg_test @@ -661,7 +648,7 @@ pkg:make-archive: # archive is created once and reused in other pkg jobs <<: *pkg_deb_extras stage: pkg - image: $CI_REGISTRY/packaging/apkg/full/debian-11 + image: $CI_REGISTRY/packaging/apkg/full/ubuntu-24.04 tags: - lxc - amd64 @@ -675,10 +662,12 @@ pkg:make-archive: pkg:debian-12: <<: *pkg_test_deb + <<: *enable_repo_build image: $CI_REGISTRY/packaging/apkg/full/debian-12 pkg:debian-11: <<: *pkg_test_deb + <<: *enable_repo_build image: $CI_REGISTRY/packaging/apkg/full/debian-11 pkg:ubuntu-24.04: @@ -687,6 +676,7 @@ pkg:ubuntu-24.04: pkg:ubuntu-22.04: <<: *pkg_test_deb + <<: *enable_repo_build image: $CI_REGISTRY/packaging/apkg/full/ubuntu-22.04 pkg:ubuntu-20.04: @@ -694,13 +684,13 @@ pkg:ubuntu-20.04: <<: *enable_repo_build image: $CI_REGISTRY/packaging/apkg/full/ubuntu-20.04 -pkg:fedora-39: +pkg:fedora-40: <<: *pkg_test - image: $CI_REGISTRY/packaging/apkg/full/fedora-39 + image: $CI_REGISTRY/packaging/apkg/full/fedora-40 -pkg:fedora-38: +pkg:fedora-39: <<: *pkg_test - image: $CI_REGISTRY/packaging/apkg/full/fedora-38 + image: $CI_REGISTRY/packaging/apkg/full/fedora-39 pkg:alma-9: <<: *pkg_test @@ -1,17 +1,23 @@ # SPDX-License-Identifier: GPL-3.0-or-later # Intermediate container for build -FROM debian:11 AS build +FROM debian:12 AS build ENV OBS_REPO=knot-resolver-latest -ENV DISTROTEST_REPO=Debian_11 +ENV DISTROTEST_REPO=Debian_12 RUN apt-get update -qq && \ - apt-get -qqq -y install python3-pip python3-venv devscripts && \ - pip3 install pipx && \ + apt-get -qqq -y install \ + apt-transport-https ca-certificates wget \ + pipx devscripts && \ pipx install apkg +RUN wget -O /usr/share/keyrings/cznic-labs-pkg.gpg https://pkg.labs.nic.cz/gpg && \ + echo "deb [signed-by=/usr/share/keyrings/cznic-labs-pkg.gpg] https://pkg.labs.nic.cz/knot-resolver bookworm main" \ + > /etc/apt/sources.list.d/cznic-labs-knot-resolver.list && \ + apt-get update -qq + COPY . /source RUN cd /source && \ @@ -24,15 +30,25 @@ RUN cd /source && \ # Real container -FROM debian:11-slim AS runtime +FROM debian:12-slim AS runtime ENV OBS_REPO=knot-resolver-latest -ENV DISTROTEST_REPO=Debian_11 +ENV DISTROTEST_REPO=Debian_12 + +RUN apt-get update -qq && \ + apt-get -qqq -y install apt-transport-https ca-certificates + +COPY --from=build \ + /usr/share/keyrings/cznic-labs-pkg.gpg \ + /usr/share/keyrings/cznic-labs-pkg.gpg +COPY --from=build \ + /etc/apt/sources.list.d/cznic-labs-knot-resolver.list \ + /etc/apt/sources.list.d/cznic-labs-knot-resolver.list RUN apt-get update -qq && \ apt-get upgrade -qq -COPY --from=build /source/pkg/pkgs/debian-11 /pkg +COPY --from=build /source/pkg/pkgs/debian-12 /pkg # install resolver, minimize image and prepare config directory RUN apt-get install -y /pkg/*/*.deb && \ @@ -1,34 +1,80 @@ -Knot Resolver 6.0.8 (2024-0m-dd) +Knot Resolver 6.0.9 (2024-mm-dd) ================================ Improvements ------------ + +- manager: secret for TLS session resumption via ticket (RFC5077) (!1567) + + The manager creates and sets the secret for all running 'kresd' workers. The secret is created automatically if the user does not configure his own secret in the configuration. This means that the workers will be able to resume each other's TLS sessions, regardless of whether the user has configured it to do so. + +Knot Resolver 6.0.8 (2024-07-23) +================================ + +Security +-------- +- reduce buffering of transmitted data, especially TCP-based in userspace + Also expose some of the new tweaks in lua: + (require 'ffi').C.the_worker.engine.net.tcp.user_timeout = 1000 + (require 'ffi').C.the_worker.engine.net.listen_{tcp,udp}_buflens.{snd,rcv} + +Packaging +--------- + +- all packages: + - remove unused dependency on `libedit` (!1553) +- deb packages: + - packages ``knot-resolver-core`` and ``knot-resolver-manager`` have + been merged into a single ``knot-resolver6`` package. Suffix packages + ``knot-resolver-*`` have been renamed to ``knot-resolver6-*``. This + change _should_ be transparent, but please do let us know if you + encounter any issues while updating. (!1549) + - package ``python3-prometheus-client`` is now only an optional dependency +- rpm packages: + - packages ``knot-resolver-core`` and ``knot-resolver-manager`` have + been merged into a single ``knot-resolver`` package. This change + _should_ be transparent, but please do let us know if you encounter + any issues while updating. (!1549) + - bugfix: do not overwrite config.yaml (!1525) + - package ``python3-prometheus_client`` is now only an optional dependency +- arch package: + - fix after they renamed a dependency (!1536) + +Improvements +------------ - TLS (DoT, DoH): respect crypto policy overrides in OS (!1526) -- arch package: fix after they renamed a dependency (!1536) - manager: export metrics to JSON via management HTTP API (!1527) - * JSON is the new default metrics output format * the ``prometheus-client`` Python package is now an optional dependency, required only for Prometheus export to work - cache: prefetching records - * 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. +- add the fresh DNSSEC root key "KSK-2024" already, Key ID 38696 (!1556) +- manager: policy-loader: new component for separate loading of policy rules (!1540) + The ``policy-loader`` ensures that configured policies are loaded into the rules database + where they are made available to all running kresd workers. This loading is no longer done + by all kresd workers as it was before, so this should significantly improve the resolver's + startup/reload time when loading large sets of policy rules, e.g. large RPZs. Incompatible changes -------------------- -- cache: the ``/cache/prediction`` configuration property has been reorganized - into ``/cache/prefetch/expiring`` and ``/cache/prefetch/prediction``, changing +- cache: the ``cache.prediction`` configuration property has been reorganized + into ``cache.prefetch.expiring`` and ``cache.prefetch.prediction``, changing the default behaviour as well. See the `relevant documentation section - <https://www.knot-resolver.cz/documentation/latest/config-cache-predict.html>`_ + <https://www.knot-resolver.cz/documentation/v6.0.8/config-cache-predict.html>`_ for more. +- libknot <=3.2.x support is dropped (!1565) Bugfixes -------- +- arch package: fix after they renamed a dependency (!1536) - fix startup with `dnssec: false` (!1548) +- rpm packages: do not overwrite config.yaml (!1525) +- fix NSEC3 records missing in answer for positive wildcard expansion + with the NSEC3 having over-limit iteration count (#910, !1550) +- views: fix a bug in subnet matching (!1562) Knot Resolver 6.0.7 (2024-03-27) @@ -105,13 +151,39 @@ https://www.knot-resolver.cz/documentation/latest/upgrading-to-6.html 5.x branch longterm support ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Knot Resolver 5.7.3 (2024-0m-dd) +Knot Resolver 5.7.4 (2024-07-23) +================================ + +Security +-------- +- reduce buffering of transmitted data, especially TCP-based in userspace + Also expose some of the new tweaks in lua: + (require 'ffi').C.the_worker.engine.net.tcp.user_timeout = 1000 + (require 'ffi').C.the_worker.engine.net.listen_{tcp,udp}_buflens.{snd,rcv} + +Improvements +------------ +- add the fresh DNSSEC root key "KSK-2024" already, Key ID 38696 (!1556) + +Incompatible changes +-------------------- +- libknot 3.0.x support is dropped (!1558) + Upstream last maintained 3.0.x in spring 2022. + + +Knot Resolver 5.7.3 (2024-05-30) ================================ Improvements ------------ - stats: add separate metrics for IPv6 and IPv4 (!1544) +Bugfixes +-------- +- fix NSEC3 records missing in answer for positive wildcard expansion + with the NSEC3 having over-limit iteration count (#910, !1550) + + Knot Resolver 5.7.2 (2024-03-27) ================================ diff --git a/ci/images/debian-12/Dockerfile b/ci/images/debian-12/Dockerfile deleted file mode 100644 index 15b25add..00000000 --- a/ci/images/debian-12/Dockerfile +++ /dev/null @@ -1,149 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-or-later - -FROM debian:12 -MAINTAINER Knot Resolver <knot-resolver@labs.nic.cz> -# >= 3.0 needed because of --enable-xdp=yes -ARG KNOT_BRANCH=3.2 -ENV DEBIAN_FRONTEND=noninteractive -ENV PYTHONUNBUFFERED=1 - -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 python3-venv wget augeas-tools -RUN python3 -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" -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-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" diff --git a/contrib/mempattern.c b/contrib/mempattern.c index 6c237eac..e0c784de 100644 --- a/contrib/mempattern.c +++ b/contrib/mempattern.c @@ -125,7 +125,7 @@ void mm_ctx_mempool(knot_mm_t *mm, size_t chunk_size) void *mm_malloc_aligned(void *ctx, size_t n) { - size_t alignment = (size_t)ctx; + size_t alignment = (uintptr_t)ctx; void *res; int err = posix_memalign(&res, alignment, n); if (err == 0) { diff --git a/contrib/mempattern.h b/contrib/mempattern.h index 4db147ae..7cb2bae8 100644 --- a/contrib/mempattern.h +++ b/contrib/mempattern.h @@ -81,7 +81,7 @@ static inline void mm_ctx_init_aligned(knot_mm_t *mm, size_t alignment) { assert(__builtin_popcount(alignment) == 1); mm_ctx_init(mm); - mm->ctx = (uint8_t *)NULL + alignment; /*< roundabout to satisfy linters */ + mm->ctx = (void *)(uintptr_t)alignment; /*< roundabout to satisfy linters */ /* posix_memalign() doesn't allow alignment < sizeof(void*), * and there's no point in using it for small values anyway, * as plain malloc() guarantees at least max_align_t. */ diff --git a/daemon/bindings/net.c b/daemon/bindings/net.c index aaeef238..55e9a914 100644 --- a/daemon/bindings/net.c +++ b/daemon/bindings/net.c @@ -1191,7 +1191,7 @@ static int net_register_endpoint_kind(lua_State *L) if (param_count == 1) { void *val; if (trie_del(the_network->endpoint_kinds, kind, kind_len, &val) == KNOT_EOK) { - const int fun_id = (char *)val - (char *)NULL; + const int fun_id = (intptr_t)val; luaL_unref(L, LUA_REGISTRYINDEX, fun_id); return 0; } @@ -1209,7 +1209,7 @@ static int net_register_endpoint_kind(lua_State *L) if (!pp) lua_error_maybe(L, kr_error(ENOMEM)); if (*pp != NULL || !strcasecmp(kind, "dns") || !strcasecmp(kind, "tls")) lua_error_p(L, "attempt to register known kind '%s'\n", kind); - *pp = (char *)NULL + fun_id; + *pp = (void *)(intptr_t)fun_id; /* We don't attempt to engage corresponding endpoints now. * That's the job for network_engage_endpoints() later. */ return 0; diff --git a/daemon/bindings/net_buffering.rst b/daemon/bindings/net_buffering.rst new file mode 100644 index 00000000..946fc28e --- /dev/null +++ b/daemon/bindings/net_buffering.rst @@ -0,0 +1,25 @@ +.. SPDX-License-Identifier: GPL-3.0-or-later + +Buffering tweaks +---------------- + +We (can) set various server-side socket options that affect buffering. +The values are stored in C structures without real Lua bindings, +so setting them is a bit long. + +.. py:data:: (require 'ffi').C.the_worker.engine.net.tcp.user_timeout + + On TCP-based server-side sockets we set ``TCP_USER_TIMEOUT`` option if available (~Linux). + We use default 1000, i.e. one second. For details see the definition in ``man tcp.7``. + +.. py:data:: (require 'ffi').C.the_worker.engine.net.listen_tcp_buflens.snd +.. py:data:: (require 'ffi').C.the_worker.engine.net.listen_tcp_buflens.rcv +.. py:data:: (require 'ffi').C.the_worker.engine.net.listen_udp_buflens.snd +.. py:data:: (require 'ffi').C.the_worker.engine.net.listen_udp_buflens.rcv + + If overridden to nonzero, these variables instruct the OS to modify kernel-space buffers + for server-side sockets. We split the setting for UDP vs. TCP and sending vs. receiving. + + For details see ``SO_SNDBUF`` and ``SO_RCVBUF`` in ``man socket.7``. + There is no user-space buffering beyond immediate manipulation, only the OS keeps some. + diff --git a/daemon/http.c b/daemon/http.c index 61ebcf9e..89b5e4c4 100644 --- a/daemon/http.c +++ b/daemon/http.c @@ -13,8 +13,6 @@ #include "daemon/session2.h" #include "daemon/worker.h" -#include "daemon/http.h" - /** Makes a `nghttp2_nv`. `K` is the key, `KS` is the key length, * `V` is the value, `VS` is the value length. */ #define MAKE_NV(K, KS, V, VS) \ @@ -1030,7 +1028,8 @@ static void pl_http_request_init(struct session2 *session, } } -void http_protolayers_init(void) +__attribute__((constructor)) +static void http_protolayers_init(void) { protolayer_globals[PROTOLAYER_TYPE_HTTP] = (struct protolayer_globals) { .sess_size = sizeof(struct pl_http_sess_data), diff --git a/daemon/http.h b/daemon/http.h deleted file mode 100644 index cf5eaaca..00000000 --- a/daemon/http.h +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz> - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -/** Initializes the protocol layers managed by http. */ -void http_protolayers_init(void); diff --git a/daemon/io.c b/daemon/io.c index b6b289ae..86bd314e 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -19,7 +19,6 @@ #include "daemon/network.h" #include "daemon/worker.h" #include "daemon/tls.h" -#include "daemon/http.h" #include "daemon/session2.h" #include "contrib/cleanup.h" #include "lib/utils.h" @@ -166,18 +165,24 @@ static enum protolayer_event_cb_result pl_tcp_event_wrap( enum protolayer_event_type event, void **baton, struct session2 *session, void *sess_data) { - if (event == PROTOLAYER_EVENT_STATS_SEND_ERR) { + switch (event) { + case PROTOLAYER_EVENT_STATS_SEND_ERR: the_worker->stats.err_tcp += 1; return PROTOLAYER_EVENT_CONSUME; - } else if (event == PROTOLAYER_EVENT_STATS_QRY_OUT) { + case PROTOLAYER_EVENT_STATS_QRY_OUT: the_worker->stats.tcp += 1; return PROTOLAYER_EVENT_CONSUME; + case PROTOLAYER_EVENT_OS_BUFFER_FULL: + session2_force_close(session); + return PROTOLAYER_EVENT_CONSUME; + default: + return PROTOLAYER_EVENT_PROPAGATE; } - return PROTOLAYER_EVENT_PROPAGATE; } -void io_protolayers_init(void) +__attribute__((constructor)) +static void io_protolayers_init(void) { protolayer_globals[PROTOLAYER_TYPE_UDP] = (struct protolayer_globals){ .event_wrap = pl_udp_event_wrap, @@ -261,6 +266,17 @@ int io_bind(const struct sockaddr *addr, int type, const endpoint_flags_t *flags return fd; } +/// Optionally set a socket option and log error on failure. +static void set_so(int fd, int so_option, int value, const char *descr) +{ + if (!value) return; + if (setsockopt(fd, SOL_SOCKET, so_option, &value, sizeof(value))) { + kr_log_error(IO, "failed to set %s to %d: %s\n", + descr, value, strerror(errno)); + // we treat this as non-critical failure + } +} + int io_listen_udp(uv_loop_t *loop, uv_udp_t *handle, int fd) { if (!handle) { @@ -272,6 +288,9 @@ int io_listen_udp(uv_loop_t *loop, uv_udp_t *handle, int fd) ret = uv_udp_open(handle, fd); if (ret) return ret; + set_so(fd, SO_SNDBUF, the_network->listen_udp_buflens.snd, "UDP send buffer size"); + set_so(fd, SO_RCVBUF, the_network->listen_udp_buflens.rcv, "UDP receive buffer size"); + uv_handle_t *h = (uv_handle_t *)handle; check_bufsize(h); /* Handle is already created, just create context. */ @@ -314,7 +333,7 @@ static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) uv_strerror(nread)); } session2_penalize(s); - worker_end_tcp(s); + session2_force_close(s); return; } @@ -464,6 +483,17 @@ int io_listen_tcp(uv_loop_t *loop, uv_tcp_t *handle, int fd, int tcp_backlog, bo } #endif + /* These get inherited into the individual connections (on Linux at least). */ + set_so(fd, SO_SNDBUF, the_network->listen_tcp_buflens.snd, "TCP send buffer size"); + set_so(fd, SO_RCVBUF, the_network->listen_tcp_buflens.rcv, "TCP receive buffer size"); +#ifdef TCP_USER_TIMEOUT + val = the_network->tcp.user_timeout; + if (val && setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &val, sizeof(val))) { + kr_log_error(IO, "listen TCP (user_timeout): %s\n", strerror(errno)); + } + // TODO: also for upstream connections, at least this one option? +#endif + handle->data = NULL; return 0; } @@ -742,11 +772,7 @@ static void xdp_rx(uv_poll_t* handle, int status, int events) kr_require(xhd && xhd->session && xhd->socket); uint32_t rcvd; knot_xdp_msg_t msgs[XDP_RX_BATCH_SIZE]; - int ret = knot_xdp_recv(xhd->socket, msgs, XDP_RX_BATCH_SIZE, &rcvd - #if KNOT_VERSION_HEX >= 0x030100 - , NULL - #endif - ); + int ret = knot_xdp_recv(xhd->socket, msgs, XDP_RX_BATCH_SIZE, &rcvd, NULL); if (kr_fails_assert(ret == KNOT_EOK)) { /* ATM other error codes can only be returned when called incorrectly */ @@ -827,19 +853,10 @@ int io_listen_xdp(uv_loop_t *loop, struct endpoint *ep, const char *ifname) // This call is a libknot version hell, unfortunately. int ret = knot_xdp_init(&xhd->socket, ifname, ep->nic_queue, - #if KNOT_VERSION_HEX < 0x030100 - ep->port ? ep->port : KNOT_XDP_LISTEN_PORT_ALL, - KNOT_XDP_LOAD_BPF_MAYBE - #elif KNOT_VERSION_HEX < 0x030200 - ep->port ? ep->port : (KNOT_XDP_LISTEN_PORT_PASS | 0), - KNOT_XDP_LOAD_BPF_MAYBE - #else KNOT_XDP_FILTER_UDP | (ep->port ? 0 : KNOT_XDP_FILTER_PASS), ep->port, 0/*quic_port*/, KNOT_XDP_LOAD_BPF_MAYBE, - NULL/*xdp_config*/ - #endif - ); + NULL/*xdp_config*/); if (!ret) xdp_warn_mode(ifname); diff --git a/daemon/io.h b/daemon/io.h index b03c6aae..268a8c9d 100644 --- a/daemon/io.h +++ b/daemon/io.h @@ -17,9 +17,6 @@ struct tls_ctx; struct tls_client_ctx; struct io_stream_data; -/** Initializes the protocol layers managed by io. */ -void io_protolayers_init(void); - /** Bind address into a file-descriptor (only, no libuv). type is e.g. SOCK_DGRAM */ int io_bind(const struct sockaddr *addr, int type, const endpoint_flags_t *flags); /** Initialize a UDP handle and start listening. */ diff --git a/daemon/lua/kres-gen-30.lua b/daemon/lua/kres-gen-30.lua deleted file mode 100644 index b5ff1478..00000000 --- a/daemon/lua/kres-gen-30.lua +++ /dev/null @@ -1,689 +0,0 @@ --- SPDX-License-Identifier: GPL-3.0-or-later - -local ffi = require('ffi') ---[[ This file is generated by ./kres-gen.sh ]] ffi.cdef[[ - -typedef @time_t@ time_t; -typedef @time_t@ __time_t; -typedef @time_t@ __suseconds_t; -struct timeval { - __time_t tv_sec; - __suseconds_t tv_usec; -}; - -typedef struct knot_dump_style knot_dump_style_t; -extern const knot_dump_style_t KR_DUMP_STYLE_DEFAULT; -struct kr_cdb_api {}; -struct lru {}; -typedef enum {KNOT_ANSWER, KNOT_AUTHORITY, KNOT_ADDITIONAL} knot_section_t; -typedef struct { - uint16_t pos; - uint16_t flags; - uint16_t compress_ptr[16]; -} knot_rrinfo_t; -typedef unsigned char knot_dname_t; -typedef struct { - uint16_t len; - uint8_t data[]; -} knot_rdata_t; -typedef struct { - uint16_t count; - uint32_t size; - knot_rdata_t *rdata; -} knot_rdataset_t; -typedef struct knot_db_val { - void *data; - size_t len; -} knot_db_val_t; - -typedef struct knot_mm { - void *ctx, *alloc, *free; -} knot_mm_t; - -typedef void *(*map_alloc_f)(void *, size_t); -typedef void (*map_free_f)(void *baton, void *ptr); -typedef void (*trace_log_f) (const struct kr_request *, const char *); -typedef void (*trace_callback_f)(struct kr_request *); -typedef uint8_t * (*alloc_wire_f)(struct kr_request *req, uint16_t *maxlen); -typedef bool (*addr_info_f)(struct sockaddr*); -typedef void (*zi_callback)(int state, void *param); -typedef struct { - knot_dname_t *_owner; - uint32_t _ttl; - uint16_t type; - uint16_t rclass; - knot_rdataset_t rrs; - void *additional; -} knot_rrset_t; - -struct kr_module; -typedef char *(kr_prop_cb)(void *, struct kr_module *, const char *); -typedef unsigned char knot_dname_storage_t[255]; -typedef struct knot_pkt knot_pkt_t; -typedef struct { - uint8_t *ptr[15]; -} knot_edns_options_t; -typedef struct { - knot_pkt_t *pkt; - uint16_t pos; - uint16_t count; -} knot_pktsection_t; -typedef struct knot_compr { - uint8_t *wire; - knot_rrinfo_t *rrinfo; - struct { - uint16_t pos; - uint8_t labels; - } suffix; -} knot_compr_t; -struct knot_pkt { - uint8_t *wire; - size_t size; - size_t max_size; - size_t parsed; - uint16_t reserved; - uint16_t qname_size; - uint16_t rrset_count; - uint16_t flags; - knot_rrset_t *opt_rr; - knot_rrset_t *tsig_rr; - knot_edns_options_t *edns_opts; - struct { - uint8_t *pos; - size_t len; - } tsig_wire; - knot_section_t current; - knot_pktsection_t sections[3]; - size_t rrset_allocd; - knot_rrinfo_t *rr_info; - knot_rrset_t *rr; - knot_mm_t mm; - knot_compr_t compr; -}; -typedef struct trie trie_t; -struct kr_qflags { - _Bool NO_MINIMIZE : 1; - _Bool NO_IPV6 : 1; - _Bool NO_IPV4 : 1; - _Bool TCP : 1; - _Bool NO_ANSWER : 1; - _Bool RESOLVED : 1; - _Bool AWAIT_IPV4 : 1; - _Bool AWAIT_IPV6 : 1; - _Bool AWAIT_CUT : 1; - _Bool NO_EDNS : 1; - _Bool CACHED : 1; - _Bool NO_CACHE : 1; - _Bool EXPIRING : 1; - _Bool ALLOW_LOCAL : 1; - _Bool DNSSEC_WANT : 1; - _Bool DNSSEC_BOGUS : 1; - _Bool DNSSEC_INSECURE : 1; - _Bool DNSSEC_CD : 1; - _Bool STUB : 1; - _Bool ALWAYS_CUT : 1; - _Bool DNSSEC_WEXPAND : 1; - _Bool PERMISSIVE : 1; - _Bool STRICT : 1; - _Bool BADCOOKIE_AGAIN : 1; - _Bool CNAME : 1; - _Bool REORDER_RR : 1; - _Bool TRACE : 1; - _Bool NO_0X20 : 1; - _Bool DNSSEC_NODS : 1; - _Bool DNSSEC_OPTOUT : 1; - _Bool NONAUTH : 1; - _Bool FORWARD : 1; - _Bool DNS64_MARK : 1; - _Bool CACHE_TRIED : 1; - _Bool NO_NS_FOUND : 1; - _Bool PKT_IS_SANE : 1; - _Bool DNS64_DISABLE : 1; - _Bool PASSTHRU_LEGACY : 1; -}; -typedef struct ranked_rr_array_entry { - uint32_t qry_uid; - uint8_t rank; - uint8_t revalidation_cnt; - _Bool cached : 1; - _Bool yielded : 1; - _Bool to_wire : 1; - _Bool expiring : 1; - _Bool in_progress : 1; - _Bool dont_cache : 1; - knot_rrset_t *rr; -} ranked_rr_array_entry_t; -typedef struct { - ranked_rr_array_entry_t **at; - size_t len; - size_t cap; -} ranked_rr_array_t; -typedef struct kr_http_header_array_entry { - char *name; - char *value; -} kr_http_header_array_entry_t; -typedef struct { - kr_http_header_array_entry_t *at; - size_t len; - size_t cap; -} kr_http_header_array_t; -typedef struct { - union kr_sockaddr *at; - size_t len; - size_t cap; -} kr_sockaddr_array_t; -struct kr_zonecut { - knot_dname_t *name; - knot_rrset_t *key; - knot_rrset_t *trust_anchor; - struct kr_zonecut *parent; - trie_t *nsset; - knot_mm_t *pool; - _Bool avoid_resolving; -}; -typedef struct { - struct kr_query **at; - size_t len; - size_t cap; -} kr_qarray_t; -struct kr_rplan { - kr_qarray_t pending; - kr_qarray_t resolved; - struct kr_query *initial; - struct kr_request *request; - knot_mm_t *pool; - uint32_t next_uid; -}; -struct kr_request_qsource_flags { - _Bool tcp : 1; - _Bool tls : 1; - _Bool http : 1; - _Bool xdp : 1; -}; -typedef unsigned long kr_rule_tags_t; -struct kr_rule_zonefile_config { - const char *filename; - const char *input_str; - size_t input_len; - _Bool is_rpz; - _Bool nodata; - kr_rule_tags_t tags; - const char *origin; - uint32_t ttl; -}; -struct kr_rule_fwd_flags { - _Bool is_auth : 1; - _Bool is_tcp : 1; - _Bool is_nods : 1; -}; -typedef struct kr_rule_fwd_flags kr_rule_fwd_flags_t; -struct kr_extended_error { - int32_t info_code; - const char *extra_text; -}; -struct kr_request { - struct kr_context *ctx; - knot_pkt_t *answer; - struct kr_query *current_query; - struct { - const struct sockaddr *addr; - const struct sockaddr *comm_addr; - const struct sockaddr *dst_addr; - const knot_pkt_t *packet; - struct kr_request_qsource_flags flags; - struct kr_request_qsource_flags comm_flags; - size_t size; - int32_t stream_id; - kr_http_header_array_t headers; - } qsource; - struct { - unsigned int rtt; - const struct kr_transport *transport; - } upstream; - struct kr_qflags options; - int state; - ranked_rr_array_t answ_selected; - ranked_rr_array_t auth_selected; - ranked_rr_array_t add_selected; - _Bool answ_validated; - _Bool auth_validated; - uint8_t rank; - struct kr_rplan rplan; - trace_log_f trace_log; - trace_callback_f trace_finish; - int vars_ref; - knot_mm_t pool; - unsigned int uid; - struct { - addr_info_f is_tls_capable; - addr_info_f is_tcp_connected; - addr_info_f is_tcp_waiting; - kr_sockaddr_array_t forwarding_targets; - } selection_context; - unsigned int count_no_nsaddr; - unsigned int count_fail_row; - alloc_wire_f alloc_wire_cb; - kr_rule_tags_t rule_tags; - struct kr_extended_error extended_error; -}; -enum kr_rank {KR_RANK_INITIAL, KR_RANK_OMIT, KR_RANK_TRY, KR_RANK_INDET = 4, KR_RANK_BOGUS, KR_RANK_MISMATCH, KR_RANK_MISSING, KR_RANK_INSECURE, KR_RANK_AUTH = 16, KR_RANK_SECURE = 32}; -typedef struct kr_cdb * kr_cdb_pt; -struct kr_cdb_stats { - uint64_t open; - uint64_t close; - uint64_t count; - uint64_t count_entries; - uint64_t clear; - uint64_t commit; - uint64_t read; - uint64_t read_miss; - uint64_t write; - uint64_t remove; - uint64_t remove_miss; - uint64_t match; - uint64_t match_miss; - uint64_t read_leq; - uint64_t read_leq_miss; - uint64_t read_less; - double usage_percent; -}; -typedef struct uv_timer_s uv_timer_t; -struct kr_cache { - kr_cdb_pt db; - const struct kr_cdb_api *api; - struct kr_cdb_stats stats; - uint32_t ttl_min; - uint32_t ttl_max; - struct timeval checkpoint_walltime; - uint64_t checkpoint_monotime; - uv_timer_t *health_timer; -}; -typedef struct kr_layer { - int state; - struct kr_request *req; - const struct kr_layer_api *api; - knot_pkt_t *pkt; - struct sockaddr *dst; - _Bool is_stream; -} kr_layer_t; -typedef struct kr_layer_api { - int (*begin)(kr_layer_t *); - int (*reset)(kr_layer_t *); - int (*finish)(kr_layer_t *); - int (*consume)(kr_layer_t *, knot_pkt_t *); - int (*produce)(kr_layer_t *, knot_pkt_t *); - int (*checkout)(kr_layer_t *, knot_pkt_t *, struct sockaddr *, int); - int (*answer_finalize)(kr_layer_t *); - void *data; - int cb_slots[]; -} kr_layer_api_t; -struct kr_prop { - kr_prop_cb *cb; - const char *name; - const char *info; -}; -struct kr_module { - char *name; - int (*init)(struct kr_module *); - int (*deinit)(struct kr_module *); - int (*config)(struct kr_module *, const char *); - const kr_layer_api_t *layer; - const struct kr_prop *props; - void *lib; - void *data; -}; -struct kr_server_selection { - _Bool initialized; - void (*choose_transport)(struct kr_query *, struct kr_transport **); - void (*update_rtt)(struct kr_query *, const struct kr_transport *, unsigned int); - void (*error)(struct kr_query *, const struct kr_transport *, enum kr_selection_error); - struct local_state *local_state; -}; -typedef int kr_log_level_t; -enum kr_log_group {LOG_GRP_UNKNOWN = -1, LOG_GRP_SYSTEM = 1, LOG_GRP_CACHE, LOG_GRP_IO, LOG_GRP_NETWORK, LOG_GRP_TA, LOG_GRP_TLS, LOG_GRP_GNUTLS, LOG_GRP_TLSCLIENT, LOG_GRP_XDP, LOG_GRP_DOH, LOG_GRP_DNSSEC, LOG_GRP_HINT, LOG_GRP_PLAN, LOG_GRP_ITERATOR, LOG_GRP_VALIDATOR, LOG_GRP_RESOLVER, LOG_GRP_SELECTION, LOG_GRP_ZCUT, LOG_GRP_COOKIES, LOG_GRP_STATISTICS, LOG_GRP_REBIND, LOG_GRP_WORKER, LOG_GRP_POLICY, LOG_GRP_TASENTINEL, LOG_GRP_TASIGNALING, LOG_GRP_TAUPDATE, LOG_GRP_DAF, LOG_GRP_DETECTTIMEJUMP, LOG_GRP_DETECTTIMESKEW, LOG_GRP_GRAPHITE, LOG_GRP_PREFILL, LOG_GRP_PRIMING, LOG_GRP_SRVSTALE, LOG_GRP_WATCHDOG, LOG_GRP_NSID, LOG_GRP_DNSTAP, LOG_GRP_TESTS, LOG_GRP_DOTAUTH, LOG_GRP_HTTP, LOG_GRP_CONTROL, LOG_GRP_MODULE, LOG_GRP_DEVEL, LOG_GRP_RENUMBER, LOG_GRP_EDE, LOG_GRP_RULES, LOG_GRP_PROTOLAYER, LOG_GRP_REQDBG}; -struct kr_query_data_src { - _Bool initialized; - _Bool all_set; - uint8_t rule_depth; - kr_rule_fwd_flags_t flags; - knot_db_val_t targets_ptr; -}; -enum kr_rule_sub_t {KR_RULE_SUB_EMPTY = 1, KR_RULE_SUB_NXDOMAIN, KR_RULE_SUB_NODATA, KR_RULE_SUB_REDIRECT}; -enum kr_proto {KR_PROTO_INTERNAL, KR_PROTO_UDP53, KR_PROTO_TCP53, KR_PROTO_DOT, KR_PROTO_DOH, KR_PROTO_DOQ, KR_PROTO_COUNT}; -typedef unsigned char kr_proto_set; -kr_layer_t kr_layer_t_static; -_Bool kr_dbg_assertion_abort; -int kr_dbg_assertion_fork; -const uint32_t KR_RULE_TTL_DEFAULT; - -typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type, - const struct kr_query *qry); - -void kr_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner, - uint16_t type, uint16_t rclass, uint32_t ttl); -struct kr_query { - struct kr_query *parent; - knot_dname_t *sname; - uint16_t stype; - uint16_t sclass; - uint16_t id; - uint16_t reorder; - struct kr_qflags flags; - struct kr_qflags forward_flags; - uint32_t secret; - uint32_t uid; - int32_t vld_limit_crypto_remains; - uint32_t vld_limit_uid; - uint64_t creation_time_mono; - uint64_t timestamp_mono; - struct timeval timestamp; - struct kr_zonecut zone_cut; - struct kr_layer_pickle *deferred; - struct kr_query_data_src data_src; - int8_t cname_depth; - struct kr_query *cname_parent; - struct kr_request *request; - kr_stale_cb stale_cb; - struct kr_server_selection server_selection; -}; -struct kr_context { - struct kr_qflags options; - knot_rrset_t *downstream_opt_rr; - knot_rrset_t *upstream_opt_rr; - trie_t *trust_anchors; - trie_t *negative_anchors; - int32_t vld_limit_crypto; - struct kr_zonecut root_hints; - struct kr_cache cache; - unsigned int cache_rtt_tout_retry_interval; - char _stub[]; -}; -struct kr_transport { - knot_dname_t *ns_name; - /* beware: hidden stub, to avoid hardcoding sockaddr lengths */ -}; -const char *knot_strerror(int); -knot_dname_t *knot_dname_copy(const knot_dname_t *, knot_mm_t *); -knot_dname_t *knot_dname_from_str(uint8_t *, const char *, size_t); -int knot_dname_in_bailiwick(const knot_dname_t *, const knot_dname_t *); -_Bool knot_dname_is_equal(const knot_dname_t *, const knot_dname_t *); -size_t knot_dname_labels(const uint8_t *, const uint8_t *); -size_t knot_dname_size(const knot_dname_t *); -void knot_dname_to_lower(knot_dname_t *); -char *knot_dname_to_str(char *, const knot_dname_t *, size_t); -knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *, uint16_t); -int knot_rdataset_merge(knot_rdataset_t *, const knot_rdataset_t *, knot_mm_t *); -int knot_rrset_add_rdata(knot_rrset_t *, const uint8_t *, uint16_t, knot_mm_t *); -void knot_rrset_free(knot_rrset_t *, knot_mm_t *); -int knot_rrset_txt_dump(const knot_rrset_t *, char **, size_t *, const knot_dump_style_t *); -int knot_rrset_txt_dump_data(const knot_rrset_t *, const size_t, char *, const size_t, const knot_dump_style_t *); -size_t knot_rrset_size(const knot_rrset_t *); -int knot_pkt_begin(knot_pkt_t *, knot_section_t); -int knot_pkt_put_question(knot_pkt_t *, const knot_dname_t *, uint16_t, uint16_t); -int knot_pkt_put_rotate(knot_pkt_t *, uint16_t, const knot_rrset_t *, uint16_t, uint16_t); -knot_pkt_t *knot_pkt_new(void *, uint16_t, knot_mm_t *); -void knot_pkt_free(knot_pkt_t *); -int knot_pkt_parse(knot_pkt_t *, unsigned int); -knot_rrset_t *kr_request_ensure_edns(struct kr_request *); -knot_pkt_t *kr_request_ensure_answer(struct kr_request *); -int kr_request_set_extended_error(struct kr_request *, int, const char *); -struct kr_rplan *kr_resolve_plan(struct kr_request *); -knot_mm_t *kr_resolve_pool(struct kr_request *); -struct kr_query *kr_rplan_push(struct kr_rplan *, struct kr_query *, const knot_dname_t *, uint16_t, uint16_t); -int kr_rplan_pop(struct kr_rplan *, struct kr_query *); -struct kr_query *kr_rplan_resolved(struct kr_rplan *); -struct kr_query *kr_rplan_last(struct kr_rplan *); -int kr_forward_add_target(struct kr_request *, const struct sockaddr *); -_Bool kr_log_is_debug_fun(enum kr_log_group, const struct kr_request *); -void kr_log_req1(const struct kr_request * const, uint32_t, const unsigned int, enum kr_log_group, const char *, const char *, ...); -void kr_log_q1(const struct kr_query * const, enum kr_log_group, const char *, const char *, ...); -const char *kr_log_grp2name(enum kr_log_group); -void kr_log_fmt(enum kr_log_group, kr_log_level_t, const char *, const char *, const char *, const char *, ...); -int kr_make_query(struct kr_query *, knot_pkt_t *); -void kr_pkt_make_auth_header(knot_pkt_t *); -int kr_pkt_put(knot_pkt_t *, const knot_dname_t *, uint32_t, uint16_t, uint16_t, const uint8_t *, uint16_t); -int kr_pkt_recycle(knot_pkt_t *); -int kr_pkt_clear_payload(knot_pkt_t *); -_Bool kr_pkt_has_wire(const knot_pkt_t *); -_Bool kr_pkt_has_dnssec(const knot_pkt_t *); -uint16_t kr_pkt_qclass(const knot_pkt_t *); -uint16_t kr_pkt_qtype(const knot_pkt_t *); -char *kr_pkt_text(const knot_pkt_t *); -void kr_rnd_buffered(void *, unsigned int); -uint32_t kr_rrsig_sig_inception(const knot_rdata_t *); -uint32_t kr_rrsig_sig_expiration(const knot_rdata_t *); -uint16_t kr_rrsig_type_covered(const knot_rdata_t *); -const char *kr_inaddr(const struct sockaddr *); -int kr_inaddr_family(const struct sockaddr *); -int kr_inaddr_len(const struct sockaddr *); -int kr_inaddr_str(const struct sockaddr *, char *, size_t *); -int kr_sockaddr_cmp(const struct sockaddr *, const struct sockaddr *); -int kr_sockaddr_len(const struct sockaddr *); -uint16_t kr_inaddr_port(const struct sockaddr *); -int kr_straddr_family(const char *); -int kr_straddr_subnet(void *, const char *); -int kr_bitcmp(const char *, const char *, int); -int kr_family_len(int); -struct sockaddr *kr_straddr_socket(const char *, int, knot_mm_t *); -int kr_straddr_split(const char *, char * restrict, uint16_t *); -_Bool kr_rank_test(uint8_t, uint8_t); -int kr_ranked_rrarray_add(ranked_rr_array_t *, const knot_rrset_t *, uint8_t, _Bool, uint32_t, knot_mm_t *); -int kr_ranked_rrarray_finalize(ranked_rr_array_t *, uint32_t, knot_mm_t *); -void kr_qflags_set(struct kr_qflags *, struct kr_qflags); -void kr_qflags_clear(struct kr_qflags *, struct kr_qflags); -int kr_zonecut_add(struct kr_zonecut *, const knot_dname_t *, const void *, int); -_Bool kr_zonecut_is_empty(struct kr_zonecut *); -void kr_zonecut_set(struct kr_zonecut *, const knot_dname_t *); -uint64_t kr_now(void); -const char *kr_strptime_diff(const char *, const char *, const char *, double *); -time_t kr_file_mtime(const char *); -long long kr_fssize(const char *); -const char *kr_dirent_name(const struct dirent *); -void lru_free_items_impl(struct lru *); -struct lru *lru_create_impl(unsigned int, unsigned int, knot_mm_t *, knot_mm_t *); -void *lru_get_impl(struct lru *, const char *, unsigned int, unsigned int, _Bool, _Bool *); -void *mm_realloc(knot_mm_t *, void *, size_t, size_t); -knot_rrset_t *kr_ta_get(trie_t *, const knot_dname_t *); -int kr_ta_add(trie_t *, const knot_dname_t *, uint16_t, uint32_t, const uint8_t *, uint16_t); -int kr_ta_del(trie_t *, const knot_dname_t *); -void kr_ta_clear(trie_t *); -_Bool kr_dnssec_key_sep_flag(const uint8_t *); -_Bool kr_dnssec_key_revoked(const uint8_t *); -int kr_dnssec_key_tag(uint16_t, const uint8_t *, size_t); -int kr_dnssec_key_match(const uint8_t *, size_t, const uint8_t *, size_t); -int kr_cache_closest_apex(struct kr_cache *, const knot_dname_t *, _Bool, knot_dname_t **); -int kr_cache_insert_rr(struct kr_cache *, const knot_rrset_t *, const knot_rrset_t *, uint8_t, uint32_t, _Bool); -int kr_cache_remove(struct kr_cache *, const knot_dname_t *, uint16_t); -int kr_cache_remove_subtree(struct kr_cache *, const knot_dname_t *, _Bool, int); -int kr_cache_commit(struct kr_cache *); -uint32_t packet_ttl(const knot_pkt_t *); -int kr_rules_init(const char *, size_t); -int kr_rules_commit(_Bool); -int kr_view_insert_action(const char *, const char *, kr_proto_set, const char *); -int kr_view_select_action(const struct kr_request *, knot_db_val_t *); -int kr_rule_tag_add(const char *, kr_rule_tags_t *); -int kr_rule_local_subtree(const knot_dname_t *, enum kr_rule_sub_t, uint32_t, kr_rule_tags_t); -int kr_rule_zonefile(const struct kr_rule_zonefile_config *); -int kr_rule_forward(const knot_dname_t *, kr_rule_fwd_flags_t, const struct sockaddr **); -int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t); -int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t); -typedef struct { - int sock_type; - _Bool tls; - _Bool http; - _Bool xdp; - _Bool freebind; - const char *kind; -} endpoint_flags_t; -typedef struct { - char **at; - size_t len; - size_t cap; -} addr_array_t; -typedef struct { - int fd; - endpoint_flags_t flags; -} flagged_fd_t; -typedef struct { - flagged_fd_t *at; - size_t len; - size_t cap; -} flagged_fd_array_t; -typedef struct { - const char **at; - size_t len; - size_t cap; -} config_array_t; -struct args { - addr_array_t addrs; - addr_array_t addrs_tls; - flagged_fd_array_t fds; - int control_fd; - int forks; - config_array_t config; - const char *rundir; - _Bool interactive; - _Bool quiet; - _Bool tty_binary_output; -}; -typedef struct { - const char *zone_file; - const char *origin; - uint32_t ttl; - enum {ZI_STAMP_NOW, ZI_STAMP_MTIM} time_src; - _Bool downgrade; - _Bool zonemd; - const knot_rrset_t *ds; - zi_callback cb; - void *cb_param; -} zi_config_t; -struct args *the_args; -struct endpoint { - void *handle; - int fd; - int family; - uint16_t port; - int16_t nic_queue; - _Bool engaged; - endpoint_flags_t flags; -}; -struct request_ctx { - struct kr_request req; - struct qr_task *task; - /* beware: hidden stub, to avoid hardcoding sockaddr lengths */ -}; -struct qr_task { - struct request_ctx *ctx; - /* beware: hidden stub, to avoid qr_tasklist_t */ -}; -int worker_resolve_exec(struct qr_task *, knot_pkt_t *); -knot_pkt_t *worker_resolve_mk_pkt(const char *, uint16_t, uint16_t, const struct kr_qflags *); -struct qr_task *worker_resolve_start(knot_pkt_t *, struct kr_qflags); -int zi_zone_import(const zi_config_t); -_Bool ratelimiting_request_begin(struct kr_request *); -int ratelimiting_init(const char *, size_t, uint32_t, uint32_t, int); -struct engine { - char _stub[]; -}; -struct worker_ctx { - char _stub[]; -}; -struct kr_context *the_resolver; -struct worker_ctx *the_worker; -struct engine *the_engine; -typedef struct { - uint8_t bitmap[32]; - uint8_t length; -} zs_win_t; -typedef struct { - uint8_t excl_flag; - uint16_t addr_family; - uint8_t prefix_length; -} zs_apl_t; -typedef struct { - uint32_t d1; - uint32_t d2; - uint32_t m1; - uint32_t m2; - uint32_t s1; - uint32_t s2; - uint32_t alt; - uint64_t siz; - uint64_t hp; - uint64_t vp; - int8_t lat_sign; - int8_t long_sign; - int8_t alt_sign; -} zs_loc_t; -typedef enum {ZS_STATE_NONE, ZS_STATE_DATA, ZS_STATE_ERROR, ZS_STATE_INCLUDE, ZS_STATE_EOF, ZS_STATE_STOP} zs_state_t; -typedef struct zs_scanner zs_scanner_t; -typedef struct zs_scanner { - int cs; - int top; - int stack[16]; - _Bool multiline; - uint64_t number64; - uint64_t number64_tmp; - uint32_t decimals; - uint32_t decimal_counter; - uint32_t item_length; - uint32_t item_length_position; - uint8_t *item_length_location; - uint32_t buffer_length; - uint8_t buffer[65535]; - char include_filename[65535]; - char *path; - zs_win_t windows[256]; - int16_t last_window; - zs_apl_t apl; - zs_loc_t loc; - uint8_t addr[16]; - _Bool long_string; - uint8_t *dname; - uint32_t *dname_length; - uint32_t dname_tmp_length; - uint32_t r_data_tail; - uint32_t zone_origin_length; - uint8_t zone_origin[318]; - uint16_t default_class; - uint32_t default_ttl; - zs_state_t state; - struct { - _Bool automatic; - void (*record)(zs_scanner_t *); - void (*error)(zs_scanner_t *); - void (*comment)(zs_scanner_t *); - void *data; - } process; - struct { - const char *start; - const char *current; - const char *end; - _Bool eof; - _Bool mmaped; - } input; - struct { - char *name; - int descriptor; - } file; - struct { - int code; - uint64_t counter; - _Bool fatal; - } error; - uint64_t line_counter; - uint32_t r_owner_length; - uint8_t r_owner[318]; - uint16_t r_class; - uint32_t r_ttl; - uint16_t r_type; - uint32_t r_data_length; - uint8_t r_data[65535]; -} zs_scanner_t; -void zs_deinit(zs_scanner_t *); -int zs_init(zs_scanner_t *, const char *, const uint16_t, const uint32_t); -int zs_parse_record(zs_scanner_t *); -int zs_set_input_file(zs_scanner_t *, const char *); -int zs_set_input_string(zs_scanner_t *, const char *, size_t); -const char *zs_strerror(const int); -]] diff --git a/daemon/lua/kres-gen-31.lua b/daemon/lua/kres-gen-31.lua deleted file mode 100644 index 51f93dc7..00000000 --- a/daemon/lua/kres-gen-31.lua +++ /dev/null @@ -1,698 +0,0 @@ --- SPDX-License-Identifier: GPL-3.0-or-later - -local ffi = require('ffi') ---[[ This file is generated by ./kres-gen.sh ]] ffi.cdef[[ - -typedef @time_t@ time_t; -typedef @time_t@ __time_t; -typedef @time_t@ __suseconds_t; -struct timeval { - __time_t tv_sec; - __suseconds_t tv_usec; -}; - -typedef struct knot_dump_style knot_dump_style_t; -extern const knot_dump_style_t KR_DUMP_STYLE_DEFAULT; -struct kr_cdb_api {}; -struct lru {}; -typedef enum {KNOT_ANSWER, KNOT_AUTHORITY, KNOT_ADDITIONAL} knot_section_t; -typedef struct { - uint16_t pos; - uint16_t flags; - uint16_t compress_ptr[16]; -} knot_rrinfo_t; -typedef unsigned char knot_dname_t; -typedef struct { - uint16_t len; - uint8_t data[]; -} knot_rdata_t; -typedef struct { - uint16_t count; - uint32_t size; - knot_rdata_t *rdata; -} knot_rdataset_t; -typedef struct knot_db_val { - void *data; - size_t len; -} knot_db_val_t; - -typedef struct knot_mm { - void *ctx, *alloc, *free; -} knot_mm_t; - -typedef void *(*map_alloc_f)(void *, size_t); -typedef void (*map_free_f)(void *baton, void *ptr); -typedef void (*trace_log_f) (const struct kr_request *, const char *); -typedef void (*trace_callback_f)(struct kr_request *); -typedef uint8_t * (*alloc_wire_f)(struct kr_request *req, uint16_t *maxlen); -typedef bool (*addr_info_f)(struct sockaddr*); -typedef void (*zi_callback)(int state, void *param); -typedef struct { - knot_dname_t *_owner; - uint32_t _ttl; - uint16_t type; - uint16_t rclass; - knot_rdataset_t rrs; - void *additional; -} knot_rrset_t; - -struct kr_module; -typedef char *(kr_prop_cb)(void *, struct kr_module *, const char *); -typedef unsigned char knot_dname_storage_t[255]; -typedef struct knot_pkt knot_pkt_t; -typedef struct { - uint8_t *ptr[18]; -} knot_edns_options_t; -typedef struct { - knot_pkt_t *pkt; - uint16_t pos; - uint16_t count; -} knot_pktsection_t; -typedef struct knot_compr { - uint8_t *wire; - knot_rrinfo_t *rrinfo; - struct { - uint16_t pos; - uint8_t labels; - } suffix; -} knot_compr_t; -struct knot_pkt { - uint8_t *wire; - size_t size; - size_t max_size; - size_t parsed; - uint16_t reserved; - uint16_t qname_size; - uint16_t rrset_count; - uint16_t flags; - knot_rrset_t *opt_rr; - knot_rrset_t *tsig_rr; - knot_edns_options_t *edns_opts; - struct { - uint8_t *pos; - size_t len; - } tsig_wire; - knot_section_t current; - knot_pktsection_t sections[3]; - size_t rrset_allocd; - knot_rrinfo_t *rr_info; - knot_rrset_t *rr; - knot_mm_t mm; - knot_compr_t compr; -}; -typedef struct trie trie_t; -struct kr_qflags { - _Bool NO_MINIMIZE : 1; - _Bool NO_IPV6 : 1; - _Bool NO_IPV4 : 1; - _Bool TCP : 1; - _Bool NO_ANSWER : 1; - _Bool RESOLVED : 1; - _Bool AWAIT_IPV4 : 1; - _Bool AWAIT_IPV6 : 1; - _Bool AWAIT_CUT : 1; - _Bool NO_EDNS : 1; - _Bool CACHED : 1; - _Bool NO_CACHE : 1; - _Bool EXPIRING : 1; - _Bool ALLOW_LOCAL : 1; - _Bool DNSSEC_WANT : 1; - _Bool DNSSEC_BOGUS : 1; - _Bool DNSSEC_INSECURE : 1; - _Bool DNSSEC_CD : 1; - _Bool STUB : 1; - _Bool ALWAYS_CUT : 1; - _Bool DNSSEC_WEXPAND : 1; - _Bool PERMISSIVE : 1; - _Bool STRICT : 1; - _Bool BADCOOKIE_AGAIN : 1; - _Bool CNAME : 1; - _Bool REORDER_RR : 1; - _Bool TRACE : 1; - _Bool NO_0X20 : 1; - _Bool DNSSEC_NODS : 1; - _Bool DNSSEC_OPTOUT : 1; - _Bool NONAUTH : 1; - _Bool FORWARD : 1; - _Bool DNS64_MARK : 1; - _Bool CACHE_TRIED : 1; - _Bool NO_NS_FOUND : 1; - _Bool PKT_IS_SANE : 1; - _Bool DNS64_DISABLE : 1; - _Bool PASSTHRU_LEGACY : 1; -}; -typedef struct ranked_rr_array_entry { - uint32_t qry_uid; - uint8_t rank; - uint8_t revalidation_cnt; - _Bool cached : 1; - _Bool yielded : 1; - _Bool to_wire : 1; - _Bool expiring : 1; - _Bool in_progress : 1; - _Bool dont_cache : 1; - knot_rrset_t *rr; -} ranked_rr_array_entry_t; -typedef struct { - ranked_rr_array_entry_t **at; - size_t len; - size_t cap; -} ranked_rr_array_t; -typedef struct kr_http_header_array_entry { - char *name; - char *value; -} kr_http_header_array_entry_t; -typedef struct { - kr_http_header_array_entry_t *at; - size_t len; - size_t cap; -} kr_http_header_array_t; -typedef struct { - union kr_sockaddr *at; - size_t len; - size_t cap; -} kr_sockaddr_array_t; -struct kr_zonecut { - knot_dname_t *name; - knot_rrset_t *key; - knot_rrset_t *trust_anchor; - struct kr_zonecut *parent; - trie_t *nsset; - knot_mm_t *pool; - _Bool avoid_resolving; -}; -typedef struct { - struct kr_query **at; - size_t len; - size_t cap; -} kr_qarray_t; -struct kr_rplan { - kr_qarray_t pending; - kr_qarray_t resolved; - struct kr_query *initial; - struct kr_request *request; - knot_mm_t *pool; - uint32_t next_uid; -}; -struct kr_request_qsource_flags { - _Bool tcp : 1; - _Bool tls : 1; - _Bool http : 1; - _Bool xdp : 1; -}; -typedef unsigned long kr_rule_tags_t; -struct kr_rule_zonefile_config { - const char *filename; - const char *input_str; - size_t input_len; - _Bool is_rpz; - _Bool nodata; - kr_rule_tags_t tags; - const char *origin; - uint32_t ttl; -}; -struct kr_rule_fwd_flags { - _Bool is_auth : 1; - _Bool is_tcp : 1; - _Bool is_nods : 1; -}; -typedef struct kr_rule_fwd_flags kr_rule_fwd_flags_t; -struct kr_extended_error { - int32_t info_code; - const char *extra_text; -}; -struct kr_request { - struct kr_context *ctx; - knot_pkt_t *answer; - struct kr_query *current_query; - struct { - const struct sockaddr *addr; - const struct sockaddr *comm_addr; - const struct sockaddr *dst_addr; - const knot_pkt_t *packet; - struct kr_request_qsource_flags flags; - struct kr_request_qsource_flags comm_flags; - size_t size; - int32_t stream_id; - kr_http_header_array_t headers; - } qsource; - struct { - unsigned int rtt; - const struct kr_transport *transport; - } upstream; - struct kr_qflags options; - int state; - ranked_rr_array_t answ_selected; - ranked_rr_array_t auth_selected; - ranked_rr_array_t add_selected; - _Bool answ_validated; - _Bool auth_validated; - uint8_t rank; - struct kr_rplan rplan; - trace_log_f trace_log; - trace_callback_f trace_finish; - int vars_ref; - knot_mm_t pool; - unsigned int uid; - struct { - addr_info_f is_tls_capable; - addr_info_f is_tcp_connected; - addr_info_f is_tcp_waiting; - kr_sockaddr_array_t forwarding_targets; - } selection_context; - unsigned int count_no_nsaddr; - unsigned int count_fail_row; - alloc_wire_f alloc_wire_cb; - kr_rule_tags_t rule_tags; - struct kr_extended_error extended_error; -}; -enum kr_rank {KR_RANK_INITIAL, KR_RANK_OMIT, KR_RANK_TRY, KR_RANK_INDET = 4, KR_RANK_BOGUS, KR_RANK_MISMATCH, KR_RANK_MISSING, KR_RANK_INSECURE, KR_RANK_AUTH = 16, KR_RANK_SECURE = 32}; -typedef struct kr_cdb * kr_cdb_pt; -struct kr_cdb_stats { - uint64_t open; - uint64_t close; - uint64_t count; - uint64_t count_entries; - uint64_t clear; - uint64_t commit; - uint64_t read; - uint64_t read_miss; - uint64_t write; - uint64_t remove; - uint64_t remove_miss; - uint64_t match; - uint64_t match_miss; - uint64_t read_leq; - uint64_t read_leq_miss; - uint64_t read_less; - double usage_percent; -}; -typedef struct uv_timer_s uv_timer_t; -struct kr_cache { - kr_cdb_pt db; - const struct kr_cdb_api *api; - struct kr_cdb_stats stats; - uint32_t ttl_min; - uint32_t ttl_max; - struct timeval checkpoint_walltime; - uint64_t checkpoint_monotime; - uv_timer_t *health_timer; -}; -typedef struct kr_layer { - int state; - struct kr_request *req; - const struct kr_layer_api *api; - knot_pkt_t *pkt; - struct sockaddr *dst; - _Bool is_stream; -} kr_layer_t; -typedef struct kr_layer_api { - int (*begin)(kr_layer_t *); - int (*reset)(kr_layer_t *); - int (*finish)(kr_layer_t *); - int (*consume)(kr_layer_t *, knot_pkt_t *); - int (*produce)(kr_layer_t *, knot_pkt_t *); - int (*checkout)(kr_layer_t *, knot_pkt_t *, struct sockaddr *, int); - int (*answer_finalize)(kr_layer_t *); - void *data; - int cb_slots[]; -} kr_layer_api_t; -struct kr_prop { - kr_prop_cb *cb; - const char *name; - const char *info; -}; -struct kr_module { - char *name; - int (*init)(struct kr_module *); - int (*deinit)(struct kr_module *); - int (*config)(struct kr_module *, const char *); - const kr_layer_api_t *layer; - const struct kr_prop *props; - void *lib; - void *data; -}; -struct kr_server_selection { - _Bool initialized; - void (*choose_transport)(struct kr_query *, struct kr_transport **); - void (*update_rtt)(struct kr_query *, const struct kr_transport *, unsigned int); - void (*error)(struct kr_query *, const struct kr_transport *, enum kr_selection_error); - struct local_state *local_state; -}; -typedef int kr_log_level_t; -enum kr_log_group {LOG_GRP_UNKNOWN = -1, LOG_GRP_SYSTEM = 1, LOG_GRP_CACHE, LOG_GRP_IO, LOG_GRP_NETWORK, LOG_GRP_TA, LOG_GRP_TLS, LOG_GRP_GNUTLS, LOG_GRP_TLSCLIENT, LOG_GRP_XDP, LOG_GRP_DOH, LOG_GRP_DNSSEC, LOG_GRP_HINT, LOG_GRP_PLAN, LOG_GRP_ITERATOR, LOG_GRP_VALIDATOR, LOG_GRP_RESOLVER, LOG_GRP_SELECTION, LOG_GRP_ZCUT, LOG_GRP_COOKIES, LOG_GRP_STATISTICS, LOG_GRP_REBIND, LOG_GRP_WORKER, LOG_GRP_POLICY, LOG_GRP_TASENTINEL, LOG_GRP_TASIGNALING, LOG_GRP_TAUPDATE, LOG_GRP_DAF, LOG_GRP_DETECTTIMEJUMP, LOG_GRP_DETECTTIMESKEW, LOG_GRP_GRAPHITE, LOG_GRP_PREFILL, LOG_GRP_PRIMING, LOG_GRP_SRVSTALE, LOG_GRP_WATCHDOG, LOG_GRP_NSID, LOG_GRP_DNSTAP, LOG_GRP_TESTS, LOG_GRP_DOTAUTH, LOG_GRP_HTTP, LOG_GRP_CONTROL, LOG_GRP_MODULE, LOG_GRP_DEVEL, LOG_GRP_RENUMBER, LOG_GRP_EDE, LOG_GRP_RULES, LOG_GRP_PROTOLAYER, LOG_GRP_REQDBG}; -struct kr_query_data_src { - _Bool initialized; - _Bool all_set; - uint8_t rule_depth; - kr_rule_fwd_flags_t flags; - knot_db_val_t targets_ptr; -}; -enum kr_rule_sub_t {KR_RULE_SUB_EMPTY = 1, KR_RULE_SUB_NXDOMAIN, KR_RULE_SUB_NODATA, KR_RULE_SUB_REDIRECT}; -enum kr_proto {KR_PROTO_INTERNAL, KR_PROTO_UDP53, KR_PROTO_TCP53, KR_PROTO_DOT, KR_PROTO_DOH, KR_PROTO_DOQ, KR_PROTO_COUNT}; -typedef unsigned char kr_proto_set; -kr_layer_t kr_layer_t_static; -_Bool kr_dbg_assertion_abort; -int kr_dbg_assertion_fork; -const uint32_t KR_RULE_TTL_DEFAULT; - -typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type, - const struct kr_query *qry); - -void kr_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner, - uint16_t type, uint16_t rclass, uint32_t ttl); -struct kr_query { - struct kr_query *parent; - knot_dname_t *sname; - uint16_t stype; - uint16_t sclass; - uint16_t id; - uint16_t reorder; - struct kr_qflags flags; - struct kr_qflags forward_flags; - uint32_t secret; - uint32_t uid; - int32_t vld_limit_crypto_remains; - uint32_t vld_limit_uid; - uint64_t creation_time_mono; - uint64_t timestamp_mono; - struct timeval timestamp; - struct kr_zonecut zone_cut; - struct kr_layer_pickle *deferred; - struct kr_query_data_src data_src; - int8_t cname_depth; - struct kr_query *cname_parent; - struct kr_request *request; - kr_stale_cb stale_cb; - struct kr_server_selection server_selection; -}; -struct kr_context { - struct kr_qflags options; - knot_rrset_t *downstream_opt_rr; - knot_rrset_t *upstream_opt_rr; - trie_t *trust_anchors; - trie_t *negative_anchors; - int32_t vld_limit_crypto; - struct kr_zonecut root_hints; - struct kr_cache cache; - unsigned int cache_rtt_tout_retry_interval; - char _stub[]; -}; -struct kr_transport { - knot_dname_t *ns_name; - /* beware: hidden stub, to avoid hardcoding sockaddr lengths */ -}; -const char *knot_strerror(int); -knot_dname_t *knot_dname_copy(const knot_dname_t *, knot_mm_t *); -knot_dname_t *knot_dname_from_str(uint8_t *, const char *, size_t); -int knot_dname_in_bailiwick(const knot_dname_t *, const knot_dname_t *); -_Bool knot_dname_is_equal(const knot_dname_t *, const knot_dname_t *); -size_t knot_dname_labels(const uint8_t *, const uint8_t *); -size_t knot_dname_size(const knot_dname_t *); -void knot_dname_to_lower(knot_dname_t *); -char *knot_dname_to_str(char *, const knot_dname_t *, size_t); -knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *, uint16_t); -int knot_rdataset_merge(knot_rdataset_t *, const knot_rdataset_t *, knot_mm_t *); -int knot_rrset_add_rdata(knot_rrset_t *, const uint8_t *, uint16_t, knot_mm_t *); -void knot_rrset_free(knot_rrset_t *, knot_mm_t *); -int knot_rrset_txt_dump(const knot_rrset_t *, char **, size_t *, const knot_dump_style_t *); -int knot_rrset_txt_dump_data(const knot_rrset_t *, const size_t, char *, const size_t, const knot_dump_style_t *); -size_t knot_rrset_size(const knot_rrset_t *); -int knot_pkt_begin(knot_pkt_t *, knot_section_t); -int knot_pkt_put_question(knot_pkt_t *, const knot_dname_t *, uint16_t, uint16_t); -int knot_pkt_put_rotate(knot_pkt_t *, uint16_t, const knot_rrset_t *, uint16_t, uint16_t); -knot_pkt_t *knot_pkt_new(void *, uint16_t, knot_mm_t *); -void knot_pkt_free(knot_pkt_t *); -int knot_pkt_parse(knot_pkt_t *, unsigned int); -knot_rrset_t *kr_request_ensure_edns(struct kr_request *); -knot_pkt_t *kr_request_ensure_answer(struct kr_request *); -int kr_request_set_extended_error(struct kr_request *, int, const char *); -struct kr_rplan *kr_resolve_plan(struct kr_request *); -knot_mm_t *kr_resolve_pool(struct kr_request *); -struct kr_query *kr_rplan_push(struct kr_rplan *, struct kr_query *, const knot_dname_t *, uint16_t, uint16_t); -int kr_rplan_pop(struct kr_rplan *, struct kr_query *); -struct kr_query *kr_rplan_resolved(struct kr_rplan *); -struct kr_query *kr_rplan_last(struct kr_rplan *); -int kr_forward_add_target(struct kr_request *, const struct sockaddr *); -_Bool kr_log_is_debug_fun(enum kr_log_group, const struct kr_request *); -void kr_log_req1(const struct kr_request * const, uint32_t, const unsigned int, enum kr_log_group, const char *, const char *, ...); -void kr_log_q1(const struct kr_query * const, enum kr_log_group, const char *, const char *, ...); -const char *kr_log_grp2name(enum kr_log_group); -void kr_log_fmt(enum kr_log_group, kr_log_level_t, const char *, const char *, const char *, const char *, ...); -int kr_make_query(struct kr_query *, knot_pkt_t *); -void kr_pkt_make_auth_header(knot_pkt_t *); -int kr_pkt_put(knot_pkt_t *, const knot_dname_t *, uint32_t, uint16_t, uint16_t, const uint8_t *, uint16_t); -int kr_pkt_recycle(knot_pkt_t *); -int kr_pkt_clear_payload(knot_pkt_t *); -_Bool kr_pkt_has_wire(const knot_pkt_t *); -_Bool kr_pkt_has_dnssec(const knot_pkt_t *); -uint16_t kr_pkt_qclass(const knot_pkt_t *); -uint16_t kr_pkt_qtype(const knot_pkt_t *); -char *kr_pkt_text(const knot_pkt_t *); -void kr_rnd_buffered(void *, unsigned int); -uint32_t kr_rrsig_sig_inception(const knot_rdata_t *); -uint32_t kr_rrsig_sig_expiration(const knot_rdata_t *); -uint16_t kr_rrsig_type_covered(const knot_rdata_t *); -const char *kr_inaddr(const struct sockaddr *); -int kr_inaddr_family(const struct sockaddr *); -int kr_inaddr_len(const struct sockaddr *); -int kr_inaddr_str(const struct sockaddr *, char *, size_t *); -int kr_sockaddr_cmp(const struct sockaddr *, const struct sockaddr *); -int kr_sockaddr_len(const struct sockaddr *); -uint16_t kr_inaddr_port(const struct sockaddr *); -int kr_straddr_family(const char *); -int kr_straddr_subnet(void *, const char *); -int kr_bitcmp(const char *, const char *, int); -int kr_family_len(int); -struct sockaddr *kr_straddr_socket(const char *, int, knot_mm_t *); -int kr_straddr_split(const char *, char * restrict, uint16_t *); -_Bool kr_rank_test(uint8_t, uint8_t); -int kr_ranked_rrarray_add(ranked_rr_array_t *, const knot_rrset_t *, uint8_t, _Bool, uint32_t, knot_mm_t *); -int kr_ranked_rrarray_finalize(ranked_rr_array_t *, uint32_t, knot_mm_t *); -void kr_qflags_set(struct kr_qflags *, struct kr_qflags); -void kr_qflags_clear(struct kr_qflags *, struct kr_qflags); -int kr_zonecut_add(struct kr_zonecut *, const knot_dname_t *, const void *, int); -_Bool kr_zonecut_is_empty(struct kr_zonecut *); -void kr_zonecut_set(struct kr_zonecut *, const knot_dname_t *); -uint64_t kr_now(void); -const char *kr_strptime_diff(const char *, const char *, const char *, double *); -time_t kr_file_mtime(const char *); -long long kr_fssize(const char *); -const char *kr_dirent_name(const struct dirent *); -void lru_free_items_impl(struct lru *); -struct lru *lru_create_impl(unsigned int, unsigned int, knot_mm_t *, knot_mm_t *); -void *lru_get_impl(struct lru *, const char *, unsigned int, unsigned int, _Bool, _Bool *); -void *mm_realloc(knot_mm_t *, void *, size_t, size_t); -knot_rrset_t *kr_ta_get(trie_t *, const knot_dname_t *); -int kr_ta_add(trie_t *, const knot_dname_t *, uint16_t, uint32_t, const uint8_t *, uint16_t); -int kr_ta_del(trie_t *, const knot_dname_t *); -void kr_ta_clear(trie_t *); -_Bool kr_dnssec_key_sep_flag(const uint8_t *); -_Bool kr_dnssec_key_revoked(const uint8_t *); -int kr_dnssec_key_tag(uint16_t, const uint8_t *, size_t); -int kr_dnssec_key_match(const uint8_t *, size_t, const uint8_t *, size_t); -int kr_cache_closest_apex(struct kr_cache *, const knot_dname_t *, _Bool, knot_dname_t **); -int kr_cache_insert_rr(struct kr_cache *, const knot_rrset_t *, const knot_rrset_t *, uint8_t, uint32_t, _Bool); -int kr_cache_remove(struct kr_cache *, const knot_dname_t *, uint16_t); -int kr_cache_remove_subtree(struct kr_cache *, const knot_dname_t *, _Bool, int); -int kr_cache_commit(struct kr_cache *); -uint32_t packet_ttl(const knot_pkt_t *); -int kr_rules_init(const char *, size_t); -int kr_rules_commit(_Bool); -int kr_view_insert_action(const char *, const char *, kr_proto_set, const char *); -int kr_view_select_action(const struct kr_request *, knot_db_val_t *); -int kr_rule_tag_add(const char *, kr_rule_tags_t *); -int kr_rule_local_subtree(const knot_dname_t *, enum kr_rule_sub_t, uint32_t, kr_rule_tags_t); -int kr_rule_zonefile(const struct kr_rule_zonefile_config *); -int kr_rule_forward(const knot_dname_t *, kr_rule_fwd_flags_t, const struct sockaddr **); -int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t); -int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t); -typedef struct { - int sock_type; - _Bool tls; - _Bool http; - _Bool xdp; - _Bool freebind; - const char *kind; -} endpoint_flags_t; -typedef struct { - char **at; - size_t len; - size_t cap; -} addr_array_t; -typedef struct { - int fd; - endpoint_flags_t flags; -} flagged_fd_t; -typedef struct { - flagged_fd_t *at; - size_t len; - size_t cap; -} flagged_fd_array_t; -typedef struct { - const char **at; - size_t len; - size_t cap; -} config_array_t; -struct args { - addr_array_t addrs; - addr_array_t addrs_tls; - flagged_fd_array_t fds; - int control_fd; - int forks; - config_array_t config; - const char *rundir; - _Bool interactive; - _Bool quiet; - _Bool tty_binary_output; -}; -typedef struct { - const char *zone_file; - const char *origin; - uint32_t ttl; - enum {ZI_STAMP_NOW, ZI_STAMP_MTIM} time_src; - _Bool downgrade; - _Bool zonemd; - const knot_rrset_t *ds; - zi_callback cb; - void *cb_param; -} zi_config_t; -struct args *the_args; -struct endpoint { - void *handle; - int fd; - int family; - uint16_t port; - int16_t nic_queue; - _Bool engaged; - endpoint_flags_t flags; -}; -struct request_ctx { - struct kr_request req; - struct qr_task *task; - /* beware: hidden stub, to avoid hardcoding sockaddr lengths */ -}; -struct qr_task { - struct request_ctx *ctx; - /* beware: hidden stub, to avoid qr_tasklist_t */ -}; -int worker_resolve_exec(struct qr_task *, knot_pkt_t *); -knot_pkt_t *worker_resolve_mk_pkt(const char *, uint16_t, uint16_t, const struct kr_qflags *); -struct qr_task *worker_resolve_start(knot_pkt_t *, struct kr_qflags); -int zi_zone_import(const zi_config_t); -_Bool ratelimiting_request_begin(struct kr_request *); -int ratelimiting_init(const char *, size_t, uint32_t, uint32_t, int); -struct engine { - char _stub[]; -}; -struct worker_ctx { - char _stub[]; -}; -struct kr_context *the_resolver; -struct worker_ctx *the_worker; -struct engine *the_engine; -typedef struct { - uint8_t *params_position; - uint8_t *mandatory_position; - uint8_t *param_position; - int32_t last_key; -} zs_svcb_t; -typedef struct { - uint8_t bitmap[32]; - uint8_t length; -} zs_win_t; -typedef struct { - uint8_t excl_flag; - uint16_t addr_family; - uint8_t prefix_length; -} zs_apl_t; -typedef struct { - uint32_t d1; - uint32_t d2; - uint32_t m1; - uint32_t m2; - uint32_t s1; - uint32_t s2; - uint32_t alt; - uint64_t siz; - uint64_t hp; - uint64_t vp; - int8_t lat_sign; - int8_t long_sign; - int8_t alt_sign; -} zs_loc_t; -typedef enum {ZS_STATE_NONE, ZS_STATE_DATA, ZS_STATE_ERROR, ZS_STATE_INCLUDE, ZS_STATE_EOF, ZS_STATE_STOP} zs_state_t; -typedef struct zs_scanner zs_scanner_t; -typedef struct zs_scanner { - int cs; - int top; - int stack[16]; - _Bool multiline; - uint64_t number64; - uint64_t number64_tmp; - uint32_t decimals; - uint32_t decimal_counter; - uint32_t item_length; - uint32_t item_length_position; - uint8_t *item_length_location; - uint8_t *item_length2_location; - uint32_t buffer_length; - uint8_t buffer[65535]; - char include_filename[65535]; - char *path; - zs_win_t windows[256]; - int16_t last_window; - zs_apl_t apl; - zs_loc_t loc; - zs_svcb_t svcb; - uint8_t addr[16]; - _Bool long_string; - _Bool comma_list; - uint8_t *dname; - uint32_t *dname_length; - uint32_t dname_tmp_length; - uint32_t r_data_tail; - uint32_t zone_origin_length; - uint8_t zone_origin[318]; - uint16_t default_class; - uint32_t default_ttl; - zs_state_t state; - struct { - _Bool automatic; - void (*record)(zs_scanner_t *); - void (*error)(zs_scanner_t *); - void (*comment)(zs_scanner_t *); - void *data; - } process; - struct { - const char *start; - const char *current; - const char *end; - _Bool eof; - _Bool mmaped; - } input; - struct { - char *name; - int descriptor; - } file; - struct { - int code; - uint64_t counter; - _Bool fatal; - } error; - uint64_t line_counter; - uint32_t r_owner_length; - uint8_t r_owner[318]; - uint16_t r_class; - uint32_t r_ttl; - uint16_t r_type; - uint32_t r_data_length; - uint8_t r_data[65535]; -} zs_scanner_t; -void zs_deinit(zs_scanner_t *); -int zs_init(zs_scanner_t *, const char *, const uint16_t, const uint32_t); -int zs_parse_record(zs_scanner_t *); -int zs_set_input_file(zs_scanner_t *, const char *); -int zs_set_input_string(zs_scanner_t *, const char *, size_t); -const char *zs_strerror(const int); -]] diff --git a/daemon/lua/kres-gen-32.lua b/daemon/lua/kres-gen-33.lua index 35acdeb1..24ace53d 100644 --- a/daemon/lua/kres-gen-32.lua +++ b/daemon/lua/kres-gen-33.lua @@ -498,8 +498,9 @@ int kr_cache_remove(struct kr_cache *, const knot_dname_t *, uint16_t); int kr_cache_remove_subtree(struct kr_cache *, const knot_dname_t *, _Bool, int); int kr_cache_commit(struct kr_cache *); uint32_t packet_ttl(const knot_pkt_t *); -int kr_rules_init(const char *, size_t); +int kr_rules_init(const char *, size_t, _Bool); int kr_rules_commit(_Bool); +int kr_rules_reset(void); int kr_view_insert_action(const char *, const char *, kr_proto_set, const char *); int kr_view_select_action(const struct kr_request *, knot_db_val_t *); int kr_rule_tag_add(const char *, kr_rule_tags_t *); @@ -508,6 +509,7 @@ int kr_rule_zonefile(const struct kr_rule_zonefile_config *); int kr_rule_forward(const knot_dname_t *, kr_rule_fwd_flags_t, const struct sockaddr **); int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t); int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t); +struct tls_credentials; typedef struct { int sock_type; _Bool tls; @@ -558,6 +560,36 @@ typedef struct { zi_callback cb; void *cb_param; } zi_config_t; +typedef struct uv_loop_s uv_loop_t; +typedef struct trie tls_client_params_t; +struct net_tcp_param { + uint64_t in_idle_timeout; + uint64_t tls_handshake_timeout; + unsigned int user_timeout; +}; +struct network { + uv_loop_t *loop; + trie_t *endpoints; + trie_t *endpoint_kinds; + _Bool missing_kind_is_error : 1; + _Bool proxy_all4 : 1; + _Bool proxy_all6 : 1; + trie_t *proxy_addrs4; + trie_t *proxy_addrs6; + struct tls_credentials *tls_credentials; + tls_client_params_t *tls_client_params; + struct tls_session_ticket_ctx *tls_session_ticket_ctx; + struct net_tcp_param tcp; + int tcp_backlog; + struct { + int snd; + int rcv; + } listen_udp_buflens; + struct { + int snd; + int rcv; + } listen_tcp_buflens; +}; struct args *the_args; struct endpoint { void *handle; @@ -592,6 +624,7 @@ struct worker_ctx { struct kr_context *the_resolver; struct worker_ctx *the_worker; struct engine *the_engine; +struct network *the_network; typedef struct { uint8_t *params_position; uint8_t *mandatory_position; @@ -649,6 +682,7 @@ typedef struct zs_scanner { uint8_t addr[16]; _Bool long_string; _Bool comma_list; + _Bool pending_backslash; uint8_t *dname; uint32_t *dname_length; uint32_t dname_tmp_length; diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh index beb4b7e8..ab289b0d 100755 --- a/daemon/lua/kres-gen.sh +++ b/daemon/lua/kres-gen.sh @@ -299,6 +299,7 @@ ${CDEFS} ${LIBKRES} functions <<-EOF # New policy kr_rules_init kr_rules_commit + kr_rules_reset kr_view_insert_action kr_view_select_action kr_rule_tag_add @@ -311,6 +312,7 @@ EOF ## kresd itself: worker stuff +echo "struct tls_credentials;" ${CDEFS} ${KRESD} types <<-EOF endpoint_flags_t @@ -321,6 +323,11 @@ ${CDEFS} ${KRESD} types <<-EOF config_array_t struct args zi_config_t + # struct network - and all requirements that are missing so far + typedef uv_loop_t + typedef tls_client_params_t + struct net_tcp_param + struct network EOF echo "struct args *the_args;" @@ -350,6 +357,7 @@ printf "\tchar _stub[];\n};\n" echo "struct kr_context *the_resolver;" echo "struct worker_ctx *the_worker;" echo "struct engine *the_engine;" +echo "struct network *the_network;" ## libzscanner API for ./zonefile.lua diff --git a/daemon/lua/meson.build b/daemon/lua/meson.build index 6df5bc5b..267bb56d 100644 --- a/daemon/lua/meson.build +++ b/daemon/lua/meson.build @@ -39,12 +39,8 @@ distro_preconfig = configure_file( ) # Unfortunately the different ABI implies different contents of 'kres-gen.lua'. -if libknot.version().version_compare('>= 3.2') - kres_gen_fname = 'kres-gen-32.lua' -elif libknot.version().version_compare('>= 3.1') - kres_gen_fname = 'kres-gen-31.lua' -else - kres_gen_fname = 'kres-gen-30.lua' +if libknot.version().version_compare('>= 3.3') + kres_gen_fname = 'kres-gen-33.lua' endif # Exact types around time_t aren't easy to detect, but at least we need the same size. @@ -84,10 +80,15 @@ if get_option('kres_gen_test') and not meson.is_cross_build() { 'tname': 'knot_pkt_t', 'incl' : '#include <libknot/packet/pkt.h>', 'dep': libknot }, ] # Construct the lua tester as a meson string. + if meson.version().version_compare('>=1.4') + kres_gen_lua_path = kres_gen_lua.full_path() + else + kres_gen_lua_path = '@0@/../../@1@'.format(meson.current_build_dir(), kres_gen_lua) + endif kres_gen_test_luastr = ''' - dofile('@0@/../../@1@') + dofile('@0@') local ffi = require('ffi') - '''.format(meson.current_build_dir(), kres_gen_lua) + '''.format(kres_gen_lua_path) foreach ttc: types_to_check # We're careful with adding just includes; otherwise it's more fragile (e.g. linking flags). if 'dep' in ttc diff --git a/daemon/main.c b/daemon/main.c index 95df2e5a..d18f59f9 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -14,10 +14,6 @@ #include "daemon/ratelimiting.h" #include "daemon/defer.h" -#ifdef ENABLE_DOH2 -#include "daemon/http.h" -#endif - #include "lib/defines.h" #include "lib/dnssec.h" #include "lib/log.h" @@ -586,13 +582,6 @@ int main(int argc, char **argv) uv_strerror(ret)); } - io_protolayers_init(); - tls_protolayers_init(); - proxy_protolayers_init(); -#ifdef ENABLE_DOH2 - http_protolayers_init(); -#endif - /* Start listening, in the sense of network_listen_fd(). */ if (start_listening(&the_args->fds) != 0) { ret = EXIT_FAILURE; diff --git a/daemon/network.c b/daemon/network.c index 1ec34e90..59d47809 100644 --- a/daemon/network.c +++ b/daemon/network.c @@ -76,7 +76,12 @@ void network_init(uv_loop_t *loop, int tcp_backlog) tls_session_ticket_ctx_create(loop, NULL, 0); the_network->tcp.in_idle_timeout = 10000; the_network->tcp.tls_handshake_timeout = TLS_MAX_HANDSHAKE_TIME; + the_network->tcp.user_timeout = 1000; // 1s should be more than enough the_network->tcp_backlog = tcp_backlog; + + // On Linux, unset means some auto-tuning mechanism also depending on RAM, + // which might be OK default (together with the user_timeout above) + //the_network->listen_{tcp,udp}_buflens.{snd,rcv} } /** Notify the registered function about endpoint getting open. @@ -102,7 +107,7 @@ static int endpoint_open_lua_cb(struct endpoint *ep, if (!pp) return kr_ok(); /* Now execute the callback. */ - const int fun_id = (char *)*pp - (char *)NULL; + const int fun_id = (intptr_t)*pp; lua_rawgeti(L, LUA_REGISTRYINDEX, fun_id); lua_pushboolean(L, true /* open */); lua_pushpointer(L, ep); @@ -182,7 +187,7 @@ static void endpoint_close_lua_cb(struct endpoint *ep) } if (!pp) return; - const int fun_id = (char *)*pp - (char *)NULL; + const int fun_id = (intptr_t)*pp; lua_rawgeti(L, LUA_REGISTRYINDEX, fun_id); lua_pushboolean(L, false /* close */); lua_pushpointer(L, ep); @@ -262,7 +267,7 @@ static int free_key(trie_val_t *val, void* ext) int kind_unregister(trie_val_t *tv, void *L) { - int fun_id = (char *)*tv - (char *)NULL; + int fun_id = (intptr_t)*tv; luaL_unref(L, LUA_REGISTRYINDEX, fun_id); return 0; } diff --git a/daemon/network.h b/daemon/network.h index 9c667dbd..83d1b6f4 100644 --- a/daemon/network.h +++ b/daemon/network.h @@ -67,6 +67,10 @@ typedef array_t(struct endpoint) endpoint_array_t; struct net_tcp_param { uint64_t in_idle_timeout; uint64_t tls_handshake_timeout; + + /** Milliseconds of unacknowledged data; see TCP_USER_TIMEOUT in man tcp.7 + * Linux only, probably. */ + unsigned int user_timeout; }; /** Information about an address that is allowed to use PROXYv2. */ @@ -104,6 +108,13 @@ struct network { struct tls_session_ticket_ctx *tls_session_ticket_ctx; struct net_tcp_param tcp; int tcp_backlog; + + /** Kernel-side buffer sizes for sending and receiving. (in bytes) + * They are per socket, so in the TCP case they are per connection. + * See SO_SNDBUF and SO_RCVBUF in man socket.7 These are in POSIX. */ + struct { + int snd, rcv; + } listen_udp_buflens, listen_tcp_buflens; }; /** Pointer to the singleton network state. NULL if not initialized. */ diff --git a/daemon/proxyv2.c b/daemon/proxyv2.c index 8f1ca8f1..48eff866 100644 --- a/daemon/proxyv2.c +++ b/daemon/proxyv2.c @@ -405,7 +405,7 @@ static enum protolayer_iter_cb_result pl_proxyv2_stream_unwrap( "for this peer, close\n", kr_straddr(peer)); } - worker_end_tcp(s); + session2_force_close(s); return protolayer_break(ctx, kr_error(ECONNRESET)); } @@ -422,7 +422,7 @@ static enum protolayer_iter_cb_result pl_proxyv2_stream_unwrap( kr_straddr(comm->src_addr)); } } - worker_end_tcp(s); + session2_force_close(s); return protolayer_break(ctx, kr_error(ECONNRESET)); } else if (trimmed == 0) { session2_close(s); @@ -448,8 +448,8 @@ static enum protolayer_iter_cb_result pl_proxyv2_stream_unwrap( return protolayer_continue(ctx); } - -void proxy_protolayers_init(void) +__attribute__((constructor)) +static void proxy_protolayers_init(void) { protolayer_globals[PROTOLAYER_TYPE_PROXYV2_DGRAM] = (struct protolayer_globals){ .iter_size = sizeof(struct pl_proxyv2_dgram_iter_data), diff --git a/daemon/proxyv2.h b/daemon/proxyv2.h index 9bba3476..8f16ea10 100644 --- a/daemon/proxyv2.h +++ b/daemon/proxyv2.h @@ -34,6 +34,3 @@ struct proxy_result { /** Checks whether the use of PROXYv2 protocol is allowed for the specified * address. */ bool proxy_allowed(const struct sockaddr *saddr); - -/** 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 b7511cd7..f9be09f2 100644 --- a/daemon/session2.c +++ b/daemon/session2.c @@ -406,19 +406,21 @@ static int protolayer_iter_ctx_finish(struct protolayer_iter_ctx *ctx, int ret) globals->iter_deinit(ctx, d); } - if (ret) + if (ret) { 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(s, "iteration of group '%s' (on %u: %s) ended with status %d\n", + if (ctx->status) { + VERBOSE_LOG(s, "iteration of group '%s' (on %u: %s) ended with status '%s (%d)'\n", kr_proto_name(s->proto), - ctx->layer_ix, layer_name_ctx(ctx), ctx->status); + ctx->layer_ix, layer_name_ctx(ctx), + kr_strerror(ctx->status), ctx->status); + } if (ctx->finished_cb) - ctx->finished_cb(ret, s, ctx->comm, - ctx->finished_cb_baton); + ctx->finished_cb(ret, s, ctx->comm, ctx->finished_cb_baton); mm_ctx_delete(&ctx->pool); free(ctx); @@ -1263,7 +1265,7 @@ static void session2_event_wrap(struct session2 *s, enum protolayer_event_type e session2_transport_event(s, event, baton); } -void session2_event_unwrap(struct session2 *s, ssize_t start_ix, enum protolayer_event_type event, void *baton) +static void session2_event_unwrap(struct session2 *s, ssize_t start_ix, enum protolayer_event_type event, void *baton) { bool cont; const struct protolayer_grp *grp = &protolayer_grps[s->proto]; @@ -1284,8 +1286,9 @@ void session2_event_unwrap(struct session2 *s, ssize_t start_ix, enum protolayer * * TODO: This might be undesirable for cases with sub-sessions - the * current idea is for the layers managing sub-sessions to just return - * `false` on `event_unwrap`, but a more "automatic" mechanism may be - * added when this is relevant, to make it less error-prone. */ + * `PROTOLAYER_EVENT_CONSUME` on `event_unwrap`, but a more "automatic" + * mechanism may be added when this is relevant, to make it less + * error-prone. */ session2_event_wrap(s, event, baton); } @@ -1408,6 +1411,15 @@ static void session2_transport_pushv_ensure_long_lived( *iovcnt = 1; } +/// Count the total size of an iovec[] in bytes. +static inline size_t iovec_sum(const struct iovec iov[], const int iovcnt) +{ + size_t result = 0; + for (int i = 0; i < iovcnt; ++i) + result += iov[i].iov_len; + return result; +} + static int session2_transport_pushv(struct session2 *s, struct iovec *iov, int iovcnt, bool iov_short_lived, @@ -1462,6 +1474,11 @@ static int session2_transport_pushv(struct session2 *s, int ret = uv_udp_try_send((uv_udp_t*)handle, (uv_buf_t *)iov, iovcnt, comm->comm_addr); if (ret == UV_EAGAIN) { + ret = kr_error(ENOBUFS); + session2_event(s, PROTOLAYER_EVENT_OS_BUFFER_FULL, NULL); + } + + if (false && ret == UV_EAGAIN) { // XXX: see uv_try_write() below uv_udp_send_t *req = malloc(sizeof(*req)); req->data = ctx; session2_transport_pushv_ensure_long_lived( @@ -1472,14 +1489,23 @@ static int session2_transport_pushv(struct session2 *s, session2_transport_udp_pushv_finished); if (ret) session2_transport_udp_pushv_finished(req, ret); - } else { - session2_transport_pushv_finished(ret, ctx); + return ret; } + + session2_transport_pushv_finished(ret, ctx); return ret; } } else if (handle->type == UV_TCP) { int ret = uv_try_write((uv_stream_t *)handle, (uv_buf_t *)iov, iovcnt); - if (ret == UV_EAGAIN) { + // XXX: queueing disabled for now if the OS can't accept the data. + // Typically that happens when OS buffers are full. + // We were missing any handling of partial write success, too. + if (ret == UV_EAGAIN || (ret >= 0 && ret != iovec_sum(iov, iovcnt))) { + ret = kr_error(ENOBUFS); + session2_event(s, PROTOLAYER_EVENT_OS_BUFFER_FULL, NULL); + } + + if (false && ret == UV_EAGAIN) { uv_write_t *req = malloc(sizeof(*req)); req->data = ctx; session2_transport_pushv_ensure_long_lived( @@ -1489,9 +1515,10 @@ static int session2_transport_pushv(struct session2 *s, session2_transport_stream_pushv_finished); if (ret) session2_transport_stream_pushv_finished(req, ret); - } else { - session2_transport_pushv_finished(ret, ctx); + return ret; } + + session2_transport_pushv_finished(ret, ctx); return ret; #if ENABLE_XDP } else if (handle->type == UV_POLL) { @@ -1512,7 +1539,7 @@ static int session2_transport_pushv(struct session2 *s, &iovecmem, ctx); knot_xdp_msg_t msg; -#if KNOT_VERSION_HEX >= 0x030100 + /* We don't have a nice way of preserving the _msg_t from frame allocation, * so we manually redo all other parts of knot_xdp_send_alloc() */ memset(&msg, 0, sizeof(msg)); @@ -1520,7 +1547,7 @@ static int session2_transport_pushv(struct session2 *s, msg.flags = ipv6 ? KNOT_XDP_MSG_IPV6 : 0; memcpy(msg.eth_from, comm->eth_from, sizeof(comm->eth_from)); memcpy(msg.eth_to, comm->eth_to, sizeof(comm->eth_to)); -#endif + const struct sockaddr *ip_from = comm->dst_addr; const struct sockaddr *ip_to = comm->comm_addr; memcpy(&msg.ip_from, ip_from, kr_sockaddr_len(ip_from)); diff --git a/daemon/session2.h b/daemon/session2.h index fdcc1fc3..50fb697b 100644 --- a/daemon/session2.h +++ b/daemon/session2.h @@ -314,23 +314,31 @@ typedef void (*protolayer_finished_cb)(int status, struct session2 *session, * Event types are used to distinguish different events that can be passed to * sessions using `session2_event()`. */ #define PROTOLAYER_EVENT_MAP(XX) \ - XX(CLOSE) /**< Sending this event closes the session gracefully - - * i.e. layers add their standard disconnection - * ceremony (e.g. `gnutls_bye()`). */\ - XX(FORCE_CLOSE) /**< Sending this event closes the session forcefully - - * i.e. layers SHOULD NOT add any disconnection - * ceremony, if avoidable. */\ - XX(CONNECT_TIMEOUT) /**< Signal that a connection could not be - * established due to a timeout. */\ - XX(GENERAL_TIMEOUT) /**< Signal that a general application-defined - * timeout has occurred. */\ - XX(CONNECT) /**< Signal that a connection has been established. */\ - XX(CONNECT_FAIL) /**< Signal that a connection could not have been - * established. */\ - XX(MALFORMED) /**< Signal that a malformed request has been received. */\ - XX(DISCONNECT) /**< Signal that a connection has ended. */\ - XX(STATS_SEND_ERR) /**< Failed task send - update stats. */\ - XX(STATS_QRY_OUT) /**< Outgoing query submission - update stats. */ + /** Closes the session gracefully - i.e. layers add their standard + * disconnection ceremony (e.g. `gnutls_bye()`). */\ + XX(CLOSE) \ + /** Closes the session forcefully - i.e. layers SHOULD NOT add any + * disconnection ceremony, if avoidable. */\ + XX(FORCE_CLOSE) \ + /** Signal that a connection could not be established due to a timeout. */\ + XX(CONNECT_TIMEOUT) \ + /** Signal that a general application-defined timeout has occurred. */\ + XX(GENERAL_TIMEOUT) \ + /** Signal that a connection has been established. */\ + XX(CONNECT) \ + /** Signal that a connection could not have been established. */\ + XX(CONNECT_FAIL) \ + /** Signal that a malformed request has been received. */\ + XX(MALFORMED) \ + /** Signal that a connection has ended. */\ + XX(DISCONNECT) \ + /** Failed task send - update stats. */\ + XX(STATS_SEND_ERR) \ + /** Outgoing query submission - update stats. */\ + XX(STATS_QRY_OUT) \ + /** OS buffers are full, so not sending any more data. */\ + XX(OS_BUFFER_FULL) \ + // /** Event type, to be interpreted by a layer. */ enum protolayer_event_type { diff --git a/daemon/tls.c b/daemon/tls.c index a5169ae3..173cf3c3 100644 --- a/daemon/tls.c +++ b/daemon/tls.c @@ -789,7 +789,7 @@ static int client_verify_pin(const unsigned int cert_list_size, * * \returns GNUTLS_E_SUCCESS if certificate chain is valid, any other value is an error */ -static int client_verify_certchain(gnutls_session_t tls_session, const char *hostname) +static int client_verify_certchain(struct pl_tls_sess_data *tls, const char *hostname) { if (kr_fails_assert(hostname)) { kr_log_error(TLSCLIENT, "internal config inconsistency: no hostname set\n"); @@ -797,27 +797,30 @@ static int client_verify_certchain(gnutls_session_t tls_session, const char *hos } unsigned int status; - int ret = gnutls_certificate_verify_peers3(tls_session, hostname, &status); + int ret = gnutls_certificate_verify_peers3(tls->tls_session, hostname, &status); if ((ret == GNUTLS_E_SUCCESS) && (status == 0)) { return GNUTLS_E_SUCCESS; } + const char *addr_str = kr_straddr(session2_get_peer(tls->h.session)); if (ret == GNUTLS_E_SUCCESS) { gnutls_datum_t msg; ret = gnutls_certificate_verification_status_print( - status, gnutls_certificate_type_get(tls_session), &msg, 0); + status, gnutls_certificate_type_get(tls->tls_session), &msg, 0); if (ret == GNUTLS_E_SUCCESS) { - kr_log_error(TLSCLIENT, "failed to verify peer certificate: " - "%s\n", msg.data); + kr_log_error(TLSCLIENT, "failed to verify peer certificate of %s: " + "%s\n", addr_str, msg.data); gnutls_free(msg.data); } else { - kr_log_error(TLSCLIENT, "failed to verify peer certificate: " + kr_log_error(TLSCLIENT, "failed to verify peer certificate of %s: " "unable to print reason: %s (%s)\n", + addr_str, gnutls_strerror(ret), gnutls_strerror_name(ret)); } /* gnutls_certificate_verification_status_print end */ } else { - kr_log_error(TLSCLIENT, "failed to verify peer certificate: " + kr_log_error(TLSCLIENT, "failed to verify peer certificate of %s: " "gnutls_certificate_verify_peers3 error: %s (%s)\n", + addr_str, gnutls_strerror(ret), gnutls_strerror_name(ret)); } /* gnutls_certificate_verify_peers3 end */ return GNUTLS_E_CERTIFICATE_ERROR; @@ -856,7 +859,7 @@ static int client_verify_certificate(gnutls_session_t tls_session) /* check hash of the certificate but ignore everything else */ return client_verify_pin(cert_list_size, cert_list, tls->client_params); else - return client_verify_certchain(tls->tls_session, tls->client_params->hostname); + return client_verify_certchain(tls, tls->client_params->hostname); } static int tls_pull_timeout_func(gnutls_transport_ptr_t h, unsigned int ms) @@ -890,7 +893,21 @@ static int pl_tls_sess_data_deinit(struct pl_tls_sess_data *tls) tls_credentials_release(tls->server_credentials); } wire_buf_deinit(&tls->unwrap_buf); - queue_deinit(tls->unwrap_queue); /* TODO: break contexts? */ + + while (queue_len(tls->unwrap_queue) > 0) { + struct protolayer_iter_ctx *ctx = queue_head(tls->unwrap_queue); + protolayer_break(ctx, kr_error(EIO)); + queue_pop(tls->unwrap_queue); + } + queue_deinit(tls->unwrap_queue); + + while (queue_len(tls->wrap_queue)) { + struct protolayer_iter_ctx *ctx = queue_head(tls->wrap_queue); + protolayer_break(ctx, kr_error(EIO)); + queue_pop(tls->wrap_queue); + } + queue_deinit(tls->wrap_queue); + return kr_ok(); } @@ -1181,6 +1198,9 @@ static ssize_t pl_tls_submit(gnutls_session_t tls_session, if (payload.type == PROTOLAYER_PAYLOAD_WIRE_BUF) payload = protolayer_payload_as_buffer(&payload); + // TODO: the handling of positive gnutls_record_send() is weird/confusing, + // but it seems caught later when checking gnutls_record_uncork() + if (payload.type == PROTOLAYER_PAYLOAD_BUFFER) { ssize_t count = gnutls_record_send(tls_session, payload.buffer.buf, payload.buffer.len); @@ -1332,7 +1352,8 @@ static void pl_tls_request_init(struct session2 *session, req->qsource.comm_flags.tls = true; } -void tls_protolayers_init(void) +__attribute__((constructor)) +static void tls_protolayers_init(void) { protolayer_globals[PROTOLAYER_TYPE_TLS] = (struct protolayer_globals){ .sess_size = sizeof(struct pl_tls_sess_data), diff --git a/daemon/tls.h b/daemon/tls.h index 9fd45fb6..ff1bbea2 100644 --- a/daemon/tls.h +++ b/daemon/tls.h @@ -103,9 +103,6 @@ int tls_credentials_release(struct tls_credentials *tls_credentials); /*! Generate new ephemeral TLS credentials. */ struct tls_credentials * tls_get_ephemeral_credentials(void); -/*! Initializes the protocol layers managed by tls. */ -void tls_protolayers_init(void); - /* Session tickets, server side. Implementation in ./tls_session_ticket-srv.c */ /*! Opaque struct used by tls_session_ticket_* functions. */ diff --git a/daemon/worker.c b/daemon/worker.c index 99b5f140..6217dc8a 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -229,25 +229,16 @@ static uint8_t *alloc_wire_cb(struct kr_request *req, uint16_t *maxlen) xdp_handle_data_t *xhd = handle->data; knot_xdp_msg_t out; bool ipv6 = ctx->source.comm_addr.ip.sa_family == AF_INET6; - int ret = knot_xdp_send_alloc(xhd->socket, - #if KNOT_VERSION_HEX >= 0x030100 - ipv6 ? KNOT_XDP_MSG_IPV6 : 0, &out); - #else - ipv6, &out, NULL); - #endif + int ret = knot_xdp_send_alloc(xhd->socket, ipv6 ? KNOT_XDP_MSG_IPV6 : 0, &out); if (ret != KNOT_EOK) { kr_assert(ret == KNOT_ENOMEM); *maxlen = 0; return NULL; } *maxlen = MIN(*maxlen, out.payload.iov_len); -#if KNOT_VERSION_HEX < 0x030100 - /* It's most convenient to fill the MAC addresses at this point. */ - memcpy(out.eth_from, &ctx->source.eth_from, 6); - memcpy(out.eth_to, &ctx->source.eth_to, 6); -#endif return out.payload.iov_base; } + static void free_wire(const struct request_ctx *ctx) { if (kr_fails_assert(ctx->req.alloc_wire_cb == alloc_wire_cb)) @@ -269,12 +260,8 @@ static void free_wire(const struct request_ctx *ctx) out.payload.iov_base = ans->wire; out.payload.iov_len = 0; uint32_t sent = 0; -#if KNOT_VERSION_HEX >= 0x030100 int ret = 0; knot_xdp_send_free(xhd->socket, &out, 1); -#else - int ret = knot_xdp_send(xhd->socket, &out, 1, &sent); -#endif kr_assert(ret == KNOT_EOK && sent == 0); kr_log_debug(XDP, "freed unsent buffer, ret = %d\n", ret); } @@ -600,7 +587,7 @@ int qr_task_on_send(struct qr_task *task, struct session2 *s, int status) "=> disconnected from '%s': %s\n", peer_str, uv_strerror(status)); } - worker_end_tcp(s); + session2_force_close(s); return status; } @@ -1305,7 +1292,7 @@ static int qr_task_step(struct qr_task *task, static int worker_submit(struct session2 *session, struct comm_info *comm, knot_pkt_t *pkt) { - if (!session || !pkt) + if (!session || !pkt || session->closing) return kr_error(EINVAL); const bool is_query = pkt->size > KNOT_WIRE_OFFSET_FLAGS1 @@ -1487,16 +1474,6 @@ static struct session2* worker_find_tcp_waiting(const struct sockaddr* addr) return trie_find_tcp_session(the_worker->tcp_waiting, addr); } -int worker_end_tcp(struct session2 *session) -{ - if (!session) - return kr_error(EINVAL); - - session2_timer_stop(session); - session2_force_close(session); - return kr_ok(); -} - knot_pkt_t *worker_resolve_mk_pkt_dname(knot_dname_t *qname, uint16_t qtype, uint16_t qclass, const struct kr_qflags *options) { @@ -2206,7 +2183,7 @@ exit: wire_buf_movestart(wb); mp_flush(the_worker->pkt_pool.ctx); if (status < 0) - worker_end_tcp(session); + session2_force_close(session); return protolayer_break(ctx, status); } @@ -2274,13 +2251,9 @@ static void pl_dns_stream_request_init(struct session2 *session, req->qsource.comm_flags.tcp = true; } -int worker_init(void) +__attribute__((constructor)) +static void worker_protolayers_init(void) { - if (kr_fails_assert(the_worker == NULL)) - return kr_error(EINVAL); - kr_bindings_register(the_engine->L); // TODO move - - /* DNS protocol layers */ 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, @@ -2308,6 +2281,13 @@ int worker_init(void) 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; +} + +int worker_init(void) +{ + if (kr_fails_assert(the_worker == NULL)) + return kr_error(EINVAL); + kr_bindings_register(the_engine->L); // TODO move /* Create main worker. */ the_worker = &the_worker_value; diff --git a/daemon/worker.h b/daemon/worker.h index 8f89e586..42614cc9 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -28,12 +28,6 @@ int worker_init(void); /** Destroy the worker (free memory). */ void worker_deinit(void); -/** - * End current DNS/TCP session, this disassociates pending tasks from this session - * which may be freely closed afterwards. - */ -int worker_end_tcp(struct session2 *session); - KR_EXPORT knot_pkt_t *worker_resolve_mk_pkt_dname(knot_dname_t *qname, uint16_t qtype, uint16_t qclass, const struct kr_qflags *options); diff --git a/daemon/zimport.c b/daemon/zimport.c index 30edcaec..2f546354 100644 --- a/daemon/zimport.c +++ b/daemon/zimport.c @@ -32,16 +32,7 @@ #include <libknot/rrset.h> #include <libzscanner/scanner.h> -#include <libknot/version.h> -#define ENABLE_ZONEMD (KNOT_VERSION_HEX >= 0x030100) -#if ENABLE_ZONEMD - #include <libdnssec/digest.h> - - #if KNOT_VERSION_HEX < 0x030200 - #define KNOT_ZONEMD_ALGORITHM_SHA384 KNOT_ZONEMD_ALORITHM_SHA384 - #define KNOT_ZONEMD_ALGORITHM_SHA512 KNOT_ZONEMD_ALORITHM_SHA512 - #endif -#endif +#include <libdnssec/digest.h> #include "daemon/worker.h" #include "lib/dnssec/ta.h" @@ -72,7 +63,6 @@ struct zone_import_ctx { struct kr_svldr_ctx *svldr; /// DNSSEC validator; NULL iff we don't validate const knot_dname_t *last_cut; /// internal to zi_rrset_import() -#if ENABLE_ZONEMD uint8_t *digest_buf; /// temporary buffer for digest computation (on pool) #define DIGEST_BUF_SIZE (64*1024 - 1) #define DIGEST_ALG_COUNT 2 @@ -81,7 +71,6 @@ struct zone_import_ctx { dnssec_digest_ctx_t *ctx; const uint8_t *expected; /// expected digest (inside zonemd on pool) } digests[DIGEST_ALG_COUNT]; /// we use indices 0 and 1 for SHA 384 and 512 -#endif }; typedef struct zone_import_ctx zone_import_ctx_t; @@ -130,7 +119,6 @@ static knot_rrset_t * rrset_get(trie_t *rrsets, const knot_dname_t *name, return *rrsig_p; } -#if ENABLE_ZONEMD static int digest_rrset(trie_val_t *rr_p, void *z_import_v) { zone_import_ctx_t *z_import = z_import_v; @@ -303,8 +291,6 @@ do_digest: bool ok = has_match && (zonemd_is_valid || !z_import->svldr); return ok ? kr_ok() : kr_error(ENOENT); } -#endif - /** * @internal Import given rrset to cache. @@ -705,15 +691,9 @@ int zi_zone_import(const zi_config_t config) zonemd: (void)0; // C can't have a variable definition following a label double time_zonemd = NAN; if (c->zonemd) { - #if ENABLE_ZONEMD - kr_timer_start(&stopwatch); - ret = zonemd_verify(z_import); - time_zonemd = kr_timer_elapsed(&stopwatch); - #else - kr_log_error(PREFILL, - "ZONEMD check requested but not supported, fail\n"); - ret = kr_error(ENOSYS); - #endif + kr_timer_start(&stopwatch); + ret = zonemd_verify(z_import); + time_zonemd = kr_timer_elapsed(&stopwatch); } else { ret = kr_ok(); } diff --git a/distro/pkg/arch/PKGBUILD b/distro/pkg/arch/PKGBUILD index 6771c61c..422da695 100644 --- a/distro/pkg/arch/PKGBUILD +++ b/distro/pkg/arch/PKGBUILD @@ -1,5 +1,8 @@ -# Maintainer: Tomas Krizek <tomas.krizek@nic.cz> +# Maintainer: Knot Resolver team <knot-resolver@labs.nic.cz> +# Maintainer: Vladimír Čunát <vladimir.cunat@nic.cz> +# Contributor: Nicki Křížek <nicki@isc.org> # Contributor: Ondřej Surý <ondrej@sury.org> +# Contributor: Oto Šťáva <oto.stava@gmail.com> # SPDX-License-Identifier: GPL-3.0-or-later pkgname=knot-resolver @@ -13,7 +16,6 @@ depends=( 'dnssec-anchors' 'gnutls' 'knot' - 'libedit' 'libuv' 'lmdb' 'luajit' @@ -25,23 +27,25 @@ depends=( 'python-yaml' 'python-aiohttp' 'python-typing_extensions' - 'python-prometheus_client' 'python-jinja' 'supervisor' ) makedepends=( 'cmocka' 'meson' - 'systemd-libs' + 'pkgconfig' 'python-build' 'python-installer' 'python-poetry' + 'python-wheel' + 'systemd-libs' ) optdepends=( 'lua51-basexx: experimental_dot_auth module' 'lua51-cqueues: http and dns64 module, policy.rpz() function' 'lua51-http: http and prefill modules, trust_anchors bootstrap' 'lua51-psl: policy.slice_randomize_psl() function' + 'python-prometheus_client: stats and metrics in Prometheus format' ) backup=('etc/knot-resolver/config.yaml') options=(debug strip) diff --git a/distro/pkg/deb/control b/distro/pkg/deb/control index 19d95834..e376bd46 100644 --- a/distro/pkg/deb/control +++ b/distro/pkg/deb/control @@ -5,28 +5,29 @@ Maintainer: Knot Resolver <knot-resolver@labs.nic.cz> Build-Depends: debhelper (>= 12~), dh-python, + libcap-ng-dev, libcmocka-dev (>= 1.0.0), - libedit-dev, libfstrm-dev, libgnutls28-dev, + libjemalloc-dev, libknot-dev (>= 3.0.2), liblmdb-dev, libluajit-5.1-dev, libnghttp2-dev, libprotobuf-c-dev, + libssl-dev, libsystemd-dev (>= 227) [linux-any], - libcap-ng-dev, libuv1-dev, - libjemalloc-dev, luajit, - pkg-config, meson (>= 0.49), + pkg-config, protobuf-c-compiler, python3, python3-dev, python3-setuptools, - libssl-dev, +Standards-Version: 4.7.0 Homepage: https://www.knot-resolver.cz/ +Rules-Requires-Root: no Package: knot-resolver6 Architecture: any @@ -39,8 +40,8 @@ Depends: supervisor, systemd, ${misc:Depends}, - ${shlibs:Depends}, ${python3:Depends}, + ${shlibs:Depends}, Breaks: knot-resolver (<< 6), knot-resolver-core (<< 6.0.8), @@ -56,7 +57,7 @@ Recommends: lua-psl, python3-prometheus-client, Suggests: - knot-resolver-module-http, + knot-resolver6-module-http, Description: caching, DNSSEC-validating DNS resolver - core binaries Knot Resolver is a caching full resolver implementation written in C and LuaJIT, including both a resolver library and a @@ -82,24 +83,11 @@ Package: knot-resolver6-dev Architecture: any Depends: knot-resolver6 (= ${binary:Version}), - ${misc:Depends} - ${shlibs:Depends}, + ${misc: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 -Priority: optional -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-resolver6-module-dnstap Architecture: any Multi-Arch: same @@ -123,7 +111,7 @@ Description: dnstap module for Knot Resolver Package: knot-resolver6-module-http Architecture: all Depends: - knot-resolver6 (= ${binary:Version}), + knot-resolver6 (>= ${source:Version}), libjs-bootstrap, libjs-d3, libjs-jquery, @@ -132,7 +120,6 @@ Depends: lua-mmdb, systemd, ${misc:Depends}, - ${shlibs:Depends}, 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/copyright b/distro/pkg/deb/copyright index 96e23ca2..92eade13 100644 --- a/distro/pkg/deb/copyright +++ b/distro/pkg/deb/copyright @@ -18,26 +18,11 @@ Files: tests/config/tapered/* Copyright: 2012-2017, Peter Aronoff License: BSD-3-clause -Files: contrib/lmdb/* -Copyright: 1999-2003 The OpenLDAP Foundation -License: OpenLDAP - -Files: tests/deckard/contrib/libfaketime/* -Copyright: 2003-2017 Wolfgang Hommel -License: GPL-2 - -Files: tests/deckard/contrib/libswrap/* -Copyright: 2005,2008 Jelmer Vernooij <jelmer@samba.org> - 2006-2009 Stefan Metzmacher <metze@samba.org> - 2013 Andreas Schneider <asn@samba.org> -License: BSD-3-clause - Files: contrib/murmurhash3/* Copyright: Austin Appleby License: CC0-1.0 -Files: debian/missing-sources/dygraph-combined.js - modules/http/static/dygraph-combined.js +Files: modules/http/static/dygraph.min.js Copyright: 2006-2014 Dan Vanderkam <danvdk@gmail.com> 2016 Paul Miller 2011 Robert Konigsberg <konigsberg@google.com> @@ -68,9 +53,8 @@ Files: modules/http/static/d3.js Copyright: 2010-2015 Michael Bostock License: BSD-3-clause -Files: modules/http/static/epoch.* - debian/missing-sources/epoch/* - debian/missing-sources/epoch.* +Files: modules/http/static/epoch.js + modules/http/static/epoch.css Copyright: 2014 Fastly, Inc. License: Expat @@ -86,9 +70,8 @@ Copyright: 2012-2016 Thomas Park 2011-2015 Twitter, Inc. License: Expat -Files: modules/http/static/selectize.bootstrap3.min.css - modules/http/static/selectize.min.css - modules/http/static/selectize.min.js +Files: modules/http/static/selectize.min.js + modules/http/static/selectize.bootstrap3.css Copyright: 2013–2015 Brian Reavis & contributors License: Apache-2.0 @@ -386,48 +369,6 @@ License: MIT CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -License: OpenLDAP - Redistribution and use of this software and associated documentation - ("Software"), with or without modification, are permitted provided - that the following conditions are met: - . - 1. Redistributions in source form must retain copyright statements - and notices, - . - 2. Redistributions in binary form must reproduce applicable copyright - statements and notices, this list of conditions, and the following - disclaimer in the documentation and/or other materials provided - with the distribution, and - . - 3. Redistributions must contain a verbatim copy of this document. - . - The OpenLDAP Foundation may revise this license from time to time. - Each revision is distinguished by a version number. You may use - this Software under terms of this license revision or under the - terms of any subsequent revision of the license. - . - THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS - CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) - OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - . - The names of the authors and copyright holders must not be used in - advertising or otherwise to promote the sale, use or other dealing - in this Software without specific, written prior permission. Title - to copyright in this Software shall at all times remain with copyright - holders. - . - OpenLDAP is a registered trademark of the OpenLDAP Foundation. - License: CC0-1.0 This work is licensed under the "Creative Commons Zero" license. . diff --git a/distro/pkg/deb/knot-resolver6-module-http.install b/distro/pkg/deb/knot-resolver6-module-http.install index ffa04d01..ff9d94a3 100644 --- a/distro/pkg/deb/knot-resolver6-module-http.install +++ b/distro/pkg/deb/knot-resolver6-module-http.install @@ -1,7 +1,7 @@ usr/lib/knot-resolver/kres_modules/http*.lua -usr/lib/knot-resolver/kres_modules/prometheus.lua usr/lib/knot-resolver/kres_modules/http/*.css usr/lib/knot-resolver/kres_modules/http/*.ico usr/lib/knot-resolver/kres_modules/http/*.js usr/lib/knot-resolver/kres_modules/http/*.tpl usr/lib/knot-resolver/kres_modules/http/*.woff2 +usr/lib/knot-resolver/kres_modules/prometheus.lua diff --git a/distro/pkg/deb/knot-resolver6.dirs b/distro/pkg/deb/knot-resolver6.dirs index f8981d8d..375cca35 100644 --- a/distro/pkg/deb/knot-resolver6.dirs +++ b/distro/pkg/deb/knot-resolver6.dirs @@ -1,2 +1,2 @@ -/var/lib/knot-resolver /var/cache/knot-resolver +/var/lib/knot-resolver diff --git a/distro/pkg/deb/knot-resolver6.docs b/distro/pkg/deb/knot-resolver6.docs index 8e919d0c..9bd0e802 100644 --- a/distro/pkg/deb/knot-resolver6.docs +++ b/distro/pkg/deb/knot-resolver6.docs @@ -1,4 +1,5 @@ -debian/tmp/usr/share/doc/knot-resolver/AUTHORS -debian/tmp/usr/share/doc/knot-resolver/COPYING -debian/tmp/usr/share/doc/knot-resolver/NEWS -debian/tmp/usr/share/doc/knot-resolver/examples +README.md +usr/share/doc/knot-resolver/AUTHORS +usr/share/doc/knot-resolver/COPYING +usr/share/doc/knot-resolver/NEWS +usr/share/doc/knot-resolver/examples diff --git a/distro/pkg/deb/knot-resolver6.manpages b/distro/pkg/deb/knot-resolver6.manpages index aa59efff..e0178dca 100644 --- a/distro/pkg/deb/knot-resolver6.manpages +++ b/distro/pkg/deb/knot-resolver6.manpages @@ -1,2 +1,2 @@ -debian/tmp/usr/share/man/man8/kresctl.8* -debian/tmp/usr/share/man/man8/kresd.8* +usr/share/man/man8/kresctl.8* +usr/share/man/man8/kresd.8* diff --git a/distro/pkg/deb/rules b/distro/pkg/deb/rules index dff9df6f..037d7663 100755 --- a/distro/pkg/deb/rules +++ b/distro/pkg/deb/rules @@ -41,7 +41,7 @@ override_dh_auto_build: dh_auto_build --buildsystem=pybuild --sourcedirectory manager override_dh_auto_install: - DESTDIR="${PWD}/debian/tmp" ninja -v -C build_deb install + DESTDIR="$(shell pwd)/debian/tmp" ninja -v -C build_deb install PYBUILD_NAME=knot_resolver PYBUILD_DESTDIR="$${PYKRES_DESTDIR}" \ dh_auto_install --buildsystem=pybuild --sourcedirectory build_deb/python PYBUILD_NAME=knot_resolver_manager PYBUILD_DESTDIR="$${PYKRES_DESTDIR}" \ @@ -52,6 +52,3 @@ override_dh_auto_install: override_dh_auto_test: meson test -C build_deb - -override_dh_strip: - dh_strip --dbg-package=knot-resolver6-dbg diff --git a/distro/pkg/deb/source/lintian-overrides b/distro/pkg/deb/source/lintian-overrides new file mode 100644 index 00000000..ff8e36a3 --- /dev/null +++ b/distro/pkg/deb/source/lintian-overrides @@ -0,0 +1,16 @@ +# upstream package doesn't include missing-sources for HTTP module static files, +# they can be found in individual upstream repos or in Debian package debian/missing-sources +source: source-is-missing [modules/http/static/bootstrap.min.js] +source: source-is-missing [modules/http/static/d3.js] +source: source-is-missing [modules/http/static/datamaps.world.min.js] +source: source-is-missing [modules/http/static/dygraph.min.js] +source: source-is-missing [modules/http/static/epoch.js] +source: source-is-missing [modules/http/static/jquery.js] +source: source-is-missing [modules/http/static/selectize.min.js] +source: source-is-missing [modules/http/static/topojson.js] +# that's how HTTP module is built upstream +source: source-contains-prebuilt-javascript-object +# not relevant in upstream package +source: no-nmu-in-changelog +# upstream package uses apkg, watch file is redundant +source: debian-watch-file-is-missing diff --git a/distro/pkg/rpm/knot-resolver.spec b/distro/pkg/rpm/knot-resolver.spec index 8b30059e..de962e8c 100644 --- a/distro/pkg/rpm/knot-resolver.spec +++ b/distro/pkg/rpm/knot-resolver.spec @@ -39,7 +39,6 @@ BuildRequires: gcc-c++ BuildRequires: meson BuildRequires: pkgconfig(cmocka) BuildRequires: pkgconfig(gnutls) -BuildRequires: pkgconfig(libedit) BuildRequires: pkgconfig(libknot) >= 3.0.2 BuildRequires: pkgconfig(libzscanner) >= 3.0.2 BuildRequires: pkgconfig(libdnssec) >= 3.0.2 diff --git a/doc/architecture-manager.drawio b/doc/architecture-manager.drawio index aa8c4e7e..c6c0fcd0 100644 --- a/doc/architecture-manager.drawio +++ b/doc/architecture-manager.drawio @@ -1 +1,94 @@ -<mxfile host="Electron" modified="2023-02-13T14:53:19.113Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.8.16 Chrome/106.0.5249.199 Electron/21.4.0 Safari/537.36" etag="AMbarg0B8e5MX17HW2UZ" version="20.8.16" type="device"><diagram name="Page-1" id="veOfMoMBw9sVscwcjaa1">5ZhbU6MwFMc/TR91gADWx17cVUdnnNGZ3fUtQgrRwMEQevHT76GEUqBWdre2dfZFk39Obuf8TkjTI6No/l3SJLwFn4meZfjzHhn3LMs0+w7+y5VFoZxZdiEEkvvaqBLu+RvToqHVjPssrRkqAKF4Uhc9iGPmqZpGpYRZ3WwCoj5rQgPWEu49KtrqD+6rsFD7jlHpl4wHYTmzaeiWiJbGWkhD6sNsTSIXPTKSAKooRfMRE7nzSr8U/b6907pamGSx6tLh+eHx4bb/OibXl9cW4dGgf+Wf6FGmVGR6wxGNcU9Sr1ktSkdIyGKf5WMZPTKchVyx+4R6eesMQ49aqCKBNROLEy7ECARIrMcQo9EwRWMeBw+Q6CEEfWLiDlKuOMSoebgPnJcMp0wqjhG4aRiovOuQCh5sNB/ohidQCqJqRpROLAfreqtozubv+tBcRQaRZhAxJRdoUnY408HUNJtlcGcVG26phWtcWCUWVPMYrMauQoYFHbU/ieBZK4SYCxMe5EkR0hjxtlyByxg+YVDdIC9J9pqxVLVizHxkX1dBqhACiKm4qNRhnYLK5gaWcc1j/8yUWuhEppmCOhnoaLn4qfsvK7/yyqlTVsfz9cbxYp2WIfVeguUSGnAVO8mXvz2wuFvIpMe2+NPShwyVAVNb7MhWUE6MU8N1dWgkE1TxaX1tm0DQw90Bx1VXJjCZpEy1SFnN+vfwWC12WkzgsZXkxSwSA0/BtgRdZV4zJYvMXaMAMiV4zEarQ9vYfGjsIGWtRsaetzOWbEhY97Py9fwrZd0O84p0zCt7czQ759A/BYe08mFwd7XzT+FOqP4Ya3ufWJf3tf1yvUM+7Y58Oofk027xiVtN80vOMTLa/5hRd6+Mki/OqNORUdM6JKROC1Iscp8ubwn559il0fImv/yLSgwyQos3bXF8JJMOJJubrv2fhnK/5eM0S5ic8hSkf4wudO2GC+1Du9C0v/hpYHb9qdI/5Glguv+Lm82DXg3KZe7hKWcHx4HTPA4Ofjdof7VeJEv93vJpsXhOCVjM5NF+pJonrPWJJyxWq4fL4jGiev4lF78B</diagram></mxfile>
\ No newline at end of file +<mxfile host="app.diagrams.net" modified="2024-05-13T09:42:58.766Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" etag="BzOypqt7zxLdvAShcclR" version="24.4.0" type="google"> + <diagram name="Page-1" id="cegkDIOblt0eRo74aROd"> + <mxGraphModel grid="1" page="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0"> + <root> + <mxCell id="0" /> + <mxCell id="1" parent="0" /> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-45" value="manager" style="rounded=0;fillColor=none;verticalAlign=top;strokeWidth=2;strokeColor=#404040;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fontColor=#404040;fontStyle=1;fontSize=14;" vertex="1" parent="1"> + <mxGeometry x="209" y="-1011" width="465" height="220" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-28" value="load file" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="227" y="-881" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-29" value="API" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="227" y="-981" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-31" value="parsing" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="384" y="-931" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-41" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;strokeColor=#404040;entryX=0.02;entryY=0.667;entryDx=0;entryDy=0;dashed=1;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;entryPerimeter=0;fontColor=#404040;" edge="1" parent="1" source="CUZnaHH6iHjA6N0w_GfL-32" target="FZnD3hXAEdhVNf1liAt--8"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="719" y="-901" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-42" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;strokeWidth=2;strokeColor=#404040;edgeStyle=orthogonalEdgeStyle;dashed=1;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;entryX=0.002;entryY=0.668;entryDx=0;entryDy=0;entryPerimeter=0;fontColor=#404040;" edge="1" parent="1" target="FZnD3hXAEdhVNf1liAt--6"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="689" y="-901" as="sourcePoint" /> + <mxPoint x="709" y="-971" as="targetPoint" /> + <Array as="points"> + <mxPoint x="689" y="-990" /> + <mxPoint x="719" y="-990" /> + </Array> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-32" value="validation
normalization" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="535" y="-931" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-34" value="" style="endArrow=classic;rounded=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;exitX=1;exitY=0.5;exitDx=0;exitDy=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="CUZnaHH6iHjA6N0w_GfL-29" target="CUZnaHH6iHjA6N0w_GfL-31"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="384" y="-871" as="sourcePoint" /> + <mxPoint x="273.76" y="-681" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-36" value="kresctl" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="69" y="-981" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-37" value="" style="endArrow=classic;rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="CUZnaHH6iHjA6N0w_GfL-28" target="CUZnaHH6iHjA6N0w_GfL-31"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="339" y="-941" as="sourcePoint" /> + <mxPoint x="369" y="-891" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-43" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;strokeWidth=2;strokeColor=#404040;edgeStyle=orthogonalEdgeStyle;dashed=1;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;entryX=-0.031;entryY=0.65;entryDx=0;entryDy=0;entryPerimeter=0;fontColor=#404040;" edge="1" parent="1" target="FZnD3hXAEdhVNf1liAt--7"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="689" y="-900" as="sourcePoint" /> + <mxPoint x="709" y="-791" as="targetPoint" /> + <Array as="points"> + <mxPoint x="689" y="-811" /> + </Array> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-47" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;strokeColor=#404040;dashed=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fontColor=#404040;" edge="1" parent="1" source="CUZnaHH6iHjA6N0w_GfL-36" target="CUZnaHH6iHjA6N0w_GfL-29"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="219" y="-951" as="targetPoint" /> + <mxPoint x="189" y="-951" as="sourcePoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-48" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;exitX=0;exitY=0;exitDx=51.25;exitDy=39.5;strokeWidth=2;strokeColor=#404040;dashed=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitPerimeter=0;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fontColor=#404040;" edge="1" parent="1" source="CUZnaHH6iHjA6N0w_GfL-52" target="CUZnaHH6iHjA6N0w_GfL-28"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="234" y="-941" as="targetPoint" /> + <mxPoint x="189" y="-851" as="sourcePoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-50" value="" style="endArrow=classic;rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="CUZnaHH6iHjA6N0w_GfL-31" target="CUZnaHH6iHjA6N0w_GfL-32"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="354" y="-841" as="sourcePoint" /> + <mxPoint x="394" y="-876" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-52" value="config.yaml" style="shape=note;backgroundOutline=1;darkOpacity=0.05;fillColor=none;strokeColor=#404040;fontSize=14;fontColor=#404040;strokeWidth=2;verticalAlign=top;labelPosition=center;verticalLabelPosition=bottom;align=center;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;size=19;" vertex="1" parent="1"> + <mxGeometry x="109" y="-891" width="51.25" height="60" as="geometry" /> + </mxCell> + <mxCell id="FZnD3hXAEdhVNf1liAt--6" value="supervisord.conf" style="shape=note;backgroundOutline=1;darkOpacity=0.05;fillColor=none;strokeColor=#404040;fontSize=14;fontColor=#404040;strokeWidth=2;verticalAlign=top;labelPosition=center;verticalLabelPosition=bottom;align=center;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;size=19;" vertex="1" parent="1"> + <mxGeometry x="729" y="-1030" width="51.25" height="60" as="geometry" /> + </mxCell> + <mxCell id="FZnD3hXAEdhVNf1liAt--7" value="policy-loader.lua" style="shape=note;backgroundOutline=1;darkOpacity=0.05;fillColor=none;strokeColor=#404040;fontSize=14;fontColor=#404040;strokeWidth=2;verticalAlign=top;labelPosition=center;verticalLabelPosition=bottom;align=center;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;size=19;" vertex="1" parent="1"> + <mxGeometry x="729" y="-850" width="51.25" height="60" as="geometry" /> + </mxCell> + <mxCell id="FZnD3hXAEdhVNf1liAt--8" value="kresd_N.lua" style="shape=note;backgroundOutline=1;darkOpacity=0.05;fillColor=none;strokeColor=#404040;fontSize=14;fontColor=#404040;strokeWidth=2;verticalAlign=top;labelPosition=center;verticalLabelPosition=bottom;align=center;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;size=19;" vertex="1" parent="1"> + <mxGeometry x="729" y="-940" width="51.25" height="60" as="geometry" /> + </mxCell> + </root> + </mxGraphModel> + </diagram> +</mxfile> diff --git a/doc/architecture-manager.svg b/doc/architecture-manager.svg index 4408bfb5..a638be0b 100644 --- a/doc/architecture-manager.svg +++ b/doc/architecture-manager.svg @@ -1,3 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="771px" height="201px" viewBox="-0.5 -0.5 771 201"><defs/><g><rect x="150" y="0" width="620" height="200" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 672px; height: 1px; padding-top: 24px; margin-left: 124px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">manager</div></div></div></foreignObject><text x="460" y="24" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">manager</text></switch></g><path d="M 30 100 L 173.63 100" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 178.88 100 L 171.88 103.5 L 173.63 100 L 171.88 96.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 100px; margin-left: 100px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">config change<br />request</div></div></div></foreignObject><text x="100" y="103" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">config change...</text></switch></g><ellipse cx="15" cy="77.5" rx="7.5" ry="7.5" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 15 85 L 15 110 M 15 90 L 0 90 M 15 90 L 30 90 M 15 110 L 0 130 M 15 110 L 30 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 220 100 L 253.63 100" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 258.88 100 L 251.88 103.5 L 253.63 100 L 251.88 96.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="180" y="70" width="40" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 100px; margin-left: 181px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">API</div></div></div></foreignObject><text x="200" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">API</text></switch></g><path d="M 320 100 L 353.63 100" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 358.88 100 L 351.88 103.5 L 353.63 100 L 351.88 96.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="260" y="70" width="60" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 100px; margin-left: 261px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">parsing</div></div></div></foreignObject><text x="290" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">parsing</text></switch></g><path d="M 480 100 L 513.63 100" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 518.88 100 L 511.88 103.5 L 513.63 100 L 511.88 96.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="360" y="70" width="120" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 100px; margin-left: 361px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">validation & normalization</div></div></div></foreignObject><text x="420" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">validation & normali...</text></switch></g><rect x="620" y="20" width="120" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 621px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">supervisord</div></div></div></foreignObject><text x="680" y="54" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">supervisord</text></switch></g><path d="M 580 100 L 600.03 100 L 600.03 50 L 613.63 50" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 618.88 50 L 611.88 53.5 L 613.63 50 L 611.88 46.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 580 100 L 600.03 100 L 600.03 150 L 613.63 150" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 618.88 150 L 611.88 153.5 L 613.63 150 L 611.88 146.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="520" y="70" width="60" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 100px; margin-left: 521px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">manager</div></div></div></foreignObject><text x="550" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">manager</text></switch></g><rect x="620" y="120" width="120" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 150px; margin-left: 621px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">kresd config generation</div></div></div></foreignObject><text x="680" y="154" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">kresd config generat...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="740px" height="265px" viewBox="-0.5 -0.5 740 265"><defs><style type="text/css">@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400;500);
</style></defs><g><g><rect x="141" y="20" width="465" height="220" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" font-weight="bold" text-anchor="middle" font-size="14px"><text x="373" y="39.5">manager</text></g></g><g><rect x="159" y="150" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="218.5" y="185.5">load file</text></g></g><g><rect x="159" y="50" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="218.5" y="85.5">API</text></g></g><g><rect x="316" y="100" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="375.5" y="135.5">parsing</text></g></g><g><path d="M 587 130 L 653.79 130.91" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 659.79 130.99 L 651.74 134.88 L 653.79 130.91 L 651.84 126.88 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 621 130 L 621 41 L 651 41 L 652.87 41.01" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 658.87 41.06 L 650.84 45 L 652.87 41.01 L 650.9 37 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><rect x="467" y="100" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="526.5" y="127">validation</text><text x="526.5" y="144">normalization</text></g></g><g><path d="M 279 80 L 297.5 80 L 297.5 115 L 307.76 115" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 313.76 115 L 305.76 119 L 307.76 115 L 305.76 111 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><rect x="1" y="50" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="60.5" y="85.5">kresctl</text></g></g><g><path d="M 279 180 L 297.5 180 L 297.5 145 L 307.76 145" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 313.76 145 L 305.76 149 L 307.76 145 L 305.76 141 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 621 131 L 621 220 L 651.18 220" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 657.18 220 L 649.18 224 L 651.18 220 L 649.18 216 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 121 80 L 150.76 80" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 156.76 80 L 148.76 84 L 150.76 80 L 148.76 76 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 92.25 179.5 L 150.76 179.94" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 156.76 179.98 L 148.73 183.92 L 150.76 179.94 L 148.79 175.92 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 436 130 L 458.76 130" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 464.76 130 L 456.76 134 L 458.76 130 L 456.76 126 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 41 140 L 73.25 140 L 92.25 159 L 92.25 200 L 41 200 L 41 140 Z" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 73.25 140 L 73.25 159 L 92.25 159 Z" fill-opacity="0.05" fill="#000000" stroke="none" pointer-events="all"/><path d="M 73.25 140 L 73.25 159 L 92.25 159" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="66.13" y="219.5">config.yaml</text></g></g><g><path d="M 661 1 L 693.25 1 L 712.25 20 L 712.25 61 L 661 61 L 661 1 Z" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 693.25 1 L 693.25 20 L 712.25 20 Z" fill-opacity="0.05" fill="#000000" stroke="none" pointer-events="all"/><path d="M 693.25 1 L 693.25 20 L 712.25 20" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="686.13" y="80.5">supervisord.conf</text></g></g><g><path d="M 661 181 L 693.25 181 L 712.25 200 L 712.25 241 L 661 241 L 661 181 Z" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 693.25 181 L 693.25 200 L 712.25 200 Z" fill-opacity="0.05" fill="#000000" stroke="none" pointer-events="all"/><path d="M 693.25 181 L 693.25 200 L 712.25 200" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="686.13" y="260.5">policy-loader.lua</text></g></g><g><path d="M 661 91 L 693.25 91 L 712.25 110 L 712.25 151 L 661 151 L 661 91 Z" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 693.25 91 L 693.25 110 L 712.25 110 Z" fill-opacity="0.05" fill="#000000" stroke="none" pointer-events="all"/><path d="M 693.25 91 L 693.25 110 L 712.25 110" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="686.13" y="170.5">kresd_N.lua</text></g></g></g></svg>
\ No newline at end of file diff --git a/doc/architecture-schema.drawio b/doc/architecture-schema.drawio index c58a4b9b..d23d84cd 100644 --- a/doc/architecture-schema.drawio +++ b/doc/architecture-schema.drawio @@ -1 +1,85 @@ -<mxfile host="www.diagrameditor.com" modified="2023-02-13T13:13:34.892Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" etag="Tj-oP8z-b8JEGXK27IVH" version="12.1.3" type="device" pages="1"><diagram id="fziuQaxv5VFMaYUHGL-k" name="Page-1">7Vlbb5swGP01eezENSGPbZptmlZpUqXu8uaAA14MRsaQsF8/G0zAkNIkLQlaF1WKffwZ2+ccm8/NxFyEu08UxMED8SCeGJq3m5j3E8PQ9emcfwkkLxF7apeAT5Eng2rgEf2BEtQkmiIPJkogIwQzFKugS6IIukzBAKVkq4atCVZHjYEPO8CjC3AX/Y48FpSoY8xq/DNEfsDaCw5BFSxXkgTAI9sGZC4n5oISwspSuFtALMireCn7fXymdT8xCiN2TIdsY66fwiewZpuHmy9LB/7arm4cOTeWVwuGHl+/rBLKAuKTCOBljd5RkkYeFE/VeO13GsZVfEQiEVB3+0pIzHFdxEHGcqkvSBnhUMBCLFu7i5HrS0hKXdizgsoUgPqQ9cSZZZxYXmMASdUnSELIaM4DKMSAoUyVH0gX+fs42fWWUpA3AmKCIpY0nvxNADxAbgjDkm6Q22HW0uykcF4ox69qjYXUUGGDEywxfzeWsEZhCXN6kiX6w4exRHUYvwNP2KPwhOWoIs/7PdEfPpAn9HfjCWMUntA1VWSn3xP94QN5ohwxAziVJCRpDGmGEkK9jl1UM2wDxOBjDArFtjyZPFLlDFIGd726VLtEJaTKy7Z1WmfJw1QLGild1e2QkA06z2DLGMkOclOaFY8UlTXCeEEwocWMzPUaTl2X4wmjZAMbLd5svtLEJDyQBPvu5+9G48jdqI9jN1onndCGdoUT2jzDX4oXhjCb4pbTzTa8v8ZxUWj7S3/ppmD0xg/kMOsfdBg3Fs1/iBl9MOyq/lM+rqjc7+R8y1oua8Nbc5gLS/eK0fae3XoFlhOVvWqTvdrjL6Q0nXldJKex/3v8kh4f5gLWvTK1rtG6Pr+Mx1+6ytm98cN4XGrTyNtDEAEf0o71r5yz6weS9j12kaTd7FA1MaaYiS2JMl70RXFDYeLpVQMfp9F2dUrbqeghTp1LUmodTakxUkrNdvJ1bUrtDqW+e3WWLHNkLOmzZ523JuJQLu3l8jIlOKnaVrQ23t6OzQ4dpjlBTKVTfTXLPID/AYz8iCMup5kfv+adoBe5AN/KhhB5XpFiHNJLVVRM6dDLH4MVxHfA3fhFfHsSrxdab73D5gf+03JAZ2MwnZ2OzjElLkwSkZBQCM8VrJl4SegtBewXqiWvVnzeRsCWfs5g+vFq/QNomc3UPyOby78=</diagram></mxfile>
\ No newline at end of file +<mxfile host="app.diagrams.net" modified="2024-05-13T09:43:23.932Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" etag="1Ox14oRcA9rMSHpwIPVC" version="24.4.0" type="google"> + <diagram name="Page-1" id="cegkDIOblt0eRo74aROd"> + <mxGraphModel grid="1" page="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0"> + <root> + <mxCell id="0" /> + <mxCell id="1" parent="0" /> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-21" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;entryX=0.5;entryY=1;entryDx=0;entryDy=0;dashed=1;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;" edge="1" parent="1" target="CUZnaHH6iHjA6N0w_GfL-4"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="505" y="-890" as="sourcePoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-22" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;entryX=0.5;entryY=1;entryDx=0;entryDy=0;dashed=1;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;exitX=0.5;exitY=1;exitDx=0;exitDy=0;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;" edge="1" parent="1" source="CUZnaHH6iHjA6N0w_GfL-3" target="CUZnaHH6iHjA6N0w_GfL-7"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="185" y="-910" as="sourcePoint" /> + <mxPoint x="825.0000000000002" y="-920" as="targetPoint" /> + <Array as="points"> + <mxPoint x="185" y="-889.5" /> + <mxPoint x="665" y="-889.5" /> + </Array> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-3" value="manager" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fontStyle=1;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="125" y="-980" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-4" value="cache-gc" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="445" y="-980" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-7" value="policy-loader" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="605" y="-980" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-9" value="supervisord" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;fontStyle=1" vertex="1" parent="1"> + <mxGeometry x="125" y="-1040" width="600" height="30" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-10" value="kresd_N" style="rounded=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fillColor=none;" vertex="1" parent="1"> + <mxGeometry x="285" y="-980" width="120" height="60" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-12" value="" style="endArrow=classic;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;" edge="1" parent="1" target="CUZnaHH6iHjA6N0w_GfL-3"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="185" y="-1010" as="sourcePoint" /> + <mxPoint x="184.76" y="-980" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-13" value="" style="endArrow=classic;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;" edge="1" parent="1"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="344.76" y="-1010" as="sourcePoint" /> + <mxPoint x="344.76" y="-980" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-16" value="" style="endArrow=classic;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;" edge="1" parent="1"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="504.76" y="-1010" as="sourcePoint" /> + <mxPoint x="504.76" y="-980" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-17" value="" style="endArrow=classic;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;" edge="1" parent="1"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="664.76" y="-1010" as="sourcePoint" /> + <mxPoint x="664.76" y="-980" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-19" value="" style="endArrow=none;dashed=1;rounded=0;startArrow=classic;startFill=1;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;" edge="1" parent="1"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="235" y="-1010" as="sourcePoint" /> + <mxPoint x="235" y="-980" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;entryX=0.5;entryY=1;entryDx=0;entryDy=0;dashed=1;strokeColor=#404040;fontColor=#404040;fontSize=14;strokeWidth=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;" edge="1" parent="1"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="345" y="-890" as="sourcePoint" /> + <mxPoint x="344.83000000000004" y="-920" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-25" value="configuration..." style="text;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#404040;fontStyle=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fontSize=14;" vertex="1" parent="1"> + <mxGeometry x="365" y="-920" width="120" height="30" as="geometry" /> + </mxCell> + <mxCell id="CUZnaHH6iHjA6N0w_GfL-26" value="control..." style="text;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#404040;fontStyle=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fontSize=14;" vertex="1" parent="1"> + <mxGeometry x="230" y="-1010" width="80" height="30" as="geometry" /> + </mxCell> + <mxCell id="FZnD3hXAEdhVNf1liAt--10" value="supervision..." style="text;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=#404040;fontStyle=2;fontFamily=Roboto;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto;fontSize=14;" vertex="1" parent="1"> + <mxGeometry x="370" y="-1010" width="110" height="30" as="geometry" /> + </mxCell> + </root> + </mxGraphModel> + </diagram> +</mxfile> diff --git a/doc/architecture-schema.svg b/doc/architecture-schema.svg index e32251ba..b56280f9 100644 --- a/doc/architecture-schema.svg +++ b/doc/architecture-schema.svg @@ -1,3 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="472px" height="172px" viewBox="-0.5 -0.5 472 172"><defs/><g><path d="M 200 40 L 200 50 L 200 93.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 200 98.88 L 196.5 91.88 L 200 93.63 L 203.5 91.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 320 40 L 320 50 L 320 93.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 320 98.88 L 316.5 91.88 L 320 93.63 L 323.5 91.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 440 40 L 440 70 L 440 93.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 440 98.88 L 436.5 91.88 L 440 93.63 L 443.5 91.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 60 40 L 60 60 L 60 93.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 60 98.88 L 56.5 91.88 L 60 93.63 L 63.5 91.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="0" y="0" width="470" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 468px; height: 1px; padding-top: 20px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">supervisord</div></div></div></foreignObject><text x="235" y="24" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">supervisord</text></switch></g><path d="M 100 100 Q 100 70 130 70 Q 160 70 160 46.37" fill="none" stroke="#d79b00" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 160 41.12 L 163.5 48.12 L 160 46.37 L 156.5 48.12 Z" fill="#d79b00" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><path d="M 100 140 Q 100 150 140 150 Q 180 150 180 146.37" fill="none" stroke="#d79b00" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 180 141.12 L 183.5 148.12 L 180 146.37 L 176.5 148.12 Z" fill="#d79b00" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><path d="M 100 140 Q 100 160 200 160 Q 300 160 300 146.37" fill="none" stroke="#d79b00" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 300 141.12 L 303.5 148.12 L 300 146.37 L 296.5 148.12 Z" fill="#d79b00" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><path d="M 100 140 Q 100 170 255 170 Q 410 170 410 146.37" fill="none" stroke="#d79b00" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 410 141.12 L 413.5 148.12 L 410 146.37 L 406.5 148.12 Z" fill="#d79b00" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><rect x="0" y="100" width="120" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 120px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">manager</div></div></div></foreignObject><text x="60" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">manager</text></switch></g><rect x="160" y="100" width="80" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 120px; margin-left: 161px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div>kresd1</div></div></div></div></foreignObject><text x="200" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">kresd1</text></switch></g><rect x="280" y="100" width="80" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 120px; margin-left: 281px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div>kresd2</div></div></div></div></foreignObject><text x="320" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">kresd2</text></switch></g><rect x="390" y="100" width="80" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 120px; margin-left: 391px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">gc</div></div></div></foreignObject><text x="430" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">gc</text></switch></g><rect x="110" y="70" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 80px; margin-left: 111px;"><div data-drawio-colors="color: #d79b00; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(215, 155, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><font>controls<br /></font></div></div></div></foreignObject><text x="130" y="84" fill="#d79b00" font-family="Helvetica" font-size="12px" text-anchor="middle">control...</text></switch></g><rect x="10" y="60" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 70px; margin-left: 11px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">process tree</div></div></div></foreignObject><text x="30" y="74" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">process...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="602px" height="161px" viewBox="-0.5 -0.5 602 161"><defs><style type="text/css">@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400;500);
</style></defs><g><g><path d="M 380 150.5 L 380 128.74" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 380 122.74 L 384 130.74 L 380 128.74 L 376 130.74 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 60 120.5 L 60 151 L 540 151 L 540 128.74" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 540 122.74 L 544 130.74 L 540 128.74 L 536 130.74 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><rect x="0" y="60.5" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" font-weight="bold" text-anchor="middle" font-size="14px"><text x="59.5" y="96">manager</text></g></g><g><rect x="320" y="60.5" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="379.5" y="96">cache-gc</text></g></g><g><rect x="480" y="60.5" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="539.5" y="96">policy-loader</text></g></g><g><rect x="0" y="0.5" width="600" height="30" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" font-weight="bold" text-anchor="middle" font-size="14px"><text x="299.5" y="21">supervisord</text></g></g><g><rect x="160" y="60.5" width="120" height="60" fill="none" stroke="#404040" stroke-width="2" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" text-anchor="middle" font-size="14px"><text x="219.5" y="96">kresd_N</text></g></g><g><path d="M 60 30.5 L 60 52.26" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 60 58.26 L 56 50.26 L 60 52.26 L 64 50.26 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 219.76 30.5 L 219.76 52.26" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 219.76 58.26 L 215.76 50.26 L 219.76 52.26 L 223.76 50.26 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 379.76 30.5 L 379.76 52.26" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 379.76 58.26 L 375.76 50.26 L 379.76 52.26 L 383.76 50.26 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 539.76 30.5 L 539.76 52.26" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 539.76 58.26 L 535.76 50.26 L 539.76 52.26 L 543.76 50.26 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 110 38.74 L 110 60.5" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 110 32.74 L 114 40.74 L 110 38.74 L 106 40.74 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><path d="M 220 150.5 L 219.88 128.74" fill="none" stroke="#404040" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/><path d="M 219.84 122.74 L 223.89 130.71 L 219.88 128.74 L 215.89 130.76 Z" fill="#404040" stroke="#404040" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/></g><g><rect x="240" y="120.5" width="120" height="30" fill="none" stroke="none" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" font-style="italic" text-anchor="middle" font-size="14px"><text x="299.5" y="141">configuration...</text></g></g><g><rect x="105" y="30.5" width="80" height="30" fill="none" stroke="none" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" font-style="italic" text-anchor="middle" font-size="14px"><text x="144.5" y="51">control...</text></g></g><g><rect x="245" y="30.5" width="110" height="30" fill="none" stroke="none" pointer-events="all"/></g><g><g fill="#404040" font-family="Roboto" font-style="italic" text-anchor="middle" font-size="14px"><text x="299.5" y="51">supervision...</text></g></g></g></svg>
\ No newline at end of file diff --git a/doc/dev/architecture-gc.rst b/doc/dev/architecture-gc.rst index b57c857c..38e8f5b5 100644 --- a/doc/dev/architecture-gc.rst +++ b/doc/dev/architecture-gc.rst @@ -1,12 +1,12 @@ -***************** -``kres-cache-gc`` -***************** +******** +cache-gc +******** -The garbage collector is a simple component which keeps the shared cache from overfilling. -Every second it estimates cache usage and if over 80%, records get deleted in order to free 10%. (Parameters can be configured.) - -The freeing happens in a few passes. First all items are classified by their estimated usefulness, in a simple way based on remaining TTL, type, etc. -From this histogram it's computed which "level of usefulness" will become the threshold, so that roughly the planned total size gets freed. -Then all items are passed to collect the set of keys to delete, and finally the deletion is performed. -As longer transactions can cause issues in LMDB, all passes are split into short batches. +The garbage collector is a simple component that keeps the shared cache from filling up. +Every second it estimates the cache usage and if it is over 80%, it deletes records to free up 10%. +These parameters are configurable. +The freeing happens in a few passes. First all items are classified by their estimated usefulness, in a simple way based on remaining TTL, type, etc. +From this histogram, it's calculated which "level of usefulness" will become the threshold, so that roughly the planned total size will be freed. +Then all items are passed to collect the set of keys to be deleted, and finally the deletion is performed. +Since longer transactions can cause problems in the LMDB cache, all passes are split into short batches. diff --git a/doc/dev/architecture-kresd.rst b/doc/dev/architecture-kresd.rst index 783fbb8a..aac043b0 100644 --- a/doc/dev/architecture-kresd.rst +++ b/doc/dev/architecture-kresd.rst @@ -1,3 +1,3 @@ -********* -``kresd`` -*********
\ No newline at end of file +***** +kresd +*****
\ No newline at end of file diff --git a/doc/dev/architecture-manager.rst b/doc/dev/architecture-manager.rst index 4e3371a9..989b4f67 100644 --- a/doc/dev/architecture-manager.rst +++ b/doc/dev/architecture-manager.rst @@ -1,6 +1,6 @@ -**************** -``kres-manager`` -**************** +******* +manager +******* The manager is a component written in Python and a bit of C used for native extension modules. The main goal of the manager is to ensure the system is set up according to a given configuration, provide a user-friendly interface. Performance is only secondary to correctness. diff --git a/doc/dev/architecture-pl.rst b/doc/dev/architecture-pl.rst new file mode 100644 index 00000000..724652d6 --- /dev/null +++ b/doc/dev/architecture-pl.rst @@ -0,0 +1,24 @@ +************* +policy-loader +************* + +The ``policy-loader`` is a new special kresd instance ensuring that configured policies are loaded into the rules database where they are made available to all running kresd workers. +If the policies are loaded successfully, the ``policy-loader`` exits automatically, otherwise it exits with an error code that is detected by Supervisor. + +The ``policy-loader`` is triggered on every reload or a cold start to recompile the LMDB of rules, +as changes to external files are not tracked (e.g. RPZ or /etc/hosts). +This eliminates the need to restart kresd workers if only the policies have changed. +In that case the running kresd workers are only notified of changes in the rules database by their control socket using the ``kr_rules_reset()`` function. + +The kresd workers are only restarted when a relevant configuration change is made. +In particular, options located under the ``views`` and ``local-data`` do not need kresd restarts. +The same as for the kresd workers applies to the kresd canary process, which is always run before the kresd workers to validate the new configuration. +The manager always waits for the ``policy-loader`` to finish before working with other processes. + + +The resolver's cold start +------------------------- + +First, the ``policy-loader`` is started and the manager waits for the policies to finish loading into the rules database. +Then the kresd canary process is started to validate the configuration, and then all the kresd workers are started. +The resolver will not start if any of the operations fail. diff --git a/doc/dev/architecture.rst b/doc/dev/architecture.rst index 79084e5b..dbc4eea8 100644 --- a/doc/dev/architecture.rst +++ b/doc/dev/architecture.rst @@ -2,42 +2,61 @@ System architecture ******************* -Knot Resolver is split into several components, namely the manager, ``kresd`` and the garbage collector. In addition to these custom components, we also rely on `supervisord <http://supervisord.org/>`_. +Knot Resolver consists of several independent components that are managed by the ``manager`` which combines them into one functional unit. +The components are: ``kresd`` the resolving daemon, ``cache-gc`` the cache garbage collector, and ``policy-loader`` which loads configured policy rules. +In addition to these custom components, we also rely on `supervisord <http://supervisord.org/>`_, which handles the actual process management. .. image:: ../architecture-schema.svg :width: 100% - :alt: Diagram showing process tree and contol relationship between Knot Resolver components. Supervisord is a parent to all processes, namely manager, kresd instances and gc. Manager on the other hand controls every other component and what it does. + :alt: Diagram showing the process tree and control relationships between Knot Resolver components. + Supervisord is a parent to all processes, namely manager, kresd instances and gc. + Manager on the other hand controls every other component and what it does. - -There are two different control structures in place. Semantically, the manager controls every other component in Knot Resolver. It processes configuration and passes it onto every other component. As a user you will always interact with the manager (or kresd). At the same time though, the manager is not the root of the process hierarchy, Supervisord sits at the top of the process tree and runs everything else. +There are two different control structures in place. +Semantically, the manager controls every other component in Knot Resolver. +It processes configuration and passes it to each component. +As a user you will always interact with the manager. +At the same time though, the manager is not the root of the process hierarchy, +supervisord sits at the top of the process tree and runs everything else. .. note:: - The rationale for this inverted process hierarchy is mainly stability. Supervisord sits at the top because it is a reliable and stable software we can depend upon. It also does not process user input and its therefore shielded from data processing bugs. This way, any component in Knot Resolver can crash and restart without impacting the rest of the system. + The reason for this inverted process hierarchy is mainly stability. + Supervisord is at the top because it is a reliable and stable software that we can rely on. + In addition, it does not process user input and is therefore shielded from data processing errors. + This way, any component in Knot Resolver itself can recover from potential crashes without affecting the rest of the system. Knot Resolver startup ===================== -The inverted process hierarchy complicates Resolver's launch procedure. You might notice it when reading manager's logs just after start. What happens on cold start is: +The inverted process hierarchy makes the resolver startup procedure a bit more complicated. +You may notice this when reading the manager's logs immediately after startup. + +What happens on cold start is: -1. Manager starts, reads its configuration and generates new supervisord configuration. Then, it starts supervisord by using ``exec``. -2. Supervisord loads it's configuration, loads our extensions and start a new instance of manager. -3. Manager starts again, this time as a child of supervisord. As this is desired state, it loads the configuration again and commands supervisord that it should start new instances of ``kresd``. +1. The manager starts, reads its configuration and generates a new supervisord configuration. + Then, it starts supervisord with the ``exec`` syscall, which causes supervisord to *replace* the manager process. +2. The supervisord loads its configuration, loads our custom extensions and starts a new instance of the manager. +3. The manager starts again, this time as a child of the supervisord instance. + Since this is the desired state, it reloads the configuration again and instructs the supervisord to start the other components of the resolver. Failure handling ================ -Knot Resolver is designed to handle failures automatically. Anything except for supervisord will automatically restart. If a failure is irrecoverable, all processes will stop and nothing will be left behind in a half-broken state. While a total failure like this should never happen, it is possible and you should not rely on single instance of Knot Resolver for a highly-available system. +Knot Resolver is designed to handle failures automatically. +Everything except the supervisord is automatically restarted after a failure. +If a failure is unrecoverable, all processes are killed and nothing is left behind in a half-broken state. +While a total failure like this should not happen, it is possible and you should not rely on specific instances of Knot Resolver in a highly-available system. .. note:: - The ability to restart most of the components without downtime means, that Knot Resolver is able to transparently apply updates while running. + The ability to restart most of the components without downtime means that Knot Resolver can transparently apply updates while running. Individual components ===================== -You can learn more about architecture of individual Resolver components in the following chapters. +Learn more about the architecture of each component in the following chapters: .. toctree:: :titlesonly: @@ -46,3 +65,4 @@ You can learn more about architecture of individual Resolver components in the f architecture-manager architecture-kresd architecture-gc + architecture-pl diff --git a/doc/dev/config-lua-network.rst b/doc/dev/config-lua-network.rst index 241b67ff..d4f80646 100644 --- a/doc/dev/config-lua-network.rst +++ b/doc/dev/config-lua-network.rst @@ -61,3 +61,12 @@ DNS protocol tweaks :maxdepth: 2 daemon-bindings-net_dns_tweaks + +Buffering tweaks +================ + +.. toctree:: + :maxdepth: 2 + + daemon-bindings-net_buffering + diff --git a/doc/dev/daemon-bindings-net_buffering.rst b/doc/dev/daemon-bindings-net_buffering.rst new file mode 120000 index 00000000..9386a5fa --- /dev/null +++ b/doc/dev/daemon-bindings-net_buffering.rst @@ -0,0 +1 @@ +../../daemon/bindings/net_buffering.rst
\ No newline at end of file diff --git a/doc/dev/index.rst b/doc/dev/index.rst index b340b692..1f6dc1da 100644 --- a/doc/dev/index.rst +++ b/doc/dev/index.rst @@ -2,10 +2,10 @@ .. warning:: - **This documentation is intended to help with advanced fine-tuning of Knot - Resolver!** If you are looking for help with day-to-day use without the need to - involve yourself with the Lua programming language, please see the - `user documentation <../index.html>`_. + **This documentation is intended to help with advanced fine-tuning and + development of Knot Resolver!** If you are looking for help with day-to-day + use without the need to involve yourself with C and/or Lua programming + languages, please see the `user documentation <../index.html>`_. ##################################### Knot Resolver developer documentation @@ -14,11 +14,20 @@ Knot Resolver developer documentation Welcome to Knot Resolver's documentation for developers and advanced users! .. toctree:: - :caption: Building for sources + :caption: Building from sources :name: build-chapter :maxdepth: 1 build + manager-dev-env + +.. toctree:: + :caption: Architecture + :name: architecture-chapter + :maxdepth: 1 + + architecture + manager-dev-code .. toctree:: :caption: Lua configuration @@ -45,14 +54,6 @@ Welcome to Knot Resolver's documentation for developers and advanced users! logging_api .. toctree:: - :caption: Architecture - :name: architecture-chapter - :maxdepth: 1 - - manager-dev - architecture - -.. toctree:: :caption: Infrastructure :name: infra-chapter :maxdepth: 1 diff --git a/doc/dev/manager-dev-code.rst b/doc/dev/manager-dev-code.rst new file mode 100644 index 00000000..c211d536 --- /dev/null +++ b/doc/dev/manager-dev-code.rst @@ -0,0 +1,51 @@ +.. SPDX-License-Identifier: GPL-3.0-or-later + +.. _manager-dev-code: + +********************** +Manager code structure +********************** + +The manager's code is split into several distinct logical components: + +- controllers + - the HTTP API server (*the server*, ``server.py``) + - high-level coordinator of ``kresd``'s (*the manager*, ``kres_manager.py``) + - subprocess controller for launching and stopping ``kresd`` processes (*the subprocess controller*, ``kresd_controller/``) +- data + - schema validation and definition (*the datamodel*, ``datamodel/``) + - utilities, mainly general schema validation and parsing logic (*utils*, ``utils/``) +- ``kresctl`` utility (*kresctl*, ``cli/``) + +When running, *the server* receives all inputs from the outside, passes them onto *the manager*, +which applies the requested changes through the use of *the subprocess controller*. +In all stages, we use *the datamodel* to pass current configuration around. + + +The subprocess controllers +========================== + +Internally, the subprocess controllers are hidden behind an interface and there can be multiple implementations. In practice, there is only one and that is `supervisord <http://supervisord.org>`_. Historically, we tried to support systemd as well, but due to privilege escalation issues, we started focusing only on supervisord. + +The supervisord subprocess controller actually extends supervisord with new functionality, especially it reimplements ``sd_notify`` semantics from systemd. Supervisord is extended through loading plugins, which in turn modify few internal components of supervisord. Due to the maturity of the supervisord project, we believe this will be reasonably stable even with updates for supervisord. + +We want to have the Manager restarted if it fails, so that one mishandled API request can't bring everything down. We want the subprocess controllers to control the execution of the Manager and restart it, if needed. Therefore, there is a circular dependency. To solve it, the subprocess controller implementations are allowed to ``exec()`` into anything else while starting. To give an example of how the startup works with supervisord: + +1. *the server* loads the configuration, initiates *the manager* and *the supervisord subprocess controller* +2. *the supervisord subprocess controller* detects, that there is no supervisord running at the moment, generates new supervisord configuration and exec's supervisord +3. supervisord starts, loads its configuration and starts *the server* again +4. *the server* loads the configuration, initiates *the manager* and *the supervisord subprocess controller* +5. *the supervisord subprocess controller* detects, that there is a supervisord instance running, generates new configuration for it and reloads it +6. *the manager* starts new workers based on the initial configuration +7. *the server* makes it's API available to use and the Manager is fully running + + +Processing of configuration change requests +=========================================== + +1. a change request is received by *the server* +2. the raw text input is parsed and verified into a configuration object using *the datamodel* +3. *the manager* is asked to apply new configuration +4. *the manager* starts a canary ``kresd`` process with the new configuration (Lua code generated from the configration object), monitoring for failures +5. *the manager* restarts all ``kresd`` instances one by one +6. *the server* returns a success diff --git a/doc/dev/manager-dev-env.rst b/doc/dev/manager-dev-env.rst new file mode 100644 index 00000000..430fbd23 --- /dev/null +++ b/doc/dev/manager-dev-env.rst @@ -0,0 +1,165 @@ +.. SPDX-License-Identifier: GPL-3.0-or-later + +.. _manager-dev-env: + +******************************* +Manager development environment +******************************* + +In this guide, we will setup a development environment and discuss tooling. + +The manager is written in Python 3 with the goal of supporting multiple versions of Python (3.8 or newer) available in current Linux distributions. +These compatibility requirements also force us not to rely heavily on modern runtime libraries such as Pydantic. + + +Reproducible development environment +==================================== + +Because we want to support multiple versions of Python with one codebase, +we develop against the oldest supported version and then check in our CI that it works for newer versions of Python. +In your distro, there may be a Python runtime of a different version than the one we are targeting. +So we try to isolate everything from the system we are running on. + +To start working on the manager, you need to install the following tools: + +- Python: One of the supported versions. + You can use `pyenv <https://github.com/pyenv/pyenv#installation>`_ to install and manage multiple versions of Python without affecting your system. + Alternatively, some Linux distributions ship packages for older Python versions as well. +- `Poetry <https://python-poetry.org/docs/#installation>`_: We use it to manage our dependencies and virtual environments. + Do not install the package via ``pip``, follow instructions in Poetry's official documentation. + + Note that you need the latest version of Poetry. + The setup has been tested with Poetry version 1.1.7 because of it's able to switch between Python versions, + it must be installed separately to work correctly. + +After installing the above tools, the actual fully-featured development environment is ready to be set up. + + +Running the manager from source for the first time +================================================== + +1. Clone the Knot Resolver `GitLab repository <https://gitlab.nic.cz/knot/knot-resolver>`_. +2. In the repository, change to the ``manager/`` directory and perform all of the following tasks in that directory. +3. Run ``poetry env use $(which python3.12)`` to configure Poetry to use a Python interpreter other than the system default. + + As mentioned above it is recommended to use ``pyenv`` to manage other Python versions. + Then poetry needs to be told where to look for that version of Python, e.g.: + + .. code-block:: bash + + $ poetry env use ~/.pyenv/versions/3.12.1/bin/python3.12 + +4. Run ``poetry install --all-extras`` to install all dependencies including all optional ones (--all-extras flag), in a newly created virtual environment. + All dependencies can be seen in ``pyproject.toml``. +5. Use ``./poe run`` to run the manager in development mode (Ctrl+C to exit). + The manager is started with the configuration located in ``manager/etc/knot-resolver/config.dev.yaml``. + + +Commands +======== + +In the previous section, you saw the use of the ``./poe`` command. +`PoeThePoet <https://github.com/nat-n/poethepoet>`_ is a task runner which we use to simplify invoking common commands. + +You can run it by invoking ``./poe``, or you can install it system-wide via ``pip install poethepoet`` and invoke it just by calling ``poe`` (without the leading ``./``). +When invoked globally, you don't have to worry about virtual environments and such, PoeThePoet figures that out for you and commands always run in the appropriate virtual environment. + +Or, you can create a symlink to the ``./poe`` script without installing PoeThePoet, e.g. ``ln -s path_to_the_repository/manager/poe /usr/bin/poe``. + +To list all the available commands, you can run ``poe help``. +The commands are defined in the ``pyproject.toml`` file. +The most important ones for everyday development are: + +- ``poe run`` to run the manager +- ``poe docs`` to create HTML documentation +- ``poe test`` to run unit tests (enforced by our CI) +- ``poe check`` to run static code analysis (enforced by our CI) +- ``poe format`` to autoformat the source code +- ``poe kresctl`` to run the manager's CLI tool + +With this environment, **everything else should just work**. +You can run the same checks that CI runs, all the commands listed below should pass. +If something fails and you have done all the steps above, please [open a new issue](https://gitlab.nic.cz/knot/knot-resolver-manager/-/issues/new). + +Contributing +============ + +Before committing, please ensure that both ``poe check`` and ``poe test`` pass. +Those commands are both run on the CI and if they don't pass, CI fails. + + +Minimal development environment +=============================== + +The only global tools that are strictly required are ``Python`` and ``pip`` (or other way to install PyPI packages). +You can have a look at the ``pyproject.toml`` file, manually install all other dependencies that you need and be done with that. +All ``poe`` commands can be run manually too, see their definition in ``pyproject.toml``. +We can't however guarantee, that there won't be any errors. + +Please note that Python's development files are also required, since the manager also includes a C module that interacts with it. I.e., +for distros that package development files separately, you will typically need to install ``-dev`` or ``-devel`` packages of your current Python version as well. + + +Packaging +========= + +Packaging is handled by `apkg <https://apkg.readthedocs.io/en/latest/>`_ cooperating with Poetry. +To allow for backwards compatibility with Python tooling not supporting `PEP-517 <https://peps.python.org/pep-0517/>`_, +we generate ``setup.py`` file with the command ``poe gen-setuppy``, so our project is compatible with ``setuptools`` as well. + + +Testing +======= + +The manager has two suits of tests - unit tests and packaging tests, all residing in the ``manager/tests/`` directory. +The units tests are run by `pytest <https://docs.pytest.org/>`_, while the packaging tests are distro specific and are using `apkg test <https://apkg.readthedocs.io/en/latest/commands/#test>`_. + + +Code editor +=========== + +Feel free to use any text editor you like. +However, we recommend using `Visual Studio Code <https://code.visualstudio.com/>`_ with `Pylance <https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance>`_ extension. +That's what we use to work on the manager and we know that it works really well for us. +Just make sure to configure the extension so that it uses Poetry's virtual environment. + + +FAQ +=== + +What all those dev dependencies for? +------------------------------------ + +Short answer - mainly for managing other dependencies. By using dependency management systems within the project, anyone can start developing after installing just a few core tools. Everything else will be handled automagically. The main concept behind it is that there should be nothing that can be run only in CI. + +Core dependencies which you have to install manually: + +- **pyenv**: A tools which allows you to install any version of Python regardless of your system's default. + The version used by default in the project is configured in the file `.python-version`. + + We should be all developing on the same version, because otherwise we might not be able to reproduce each others bug's. + + Written in pure shell, no dependencies on Python. + Should therefore work on any Unix-like system. + +- **Poetry**: A dependency management system for Python libraries. + Normally, all libraries in Python are installed system-wide and dependent on system's Python version. + By using virtual environments managed by Poetry, configured to use a the correct Python version through pyenv, we can specify versions of the dependencies in any way we like. + + Follows PEP 518 and uses the ``pyproject.toml`` file for all of it's configuration. + Written in Python, therefore it's problematic if installed system-wide as an ordinary Python package (because it would be unavailable in its own virtual environment). + +Automatically managed dependencies: + +- **PoeThePoet**: A task management system, or in other words glorified switch statement calling other tools. + Used for simplifying interactions with the project. + +- ``pytest``, ``pytest-cov``: unit testing +- ``pylint``, ``flake8``: linting +- ``black``: autoformatter (might be removed in the future if not used in practice) + + +Why Poetry? Why should I learn a new tool? +------------------------------------------ + +This blog post explains it nicely - https://muttdata.ai/blog/2020/08/21/a-poetic-apology.html. diff --git a/doc/dev/manager-dev.rst b/doc/dev/manager-dev.rst deleted file mode 100644 index cdf65267..00000000 --- a/doc/dev/manager-dev.rst +++ /dev/null @@ -1,115 +0,0 @@ -.. SPDX-License-Identifier: GPL-3.0-or-later - -=========================== -Manager's development guide -=========================== - -In this guide, we will setup a development environment, discuss tooling and high-level code architecture. - - -Development environment -======================= - -The Manager is written in Python 3 with the goal of supporting multiple versions of Python available in current Linux distributions. For example, at the time of writing, this means we support Python 3.7 and newer. These compatibility requirements also force us not to rely heavily on modern runtime libraries such as Pydantic. - -Tools ------ - -To start working on the Manager, you need to install the following tools: - -- Python, preferably the oldest supported version. You can use `pyenv <https://github.com/pyenv/pyenv>`_ to install and manage multiple Python versions on your system. Alternatively, some distros ship packages for older Python versions as well. -- `Poetry <https://python-poetry.org/>`_. We use it to manage our dependencies and virtual environments. - - -First run of the Manager from source ------------------------------------- - -1. clone `the Knot Resolver repository <https://gitlab.nic.cz/knot/knot-resolver>`_ -2. enter the directory ``manager/`` in the repository, all following tasks will be performed from within that directory -3. run ``poetry env use $(which python3.7)`` to configure Poetry to use a different Python interpreter than the default -4. run ``poetry install`` to install all dependencies into a newly created virtual environment -5. run ``./poe run`` to run the Manager in dev mode (Ctrl+C to exit) - -Helper scripts --------------- - -In the previous section, you saw the use of the ``./poe`` command. `PoeThePoet <https://github.com/nat-n/poethepoet>`_ is a task runner which we use to simplify invoking common commands. You can run it by invoking ``./poe``, or you can install it system-wide via ``pip install poethepoet`` and invoke it just by calling ``poe`` (without the leading ``./``). When invoked globally, you don't have to worry about virtual environments and such, PoeThePoet figures that out for you and commands always run in the appropriate virtual environment. - -To list the available commands, you can run ``poe help``. The most important ones for everyday development are: - -- ``poe run`` to compile ``kresd`` and run the Manager -- ``poe run-debug`` same as ``run``, but also injects ``debugpy`` into the process to allow remote debugging on port 5678 -- ``poe kresctl`` to run the Manager's CLI tool -- ``poe check`` to run static code analysis (enforced by our CI) -- ``poe test`` to run unit tests (enforced by our CI) -- ``poe format`` to autoformat the source code - - -The commands are defined in the ``pyproject.toml`` file. - - -Code editor ------------ - -Feel free to use any text editor you like. However, we recommend using `Visual Studio Code <https://code.visualstudio.com/>`_ with `Pylance <https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance>`_ extension. That's what we use to work on the Manager and we know that it works really well for us. Just make sure to configure the extension so that it uses Poetry's virtual environment. We have a helper for that - ``poe config-vscode``, but your mileage may vary when using it. - - -Code structure -============== - -The Manager's code is split into several distinct logical components: - -- controllers - - the HTTP API server (*the server*, ``server.py``) - - high-level coordinator of ``kresd``'s (*the manager*, ``kres_manager.py``) - - subprocess controller for launching and stopping ``kresd`` processes (*the subprocess controller*, ``kresd_controller/``) -- data - - schema validation and definition (*the datamodel*, ``datamodel/``) - - utilities, mainly general schema validation and parsing logic (*utils*, ``utils/``) -- ``kresctl`` utility (*kresctl*, ``cli/``) - -When running, *the server* receives all inputs from the outside, passes them onto *the manager*, which applies the requested changes through the use of *the subprocess controller*. In all stages, we use *the datamodel* to pass current configuration around. - - -The subprocess controllers --------------------------- - -Internally, the subprocess controllers are hidden behind an interface and there can be multiple implementations. In practice, there is only one and that is `supervisord <http://supervisord.org>`_. Historically, we tried to support systemd as well, but due to privilege escalation issues, we started focusing only on supervisord. - -The supervisord subprocess controller actually extends supervisord with new functionality, especially it reimplements ``sd_notify`` semantics from systemd. Supervisord is extended through loading plugins, which in turn modify few internal components of supervisord. Due to the maturity of the supervisord project, we believe this will be reasonably stable even with updates for supervisord. - -We want to have the Manager restarted if it fails, so that one mishandled API request can't bring everything down. We want the subprocess controllers to control the execution of the Manager and restart it, if needed. Therefore, there is a circular dependency. To solve it, the subprocess controller implementations are allowed to ``exec()`` into anything else while starting. To give an example of how the startup works with supervisord: - -1. *the server* loads the config, initiates *the manager* and *the supervisord subprocess controller* -2. *the supervisord subprocess controller* detects, that there is no supervisord running at the moment, generates new supervisord config and exec's supervisord -3. supervisord starts, loads its config and starts *the server* again -4. *the server* loads the config, initiates *the manager* and *the supervisord subprocess controller* -5. *the supervisord subprocess controller* detects, that there is a supervisord instance running, generates new config for it and reloads it -6. *the manager* starts new workers based on the initial configuration -7. *the server* makes it's API available to use and the Manager is fully running - - -Processing of config change requests ------------------------------------- - -1. a change request is received by *the server* -2. the raw text input is parsed and verified into a configuration object using *the datamodel* -3. *the manager* is asked to apply new configuration -4. *the manager* starts a canary process with the new config (Lua config generated from the configration object), monitoring for failures -5. *the manager* restarts all ``kresd`` instances one by one -6. *the server* returns a success - - -Packaging -========= - -Packaging is handled by `apkg <https://apkg.readthedocs.io/en/latest/>`_ cooperating with Poetry. To allow for backwards compatibility with Python tooling not supporting `PEP-517 <https://peps.python.org/pep-0517/>`_, we generate ``setup.py`` file with the command ``poe gen-setuppy``, so our project is compatible with ``setuptools`` as well. - - -Testing -======= - -The manager has two suits of tests - unit tests and packaging tests, all residing in the ``manager/tests/`` directory. The units tests are run by `pytest <https://docs.pytest.org/>`_, while the packaging tests are distro specific and are using `apkg test <https://apkg.readthedocs.io/en/latest/commands/#test>`_. - - - diff --git a/doc/user/manager-client.rst b/doc/user/manager-client.rst index f21a69a7..61ff2fff 100644 --- a/doc/user/manager-client.rst +++ b/doc/user/manager-client.rst @@ -262,6 +262,15 @@ single ``kresctl`` command. Ignore strict rules during validation, e.g. path/file existence. + .. option:: --type=<worker|policy-loader> + + Which type of Lua script to generate. + + * ``worker`` generates a script for the daemon (default) + * ``policy-loader`` generates a script for the one-shot policy loader, + which generates a rule database based on ``views``, ``local-data``, + and ``forward`` configuration + .. option:: <input_file> File with the declarative configuration in YAML or JSON format. diff --git a/etc/root.keys b/etc/root.keys index e292b5a7..3009e81f 100644 --- a/etc/root.keys +++ b/etc/root.keys @@ -1 +1,2 @@ . IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D +. IN DS 38696 8 2 683D2D0ACB8C9B712A1948B27F741219298D0A450D612C483AF444A4C0FB2B16 diff --git a/lib/cache/api.c b/lib/cache/api.c index 490f3d1c..0cd18534 100644 --- a/lib/cache/api.c +++ b/lib/cache/api.c @@ -175,7 +175,7 @@ int kr_cache_commit(struct kr_cache *cache) return kr_error(EINVAL); } if (cache->api->commit) { - return cache_op(cache, commit, true); + return cache_op(cache, commit, true, true); } return kr_ok(); } diff --git a/lib/cache/cdb_api.h b/lib/cache/cdb_api.h index bce8740f..23a795d5 100644 --- a/lib/cache/cdb_api.h +++ b/lib/cache/cdb_api.h @@ -58,10 +58,11 @@ struct kr_cdb_api { int (*clear)(kr_cdb_pt db, struct kr_cdb_stats *stat); /** Run after a row of operations to release transaction/lock if needed. - * \param accept true=commit / false=abort + * \param accept_rw whether the RW transaction should accept changes (commit vs. abort) + * \param reset_ro whether the RO transaction should be ended (newest data next time) * \return error code - accepting RW transactions can fail with LMDB. */ - int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat, bool accept); + int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat, bool accept_rw, bool reset_ro); /* Data access */ diff --git a/lib/cache/cdb_lmdb.c b/lib/cache/cdb_lmdb.c index 5351cd73..10611513 100644 --- a/lib/cache/cdb_lmdb.c +++ b/lib/cache/cdb_lmdb.c @@ -76,7 +76,7 @@ static inline kr_cdb_pt env2db(struct lmdb_env *env) return (kr_cdb_pt)env; } -static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept); +static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept_rw, bool reset_ro); static void txn_abort(struct lmdb_env *env); /** @brief Convert LMDB error code. */ @@ -114,7 +114,7 @@ static inline MDB_val val_knot2mdb(knot_db_val_t v) * It's much lighter than reopen_env(). */ static int refresh_mapsize(struct lmdb_env *env) { - int ret = cdb_commit(env2db(env), NULL, true); + int ret = cdb_commit(env2db(env), NULL, true, true); if (!ret) ret = lmdb_error(env, mdb_env_set_mapsize(env->env, 0)); if (ret) return ret; @@ -223,20 +223,20 @@ static int txn_get(struct lmdb_env *env, MDB_txn **txn, bool rdonly) return kr_ok(); } -static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept) +static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept_rw, bool reset_ro) { struct lmdb_env *env = db2env(db); - if (!accept) { - txn_abort(env); - return kr_ok(); - } int ret = kr_ok(); if (env->txn.rw) { - if (stats) stats->commit++; - ret = lmdb_error(env, mdb_txn_commit(env->txn.rw)); + if (accept_rw) { + if (stats) stats->commit++; + ret = lmdb_error(env, mdb_txn_commit(env->txn.rw)); + } else { + mdb_txn_abort(env->txn.rw); + } env->txn.rw = NULL; /* the transaction got freed even in case of errors */ - } else if (env->txn.ro && env->txn.ro_active) { + } else if (reset_ro && env->txn.ro && env->txn.ro_active) { mdb_txn_reset(env->txn.ro); env->txn.ro_active = false; env->txn.ro_curs_active = false; @@ -256,7 +256,7 @@ static int txn_curs_get(struct lmdb_env *env, MDB_cursor **curs, struct kr_cdb_s * At least for rules we don't do the auto-commit feature. */ if (env->txn.rw) { if (!env->is_cache) return kr_error(EINPROGRESS); - int ret = cdb_commit(env2db(env), stats, true); + int ret = cdb_commit(env2db(env), stats, true, false); if (ret) return ret; } MDB_txn *txn = NULL; @@ -312,7 +312,7 @@ static void cdb_close_env(struct lmdb_env *env, struct kr_cdb_stats *stats) /* Get rid of any transactions. */ txn_free_ro(env); - cdb_commit(env2db(env), stats, env->is_cache); + cdb_commit(env2db(env), stats, env->is_cache, true); mdb_env_sync(env->env, 1); stats->close++; @@ -574,7 +574,7 @@ static int cdb_clear(kr_cdb_pt db, struct kr_cdb_stats *stats) if (ret == kr_ok()) { ret = lmdb_error(env, mdb_drop(txn, env->dbi, 0)); if (ret == kr_ok() && env->is_cache) { - ret = cdb_commit(db, stats, true); + ret = cdb_commit(db, stats, true, true); } if (ret == kr_ok()) { return ret; @@ -588,7 +588,7 @@ static int cdb_clear(kr_cdb_pt db, struct kr_cdb_stats *stats) /* We are about to switch to a different file, so end all txns, to be sure. */ txn_free_ro(env); - (void) cdb_commit(db, stats, env->is_cache); + (void)cdb_commit(db, stats, env->is_cache, true); const char *path = NULL; int ret = mdb_env_get_path(env->env, &path); diff --git a/lib/defines.h b/lib/defines.h index e8328928..24205896 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -73,11 +73,6 @@ static inline int KR_COLD kr_error(int x) { #define KR_DNAME_STR_MAXLEN (KNOT_DNAME_TXT_MAXLEN + 1) #define KR_RRTYPE_STR_MAXLEN (16 + 1) -/* Compatibility with libknot<3.1.0 */ -#if KNOT_VERSION_HEX < 0x030100 -#define KNOT_EDNS_EDE_NONE (-1) -#endif - /* * Address sanitizer hints. */ diff --git a/lib/generic/lru.c b/lib/generic/lru.c index 857b20b3..71b8730b 100644 --- a/lib/generic/lru.c +++ b/lib/generic/lru.c @@ -50,9 +50,9 @@ static uint item_size(const struct lru *lru, uint key_len, uint val_len) /** @internal Return pointer to value in an lru_item. */ static void * item_val(const struct lru *lru, struct lru_item *it) { - size_t key_end = it->data + it->key_len - (char *)NULL; + size_t key_end = (uintptr_t)(it->data + it->key_len); size_t val_begin = round_power(key_end, lru->val_alignment); - return (char *)NULL + val_begin; + return (void *)(uintptr_t)val_begin; } /** @internal Free each item. */ diff --git a/lib/generic/test_trie.c b/lib/generic/test_trie.c index 9ecd67cd..ce164906 100644 --- a/lib/generic/test_trie.c +++ b/lib/generic/test_trie.c @@ -48,7 +48,7 @@ static void test_insert(void **state) trie_val_t *data = trie_get_ins(t, dict[i], KEY_LEN(dict[i])); assert_non_null(data); assert_null(*data); - *data = (char *)NULL + i; // yes, ugly + *data = (void *)(intptr_t)i; // yes, ugly assert_ptr_equal(trie_get_try(t, dict[i], KEY_LEN(dict[i])), data); } assert_int_equal(trie_weight(t), dict_size); @@ -82,7 +82,7 @@ static void test_iter(void **state) const char *key = trie_it_key(it, &len); assert_int_equal(KEY_LEN(key), len); assert_string_equal(key, dict_sorted[i]); - assert_ptr_equal(dict[(char *)*trie_it_val(it) - (char *)NULL], + assert_ptr_equal(dict[(uintptr_t)*trie_it_val(it)], dict_sorted[i]); } assert_true(trie_it_finished(it)); @@ -100,7 +100,7 @@ static void test_queue(void **state) assert_non_null(key); assert_int_equal(len, KEY_LEN(key)); assert_non_null(data); - ptrdiff_t key_i = (char *)*data - (char *)NULL; + uintptr_t key_i = (uintptr_t)*data; assert_string_equal(key, dict[key_i]); len = 30; diff --git a/lib/generic/trie.c b/lib/generic/trie.c index 21254eb4..e2ce061e 100644 --- a/lib/generic/trie.c +++ b/lib/generic/trie.c @@ -116,7 +116,7 @@ static inline void empty_root(node_t *root) { static void assert_portability(void) { #if FLAGS_HACK kr_require(((union node){ .leaf = { - .key = (tkey_t *)(((uint8_t *)NULL) + 1), + .key = (tkey_t *)(void *)(uintptr_t)1, .val = NULL } }).branch.flags == 1); #endif diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 6f312ca7..69fe344c 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -825,7 +825,10 @@ static int process_answer(knot_pkt_t *pkt, struct kr_request *req) } } else if (!query->parent) { /* Answer for initial query */ - const bool to_wire = ((pkt_class & (PKT_NXDOMAIN|PKT_NODATA)) != 0); + const bool to_wire = ((pkt_class & (PKT_NXDOMAIN|PKT_NODATA)) != 0) + /* We need to cover the case of positive wildcard answer + * with over-limit NSEC3 iterations. */ + || query->flags.DNSSEC_WEXPAND; state = pick_authority(pkt, req, to_wire); if (state != kr_ok()) { return KR_STATE_FAIL; diff --git a/lib/resolve.c b/lib/resolve.c index ec00b215..4730f105 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -246,11 +246,7 @@ static int pkt_padding(knot_pkt_t *packet, int32_t padding) if (padding == -1) { /* use the default padding policy from libknot */ const size_t block_size = knot_wire_get_qr(packet->wire) ? KNOT_EDNS_ALIGNMENT_RESPONSE_DEFAULT - #if KNOT_VERSION_HEX < 0x030200 - : KNOT_EDNS_ALIGNMENT_QUERY_DEFALT; - #else : KNOT_EDNS_ALIGNMENT_QUERY_DEFAULT; - #endif pad_bytes = knot_edns_alignment_size(packet->size, knot_rrset_size(opt_rr), block_size); } diff --git a/lib/rules/api.c b/lib/rules/api.c index 8e908a7a..5ecbe29e 100644 --- a/lib/rules/api.c +++ b/lib/rules/api.c @@ -141,9 +141,9 @@ int kr_rules_init_ensure(void) { if (the_rules) return kr_ok(); - return kr_rules_init(NULL, 0); + return kr_rules_init(NULL, 0, true); } -int kr_rules_init(const char *path, size_t maxsize) +int kr_rules_init(const char *path, size_t maxsize, bool overwrite) { if (the_rules) return kr_error(EINVAL); @@ -157,22 +157,17 @@ int kr_rules_init(const char *path, size_t maxsize) // FIXME: the file will be sparse, but we still need to choose its size somehow. // 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 : - (size_t)(sizeof(size_t) > 4 ? 2048 : 500) * 1024*1024, + .maxsize = !overwrite ? 0 : + (maxsize ? maxsize : (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. - * LATER: - * - Make it include versioning? - * - "\0stamp" key when loading config(s)? - * - Don't clear ruleset data that doesn't come directly from config; - * and add marks for that, etc. - * (after there actually are any kinds of rules like that) - */ - if (ret == 0) ret = ruledb_op(clear); + + if (ret == 0 && overwrite) ret = ruledb_op(clear); if (ret != 0) goto failure; kr_require(the_rules->db); + if (!overwrite) return kr_ok(); // we assume that the caller ensured OK contents + ret = tag_names_default(); if (ret != 0) goto failure; @@ -205,7 +200,13 @@ void kr_rules_deinit(void) int kr_rules_commit(bool accept) { if (!the_rules) return kr_error(EINVAL); - return ruledb_op(commit, accept); + return ruledb_op(commit, accept, false); +} + +int kr_rules_reset(void) +{ + if (!the_rules) return kr_error(EINVAL); + return ruledb_op(commit, false, true); } static bool kr_rule_consume_tags(knot_db_val_t *val, const struct kr_request *req) @@ -817,16 +818,28 @@ int kr_rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type, } -/** Encode a subnet into a (longer) string. +/** Encode a subnet into a (longer) string. The result is in `buf` with returned length. * * The point is to have different encodings for different subnets, * with using just byte-length strings (e.g. for ::/1 vs. ::/2). - * And we need to preserve order: FIXME description - * - natural partial order on subnets, one included in another - * - partial order on strings, one being a prefix of another - * - implies lexicographical order on the encoded strings + * You might imagine this as the space of all nodes of a binary trie. * - * Consequently, given a set of subnets, the t + * == Key properties == + * We're utilizing the order on the encoded strings. LMDB uses lexicographical order. + * Optimization: the properties should cut down LMDB operation count when searching + * for rule sets typical in practice. Some properties: + * - full address is just a subnet containing only that address (/128 and /32) + * - order of full addresses is kept the same as before encoding + * - ancestor first: if subnet B is included inside subnet A, we get A < B + * - subnet mixing: if two subnets do not share any address, all addresses of one + * of them are ordered before all addresses of the other one + * + * == The encoding == + * The encoding replaces each address bit by a pair of bits: + * - 00 -> beyond the subnet's prefix + * - 10 -> zero bit within the subnet's prefix + * - 11 -> one bit within the subnet's prefix + * - we cut the byte-length - no need for all-zero suffixes */ static int subnet_encode(const struct sockaddr *addr, int sub_len, uint8_t buf[32]) { @@ -837,17 +850,22 @@ static int subnet_encode(const struct sockaddr *addr, int sub_len, uint8_t buf[3 return kr_error(EINVAL); const uint8_t *a = (const uint8_t *)/*sign*/kr_inaddr(addr); - // Algo: interleave bits of the address. Bit pairs: - // - 00 -> beyond the subnet's prefix - // - 10 -> zero bit within the subnet's prefix - // - 11 -> one bit within the subnet's prefix - // Multiplying one uint8_t by 01010101 (in binary) will do interleaving. int i; // Let's hope that compiler optimizes this into something reasonable. for (i = 0; sub_len > 0; ++i, sub_len -= 8) { - 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); + // r = a[i] interleaved by 1 bits (with 1s on the higher-value positions) + // https://graphics.stanford.edu/~seander/bithacks.html#Interleave64bitOps + // but we modify it slightly: no need for the 0x5555 mask (==0b0101010101010101) + // or the y-part - we instead just set all odd bits to 1s. + uint16_t r = ( + (a[i] * 0x0101010101010101ULL & 0x8040201008040201ULL) + * 0x0102040810204081ULL >> 49 + ) | 0xAAAAU/* = 0b1010'1010'1010'1010 */; + // now r might just need clipping + if (sub_len < 8) { + uint16_t mask = 0xFFFFffffU << (2 * (8 - sub_len)); + r &= mask; + } buf[(ssize_t)2*i] = r / 256; buf[(ssize_t)2*i + 1] = r % 256; } @@ -855,7 +873,7 @@ static int subnet_encode(const struct sockaddr *addr, int sub_len, uint8_t buf[3 } // Is `a` subnet-prefix of `b`? (a byte format of subnet_encode()) -bool subnet_is_prefix(uint8_t a, uint8_t b) +static bool subnet_is_prefix(uint8_t a, uint8_t b) { while (true) { if (a >> 6 == 0) diff --git a/lib/rules/api.h b/lib/rules/api.h index 1069ef4d..f1737a19 100644 --- a/lib/rules/api.h +++ b/lib/rules/api.h @@ -19,11 +19,13 @@ typedef uint64_t kr_rule_tags_t; /** Open the rule DB. * - * You can call this to override the path or size (NULL/0 -> default). - * Not allowed if already open (EINVAL), so this optional call has to come - * before writing anything into the DB. */ + * You can call this to override the path or size (NULL/0 -> default) + * or choose not to overwrite the DB with just the defaults. + * + * \return error code. Not allowed if already open (EINVAL), + * so this optional call has to come before writing anything into the DB. */ KR_EXPORT -int kr_rules_init(const char *path, size_t maxsize); +int kr_rules_init(const char *path, size_t maxsize, bool overwrite); /** kr_rules_init() but OK if already open, and not allowing to override defaults. */ KR_EXPORT int kr_rules_init_ensure(void); @@ -36,10 +38,22 @@ void kr_rules_deinit(void); * Normally commit happens only on successfully loading a config file. * However, an advanced user may get in trouble e.g. if calling resolve() from there, * causing even an assertion failure. In that case they might want to commit explicitly. + * + * If only read-only transaction is open, this will NOT reset it to the newest data. */ KR_EXPORT int kr_rules_commit(bool accept); +/** Reset to the latest version of rules committed in the DB. + * + * Note that this is not always a good idea. For example, the `forward` rules + * now use data from both the DB and lua config, so reloading only the DB + * may lead to weird behavior in some cases. + * (Modifications will also do this, as you can only modify the latest DB.) + */ +KR_EXPORT +int kr_rules_reset(void); + /** Try answering the query from local data; WIP: otherwise determine data source overrides. * * \return kr_error() on errors, >0 if answered, 0 otherwise (also when forwarding) diff --git a/lib/rules/impl.h b/lib/rules/impl.h index 0d7de513..1a2ee4dd 100644 --- a/lib/rules/impl.h +++ b/lib/rules/impl.h @@ -20,7 +20,7 @@ extern struct kr_rules *the_rules; #define ENSURE_the_rules \ if (!the_rules) { \ - int ret = kr_rules_init(NULL, 0); \ + int ret = kr_rules_init(NULL, 0, true); \ if (ret) return ret; \ } diff --git a/lib/selection.c b/lib/selection.c index 9cdd1a60..cdef1701 100644 --- a/lib/selection.c +++ b/lib/selection.c @@ -173,7 +173,7 @@ int put_rtt_state(const uint8_t *ip, size_t len, struct rtt_state state, .data = &state }; int ret = cache->api->write(db, stats, &key, &value, 1); - cache->api->commit(db, stats, true); + kr_cache_commit(cache); free(key.data); return ret; diff --git a/lib/utils.c b/lib/utils.c index 04b1bcb9..de7c02cb 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1232,11 +1232,7 @@ char *kr_pkt_text(const knot_pkt_t *pkt) const knot_dump_style_t KR_DUMP_STYLE_DEFAULT = { /* almost all = false, */ .show_ttl = true, -#if KNOT_VERSION_HEX >= 0x030200 .human_timestamp = true, -#else - .human_tmstamp = true, -#endif }; char *kr_rrset_text(const knot_rrset_t *rr) diff --git a/manager/.gitlab-ci.yml b/manager/.gitlab-ci.yml index 851914d2..369035c8 100644 --- a/manager/.gitlab-ci.yml +++ b/manager/.gitlab-ci.yml @@ -2,7 +2,7 @@ stages: - check default: - image: $CI_REGISTRY/knot/knot-resolver/ci/manager:knot-$KNOT_VERSION + image: $IMAGE_PREFIX/manager:$IMAGE_TAG before_script: - cd manager - poetry --version diff --git a/manager/README.md b/manager/README.md index 7f323337..48919c21 100644 --- a/manager/README.md +++ b/manager/README.md @@ -2,84 +2,6 @@ Knot Resolver Manager is a configuration tool for [Knot Resolver](https://gitlab.nic.cz/knot/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. -## Development environment +## Development -### Reproducible development environment - -Because we want to support multiple versions of Python with one codebase, we develop against the oldest supported version and then check in our CI that it works for newer Python versions. In your distro, there might be a Python runtime of a different version than what we target. We therefore attempt to isolate everything from the system we are running on. - -Install these tools: -* [pyenv](https://github.com/pyenv/pyenv#installation) - a tool for switching between Python versions without affecting the system (can be installed using distro's package manager) -* [Poetry](https://python-poetry.org/docs/#installation) - dependency management (note: do not install the package via pip, follow instructions in Poetry's official documentation) - -Be careful, that you need the latest version of Poetry. The setup was tested with Poetry version 1.1.7. Due to it's ability to switch between Python versions, it has to be installed separately to work correctly. Make sure to follow [the latest setup guide](https://python-poetry.org/docs/#installation). - -After installing the tools above, the actual fully-featured development environment can be setup using these commands: - -```sh -pyenv install -poetry env use $(pyenv which python) -poetry install -``` - -With this environment, **everything else should just work**. You can run the same checks the CI runs, all commands listed bellow should pass. If something fails and you did all the steps above, please [open a new issue](https://gitlab.nic.cz/knot/knot-resolver-manager/-/issues/new). - -### Minimal development environment - -The only global tools that are strictly required are `Python` and `pip` (or other way to install PyPI packages). You can have a look at the `pyproject.toml` file, manually install all other dependencies that you need and be done with that. All `poe` commands (see bellow) can be run manually too, see their definition in `pyproject.toml`. We can't however guarantee, that there won't be any errors. - -Please note that Python's development files are also required, since the Manager also includes a C module that interacts with it. I.e., for distros that package development files separately, you will typically need to install `-dev` or `-devel` packages of your current Python version as well. - -### Common tasks and interactions with the project - -After setting up the environment, you should be able to interact with the project by using the `./poe` script. Common actions are: - -* `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) -* `poe check` - static code analysis -* `poe format` - runs code formater -* `poe fixdeps` - update installed dependencies according to the project's configuration -* `poe clean` - cleanup the repository from unwanted files -* `poe integration` - run the integration tests - -All possible commands can be listed by running the `poe` command without arguments. The definition of these commands can be found in the `pyproject.toml` file. - -If you don't want to be writing the `./` prefix, you can install [PoeThePoet](https://github.com/nat-n/poethepoet) Python package globally and call `poe` directly. I would also recommend setting up its tab completition. Instructions can be found on [their GitHub page](https://github.com/nat-n/poethepoet#enable-tab-completion-for-your-shell). - -### Contributing - -Before commiting, please ensure that both `poe check` and `poe test` pass. Those commands are both run on the CI and if they don't pass, CI fails. - -### Packaging - -This project uses [`apkg`](https://gitlab.nic.cz/packaging/apkg) for packaging. See [`distro/README.md`](distro/README.md) for packaging specific instructions. - -## FAQ - -### What all those dev dependencies for? - -Short answer - mainly for managing other dependencies. By using dependency management systems within the project, anyone can start developing after installing just a few core tools. Everything else will be handled automagically. The main concept behind it is that there should be nothing that can be run only in CI. - -* core dependencies which you have to install manually - * pyenv - * A tools which allows you to install any version of Python regardless of your system's default. The version used by default in the project is configured in the file `.python-version`. - * We should be all developing on the same version, because otherwise we might not be able to reproduce each others bug's. - * Written in pure shell, no dependencies on Python. Should therefore work on any Unix-like system. - * Poetry - * A dependency management system for Python libraries. Normally, all libraries in Python are installed system-wide and dependent on system's Python version. By using virtual environments managed by Poetry, configured to use a the correct Python version through pyenv, we can specify versions of the dependencies in any way we like. - * Follows PEP 518 and uses the `pyproject.toml` file for all of it's configuration. - * Written in Python, therefore it's problematic if installed system-wide as an ordinary Python package (because it would be unavailable in its own virtual environment). -* automatically managed dependencies - * PoeThePoet - A task management system, or in other words glorified switch statement calling other tools. Used for simplifying interractions with the project. - * pytest, pytest-cov - unit testing - * pylint, flake8 - linting - * black - autoformatter (might be removed in the future if not used in practice) - * tox - testing automation - * tox-pyenv - plugin for tox that makes use of pyenv provided Python binaries - -### Why Poetry? Why should I learn a new tool? - -This blog post explains it nicely - https://muttdata.ai/blog/2020/08/21/a-poetic-apology.html. +If you want to learn more about the architecture or start developing, check out our [Developer Documentation](https://www.knot-resolver.cz/documentation/latest/dev/).
\ No newline at end of file diff --git a/manager/etc/knot-resolver/config.dev.yaml b/manager/etc/knot-resolver/config.dev.yaml index 9288b1d0..aa97a41f 100644 --- a/manager/etc/knot-resolver/config.dev.yaml +++ b/manager/etc/knot-resolver/config.dev.yaml @@ -47,7 +47,7 @@ local-data: tags: [t02] ttl: 10m - subtree: empty - tags: [ t2 ] + tags: [ t02 ] name: [ example1.org ] - subtree: nxdomain name: [ sub4.example.org ] diff --git a/manager/knot_resolver_manager/cli/cmd/convert.py b/manager/knot_resolver_manager/cli/cmd/convert.py index aab2740a..7bb2858f 100644 --- a/manager/knot_resolver_manager/cli/cmd/convert.py +++ b/manager/knot_resolver_manager/cli/cmd/convert.py @@ -21,6 +21,7 @@ class ConvertCommand(Command): self.input_file: str = namespace.input_file self.output_file: Optional[str] = namespace.output_file self.strict: bool = namespace.strict + self.type: str = namespace.type @staticmethod def register_args_subparser( @@ -35,6 +36,9 @@ class ConvertCommand(Command): dest="strict", ) convert.add_argument( + "--type", help="The type of Lua script to generate", choices=["worker", "policy-loader"], default="worker" + ) + convert.add_argument( "input_file", type=str, help="File with configuration in YAML or JSON format.", @@ -61,7 +65,14 @@ class ConvertCommand(Command): try: parsed = try_to_parse(data) set_global_validation_context(Context(Path(Path(self.input_file).parent), self.strict)) - lua = KresConfig(parsed).render_lua() + + if self.type == "worker": + lua = KresConfig(parsed).render_lua() + elif self.type == "policy-loader": + lua = KresConfig(parsed).render_lua_policy() + else: + raise ValueError(f"Invalid self.type={self.type}") + reset_global_validation_context() except (DataParsingError, DataValidationError) as e: print(e, file=sys.stderr) diff --git a/manager/knot_resolver_manager/config_store.py b/manager/knot_resolver_manager/config_store.py index 03519602..e5fbaf60 100644 --- a/manager/knot_resolver_manager/config_store.py +++ b/manager/knot_resolver_manager/config_store.py @@ -6,6 +6,7 @@ from knot_resolver_manager.datamodel import KresConfig from knot_resolver_manager.exceptions import KresManagerException from knot_resolver_manager.utils.functional import Result from knot_resolver_manager.utils.modeling.exceptions import DataParsingError +from knot_resolver_manager.utils.modeling.types import NoneType VerifyCallback = Callable[[KresConfig, KresConfig], Awaitable[Result[None, str]]] UpdateCallback = Callable[[KresConfig], Awaitable[None]] @@ -26,9 +27,7 @@ class ConfigStore: err_res = filter(lambda r: r.is_err(), results) errs = list(map(lambda r: r.unwrap_err(), err_res)) if len(errs) > 0: - raise KresManagerException( - "Validation of the new config failed. The reasons are:\n - " + "\n - ".join(errs) - ) + raise KresManagerException("Configuration validation failed. The reasons are:\n - " + "\n - ".join(errs)) async with self._update_lock: # update the stored config with the new version @@ -38,6 +37,9 @@ class ConfigStore: for call in self._callbacks: await call(config) + async def renew(self) -> None: + await self.update(self._config) + async def register_verifier(self, verifier: VerifyCallback) -> None: self._verifiers.append(verifier) res = await verifier(self.get(), self.get()) @@ -56,12 +58,12 @@ class ConfigStore: return self._config -def only_on_real_changes(selector: Callable[[KresConfig], Any]) -> Callable[[UpdateCallback], UpdateCallback]: +def only_on_real_changes_update(selector: Callable[[KresConfig], Any]) -> Callable[[UpdateCallback], UpdateCallback]: def decorator(orig_func: UpdateCallback) -> UpdateCallback: original_value_set: Any = False original_value: Any = None - async def new_func(config: KresConfig) -> None: + async def new_func_update(config: KresConfig) -> None: nonlocal original_value_set nonlocal original_value if not original_value_set: @@ -72,6 +74,28 @@ def only_on_real_changes(selector: Callable[[KresConfig], Any]) -> Callable[[Upd original_value = selector(config) await orig_func(config) - return new_func + return new_func_update + + return decorator + + +def only_on_real_changes_verifier(selector: Callable[[KresConfig], Any]) -> Callable[[VerifyCallback], VerifyCallback]: + def decorator(orig_func: VerifyCallback) -> VerifyCallback: + original_value_set: Any = False + original_value: Any = None + + async def new_func_verifier(old: KresConfig, new: KresConfig) -> Result[NoneType, str]: + nonlocal original_value_set + nonlocal original_value + if not original_value_set: + original_value_set = True + original_value = selector(new) + await orig_func(old, new) + elif original_value != selector(new): + original_value = selector(new) + await orig_func(old, new) + return Result.ok(None) + + return new_func_verifier return decorator diff --git a/manager/knot_resolver_manager/constants.py b/manager/knot_resolver_manager/constants.py index 2d9ebd23..90ceed9f 100644 --- a/manager/knot_resolver_manager/constants.py +++ b/manager/knot_resolver_manager/constants.py @@ -39,6 +39,10 @@ def kresd_cache_dir(config: "KresConfig") -> Path: return config.cache.storage.to_path() +def policy_loader_config_file(_config: "KresConfig") -> Path: + return Path("policy-loader.conf") + + def kresd_config_file(_config: "KresConfig", kres_id: "KresID") -> Path: return Path(f"kresd{int(kres_id)}.conf") diff --git a/manager/knot_resolver_manager/datamodel/config_schema.py b/manager/knot_resolver_manager/datamodel/config_schema.py index 9da7007e..d80f664a 100644 --- a/manager/knot_resolver_manager/datamodel/config_schema.py +++ b/manager/knot_resolver_manager/datamodel/config_schema.py @@ -1,7 +1,7 @@ import logging import os import socket -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Literal @@ -10,20 +10,21 @@ from knot_resolver_manager.datamodel.cache_schema import CacheSchema from knot_resolver_manager.datamodel.dns64_schema import Dns64Schema from knot_resolver_manager.datamodel.dnssec_schema import DnssecSchema from knot_resolver_manager.datamodel.forward_schema import ForwardSchema -from knot_resolver_manager.datamodel.local_data_schema import LocalDataSchema +from knot_resolver_manager.datamodel.local_data_schema import LocalDataSchema, RPZSchema, RuleSchema from knot_resolver_manager.datamodel.logging_schema import LoggingSchema from knot_resolver_manager.datamodel.lua_schema import LuaSchema from knot_resolver_manager.datamodel.management_schema import ManagementSchema from knot_resolver_manager.datamodel.monitoring_schema import MonitoringSchema from knot_resolver_manager.datamodel.network_schema import NetworkSchema from knot_resolver_manager.datamodel.options_schema import OptionsSchema -from knot_resolver_manager.datamodel.templates import MAIN_TEMPLATE +from knot_resolver_manager.datamodel.templates import POLICY_CONFIG_TEMPLATE, WORKER_CONFIG_TEMPLATE from knot_resolver_manager.datamodel.types import Dir, EscapedStr, IntPositive from knot_resolver_manager.datamodel.view_schema import ViewSchema from knot_resolver_manager.datamodel.webmgmt_schema import WebmgmtSchema from knot_resolver_manager.datamodel.rate_limiting_schema import RateLimitingSchema from knot_resolver_manager.utils.modeling import ConfigSchema from knot_resolver_manager.utils.modeling.base_schema import lazy_default +from knot_resolver_manager.utils.modeling.exceptions import AggregateDataValidationError, DataValidationError _DEFAULT_RUNDIR = "/var/run/knot-resolver" @@ -50,6 +51,40 @@ def _default_max_worker_count() -> int: return MAX_WORKERS +def _get_views_tags(views: List[ViewSchema]) -> List[str]: + tags = [] + for view in views: + if view.tags: + tags += [str(tag) for tag in view.tags if tag not in tags] + return tags + + +def _check_local_data_tags( + views_tags: List[str], rules_or_rpz: Union[List[RuleSchema], List[RPZSchema]] +) -> Tuple[List[str], List[DataValidationError]]: + tags = [] + errs = [] + + i = 0 + for rule in rules_or_rpz: + tags_not_in = [] + if rule.tags: + for tag in rule.tags: + tag_str = str(tag) + if tag_str not in tags: + tags.append(tag_str) + if tag_str not in views_tags: + tags_not_in.append(tag_str) + if len(tags_not_in) > 0: + errs.append( + DataValidationError( + f"some tags {tags_not_in} not found in '/views' tags", f"/local-data/rules[{i}]/tags" + ) + ) + i += 1 + return tags, errs + + class KresConfig(ConfigSchema): class Raw(ConfigSchema): """ @@ -159,11 +194,45 @@ class KresConfig(ConfigSchema): "refusing to run with more then 10 workers per cpu core, the system wouldn't behave nicely" ) + # get all tags from views + views_tags = [] + if self.views: + views_tags = _get_views_tags(self.views) + + # get local-data tags and check its existence in views + errs = [] + local_data_tags = [] + if self.local_data.rules: + rules_tags, rules_errs = _check_local_data_tags(views_tags, self.local_data.rules) + errs += rules_errs + local_data_tags += rules_tags + if self.local_data.rpz: + rpz_tags, rpz_errs = _check_local_data_tags(views_tags, self.local_data.rpz) + errs += rpz_errs + local_data_tags += rpz_tags + + # look for unused tags in /views + unused_tags = views_tags.copy() + for tag in local_data_tags: + if tag in unused_tags: + unused_tags.remove(tag) + if len(unused_tags) > 1: + errs.append(DataValidationError(f"unused tags {unused_tags} found", "/views")) + + # raise all validation errors + if len(errs) == 1: + raise errs[0] + elif len(errs) > 1: + raise AggregateDataValidationError("/", errs) + def render_lua(self) -> str: # FIXME the `cwd` argument is used only for configuring control socket path # it should be removed and relative path used instead as soon as issue # https://gitlab.nic.cz/knot/knot-resolver/-/issues/720 is fixed - return MAIN_TEMPLATE.render(cfg=self, cwd=os.getcwd()) + return WORKER_CONFIG_TEMPLATE.render(cfg=self, cwd=os.getcwd()) + + def render_lua_policy(self) -> str: + return POLICY_CONFIG_TEMPLATE.render(cfg=self, cwd=os.getcwd()) def get_rundir_without_validation(data: Dict[str, Any]) -> Dir: diff --git a/manager/knot_resolver_manager/datamodel/templates/__init__.py b/manager/knot_resolver_manager/datamodel/templates/__init__.py index 1846797b..832503b7 100644 --- a/manager/knot_resolver_manager/datamodel/templates/__init__.py +++ b/manager/knot_resolver_manager/datamodel/templates/__init__.py @@ -17,8 +17,15 @@ def _get_templates_dir() -> str: _TEMPLATES_DIR = _get_templates_dir() -def _import_main_template() -> Template: - path = os.path.join(_TEMPLATES_DIR, "config.lua.j2") +def _import_kresd_worker_config_template() -> Template: + path = os.path.join(_TEMPLATES_DIR, "worker-config.lua.j2") + with open(path, "r", encoding="UTF-8") as file: + template = file.read() + return template_from_str(template) + + +def _import_kresd_policy_config_template() -> Template: + path = os.path.join(_TEMPLATES_DIR, "policy-config.lua.j2") with open(path, "r", encoding="UTF-8") as file: template = file.read() return template_from_str(template) @@ -30,4 +37,7 @@ def template_from_str(template: str) -> Template: return env.from_string(template) -MAIN_TEMPLATE = _import_main_template() +WORKER_CONFIG_TEMPLATE = _import_kresd_worker_config_template() + + +POLICY_CONFIG_TEMPLATE = _import_kresd_policy_config_template() diff --git a/manager/knot_resolver_manager/datamodel/templates/policy-config.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/policy-config.lua.j2 new file mode 100644 index 00000000..4c5c9048 --- /dev/null +++ b/manager/knot_resolver_manager/datamodel/templates/policy-config.lua.j2 @@ -0,0 +1,40 @@ +{% if not cfg.lua.script_only %} + +-- FFI library +ffi = require('ffi') +local C = ffi.C + +-- logging.level +log_level('{{ cfg.logging.level }}') + +{% if cfg.logging.target -%} +-- logging.target +log_target('{{ cfg.logging.target }}') +{%- endif %} + +{% if cfg.logging.groups %} +-- logging.groups +log_groups({ +{% for g in cfg.logging.groups %} +{% if g != "manager" and g != "supervisord" and g != "cache-gc" %} + '{{ g }}', +{% endif %} +{% endfor %} +}) +{% endif %} + +-- Config required for the cache opening +cache.open({{ cfg.cache.size_max.bytes() }}, 'lmdb://{{ cfg.cache.storage }}') + +-- VIEWS section ------------------------------------ +{% include "views.lua.j2" %} + +-- LOCAL-DATA section ------------------------------- +{% include "local_data.lua.j2" %} + +-- FORWARD section ---------------------------------- +{% include "forward.lua.j2" %} + +{% endif %} + +quit() diff --git a/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/worker-config.lua.j2 index fc823936..c97f0820 100644 --- a/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 +++ b/manager/knot_resolver_manager/datamodel/templates/worker-config.lua.j2 @@ -4,6 +4,9 @@ ffi = require('ffi') local C = ffi.C +-- Do not clear the DB with rules; we had it prepared by a different process. +assert(C.kr_rules_init(nil, 0, false) == 0) + -- hostname hostname('{{ cfg.hostname }}') @@ -28,15 +31,9 @@ nsid.name('{{ cfg.nsid }}' .. worker.id) -- NETWORK section ---------------------------------- {% include "network.lua.j2" %} --- VIEWS section ------------------------------------ -{% include "views.lua.j2" %} - -- DNSSEC section ----------------------------------- {% include "dnssec.lua.j2" %} --- LOCAL-DATA section ------------------------------- -{% include "local_data.lua.j2" %} - -- FORWARD section ---------------------------------- {% include "forward.lua.j2" %} diff --git a/manager/knot_resolver_manager/datamodel/types/types.py b/manager/knot_resolver_manager/datamodel/types/types.py index 7c2d4dcb..fa0d2793 100644 --- a/manager/knot_resolver_manager/datamodel/types/types.py +++ b/manager/knot_resolver_manager/datamodel/types/types.py @@ -454,6 +454,9 @@ class IPNetwork(BaseValueType): def __repr__(self) -> str: return f'{type(self).__name__}("{self._value}")' + def __eq__(self, o: object) -> bool: + return isinstance(o, IPNetwork) and o._value == self._value + def to_std(self) -> Union[ipaddress.IPv4Network, ipaddress.IPv6Network]: return self._value diff --git a/manager/knot_resolver_manager/kres_manager.py b/manager/knot_resolver_manager/kres_manager.py index 8cfd73c8..dbe56817 100644 --- a/manager/knot_resolver_manager/kres_manager.py +++ b/manager/knot_resolver_manager/kres_manager.py @@ -3,11 +3,12 @@ import logging import sys import time import os +from secrets import token_hex from subprocess import SubprocessError -from typing import Callable, List, Optional +from typing import Any, Callable, List, Optional from knot_resolver_manager.compat.asyncio import create_task -from knot_resolver_manager.config_store import ConfigStore +from knot_resolver_manager.config_store import ConfigStore, only_on_real_changes_update, only_on_real_changes_verifier from knot_resolver_manager.constants import ( FIX_COUNTER_DECREASE_INTERVAL_SEC, MANAGER_FIX_ATTEMPT_MAX_COUNTER, @@ -20,6 +21,10 @@ from knot_resolver_manager.kresd_controller.interface import ( SubprocessStatus, SubprocessType, ) +from knot_resolver_manager.kresd_controller.registered_workers import ( + command_registered_workers, + get_registered_workers_kresids, +) from knot_resolver_manager.utils.functional import Result from knot_resolver_manager.utils.modeling.types import NoneType @@ -55,7 +60,9 @@ class _FixCounter: async def _deny_max_worker_changes(config_old: KresConfig, config_new: KresConfig) -> Result[None, str]: if config_old.max_workers != config_new.max_workers: - return Result.err("Changing manager's `rundir` during runtime is not allowed.") + return Result.err( + "Changing 'max-workers', the maximum number of workers allowed to run, is not allowed at runtime." + ) return Result.ok(None) @@ -78,7 +85,9 @@ class KresManager: # pylint: disable=too-many-instance-attributes self._workers: List[Subprocess] = [] self._gc: Optional[Subprocess] = None + self._policy_loader: Optional[Subprocess] = None self._manager_lock = asyncio.Lock() + self._workers_reset_needed: bool = False self._controller: SubprocessController self._watchdog_task: Optional["asyncio.Task[None]"] = None self._fix_counter: _FixCounter = _FixCounter() @@ -110,9 +119,41 @@ class KresManager: # pylint: disable=too-many-instance-attributes logger.debug("Looking for already running workers") await self._collect_already_running_workers() - # registering the function calls them immediately, therefore after this, the config is applied - await config_store.register_verifier(self.validate_config) - await config_store.register_on_change_callback(self.apply_config) + # register and immediately call a verifier that loads policy rules into the rules database + await config_store.register_verifier(self.load_policy_rules) + + # configuration nodes that are relevant to kresd workers and the cache garbage collector + def config_nodes(config: KresConfig) -> List[Any]: + return [ + config.nsid, + config.hostname, + config.workers, + config.max_workers, + config.webmgmt, + config.options, + config.network, + config.forward, + config.cache, + config.dnssec, + config.dns64, + config.logging, + config.monitoring, + config.lua, + ] + + # register and immediately call a verifier that validates config with 'canary' kresd process + await config_store.register_verifier(only_on_real_changes_verifier(config_nodes)(self.validate_config)) + + # register and immediately call a callback to apply config to all 'kresd' workers and 'cache-gc' + await config_store.register_on_change_callback(only_on_real_changes_update(config_nodes)(self.apply_config)) + + # register callback to reset policy rules for each 'kresd' worker + await config_store.register_on_change_callback(self.reset_workers_policy_rules) + + # register and immediately call a callback to set new TLS session ticket secret for 'kresd' workers + await config_store.register_on_change_callback( + only_on_real_changes_update(config_nodes)(self.set_new_tls_sticket_secret) + ) # register controller config change listeners await config_store.register_verifier(_deny_max_worker_changes) @@ -136,6 +177,9 @@ class KresManager: # pylint: disable=too-many-instance-attributes elif subp.type == SubprocessType.GC: assert self._gc is None self._gc = subp + elif subp.type == SubprocessType.POLICY_LOADER: + assert self._policy_loader is None + self._policy_loader = subp else: raise RuntimeError("unexpected subprocess type") @@ -152,6 +196,19 @@ class KresManager: # pylint: disable=too-many-instance-attributes while len(self._workers) < n: await self._spawn_new_worker(config) + async def _run_policy_loader(self, config: KresConfig) -> None: + if self._policy_loader: + await self._policy_loader.start(config) + else: + subprocess = await self._controller.create_subprocess(config, SubprocessType.POLICY_LOADER) + await subprocess.start() + self._policy_loader = subprocess + + def _is_policy_loader_exited(self) -> bool: + if self._policy_loader: + return self._policy_loader.status() is SubprocessStatus.EXITED + return False + def _is_gc_running(self) -> bool: return self._gc is not None @@ -190,9 +247,40 @@ class KresManager: # pylint: disable=too-many-instance-attributes async def _reload_system_state(self) -> None: async with self._manager_lock: self._workers = [] + self._policy_loader = None self._gc = None await self._collect_already_running_workers() + async def reset_workers_policy_rules(self, _config: KresConfig) -> None: + + # command all running 'kresd' workers to reset their old policy rules, + # unless the workers have already been started with a new config so reset is not needed + if self._workers_reset_needed and get_registered_workers_kresids(): + logger.debug("Resetting policy rules for all running 'kresd' workers") + cmd_results = await command_registered_workers("require('ffi').C.kr_rules_reset()") + for worker, res in cmd_results.items(): + if res != 0: + logger.error("Failed to reset policy rules in %s: %s", worker, res) + else: + logger.debug( + "Skipped resetting policy rules for all running 'kresd' workers:" + " the workers are already running with new configuration" + ) + + async def set_new_tls_sticket_secret(self, config: KresConfig) -> None: + + if config.network.tls.sticket_secret or config.network.tls.sticket_secret_file: + logger.debug("User-configured TLS resumption secret found - skipping auto-generation.") + return + + logger.debug("Creating TLS session ticket secret") + secret = token_hex(32) + logger.debug("Setting TLS session ticket secret for all running 'kresd' workers") + cmd_results = await command_registered_workers(f"net.tls_sticket_secret('{secret}')") + for worker, res in cmd_results.items(): + if res not in (0, True): + logger.error("Failed to set TLS session ticket secret in %s: %s", worker, res) + async def apply_config(self, config: KresConfig, _noretry: bool = False) -> None: try: async with self._manager_lock: @@ -221,6 +309,27 @@ class KresManager: # pylint: disable=too-many-instance-attributes await self._reload_system_state() await self.apply_config(config, _noretry=True) + self._workers_reset_needed = False + + async def load_policy_rules(self, _old: KresConfig, new: KresConfig) -> Result[NoneType, str]: + try: + async with self._manager_lock: + logger.debug("Running kresd 'policy-loader'") + await self._run_policy_loader(new) + + # wait for 'policy-loader' to finish + logger.debug("Waiting for 'policy-loader' to finish loading policy rules") + while not self._is_policy_loader_exited(): + await asyncio.sleep(1) + + except (SubprocessError, SubprocessControllerException) as e: + logger.error(f"Failed to load policy rules: {e}") + return Result.err("kresd 'policy-loader' process failed to start. Config might be invalid.") + + self._workers_reset_needed = True + logger.debug("Loading policy rules has been successfully completed") + return Result.ok(None) + async def stop(self): if self._watchdog_task is not None: self._watchdog_task.cancel() # cancel it @@ -245,7 +354,7 @@ class KresManager: # pylint: disable=too-many-instance-attributes async def _instability_handler(self) -> None: if self._fix_counter.is_too_high(): logger.error( - "Already attempted to many times to fix system state. Refusing to try again and shutting down." + "Already attempted too many times to fix system state. Refusing to try again and shutting down." ) await self.forced_shutdown() return @@ -255,13 +364,13 @@ class KresManager: # pylint: disable=too-many-instance-attributes self._fix_counter.increase() await self._reload_system_state() logger.warning("Workers reloaded. Applying old config....") - await self.apply_config(self._config_store.get(), _noretry=True) + await self._config_store.renew() logger.warning(f"System stability hopefully renewed. Fix attempt counter is currently {self._fix_counter}") except BaseException: logger.error("Failed attempting to fix an error. Forcefully shutting down.", exc_info=True) await self.forced_shutdown() - async def _watchdog(self) -> None: + async def _watchdog(self) -> None: # pylint: disable=too-many-branches while True: await asyncio.sleep(WATCHDOG_INTERVAL) @@ -274,26 +383,36 @@ class KresManager: # pylint: disable=too-many-instance-attributes expected_ids = [x.id for x in self._workers] if self._gc: expected_ids.append(self._gc.id) + invoke_callback = False + if self._policy_loader: + expected_ids.append(self._policy_loader.id) + for eid in expected_ids: if eid not in detected_subprocesses: logger.error("Subprocess with id '%s' was not found in the system!", eid) invoke_callback = True continue - if detected_subprocesses[eid] is SubprocessStatus.FAILED: - logger.error("Subprocess '%s' is failed.", eid) + if detected_subprocesses[eid] is SubprocessStatus.FATAL: + if self._policy_loader and self._policy_loader.id == eid: + logger.info( + "Subprocess '%s' is skipped by WatchDog because its status is monitored in a different way.", + eid, + ) + continue + logger.error("Subprocess '%s' is in FATAL state!", eid) invoke_callback = True continue if detected_subprocesses[eid] is SubprocessStatus.UNKNOWN: - logger.warning("Subprocess '%s' is in unknown state!", eid) + logger.warning("Subprocess '%s' is in UNKNOWN state!", eid) non_registered_ids = detected_subprocesses.keys() - set(expected_ids) if len(non_registered_ids) != 0: logger.error( - "Found additional kresd instances in the system, which shouldn't be there - %s", + "Found additional process in the system, which shouldn't be there - %s", non_registered_ids, ) invoke_callback = True diff --git a/manager/knot_resolver_manager/kresd_controller/interface.py b/manager/knot_resolver_manager/kresd_controller/interface.py index 1dc99505..63caea49 100644 --- a/manager/knot_resolver_manager/kresd_controller/interface.py +++ b/manager/knot_resolver_manager/kresd_controller/interface.py @@ -6,10 +6,11 @@ import struct import sys from abc import ABC, abstractmethod # pylint: disable=no-name-in-module from enum import Enum, auto +from pathlib import Path from typing import Dict, Iterable, Optional, Type, TypeVar from weakref import WeakValueDictionary -from knot_resolver_manager.constants import kresd_config_file +from knot_resolver_manager.constants import kresd_config_file, policy_loader_config_file from knot_resolver_manager.datamodel.config_schema import KresConfig from knot_resolver_manager.exceptions import SubprocessControllerException from knot_resolver_manager.kresd_controller.registered_workers import register_worker, unregister_worker @@ -20,9 +21,17 @@ logger = logging.getLogger(__name__) class SubprocessType(Enum): KRESD = auto() + POLICY_LOADER = auto() GC = auto() +class SubprocessStatus(Enum): + RUNNING = auto() + FATAL = auto() + EXITED = auto() + UNKNOWN = auto() + + T = TypeVar("T", bound="KresID") @@ -104,25 +113,46 @@ class Subprocess(ABC): self._config = config self._registered_worker: bool = False - async def start(self) -> None: - # create config file - lua_config = self._config.render_lua() - await writefile(kresd_config_file(self._config, self.id), lua_config) + async def start(self, new_config: Optional[KresConfig] = None) -> None: + if new_config: + self._config = new_config + + config_file: Optional[Path] = None + if self.type is SubprocessType.KRESD: + config_lua = self._config.render_lua() + config_file = kresd_config_file(self._config, self.id) + await writefile(config_file, config_lua) + elif self.type is SubprocessType.POLICY_LOADER: + config_lua = self._config.render_lua_policy() + config_file = policy_loader_config_file(self._config) + await writefile(config_file, config_lua) + try: await self._start() if self.type is SubprocessType.KRESD: register_worker(self) self._registered_worker = True except SubprocessControllerException as e: - kresd_config_file(self._config, self.id).unlink() + if config_file: + config_file.unlink() raise e async def apply_new_config(self, new_config: KresConfig) -> None: self._config = new_config + # update config file logger.debug(f"Writing config file for {self.id}") - lua_config = new_config.render_lua() - await writefile(kresd_config_file(new_config, self.id), lua_config) + + config_file: Optional[Path] = None + if self.type is SubprocessType.KRESD: + config_lua = self._config.render_lua() + config_file = kresd_config_file(self._config, self.id) + await writefile(config_file, config_lua) + elif self.type is SubprocessType.POLICY_LOADER: + config_lua = self._config.render_lua_policy() + config_file = policy_loader_config_file(self._config) + await writefile(config_file, config_lua) + # update runtime status logger.debug(f"Restarting {self.id}") await self._restart() @@ -138,7 +168,13 @@ class Subprocess(ABC): Remove temporary files and all traces of this instance running. It is NOT SAFE to call this while the kresd is running, because it will break automatic restarts (at the very least). """ - kresd_config_file(self._config, self.id).unlink() + + if self.type is SubprocessType.KRESD: + config_file = kresd_config_file(self._config, self.id) + config_file.unlink() + elif self.type is SubprocessType.POLICY_LOADER: + config_file = policy_loader_config_file(self._config) + config_file.unlink() def __eq__(self, o: object) -> bool: return isinstance(o, type(self)) and o.type == self.type and o.id == self.id @@ -158,6 +194,10 @@ class Subprocess(ABC): async def _restart(self) -> None: pass + @abstractmethod + def status(self) -> SubprocessStatus: + pass + @property def type(self) -> SubprocessType: return self.id.subprocess_type @@ -167,8 +207,12 @@ class Subprocess(ABC): return self._id async def command(self, cmd: str) -> object: + if not self._registered_worker: + raise RuntimeError("the command cannot be sent to a process other than the kresd worker") + reader: asyncio.StreamReader writer: Optional[asyncio.StreamWriter] = None + try: reader, writer = await asyncio.open_unix_connection(f"./control/{int(self.id)}") @@ -197,12 +241,6 @@ class Subprocess(ABC): await writer.wait_closed() # type: ignore -class SubprocessStatus(Enum): - RUNNING = auto() - FAILED = auto() - UNKNOWN = auto() - - class SubprocessController(ABC): """ The common Subprocess Controller interface. This is what KresManager requires and what has to be implemented by all diff --git a/manager/knot_resolver_manager/kresd_controller/supervisord/__init__.py b/manager/knot_resolver_manager/kresd_controller/supervisord/__init__.py index f9d3171f..5fb4d81d 100644 --- a/manager/knot_resolver_manager/kresd_controller/supervisord/__init__.py +++ b/manager/knot_resolver_manager/kresd_controller/supervisord/__init__.py @@ -139,35 +139,39 @@ def _create_fast_proxy(config: KresConfig) -> Any: return getattr(proxy, "fast") +def _convert_subprocess_status(proc: Any) -> SubprocessStatus: + conversion_tbl = { + # "STOPPED": None, # filtered out elsewhere + "STARTING": SubprocessStatus.RUNNING, + "RUNNING": SubprocessStatus.RUNNING, + "BACKOFF": SubprocessStatus.RUNNING, + "STOPPING": SubprocessStatus.RUNNING, + "EXITED": SubprocessStatus.EXITED, + "FATAL": SubprocessStatus.FATAL, + "UNKNOWN": SubprocessStatus.UNKNOWN, + } + + if proc["statename"] in conversion_tbl: + status = conversion_tbl[proc["statename"]] + else: + logger.warning(f"Unknown supervisord process state {proc['statename']}") + status = SubprocessStatus.UNKNOWN + return status + + def _list_running_subprocesses(config: KresConfig) -> Dict[SupervisordKresID, SubprocessStatus]: - supervisord = _create_supervisord_proxy(config) - processes: Any = supervisord.getAllProcessInfo() - - def convert(proc: Any) -> SubprocessStatus: - conversion_tbl = { - # "STOPPED": None, # filtered out elsewhere - "STARTING": SubprocessStatus.RUNNING, - "RUNNING": SubprocessStatus.RUNNING, - "BACKOFF": SubprocessStatus.RUNNING, - "STOPPING": SubprocessStatus.RUNNING, - "EXITED": SubprocessStatus.FAILED, - "FATAL": SubprocessStatus.FAILED, - "UNKNOWN": SubprocessStatus.UNKNOWN, - } - - if proc["statename"] in conversion_tbl: - status = conversion_tbl[proc["statename"]] - else: - logger.warning(f"Unknown supervisord process state {proc['statename']}") - status = SubprocessStatus.UNKNOWN - return status + try: + supervisord = _create_supervisord_proxy(config) + processes: Any = supervisord.getAllProcessInfo() + except Fault as e: + raise SubprocessControllerException(f"failed to get info from all running processes: {e}") from e # there will be a manager process as well, but we don't want to report anything on ourselves processes = [pr for pr in processes if pr["name"] != "manager"] # convert all the names return { - SupervisordKresID.from_string(f"{pr['group']}:{pr['name']}"): convert(pr) + SupervisordKresID.from_string(f"{pr['group']}:{pr['name']}"): _convert_subprocess_status(pr) for pr in processes if pr["statename"] != "STOPPED" } @@ -190,6 +194,14 @@ class SupervisordSubprocess(Subprocess): def name(self): return str(self.id) + def status(self) -> SubprocessStatus: + try: + supervisord = _create_supervisord_proxy(self._config) + status = supervisord.getProcessInfo(self.name) + except Fault as e: + raise SubprocessControllerException(f"failed to get status from '{self.id}' process: {e}") from e + return _convert_subprocess_status(status) + @async_in_a_thread def _start(self) -> None: # +1 for canary process (same as in config_file.py) diff --git a/manager/knot_resolver_manager/kresd_controller/supervisord/config_file.py b/manager/knot_resolver_manager/kresd_controller/supervisord/config_file.py index fab0a143..15a81ba7 100644 --- a/manager/knot_resolver_manager/kresd_controller/supervisord/config_file.py +++ b/manager/knot_resolver_manager/kresd_controller/supervisord/config_file.py @@ -10,6 +10,7 @@ from knot_resolver_manager.constants import ( kresd_cache_dir, kresd_config_file_supervisord_pattern, kresd_executable, + policy_loader_config_file, supervisord_config_file, supervisord_config_file_tmp, supervisord_pid_file, @@ -32,9 +33,11 @@ class SupervisordKresID(KresID): @staticmethod def from_string(val: str) -> "SupervisordKresID": + # the double name is checked because thats how we read it from supervisord if val in ("cache-gc", "cache-gc:cache-gc"): - # the double name is checked because thats how we read it from supervisord return SupervisordKresID.new(SubprocessType.GC, 0) + elif val in ("policy-loader", "policy-loader:policy-loader"): + return SupervisordKresID.new(SubprocessType.POLICY_LOADER, 0) else: val = val.replace("kresd:kresd", "") return SupervisordKresID.new(SubprocessType.KRESD, int(val)) @@ -42,6 +45,8 @@ class SupervisordKresID(KresID): def __str__(self) -> str: if self.subprocess_type is SubprocessType.GC: return "cache-gc" + elif self.subprocess_type is SubprocessType.POLICY_LOADER: + return "policy-loader" elif self.subprocess_type is SubprocessType.KRESD: return f"kresd:kresd{self._id}" else: @@ -95,6 +100,16 @@ class ProcessTypeConfig: ) @staticmethod + def create_policy_loader_config(config: KresConfig) -> "ProcessTypeConfig": + cwd = str(os.getcwd()) + return ProcessTypeConfig( # type: ignore[call-arg] + logfile=supervisord_subprocess_log_dir(config) / "policy-loader.log", + workdir=cwd, + command=f"{kresd_executable()} -c {(policy_loader_config_file(config))} -c - -n", + environment="X-SUPERVISORD-TYPE=notify", + ) + + @staticmethod def create_kresd_config(config: KresConfig) -> "ProcessTypeConfig": cwd = str(os.getcwd()) return ProcessTypeConfig( # type: ignore[call-arg] @@ -172,11 +187,11 @@ async def write_config_file(config: KresConfig) -> None: template = template.decode("utf8") config_string = Template(template).render( gc=ProcessTypeConfig.create_gc_config(config), + loader=ProcessTypeConfig.create_policy_loader_config(config), kresd=ProcessTypeConfig.create_kresd_config(config), manager=ProcessTypeConfig.create_manager_config(config), config=SupervisordConfig.create(config), ) - print(config_string) await writefile(supervisord_config_file_tmp(config), config_string) # atomically replace (we don't technically need this right now, but better safe then sorry) os.rename(supervisord_config_file_tmp(config), supervisord_config_file(config)) diff --git a/manager/knot_resolver_manager/kresd_controller/supervisord/plugin/sd_notify.py b/manager/knot_resolver_manager/kresd_controller/supervisord/plugin/sd_notify.py index 53711c86..cffe6fd3 100644 --- a/manager/knot_resolver_manager/kresd_controller/supervisord/plugin/sd_notify.py +++ b/manager/knot_resolver_manager/kresd_controller/supervisord/plugin/sd_notify.py @@ -49,25 +49,37 @@ class NotifySocketDispatcher: return None # there was some junk pid, data = res + # pylint: disable=undefined-loop-variable + for proc in starting_processes: + if proc.pid == pid: + break + else: + logger.warn(f"ignoring ready notification from unregistered PID={pid}") + return None + if data.startswith(b"READY=1"): # handle case, when some process is really ready - # pylint: disable=undefined-loop-variable - for proc in starting_processes: - if proc.pid == pid: - break - else: - logger.warn(f"ignoring ready notification from unregistered PID={pid}") - return None - if is_type_notify(proc): proc._assertInState(ProcessStates.STARTING) proc.change_state(ProcessStates.RUNNING) logger.info( - f"success: {proc.config.name} entered RUNNING state, process sent ready notification via $NOTIFY_SOCKET" + f"success: {proc.config.name} entered RUNNING state, process sent notification via $NOTIFY_SOCKET" ) else: - logger.warn(f"ignoring ready notification from {proc.config.name}, which is not configured to send it") + logger.warn(f"ignoring READY notification from {proc.config.name}, which is not configured to send it") + + elif data.startswith(b"STOPPING=1"): + # just accept the message, filter unwanted notifications and do nothing else + + if is_type_notify(proc): + logger.info( + f"success: {proc.config.name} entered STOPPING state, process sent notification via $NOTIFY_SOCKET" + ) + else: + logger.warn( + f"ignoring STOPPING notification from {proc.config.name}, which is not configured to send it" + ) else: # handle case, when we got something unexpected @@ -103,6 +115,7 @@ def keep_track_of_starting_processes(event: ProcessStateEvent) -> None: # process is starting # if proc not in starting_processes: starting_processes.append(proc) + else: # not starting starting_processes = [p for p in starting_processes if p.pid is not proc.pid] diff --git a/manager/knot_resolver_manager/kresd_controller/supervisord/supervisord.conf.j2 b/manager/knot_resolver_manager/kresd_controller/supervisord/supervisord.conf.j2 index dcbb645d..b1fed1aa 100644 --- a/manager/knot_resolver_manager/kresd_controller/supervisord/supervisord.conf.j2 +++ b/manager/knot_resolver_manager/kresd_controller/supervisord/supervisord.conf.j2 @@ -12,7 +12,6 @@ silent = true loglevel = {{ config.loglevel }} {# there are more options in the plugin section #} - [unix_http_server] file = {{ config.unix_http_server }} @@ -37,8 +36,6 @@ supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [rpcinterface:fast] supervisor.rpcinterface_factory = knot_resolver_manager.kresd_controller.supervisord.plugin.fast_rpcinterface:make_main_rpcinterface - - [program:manager] redirect_stderr=false directory={{ manager.workdir }} @@ -71,6 +68,17 @@ environment={{ kresd.environment }} stdout_logfile=NONE stderr_logfile=NONE +[program:policy-loader] +directory={{ loader.workdir }} +command={{ loader.command }} +autostart=false +stopsignal=TERM +killasgroup=true +startsecs=300 +environment={{ loader.environment }} +stdout_logfile=NONE +stderr_logfile=NONE + [program:cache-gc] redirect_stderr=false directory={{ gc.workdir }} @@ -82,4 +90,4 @@ killasgroup=true startsecs=0 environment={{ gc.environment }} stdout_logfile=NONE -stderr_logfile=NONE
\ No newline at end of file +stderr_logfile=NONE diff --git a/manager/knot_resolver_manager/log.py b/manager/knot_resolver_manager/log.py index 08da675b..19271c52 100644 --- a/manager/knot_resolver_manager/log.py +++ b/manager/knot_resolver_manager/log.py @@ -4,7 +4,7 @@ import os import sys from typing import Optional -from knot_resolver_manager.config_store import ConfigStore, only_on_real_changes +from knot_resolver_manager.config_store import ConfigStore, only_on_real_changes_update from knot_resolver_manager.constants import STARTUP_LOG_LEVEL from knot_resolver_manager.datamodel.config_schema import KresConfig from knot_resolver_manager.datamodel.logging_schema import LogTargetEnum @@ -88,7 +88,7 @@ async def _set_logging_handler(config: KresConfig) -> None: root.addHandler(handler) -@only_on_real_changes(lambda config: config.logging) +@only_on_real_changes_update(lambda config: config.logging) async def _configure_logger(config: KresConfig) -> None: await _set_logging_handler(config) await _set_log_level(config) diff --git a/manager/knot_resolver_manager/statistics.py b/manager/knot_resolver_manager/statistics.py index 0dcfdac0..4a0eb783 100644 --- a/manager/knot_resolver_manager/statistics.py +++ b/manager/knot_resolver_manager/statistics.py @@ -5,7 +5,7 @@ import logging from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Tuple from knot_resolver_manager import compat -from knot_resolver_manager.config_store import ConfigStore, only_on_real_changes +from knot_resolver_manager.config_store import ConfigStore, only_on_real_changes_update from knot_resolver_manager.datamodel.config_schema import KresConfig from knot_resolver_manager.kresd_controller.registered_workers import ( command_registered_workers, @@ -250,7 +250,7 @@ if _prometheus_support: _graphite_bridge: Optional[GraphiteBridge] = None - @only_on_real_changes(lambda c: c.monitoring.graphite) + @only_on_real_changes_update(lambda c: c.monitoring.graphite) async def _configure_graphite_bridge(config: KresConfig) -> None: """ Starts graphite bridge if required diff --git a/manager/knot_resolver_manager/utils/requests.py b/manager/knot_resolver_manager/utils/requests.py index 72a4d1fa..e52e54a3 100644 --- a/manager/knot_resolver_manager/utils/requests.py +++ b/manager/knot_resolver_manager/utils/requests.py @@ -115,7 +115,7 @@ class UnixHTTPConnection(HTTPConnection): def connect(self): sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.settimeout(1) # there is something weird stored in self.timeout + sock.settimeout(self.timeout) sock.connect(self.unix_socket_path) self.sock = sock diff --git a/manager/pyproject.toml b/manager/pyproject.toml index 1da53a48..7f1bde1f 100644 --- a/manager/pyproject.toml +++ b/manager/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "knot-resolver-manager" -version = "6.0.7" +version = "6.0.8" description = "A central tool for managing individual parts of Knot Resolver" authors = [ @@ -27,7 +27,7 @@ prometheus-client = { version = "*", optional = true } prometheus = ["prometheus-client"] [tool.poetry.group.dev.dependencies] -poetry = "^1.7.1" +poetry = "^1.8.3" pyparsing = "^3.1.1" poethepoet = "^0.24.4" debugpy = "^1.8.1" @@ -66,8 +66,6 @@ test = { shell = "env PYTHONPATH=. pytest --junitxml=unit.junit.xml --cov=knot_r check = { cmd = "scripts/codecheck", help = "Run static code analysis" } format = { shell = "black knot_resolver_manager/ tests/ scripts/ build_c_extensions.py; isort .", help = "Run code formatter" } fixdeps = { shell = "poetry install; npm install; npm update", help = "Install/update dependencies according to configuration files"} -commit = { shell = "scripts/commit", help = "Invoke every single check before commiting" } -container = { cmd = "scripts/container.py", help = "Manage containers" } examples = { cmd = "scripts/examples", help = "Validate all configuration examples" } kresctl = { script = "knot_resolver_manager.cli.main:main", cwd="${POE_PWD}", help="run kresctl" } kresctl-nocwd = { script = "knot_resolver_manager.cli.main:main", help="run kresctl" } # Python <3.8 and poethepoet <0.22.0 compatibility (see also `./poe`) @@ -79,8 +77,6 @@ clean = """ dist """ gen-setuppy = { shell = "python scripts/create_setup.py > setup.py", help = "Generate setup.py file for backwards compatibility" } -integration = {cmd = "python tests/integration/runner.py", help = "Run integration tests" } -configure-vscode = {cmd = "scripts/configure-vscode", help = "Create VSCode configuration for debugging, virtual envs etc" } man = {cmd = "scripts/man", help = "Display manpage from sources" } [tool.black] diff --git a/manager/scripts/commit b/manager/scripts/commit deleted file mode 100755 index 17973159..00000000 --- a/manager/scripts/commit +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# ensure consistent behaviour -src_dir="$(dirname "$(realpath "$0")")" -source $src_dir/_env.sh - - -# run code check -poe check - -# run unit tests -poe test - -# run integration tests -poe integration - -# invoke commit -git commit $@
\ No newline at end of file diff --git a/manager/scripts/configure-vscode b/manager/scripts/configure-vscode deleted file mode 100755 index 5032a6ba..00000000 --- a/manager/scripts/configure-vscode +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -# ensure consistent behaviour -src_dir="$(dirname "$(realpath "$0")")" -source $src_dir/_env.sh - - -echo -e "${yellow}This script will overwrite your existing VSCode configuration in the .vscode directory${reset}" -echo -e "${red}Should we proceed? [yN]${reset}" -read confirmation -if test "$confirmation" = "y" -o "$confirmation" = "Y"; then - echo -e "${green}OK, changing your VSCode configuration${reset}" -else - echo -e "${red}Aborting${reset}" - exit 1 -fi - - -mkdir -p .vscode - -# settings.json -cat > .vscode/settings.json <<EOF -{ - "python.defaultInterpreterPath": "$(poetry env info -p)", - "python.venvPath": "~/.cache/pypoetry/virtualenvs" -} -EOF - - -# launch.json -cat > .vscode/launch.json <<EOF -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Python: Remote Attach", - "type": "python", - "request": "attach", - "connect": { - "host": "localhost", - "port": 5678 - }, - "pathMappings": [ - { - "localRoot": "\${workspaceFolder}", - "remoteRoot": "." - } - ] - } - ] -} -EOF
\ No newline at end of file diff --git a/manager/scripts/container.py b/manager/scripts/container.py deleted file mode 100755 index 191fcae2..00000000 --- a/manager/scripts/container.py +++ /dev/null @@ -1,284 +0,0 @@ -#!/usr/bin/env python - -import atexit -import subprocess -import sys -import time -from os import environ -from pathlib import Path -from typing import Dict, List, NoReturn, Optional - -import click - - -def _get_git_root() -> Path: - result = subprocess.run("git rev-parse --show-toplevel", shell=True, stdout=subprocess.PIPE) - return Path(str(result.stdout, encoding="utf8").strip()) - - -GIT_ROOT: Path = _get_git_root() -PODMAN_EXECUTABLE = "/usr/bin/podman" -CACHE_DIR: Path = GIT_ROOT / ".podman-cache" - - -def _start_detached(image: str, publish: List[int] = [], ro_mounts: Dict[Path, Path] = {}) -> str: - """Start a detached container""" - options = [f"--publish={port}:{port}/tcp" for port in publish] + [ - f"--volume={str(src)}:{str(dst)}:O" for src, dst in ro_mounts.items() - ] - command = ["podman", "run", "--rm", "-d", "--security-opt=seccomp=unconfined", *options, image] - proc = subprocess.run(command, shell=False, executable=PODMAN_EXECUTABLE, stdout=subprocess.PIPE) - assert proc.returncode == 0 - return str(proc.stdout, "utf8").strip() - - -def _exec(container_id: str, cmd: List[str]) -> int: - command = ["podman", "exec", container_id] + cmd - return subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - - -def _exec_interactive(container_id: str, cmd: List[str]) -> int: - command = ["podman", "exec", "-ti", container_id] + cmd - return subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - - -def _stop(container_id: str): - command = ["podman", "stop", container_id] - ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - assert ret == 0 - - -def _list_available_image_tags() -> List[str]: - res: List[str] = [] - for c in (GIT_ROOT / "containers").iterdir(): - if c.is_dir(): - res.append(c.name) - res.sort() # make the order reproducible - return res - - -def _extract_tag_from_name(name: str, all: List[str] = _list_available_image_tags()) -> str: - if ":" in name: - s = name.split(":") - if not s[0].endswith("knot-manager"): - click.secho(f"Unexpected image name '{s[0]}', expected 'knot-manager'", fg="red") - sys.exit(1) - name = s[-1] - - if not name in all: - click.secho(f"Unexpected tag '{name}'", fg="red") - click.secho(f"Available tags are [{' '.join(all)}]", fg="yellow") - sys.exit(1) - - return name - - -def _get_tags_to_work_on(args: List[str]) -> List[str]: - args = list(args) - - all = _list_available_image_tags() - - # convert to tags, if the user specified full names - for i, a in enumerate(args): - args[i] = _extract_tag_from_name(a, all) - - if len(args) == 0: - args = all - - return args - - -def _full_name_from_tag(tag: str) -> str: - return f"registry.nic.cz/knot/knot-resolver-manager/knot-manager:{tag}" - - -def _build(tag: str): - command = [ - "podman", - "build", - "--security-opt=seccomp=unconfined", - "-f", - str(GIT_ROOT / "containers" / tag / "Containerfile"), - "-t", - _full_name_from_tag(tag), - str(GIT_ROOT), - ] - ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - assert ret == 0 - - -def _pull(tag: str): - command = ["podman", "pull", _full_name_from_tag(tag)] - ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - assert ret == 0 - - -def _push(tag: str): - command = ["podman", "push", _full_name_from_tag(tag)] - ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - assert ret == 0 - - -def _login_ci(): - command = [ - "podman", - "login", - "-u", - environ["CI_REGISTRY_USER"], - "-p", - environ["CI_REGISTRY_PASSWORD"], - environ["CI_REGISTRY"], - ] - ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - assert ret == 0 - - -def _save(tag: str): - CACHE_DIR.mkdir(exist_ok=True) - command = [ - "podman", - "save", - "--format", - "oci-archive", - "-o", - str(CACHE_DIR / (tag + ".tar")), - _full_name_from_tag(tag), - ] - ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - assert ret == 0 - - -def _load(tag: str): - cache_file = CACHE_DIR / (tag + ".tar") - if cache_file.exists(): - command = ["podman", "load", "-i", str(CACHE_DIR / (tag + ".tar"))] - ret = subprocess.call(command, shell=False, executable=PODMAN_EXECUTABLE) - assert ret == 0 - - -@click.group() -def main(): - pass - - -@main.command(help="Pull CI built images") -@click.argument("images", nargs=-1) -def pull(images: List[str]): - tags = _get_tags_to_work_on(images) - - for tag in tags: - click.secho(f"Pulling image with tag {tag}", fg="yellow") - _pull(tag) - - -@main.command(help="Build project containers") -@click.argument("images", nargs=-1) -@click.option("-f", "--fetch", "fetch", is_flag=True, default=False, type=bool, help="Pull before building") -@click.option("--ci-login", "ci_login", is_flag=True, default=False, type=bool, help="Login to registry in CI") -@click.option("-p", "--push", "push", is_flag=True, default=False, type=bool, help="Push images after building") -@click.option("--file-cache", is_flag=True, default=False, help="Try to utilise file cache") -def build(images: List[str], fetch: bool, ci_login: bool, push: bool, file_cache: bool): - tags = _get_tags_to_work_on(images) - - if ci_login: - _login_ci() - - for tag in tags: - if fetch: - click.secho(f"Pulling image with tag {tag}", fg="yellow") - _pull(tag) - - if file_cache: - _load(tag) - - click.secho(f"Building image with tag {tag}", fg="yellow") - _build(tag) - - if push: - click.secho(f"Pushing image with {tag}", fg="yellow") - _push(tag) - - if file_cache: - _save(tag) - - -@main.command(help="Run project containers") -@click.argument("image", nargs=1) -@click.argument("command", nargs=-1) -@click.option("-p", "--publish", "publish", multiple=True, type=int, help="Port which should be published") -@click.option( - "-m", - "--mount", - "mount", - multiple=True, - nargs=1, - type=str, - help="Read-only bind mounts into the container, value /path/on/host:/path/in/container", -) -@click.option( - "-c", - "--code", - "mount_code", - default=False, - is_flag=True, - type=bool, - help="Shortcut to mount gitroot into /code", -) -@click.option( - "-i", - "--interactive", - "interactive_inspection", - default=False, - is_flag=True, - type=bool, - help="Drop into interactive shell if the command fails", -) -def run( - image: str, - command: List[str], - publish: Optional[List[int]], - mount: Optional[List[str]], - mount_code: bool, - interactive_inspection: bool, -) -> NoReturn: - # make sure arguments have the correct type - tag = _extract_tag_from_name(image) - command = list(command) - publishI = [] if publish is None else [int(p) for p in publish] - mountI = [] if mount is None else [x.split(":") for x in mount] - mount_path = {Path(x[0]).absolute(): Path(x[1]).absolute() for x in mountI} - for src_path in mount_path: - if not src_path.exists(): - print( - f'The specified path "{str(src_path)}" does not exist on the host system', - file=sys.stderr, - ) - exit(1) - if mount_code: - mount_path[GIT_ROOT] = Path("/code") - - cont = _start_detached(_full_name_from_tag(tag), publish=publishI, ro_mounts=mount_path) - - # register cleanup function - def cleanup(): - _stop(cont) - - atexit.register(cleanup) - - # wait for the container to boot properly - time.sleep(0.5) - # run the command - exit_code = _exec_interactive(cont, command) - - if interactive_inspection and exit_code != 0: - print(f"The command {command} failed with exit code {exit_code}.") - print("Dropping into an interactive shell as requested. Stop the shell to stop the whole container.") - print("-----------------------------") - _exec_interactive(cont, ["/bin/bash"]) - - # the container should be stopped by the `atexit` module - sys.exit(exit_code) - - -if __name__ == "__main__": - main() diff --git a/manager/setup.py b/manager/setup.py index bbd244d7..e3abf0f1 100644 --- a/manager/setup.py +++ b/manager/setup.py @@ -30,7 +30,7 @@ entry_points = \ setup_kwargs = { 'name': 'knot-resolver-manager', - 'version': '6.0.7', + 'version': '6.0.8', 'description': 'A central tool for managing individual parts of Knot Resolver', 'long_description': 'None', 'author': 'Aleš Mrázek', diff --git a/manager/tests/integration/.gitignore b/manager/tests/integration/.gitignore deleted file mode 100644 index 3feccc83..00000000 --- a/manager/tests/integration/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -cache/ -run/
\ No newline at end of file diff --git a/manager/tests/integration/config.yml b/manager/tests/integration/config.yml deleted file mode 100644 index b05f18b3..00000000 --- a/manager/tests/integration/config.yml +++ /dev/null @@ -1,13 +0,0 @@ -network: - listen: - - interface: 127.0.0.1@5353 -server: - id: integration-test - workers: 1 - rundir: tests/integration/run - management: - interface: 127.0.0.1@5001 -cache: - storage: cache -logging: - level: debug
\ No newline at end of file diff --git a/manager/tests/integration/runner.py b/manager/tests/integration/runner.py deleted file mode 100644 index 000d7ae8..00000000 --- a/manager/tests/integration/runner.py +++ /dev/null @@ -1,96 +0,0 @@ -import logging -import sys -from pathlib import Path -from typing import Callable - -from knot_resolver_manager.client import KnotManagerClient, count_running_kresds, start_manager_in_background - -PORT = 5001 -HOST = "localhost" -BASE_URL = f"http://{HOST}:{PORT}" - - -Test = Callable[[KnotManagerClient], None] - - -logger = logging.getLogger(__name__) - - -def test_wrapper(test: Test) -> bool: - p = start_manager_in_background(Path("tests/integration/config.yaml")) - client = KnotManagerClient(BASE_URL) - client.wait_for_initialization() - - logger.info("Starting test %s", test.__name__) - try: - test(client) - res = True - except AssertionError: - logger.error("Test %s failed", exc_info=True) - res = False - - try: - client.stop() - p.join() - except Exception: - logger.warn("Failed to stop manager gracefully, terminating by force...") - p.terminate() - p.join() - - return res - - -def worker_count(client: KnotManagerClient): - client.set_num_workers(2) - cnt = count_running_kresds() - assert cnt == 2, f"Expected 2 kresd instances, found {cnt}" - - client.set_num_workers(1) - cnt = count_running_kresds() - assert cnt == 1, f"Expected 1 kresd instance, found {cnt}" - - -def crash_resistance(client: KnotManagerClient): - client.set_num_workers(2) - cnt = count_running_kresds() - assert cnt == 2, f"Expected 2 kresd instances, found {cnt}" - - # kill the server - # p.terminate() - # p.join() - - # no change in number of workers should be visible - cnt = count_running_kresds() - assert cnt == 2, f"Expected 2 kresd instances, found {cnt}" - - # start the server again - p = start_manager_in_background(Path("test/integration/config.yaml")) - try: - client.wait_for_initialization() - except TimeoutError as e: - p.terminate() - raise e - - # no change in number of workers should be visible - cnt = count_running_kresds() - assert cnt == 2, f"Expected 2 kresd instances, found {cnt}" - - # however the manager should now react to changes - client.set_num_workers(1) - cnt = count_running_kresds() - assert cnt == 1, f"Expected 1 kresd instance, found {cnt}" - - -if __name__ == "__main__": - logging.basicConfig(level=logging.DEBUG) - - # create run directories if it does not exist - Path("tests/integration/run").mkdir(exist_ok=True) - - # run the tests - success = True - success &= test_wrapper(worker_count) - # success &= test_wrapper(crash_resistance) - - # exit with proper exitcode - sys.exit(int(not success)) diff --git a/manager/tests/packaging/systemd_service.sh b/manager/tests/packaging/systemd_service.sh index 24f48071..c6ac826b 100755 --- a/manager/tests/packaging/systemd_service.sh +++ b/manager/tests/packaging/systemd_service.sh @@ -29,7 +29,7 @@ else set +e # check that the resolvers are actually running - kdig @127.0.0.1 nic.cz + kdig @127.0.0.1 +edns nic.cz | tee /dev/stderr | grep -qi 'status: NOERROR' if [ "$?" -ne "0" ]; then echo "Could not 'kdig' the resolvers - are they running?" exit 1 diff --git a/manager/tests/unit/test_config_store.py b/manager/tests/unit/test_config_store.py index 9b843bb9..f4fd8c03 100644 --- a/manager/tests/unit/test_config_store.py +++ b/manager/tests/unit/test_config_store.py @@ -1,6 +1,6 @@ import pytest -from knot_resolver_manager.config_store import ConfigStore, only_on_real_changes +from knot_resolver_manager.config_store import ConfigStore, only_on_real_changes_update from knot_resolver_manager.datamodel.config_schema import KresConfig @@ -8,7 +8,7 @@ from knot_resolver_manager.datamodel.config_schema import KresConfig async def test_only_once(): count = 0 - @only_on_real_changes(lambda config: config.logging.level) + @only_on_real_changes_update(lambda config: config.logging.level) async def change_callback(config: KresConfig) -> None: nonlocal count count += 1 diff --git a/meson.build b/meson.build index 2cdc445d..8b4bd83b 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,7 @@ project( 'knot-resolver', ['c', 'cpp'], license: 'GPLv3+', - version: '6.0.7', + version: '6.0.8', default_options: ['c_std=gnu11', 'b_ndebug=true'], meson_version: '>=0.49', ) @@ -18,7 +18,7 @@ endif message('--- required dependencies ---') -knot_version = '>=3.0.2' +knot_version = '>=3.3' libknot = dependency('libknot', version: knot_version) libdnssec = dependency('libdnssec', version: knot_version) libzscanner = dependency('libzscanner', version: knot_version) diff --git a/modules/workarounds/README.rst b/modules/workarounds/README.rst index fcb04aa3..f456c6c1 100644 --- a/modules/workarounds/README.rst +++ b/modules/workarounds/README.rst @@ -2,7 +2,7 @@ .. _mod-workarounds: -Module `workarounds` resolver behavior on specific broken sub-domains. +Module `workarounds` tweaks resolver behavior on specific broken sub-domains. Currently it mainly disables case randomization. .. code-block:: lua diff --git a/scripts/enable-repo-cznic-labs.sh b/scripts/enable-repo-cznic-labs.sh new file mode 100755 index 00000000..cbc64c68 --- /dev/null +++ b/scripts/enable-repo-cznic-labs.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# enable CZ.NIC Labs Debian/Ubuntu repos - see https://pkg.labs.nic.cz/doc/ +set -e + +REPO=$1 +if [ -z "${REPO}" ]; then + echo "usage: $0 REPOSITORY" + echo -e "\nPlease see: https://pkg.labs.nic.cz/doc/" + exit 1 +fi +if [ "$(whoami)" != "root" ]; then + echo "ERROR: this script must be run as ROOT" + echo -e "\nTry running with sudo:\n\n sudo $0\n" + exit 2 +fi + +# update apt metadata and install requirements +apt-get update +apt-get install -y apt-transport-https ca-certificates lsb-release wget + +DISTRO=$(lsb_release -si | tr '[:upper:]' '[:lower:]') +CODENAME=$(lsb_release -sc) + +echo "Enabling $REPO repo on $DISTRO $CODENAME..." +# get repo signing key +wget -O /usr/share/keyrings/cznic-labs-pkg.gpg https://pkg.labs.nic.cz/gpg +# create repo entry +echo "deb [signed-by=/usr/share/keyrings/cznic-labs-pkg.gpg] https://pkg.labs.nic.cz/$REPO $CODENAME main" > /etc/apt/sources.list.d/cznic-labs-$REPO.list +# update apt metadata from the new repo +apt-get update diff --git a/scripts/enable-repo.py b/scripts/enable-repo.py deleted file mode 100755 index 2b9319eb..00000000 --- a/scripts/enable-repo.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/python3 -""" -Enable Knot Resolver upstream repo on current system. - -Requires python3-distro. - -Run this as ROOT. -""" - -import argparse -import distro as distro_ -from pathlib import Path -from subprocess import run, PIPE -import sys - - -REPO_CHOICES = ['latest', 'testing', 'build'] - - -def detect_distro(): - return '%s-%s' % (distro_.id(), distro_.version()) - - -def parse_distro(distro): - id_, _, ver_ = distro.rpartition('-') - return id_, ver_ - - -def distro2obs(distro): - distro_id, distro_ver = parse_distro(distro) - if not str(distro_ver): - return None - if distro_id == 'debian': - return 'Debian_%s' % distro_ver - if distro_id == 'ubuntu': - return 'xUbuntu_%s' % distro_ver - if distro_id == 'opensuse-leap': - return 'openSUSE_Leap_%s' % distro_ver - return None - - -def show_info(): - print("distro ID: %s" % detect_distro()) - print("distro name: %s %s" % (distro_.name(), distro_.version(pretty=True))) - - -def enable_deb_repo(repo_id, distro): - obs_distro = distro2obs(distro) - if not obs_distro: - return fail('unsupported Debian-based distro: %s' % distro) - - requires = ['python3-requests', 'gnupg'] - print("installing required packages: %s" % ' '.join(requires)) - p = run(['apt', 'install', '-y'] + requires) - import requests - - sources_p = Path('/etc/apt/sources.list.d/%s.list' % repo_id) - sources_txt = 'deb http://download.opensuse.org/repositories/home:/CZ-NIC:/%s/%s/ /' % (repo_id, obs_distro) - key_url = 'https://download.opensuse.org/repositories/home:CZ-NIC:%s/%s/Release.key' % (repo_id, obs_distro) - print("writing sources list: %s" % sources_p) - with sources_p.open('wt') as f: - f.write(sources_txt + '\n') - print(sources_txt) - print("fetching key: %s" % key_url) - r = requests.get(key_url) - if not r.ok: - return fail('failed to fetch repo key: %s' % key_url) - key_txt = r.content.decode('utf-8') - print("adding key using `apt-key add`") - p = run(['apt-key', 'add', '-'], input=key_txt, encoding='utf-8') - if p.returncode != 0: - print('apt-key add failed :(') - run(['apt', 'update']) - print("%s repo added" % repo_id) - - -def enable_suse_repo(repo_id, distro): - obs_distro = distro2obs(distro) - if not obs_distro: - return fail('unsupported SUSE distro: %s' % distro) - - repo_url = 'https://download.opensuse.org/repositories/home:CZ-NIC:{repo}/{distro}/home:CZ-NIC:{repo}.repo'.format( - repo=repo_id, distro=obs_distro) - print("adding OBS repo: %s" % repo_url) - run(['zypper', 'addrepo', repo_url]) - run(['zypper', '--no-gpg-checks', 'refresh']) - - -def enable_repo(repo_id, distro): - distro_id, distro_ver = parse_distro(distro) - print("enable %s repo on %s" % (repo_id, distro)) - - if distro_id in ['debian', 'ubuntu']: - enable_deb_repo(repo_id, distro) - elif distro_id == 'opensuse-leap': - enable_suse_repo(repo_id, distro) - elif distro_id == 'arch': - print("no external repo needed on %s" % distro_id) - else: - fail("unsupported distro: %s" % distro_id) - - -def fail(msg): - print(msg) - sys.exit(1) - - -def main(): - parser = argparse.ArgumentParser( - description="Enable Knot Resolver repo on this system") - parser.add_argument('repo', choices=REPO_CHOICES, nargs='?', default=REPO_CHOICES[0], - help="repo to enable") - parser.add_argument('-d', '--distro', type=str, - help="override target distro (DISTRO-VERSION format)") - parser.add_argument('-i', '--info', action='store_true', - help="show distro information and exit") - - args = parser.parse_args() - if args.info: - show_info() - return - - distro = args.distro - if not distro: - distro = detect_distro() - - repo = 'knot-resolver-%s' % args.repo - enable_repo(repo, distro) - - -if __name__ == '__main__': - main() diff --git a/tests/config/meson.build b/tests/config/meson.build index dc345a88..2a9e2487 100644 --- a/tests/config/meson.build +++ b/tests/config/meson.build @@ -22,8 +22,11 @@ foreach config_test : config_tests conftest_env.prepend('PATH', sbin_dir) conftest_env.set('KRESD_NO_LISTEN', '1') conftest_env.set('SOURCE_PATH', meson.current_source_dir()) - conftest_env.set( - 'TEST_FILE', '@0@/@1@'.format(meson.source_root(), config_test[1][0])) + if meson.version().version_compare('>=1.4') + conftest_env.set('TEST_FILE', '@0@'.format(config_test[1][0].full_path())) + else + conftest_env.set('TEST_FILE', '@0@/@1@'.format(meson.source_root(), config_test[1][0])) + endif test( 'config.' + config_test[0], |